diff --git a/DEPS b/DEPS index c0b8a6a..112d1069 100644 --- a/DEPS +++ b/DEPS
@@ -167,11 +167,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': '106e86516480c7519becf7da1c4e6e42040b62a3', + 'skia_revision': '27c4369651a868d6d0dcf367456efc39eeaf2c98', # 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': 'ddd5171bc2abfa9eff5f957c2279268c324cef8c', + 'v8_revision': '8be37a6d57ad9559e0a794b414a9d869f2b0a1a7', # 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. @@ -179,7 +179,7 @@ # 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': 'a21362f5a6ae8929899fb54fb646f395d141d98b', + 'angle_revision': '741c0aa6f5a12659520437b381c6f522c5ee6d77', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -862,7 +862,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'af9c6ce85491f6cb57b6919cb8fb878020fc1612', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '4d4275fc6a5d6f61bd93b654a158f3d696700ab5', 'condition': 'checkout_linux', }, @@ -887,7 +887,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e3703bb8b8af7978ecf1bdfbfe8c3e6c910be8bc', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '12265a8f7de02667caa3961b95760c0f37d743dd', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1280,7 +1280,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f5952b718415b26217c79b11afccfe850d281f96', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'dbcebd185da399ec3ea42630c8ed38d24d504b10', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1470,7 +1470,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '2701c130839edbeb226735b0775966b6423d9e83', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '5740f3e2b8fdee7288748907920d9fabe948e895', + Var('webrtc_git') + '/src.git' + '@' + '80f53b785b377ab4c781c36d371d84241c7d9b80', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/WATCHLISTS b/WATCHLISTS index e4e33bf..5d61804 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2214,7 +2214,7 @@ 'certificate_transparency': ['certificate-transparency-chrome@googlegroups.com', 'martijn+crwatch@martijnc.be', 'rsleevi+watch@chromium.org'], - 'chrome_cleaner': ['joenotcharles+watch@google.com'], + 'chrome_cleaner': ['joenotcharles+watch@chromium.org'], 'chrome_elf': ['caitkp+watch@chromium.org', 'pmonette+watch@chromium.org'], 'chrome_grc': ['chrome-grc-reviews@chromium.org'],
diff --git a/android_webview/browser/tracing/aw_tracing_controller.cc b/android_webview/browser/tracing/aw_tracing_controller.cc index 49910984..f51e7ac 100644 --- a/android_webview/browser/tracing/aw_tracing_controller.cc +++ b/android_webview/browser/tracing/aw_tracing_controller.cc
@@ -43,7 +43,7 @@ void ReceivedTraceFinalContents() override { base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(completed_callback_))); + std::move(completed_callback_)); } void ReceiveTraceChunk(std::unique_ptr<std::string> chunk) override { @@ -88,20 +88,21 @@ base::android::ConvertJavaStringToUTF8(env, jcategories); base::trace_event::TraceConfig trace_config( categories, static_cast<base::trace_event::TraceRecordMode>(jmode)); - // Required for filtering out potential PII. - trace_config.EnableArgumentFilter(); return content::TracingController::GetInstance()->StartTracing( trace_config, content::TracingController::StartTracingDoneCallback()); } bool AwTracingController::StopAndFlush(JNIEnv* env, const JavaParamRef<jobject>& obj) { + // privacy_filtering_enabled=true is required for filtering out potential PII. return content::TracingController::GetInstance()->StopTracing( AwTraceDataEndpoint::Create( base::BindRepeating(&AwTracingController::OnTraceDataReceived, weak_factory_.GetWeakPtr()), base::BindOnce(&AwTracingController::OnTraceDataComplete, - weak_factory_.GetWeakPtr()))); + weak_factory_.GetWeakPtr())), + /*agent_label=*/"", + /*privacy_filtering_enabled=*/true); } void AwTracingController::OnTraceDataComplete() {
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index f72b6fd..900846c 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -211,6 +211,8 @@ // TODO(https://crbug.com/963653): SmsReceiver is not yet supported on // WebView. features.DisableIfNotSet(::features::kSmsReceiver); + + features.DisableIfNotSet(::features::kWebXr); } android_webview::RegisterPathProvider();
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt index 237cc53..6f0a395 100644 --- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt +++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -55,13 +55,14 @@ # permissions API (crbug.com/490120), presentation API (crbug.com/521319), # share API (crbug.com/765923), custom scheme handlers (crbug.com/589502), -# media session API (crbug.com/925997), and sms API (crbug.com/963653) -# are not supported in webview. +# media session API (crbug.com/925997), sms API (crbug.com/963653), and WebXr +# API (crbug.com/1012899) are not supported in webview. interface Navigator getter mediaSession # crbug.com/925997 getter permissions # crbug.com/490120 getter presentation # crbug.com/521319 getter sms # crbug.com/963653 + getter xr # crbug.com/1012899 method registerProtocolHandler # crbug.com/589502 method unregisterProtocolHandler # crbug.com/589502 method share # crbug.com/765923 @@ -129,6 +130,31 @@ interface HTMLCanvasElement : HTMLElement method transferControlToOffscreen +# WebXR dependent interfaces are not supported on WebView crbug.com/1012899 +interface XRView +interface XRViewport +interface XR : EventTarget +interface XRFrame +interface XRRigidTransform +interface XRSpace : EventTarget +interface XRInputSourcesChangeEvent : Event +interface XRInputSource +interface XRWebGLLayer +interface XRInputSourceEvent : Event +interface XRViewerPose : XRPose +interface XRInputSourceArray +interface XRRenderState +interface XRPose +interface XRSession : EventTarget +interface XRReferenceSpaceEvent : Event +interface XRBoundedReferenceSpace : XRReferenceSpace +interface XRSessionEvent : Event +interface XRReferenceSpace : XRSpace +interface WebGLRenderingContext + method makeXRCompatible +interface WebGL2RenderingContext + method makeXRCompatible + [GLOBAL OBJECT] method openDatabase attribute eventSender # test only
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index d7e2cf15..ab1c431 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -3075,8 +3075,7 @@ EnableTabletMode(true); GetAppListTestHelper()->CheckVisibility(true); std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); EXPECT_TRUE(split_view_controller->InSplitViewMode());
diff --git a/ash/app_menu/notification_item_view.cc b/ash/app_menu/notification_item_view.cc index 2120ad4..f352705 100644 --- a/ash/app_menu/notification_item_view.cc +++ b/ash/app_menu/notification_item_view.cc
@@ -9,6 +9,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/text_elider.h" #include "ui/message_center/views/proportional_image_view.h" +#include "ui/views/animation/slide_out_controller.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" @@ -45,16 +46,15 @@ NotificationItemView::NotificationItemView( NotificationMenuView::Delegate* delegate, - message_center::SlideOutController::Delegate* slide_out_controller_delegate, + views::SlideOutControllerDelegate* slide_out_controller_delegate, const base::string16& title, const base::string16& message, const gfx::Image& icon, const std::string& notification_id) : delegate_(delegate), - slide_out_controller_( - std::make_unique<message_center::SlideOutController>( - this, - slide_out_controller_delegate)), + slide_out_controller_(std::make_unique<views::SlideOutController>( + this, + slide_out_controller_delegate)), title_(title), message_(message), notification_id_(notification_id) {
diff --git a/ash/app_menu/notification_item_view.h b/ash/app_menu/notification_item_view.h index 2c81a97..c949bb5 100644 --- a/ash/app_menu/notification_item_view.h +++ b/ash/app_menu/notification_item_view.h
@@ -11,7 +11,7 @@ #include "ash/app_menu/app_menu_export.h" #include "ash/app_menu/notification_menu_view.h" #include "base/strings/string16.h" -#include "ui/message_center/views/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller_delegate.h" #include "ui/views/view.h" namespace gfx { @@ -25,6 +25,7 @@ namespace views { class Label; +class SlideOutController; } namespace ash { @@ -32,13 +33,13 @@ // The view which contains the details of a notification. class APP_MENU_EXPORT NotificationItemView : public views::View { public: - NotificationItemView(NotificationMenuView::Delegate* delegate, - message_center::SlideOutController::Delegate* - slide_out_controller_delegate, - const base::string16& title, - const base::string16& message, - const gfx::Image& icon, - const std::string& notification_id); + NotificationItemView( + NotificationMenuView::Delegate* delegate, + views::SlideOutControllerDelegate* slide_out_controller_delegate, + const base::string16& title, + const base::string16& message, + const gfx::Image& icon, + const std::string& notification_id); ~NotificationItemView() override; @@ -79,7 +80,7 @@ NotificationMenuView::Delegate* const delegate_; // Controls the sideways gesture drag behavior. - std::unique_ptr<message_center::SlideOutController> slide_out_controller_; + std::unique_ptr<views::SlideOutController> slide_out_controller_; // Notification properties. base::string16 title_;
diff --git a/ash/app_menu/notification_menu_controller.h b/ash/app_menu/notification_menu_controller.h index 4714773..d6e622e 100644 --- a/ash/app_menu/notification_menu_controller.h +++ b/ash/app_menu/notification_menu_controller.h
@@ -10,7 +10,7 @@ #include "base/scoped_observer.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_observer.h" -#include "ui/message_center/views/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller_delegate.h" namespace views { class MenuItemView; @@ -25,7 +25,7 @@ // as notifications come and go. class APP_MENU_EXPORT NotificationMenuController : public message_center::MessageCenterObserver, - public message_center::SlideOutController::Delegate, + public views::SlideOutControllerDelegate, public NotificationMenuView::Delegate { public: NotificationMenuController(const std::string& app_id, @@ -40,7 +40,7 @@ void OnNotificationRemoved(const std::string& notification_id, bool by_user) override; - // message_center::SlideOutController::Delegate overrides: + // views::SlideOutControllerDelegate overrides: ui::Layer* GetSlideOutLayer() override; void OnSlideChanged(bool in_progress) override; void OnSlideOut() override;
diff --git a/ash/app_menu/notification_menu_view.cc b/ash/app_menu/notification_menu_view.cc index f3c8e44..872e7922 100644 --- a/ash/app_menu/notification_menu_view.cc +++ b/ash/app_menu/notification_menu_view.cc
@@ -22,7 +22,7 @@ NotificationMenuView::NotificationMenuView( Delegate* notification_item_view_delegate, - message_center::SlideOutController::Delegate* slide_out_controller_delegate, + views::SlideOutControllerDelegate* slide_out_controller_delegate, const std::string& app_id) : app_id_(app_id), notification_item_view_delegate_(notification_item_view_delegate),
diff --git a/ash/app_menu/notification_menu_view.h b/ash/app_menu/notification_menu_view.h index a785b6f..1c429d9 100644 --- a/ash/app_menu/notification_menu_view.h +++ b/ash/app_menu/notification_menu_view.h
@@ -9,7 +9,6 @@ #include <string> #include "ash/app_menu/app_menu_export.h" -#include "ui/message_center/views/slide_out_controller.h" #include "ui/views/view.h" namespace message_center { @@ -18,6 +17,7 @@ namespace views { class MenuSeparator; +class SlideOutControllerDelegate; } namespace ash { @@ -43,10 +43,10 @@ virtual void OnOverflowAddedOrRemoved() = 0; }; - NotificationMenuView(Delegate* notification_item_view_delegate, - message_center::SlideOutController::Delegate* - slide_out_controller_delegate, - const std::string& app_id); + NotificationMenuView( + Delegate* notification_item_view_delegate, + views::SlideOutControllerDelegate* slide_out_controller_delegate, + const std::string& app_id); ~NotificationMenuView() override; // views::View: @@ -103,8 +103,7 @@ NotificationMenuView::Delegate* const notification_item_view_delegate_; // Owned by AppMenuModelAdapter. - message_center::SlideOutController::Delegate* const - slide_out_controller_delegate_; + views::SlideOutControllerDelegate* const slide_out_controller_delegate_; // The deque of NotificationItemViews. The front item in the deque is the view // which is shown.
diff --git a/ash/app_menu/notification_menu_view_unittest.cc b/ash/app_menu/notification_menu_view_unittest.cc index 111c2b31..545eab01 100644 --- a/ash/app_menu/notification_menu_view_unittest.cc +++ b/ash/app_menu/notification_menu_view_unittest.cc
@@ -28,9 +28,8 @@ // The app id used in tests. constexpr char kTestAppId[] = "test-app-id"; -class MockNotificationMenuController - : public message_center::SlideOutController::Delegate, - public NotificationMenuView::Delegate { +class MockNotificationMenuController : public views::SlideOutControllerDelegate, + public NotificationMenuView::Delegate { public: MockNotificationMenuController() = default; ~MockNotificationMenuController() override = default;
diff --git a/ash/display/screen_orientation_controller.cc b/ash/display/screen_orientation_controller.cc index 5f63ed91..1ba237f 100644 --- a/ash/display/screen_orientation_controller.cc +++ b/ash/display/screen_orientation_controller.cc
@@ -162,7 +162,8 @@ OrientationLockType GetCurrentScreenOrientation() { // ScreenOrientationController might be nullptr during shutdown. // TODO(xdai|sammiequon): See if we can reorder so that users of the function - // (split_view_controller) get shutddown before screen orientation controller. + // |SplitViewController::Get| get shutdown before screen orientation + // controller. if (!Shell::Get()->screen_orientation_controller()) return OrientationLockType::kAny; return Shell::Get()->screen_orientation_controller()->GetCurrentOrientation(); @@ -217,11 +218,11 @@ user_rotation_(display::Display::ROTATE_0), current_rotation_(display::Display::ROTATE_0) { Shell::Get()->tablet_mode_controller()->AddObserver(this); - Shell::Get()->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); } ScreenOrientationController::~ScreenOrientationController() { - Shell::Get()->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); Shell::Get()->tablet_mode_controller()->RemoveObserver(this); AccelerometerReader::GetInstance()->RemoveObserver(this); Shell::Get()->window_tree_host_manager()->RemoveObserver(this); @@ -598,16 +599,14 @@ if (!ScreenOrientationProviderSupported()) return; - Shell* shell = Shell::Get(); - - if (shell->split_view_controller()->InTabletSplitViewMode()) { + if (SplitViewController::Get()->InTabletSplitViewMode()) { // While split view is enabled, ignore rotation lock set by windows. LockRotationToOrientation(user_locked_orientation_); return; } MruWindowTracker::WindowList mru_windows( - shell->mru_window_tracker()->BuildMruWindowList(kActiveDesk)); + Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk)); for (auto* window : mru_windows) { if (!window->TargetVisibility())
diff --git a/ash/display/screen_orientation_controller_unittest.cc b/ash/display/screen_orientation_controller_unittest.cc index e3ef1af..dace31f 100644 --- a/ash/display/screen_orientation_controller_unittest.cc +++ b/ash/display/screen_orientation_controller_unittest.cc
@@ -343,13 +343,13 @@ Lock(child_window2.get(), OrientationLockType::kPortrait); ASSERT_TRUE(RotationLocked()); - Shell::Get()->split_view_controller()->SnapWindow(focus_window1.get(), - SplitViewController::LEFT); - Shell::Get()->split_view_controller()->SnapWindow(focus_window1.get(), - SplitViewController::RIGHT); + SplitViewController::Get()->SnapWindow(focus_window1.get(), + SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(focus_window1.get(), + SplitViewController::RIGHT); EXPECT_FALSE(RotationLocked()); - Shell::Get()->split_view_controller()->EndSplitView(); + SplitViewController::Get()->EndSplitView(); EXPECT_TRUE(RotationLocked()); }
diff --git a/ash/home_screen/drag_window_from_shelf_controller.cc b/ash/home_screen/drag_window_from_shelf_controller.cc index d69a6c0..9e75edc 100644 --- a/ash/home_screen/drag_window_from_shelf_controller.cc +++ b/ash/home_screen/drag_window_from_shelf_controller.cc
@@ -87,8 +87,7 @@ drag_started_ = false; OverviewController* overview_controller = Shell::Get()->overview_controller(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); const bool in_overview = overview_controller->InOverviewSession(); const bool in_splitview = split_view_controller->InSplitViewMode(); @@ -152,8 +151,7 @@ // If the dragged window is one of the snapped window in splitview, it needs // to be detached from splitview before start dragging. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->OnWindowDragStarted(window_); // Note SplitViewController::OnWindowDragStarted() may open overview. OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -177,12 +175,11 @@ should_drop_window_in_overview, /*snap=*/snap_position != SplitViewController::NONE); } - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode() || snap_position != SplitViewController::NONE) { - Shell::Get()->split_view_controller()->OnWindowDragEnded( - window_, snap_position, location_in_screen); + split_view_controller->OnWindowDragEnded(window_, snap_position, + location_in_screen); } Shell::Get()->home_screen_controller()->OnWindowDragEnded(); @@ -286,7 +283,7 @@ base::Optional<float> velocity_y) const { return velocity_y.has_value() && *velocity_y < 0 && std::abs(*velocity_y) >= kVelocityToHomeScreenThreshold && - !Shell::Get()->split_view_controller()->InSplitViewMode(); + !SplitViewController::Get()->InSplitViewMode(); } SplitViewController::SnapPosition @@ -310,8 +307,7 @@ if (ShouldGoToHomeScreen(velocity_y)) return false; - const bool in_splitview = - Shell::Get()->split_view_controller()->InSplitViewMode(); + const bool in_splitview = SplitViewController::Get()->InSplitViewMode(); if (!in_splitview && ShouldRestoreToOriginalBounds(location_in_screen)) { return false; }
diff --git a/ash/home_screen/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc index b77d5f6..427ff94 100644 --- a/ash/home_screen/home_launcher_gesture_handler.cc +++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -156,8 +156,7 @@ // Returns the window of the widget of the split view divider. May be nullptr if // split view is not active. aura::Window* GetDividerWindow() { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (!split_view_controller->InSplitViewMode()) return nullptr; return split_view_controller->split_view_divider() @@ -181,8 +180,7 @@ return nullptr; aura::Window* window = nullptr; - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); const bool is_in_splitview = split_view_controller->InSplitViewMode(); const bool is_in_overview = Shell::Get()->overview_controller()->InOverviewSession(); @@ -536,9 +534,9 @@ } // Explicitly exit split view if two windows are snapped. - if (is_final_state_show && Shell::Get()->split_view_controller()->state() == + if (is_final_state_show && SplitViewController::Get()->state() == SplitViewController::State::kBothSnapped) { - Shell::Get()->split_view_controller()->EndSplitView(); + SplitViewController::Get()->EndSplitView(); } if (is_final_state_show) { @@ -795,8 +793,7 @@ Mode mode, aura::Window* window, base::Optional<gfx::Point> location_in_screen) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); overview_active_on_gesture_start_ = Shell::Get()->overview_controller()->InOverviewSession(); const bool split_view_active = split_view_controller->InSplitViewMode();
diff --git a/ash/home_screen/home_launcher_gesture_handler_unittest.cc b/ash/home_screen/home_launcher_gesture_handler_unittest.cc index 8a9c55f..7eb7468 100644 --- a/ash/home_screen/home_launcher_gesture_handler_unittest.cc +++ b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
@@ -303,8 +303,7 @@ // Snap one window and leave overview mode open with the other window. OverviewController* overview_controller = Shell::Get()->overview_controller(); overview_controller->StartOverview(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); ASSERT_TRUE(overview_controller->InOverviewSession()); ASSERT_TRUE(split_view_controller->InSplitViewMode()); @@ -350,8 +349,7 @@ auto window2 = CreateWindowForTesting(); // Snap two windows to start. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); ASSERT_TRUE(split_view_controller->InSplitViewMode()); @@ -464,8 +462,7 @@ // Test in splitview, depends on the drag position, the active dragged window // might be different. auto window2 = CreateWindowForTesting(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview, @@ -514,8 +511,7 @@ EXPECT_TRUE(window3->IsVisible()); // In splitview mode, the snapped windows will stay visible during dragging. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview, @@ -579,8 +575,7 @@ // In splitview + overview case, drag from shelf in the overview side of the // screen also does nothing. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); overview_controller->StartOverview(); @@ -649,8 +644,7 @@ EXPECT_TRUE(overview_controller->InOverviewSession()); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 200), base::nullopt); EXPECT_TRUE(overview_controller->InOverviewSession()); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); EXPECT_TRUE(split_view_controller->InSplitViewMode()); EXPECT_TRUE(split_view_controller->IsWindowInSplitView(window1.get())); EXPECT_FALSE(window2->IsVisible()); @@ -755,8 +749,7 @@ // The same thing should happen if splitview mode is active. auto window2 = CreateWindowForTesting(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview, @@ -816,8 +809,7 @@ auto window1 = CreateWindowForTesting(); auto window2 = CreateWindowForTesting(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); OverviewController* overview_controller = Shell::Get()->overview_controller(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc index befa63602..1ac0f8a 100644 --- a/ash/home_screen/home_screen_controller.cc +++ b/ash/home_screen/home_screen_controller.cc
@@ -87,9 +87,9 @@ return true; } - if (Shell::Get()->split_view_controller()->InSplitViewMode()) { + if (SplitViewController::Get()->InSplitViewMode()) { // End split view mode. - Shell::Get()->split_view_controller()->EndSplitView( + SplitViewController::Get()->EndSplitView( SplitViewController::EndReason::kHomeLauncherPressed); return true; }
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc index 44428a1..69d9c4e 100644 --- a/ash/login/ui/login_expanded_public_account_view.cc +++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -549,13 +549,18 @@ selected_language_item_ = item; } + LoginMenuView* old_language_menu_view = language_menu_view_; + language_menu_view_ = new LoginMenuView( language_items_, language_selection_ /*anchor_view*/, language_selection_ /*bubble_opener*/, base::BindRepeating(&RightPaneView::OnLanguageSelected, weak_factory_.GetWeakPtr())); - login_views_utils::GetTopLevelParentView(this)->AddChildView( + login_views_utils::GetBubbleContainer(this)->AddChildView( language_menu_view_); + + if (old_language_menu_view) + delete old_language_menu_view; } void PopulateKeyboardItems( @@ -573,13 +578,18 @@ selected_keyboard_item_ = item; } + LoginMenuView* old_keyboard_menu_view = keyboard_menu_view_; + keyboard_menu_view_ = new LoginMenuView( keyboard_items_, keyboard_selection_ /*anchor_view*/, keyboard_selection_ /*bubble_opener*/, base::BindRepeating(&RightPaneView::OnKeyboardSelected, weak_factory_.GetWeakPtr())); - login_views_utils::GetTopLevelParentView(this)->AddChildView( + login_views_utils::GetBubbleContainer(this)->AddChildView( keyboard_menu_view_); + + if (old_keyboard_menu_view) + delete old_keyboard_menu_view; } LoginBaseBubbleView* GetLanguageMenuView() { return language_menu_view_; } @@ -590,6 +600,10 @@ void Reset() { show_advanced_changed_by_user_ = false; language_changed_by_user_ = false; + if (language_menu_view_ && language_menu_view_->GetVisible()) + language_menu_view_->Hide(); + if (keyboard_menu_view_ && keyboard_menu_view_->GetVisible()) + keyboard_menu_view_->Hide(); } private:
diff --git a/ash/login/ui/login_user_view.cc b/ash/login/ui/login_user_view.cc index 5dde204..770636e 100644 --- a/ash/login/ui/login_user_view.cc +++ b/ash/login/ui/login_user_view.cc
@@ -549,7 +549,7 @@ menu_->GetBubbleOpener() && menu_->GetBubbleOpener()->HasFocus(); if (!menu_->parent()) - login_views_utils::GetTopLevelParentView(this)->AddChildView(menu_); + login_views_utils::GetBubbleContainer(this)->AddChildView(menu_); // Reset state in case the remove-user button was clicked once previously. menu_->ResetState();
diff --git a/ash/login/ui/views_utils.cc b/ash/login/ui/views_utils.cc index 7032d08..1355bb4 100644 --- a/ash/login/ui/views_utils.cc +++ b/ash/login/ui/views_utils.cc
@@ -4,13 +4,47 @@ #include "ash/login/ui/views_utils.h" +#include <algorithm> +#include <memory> + #include "ash/login/ui/non_accessible_view.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/view_targeter_delegate.h" #include "ui/views/widget/widget.h" namespace ash { + +namespace { + +class ContainerView : public NonAccessibleView, + public views::ViewTargeterDelegate { + public: + ContainerView() { + SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); + } + ~ContainerView() override = default; + + // views::ViewTargeterDelegate: + bool DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const override { + const auto& children = target->children(); + const auto hits_child = [target, rect](const views::View* child) { + gfx::RectF child_rect(rect); + views::View::ConvertRectToTarget(target, child, &child_rect); + return child->GetVisible() && + child->HitTestRect(gfx::ToEnclosingRect(child_rect)); + }; + return std::any_of(children.cbegin(), children.cend(), hits_child); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ContainerView); +}; + +} // namespace + namespace login_views_utils { std::unique_ptr<views::View> WrapViewForPreferredSize( @@ -75,13 +109,28 @@ return label; } -views::View* GetTopLevelParentView(views::View* view) { +views::View* GetBubbleContainer(views::View* view) { views::View* v = view; - while (v->parent() != nullptr) v = v->parent(); - return v; + views::View* root_view = v; + // An arbitrary id that no other child of root view should use. + const int kMenuContainerId = 1000; + views::View* container = nullptr; + for (auto* child : root_view->children()) { + if (child->GetID() == kMenuContainerId) { + container = child; + break; + } + } + + if (!container) { + container = root_view->AddChildView(std::make_unique<ContainerView>()); + container->SetID(kMenuContainerId); + } + + return container; } } // namespace login_views_utils
diff --git a/ash/login/ui/views_utils.h b/ash/login/ui/views_utils.h index 95945d8..729ff1a9 100644 --- a/ash/login/ui/views_utils.h +++ b/ash/login/ui/views_utils.h
@@ -31,8 +31,8 @@ // Creates a standard text label for use in the login bubbles. views::Label* CreateBubbleLabel(const base::string16& message, SkColor color); -// Get the topmost level parent view for |view|. -views::View* GetTopLevelParentView(views::View* view); +// Get the bubble container for |view| to place a LoginBaseBubbleView. +views::View* GetBubbleContainer(views::View* view); } // namespace login_views_utils
diff --git a/ash/magnifier/docked_magnifier_controller_impl.cc b/ash/magnifier/docked_magnifier_controller_impl.cc index aa252d2..e8f983b 100644 --- a/ash/magnifier/docked_magnifier_controller_impl.cc +++ b/ash/magnifier/docked_magnifier_controller_impl.cc
@@ -625,7 +625,7 @@ Shell* shell = Shell::Get(); auto* overview_controller = shell->overview_controller(); if (overview_controller->InOverviewSession()) { - auto* split_view_controller = shell->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode()) { // In this case, we're in a single-split-view mode, i.e. a window is // snapped to one side of the split view, while the other side has
diff --git a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc index d796d33..9e04c3f 100644 --- a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc +++ b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
@@ -410,7 +410,7 @@ CreateTestWindowInShell(SK_ColorWHITE, 100, gfx::Rect(0, 0, 200, 200))); WindowState::Get(window.get())->Maximize(); - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); EXPECT_EQ(split_view_controller->state(), SplitViewController::State::kNoSnap); EXPECT_EQ(split_view_controller->InSplitViewMode(), false); @@ -460,7 +460,7 @@ overview_controller->StartOverview(); EXPECT_TRUE(overview_controller->InOverviewSession()); - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); EXPECT_EQ(split_view_controller->InSplitViewMode(), false); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
diff --git a/ash/metrics/histogram_macros.cc b/ash/metrics/histogram_macros.cc index 20ca3bfb..8f3e126 100644 --- a/ash/metrics/histogram_macros.cc +++ b/ash/metrics/histogram_macros.cc
@@ -16,8 +16,7 @@ } bool IsInSplitView() { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); return split_view_controller && split_view_controller->InSplitViewMode(); }
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 20d5cb77..5e06d99 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -58,6 +58,7 @@ #include "ash/wm/lock_layout_manager.h" #include "ash/wm/overlay_layout_manager.h" #include "ash/wm/root_window_layout_manager.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/stacking_controller.h" #include "ash/wm/switchable_windows.h" #include "ash/wm/system_modal_container_layout_manager.h" @@ -782,6 +783,15 @@ void RootWindowController::Init(RootWindowType root_window_type) { aura::Window* root_window = GetRootWindow(); + // Create |split_view_controller_| for the primary display only. + // TODO(crbug.com/970013): If the + // |ash::features::kMultiDisplayOverviewAndSplitView| feature flag is enabled, + // create |split_view_controller_| for every display. + display::Screen* screen = display::Screen::GetScreen(); + if (screen->GetDisplayNearestWindow(root_window).id() == + screen->GetPrimaryDisplay().id()) { + split_view_controller_ = std::make_unique<SplitViewController>(); + } Shell* shell = Shell::Get(); shell->InitRootWindow(root_window); auto old_targeter =
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 38dfbc5..631f5410 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h
@@ -46,6 +46,7 @@ class RootWindowLayoutManager; class Shelf; class ShelfLayoutManager; +class SplitViewController; class StackingController; class StatusAreaWidget; class SystemModalContainerLayoutManager; @@ -100,6 +101,10 @@ aura::Window* GetRootWindow(); const aura::Window* GetRootWindow() const; + SplitViewController* split_view_controller() const { + return split_view_controller_.get(); + } + Shelf* shelf() const { return shelf_.get(); } TouchHudDebug* touch_hud_debug() const { return touch_hud_debug_; } @@ -284,6 +289,8 @@ std::unique_ptr<StackingController> stacking_controller_; + std::unique_ptr<SplitViewController> split_view_controller_; + // The shelf controller for this root window. Exists for the entire lifetime // of the RootWindowController so that it is safe for observers to be added // to it during construction of the shelf widget and status tray.
diff --git a/ash/shelf/scrollable_shelf_view.cc b/ash/shelf/scrollable_shelf_view.cc index faad0f02..163324e 100644 --- a/ash/shelf/scrollable_shelf_view.cc +++ b/ash/shelf/scrollable_shelf_view.cc
@@ -12,6 +12,7 @@ #include "ash/system/status_area_widget.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/numerics/ranges.h" +#include "chromeos/constants/chromeos_switches.h" #include "ui/compositor/paint_recorder.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/geometry/insets.h" @@ -65,16 +66,21 @@ return ShelfConfig::Get()->button_size() / 2; } -// Returns the padding between the app icon and the end of the ScrollableShelf. -int GetAppIconEndPadding() { +bool IsInTabletMode() { TabletModeController* tablet_mode_controller = Shell::Get()->tablet_mode_controller(); // TabletModeController is destructed before ScrollableShelfView. if (!tablet_mode_controller || !tablet_mode_controller->InTabletMode()) - return 0; + return false; - return 4; + return true; +} + +// Returns the padding between the app icon and the end of the ScrollableShelf. +int GetAppIconEndPadding() { + return (chromeos::switches::ShouldShowShelfHotseat() && IsInTabletMode()) ? 4 + : 0; } } // namespace @@ -200,6 +206,57 @@ }; //////////////////////////////////////////////////////////////////////////////// +// ScrollableShelfContainerView + +class ScrollableShelfContainerView : public ShelfContainerView, + public views::ViewTargeterDelegate { + public: + explicit ScrollableShelfContainerView( + ScrollableShelfView* scrollable_shelf_view) + : ShelfContainerView(scrollable_shelf_view->shelf_view()), + scrollable_shelf_view_(scrollable_shelf_view) { + SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); + } + ~ScrollableShelfContainerView() override = default; + + private: + // views::View: + void Layout() override; + + // views::ViewTargeterDelegate: + bool DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const override; + + ScrollableShelfView* scrollable_shelf_view_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(ScrollableShelfContainerView); +}; + +void ScrollableShelfContainerView::Layout() { + // Should not use ShelfView::GetPreferredSize in replace of + // CalculateIdealSize. Because ShelfView::CalculatePreferredSize relies on the + // bounds of app icon. Meanwhile, the icon's bounds may be updated by + // animation. + const gfx::Rect ideal_bounds = gfx::Rect(CalculateIdealSize()); + + const gfx::Rect local_bounds = GetLocalBounds(); + gfx::Rect shelf_view_bounds = + local_bounds.Contains(ideal_bounds) ? local_bounds : ideal_bounds; + shelf_view_->SetBoundsRect(shelf_view_bounds); +} + +bool ScrollableShelfContainerView::DoesIntersectRect( + const views::View* target, + const gfx::Rect& rect) const { + // This view's layer is clipped. So the view should only handle the events + // within the area after cilp. + + gfx::RectF bounds = gfx::RectF(scrollable_shelf_view_->visible_space()); + views::View::ConvertRectToTarget(scrollable_shelf_view_, this, &bounds); + return ToEnclosedRect(bounds).Contains(rect); +} + +//////////////////////////////////////////////////////////////////////////////// // ScrollableShelfFocusSearch class ScrollableShelfFocusSearch : public views::FocusSearch { @@ -292,7 +349,7 @@ // within the overlapping zone between the arrow button's tapping area and // the bounds of |shelf_container_view_|. shelf_container_view_ = - AddChildView(std::make_unique<ShelfContainerView>(shelf_view_)); + AddChildView(std::make_unique<ScrollableShelfContainerView>(this)); shelf_container_view_->Initialize(); // Initialize the left arrow button. @@ -560,32 +617,10 @@ right_arrow_bounds.ClampToCenteredSize(arrow_button_size); } - // The layout offset before/after |shelf_container_view_|. - int shelf_container_before_offset = 0; - int shelf_container_after_offset = 0; - - if (layout_strategy_ == kNotShowArrowButtons) { - // Paddings are within the shelf view. It makes sure that |shelf_view_|'s - // bounds are not changed under this layout strategy. It facilitates - // |shelf_view_| to create bounds animations when adding/removing app icons. - shelf_view_->set_app_icons_layout_offset(before_padding); - } else { - shelf_container_before_offset = before_padding; - shelf_container_after_offset = after_padding; - shelf_view_->set_app_icons_layout_offset(0); - } - - shelf_container_bounds.Inset( - shelf_container_before_offset + - (left_arrow_bounds.IsEmpty() ? GetAppIconEndPadding() - : kArrowButtonGroupWidth) - - ShelfConfig::Get()->scrollable_shelf_ripple_padding(), - 0, - shelf_container_after_offset + - (right_arrow_bounds.IsEmpty() ? GetAppIconEndPadding() - : kArrowButtonGroupWidth) - - ShelfConfig::Get()->scrollable_shelf_ripple_padding(), - 0); + // Paddings are within the shelf view. It makes sure that |shelf_view_|'s + // bounds are never changed. + shelf_view_->set_app_icons_layout_offset(before_padding + + GetAppIconEndPadding()); // Adjust the bounds when not showing in the horizontal // alignment.tShelf()->IsHorizontalAlignment()) { @@ -636,32 +671,14 @@ // Layout |shelf_container_view_|. shelf_container_view_->SetBoundsRect(shelf_container_bounds); - // When the left button shows, the origin of |shelf_container_view_| changes. - // So translate |shelf_container_view| to show the shelf view correctly. - gfx::Vector2d translate_vector; - if (!left_arrow_bounds.IsEmpty()) { - translate_vector = - GetShelf()->IsHorizontalAlignment() - ? gfx::Vector2d(shelf_container_bounds.x() - - GetAppIconEndPadding() - before_padding, - 0) - : gfx::Vector2d(0, shelf_container_bounds.y() - - GetAppIconEndPadding() - before_padding); - } + // Updates the clip rectangle of |shelf_container_view_|. Note that + // |shelf_container_view_|'s bounds are the same with ScrollableShelfView's. + // It is why we can use |visible_space_| directly without coordinate + // transformation. + UpdateVisibleSpace(); + shelf_container_view_->layer()->SetClipRect(visible_space_); - // If |layout_strategy_| is kShowLeftArrowButton, apply extra translation - // offset on |shelf_view_|, which assures the enough space for the ripple - // ring of the last shelf item. - if (layout_strategy_ == kShowLeftArrowButton) { - translate_vector += - GetShelf()->IsHorizontalAlignment() - ? gfx::Vector2d( - ShelfConfig::Get()->scrollable_shelf_ripple_padding(), 0) - : gfx::Vector2d( - 0, ShelfConfig::Get()->scrollable_shelf_ripple_padding()); - } - - gfx::Vector2dF total_offset = scroll_offset_ + translate_vector; + gfx::Vector2dF total_offset = scroll_offset_; if (ShouldAdaptToRTL()) total_offset = -total_offset; @@ -751,13 +768,15 @@ return false; const gfx::Rect screen_bounds = view->GetBoundsInScreen(); - const gfx::Rect visible_bounds = shelf_container_view_->GetBoundsInScreen(); - return visible_bounds.Contains(screen_bounds); + gfx::Rect visible_bounds_in_screen = visible_space_; + views::View::ConvertRectToScreen(this, &visible_bounds_in_screen); + + return visible_bounds_in_screen.Contains(screen_bounds); } bool ScrollableShelfView::ShouldHideTooltip( const gfx::Point& cursor_location) const { - return !available_space_.Contains(cursor_location); + return !visible_space_.Contains(cursor_location); } const std::vector<aura::Window*> ScrollableShelfView::GetOpenWindowsForView( @@ -1171,10 +1190,14 @@ } int actual_scroll_distance = GetActualScrollOffset(); + const gfx::Insets ripple_insets = CalculateRipplePaddingInsets(); + const int ripple_padding_sum = GetShelf()->IsHorizontalAlignment() + ? ripple_insets.width() + : ripple_insets.height(); int shelf_container_available_space = - (GetShelf()->IsHorizontalAlignment() ? shelf_container_view_->width() - : shelf_container_view_->height()) - - kGradientZoneLength; + (GetShelf()->IsHorizontalAlignment() ? visible_space_.width() + : visible_space_.height()) - + ripple_padding_sum; if (layout_strategy_ == kShowRightArrowButton || layout_strategy_ == kShowButtons) { first_tappable_app_index_ = actual_scroll_distance / GetUnit(); @@ -1264,4 +1287,47 @@ return offset; } +void ScrollableShelfView::UpdateVisibleSpace() { + const int before_padding = + (left_arrow_->GetVisible() ? kArrowButtonGroupWidth : 0); + const int after_padding = + (right_arrow_->GetVisible() ? kArrowButtonGroupWidth : 0); + + gfx::Insets visible_space_insets; + if (ShouldAdaptToRTL()) { + visible_space_insets = gfx::Insets(0, after_padding, 0, before_padding); + } else { + visible_space_insets = + GetShelf()->IsHorizontalAlignment() + ? gfx::Insets(0, before_padding, 0, after_padding) + : gfx::Insets(before_padding, 0, after_padding, 0); + } + visible_space_insets -= CalculateRipplePaddingInsets(); + + visible_space_ = + ShouldAdaptToRTL() ? available_space_ : GetMirroredRect(available_space_); + visible_space_.Inset(visible_space_insets); +} + +gfx::Insets ScrollableShelfView::CalculateRipplePaddingInsets() const { + // Indicates whether it is in tablet mode with hotseat enabled. + const bool in_hotseat_tablet = + chromeos::switches::ShouldShowShelfHotseat() && IsInTabletMode(); + + const int ripple_padding = + ShelfConfig::Get()->scrollable_shelf_ripple_padding(); + const int before_padding = + (in_hotseat_tablet && !left_arrow_->GetVisible()) ? 0 : ripple_padding; + const int after_padding = + (in_hotseat_tablet && !right_arrow_->GetVisible()) ? 0 : ripple_padding; + + if (ShouldAdaptToRTL()) + return gfx::Insets(0, after_padding, 0, before_padding); + else { + return GetShelf()->IsHorizontalAlignment() + ? gfx::Insets(0, before_padding, 0, after_padding) + : gfx::Insets(before_padding, 0, after_padding, 0); + } +} + } // namespace ash
diff --git a/ash/shelf/scrollable_shelf_view.h b/ash/shelf/scrollable_shelf_view.h index 40894a3..675a7b6 100644 --- a/ash/shelf/scrollable_shelf_view.h +++ b/ash/shelf/scrollable_shelf_view.h
@@ -86,6 +86,8 @@ default_last_focusable_child_ = default_last_focusable_child; } + const gfx::Rect& visible_space() const { return visible_space_; } + // Size of the arrow button. static int GetArrowButtonSize(); @@ -257,6 +259,12 @@ // the correct UI. int CalculateAdjustedOffset() const; + void UpdateVisibleSpace(); + + // Calculates the padding insets which help to show the edging app icon's + // ripple ring correctly. + gfx::Insets CalculateRipplePaddingInsets() const; + LayoutStrategy layout_strategy_ = kNotShowArrowButtons; // Child views Owned by views hierarchy. @@ -264,9 +272,14 @@ ScrollArrowView* right_arrow_ = nullptr; ShelfContainerView* shelf_container_view_ = nullptr; - // Available space to accommodate shelf icons. + // Available space to accommodate child views. gfx::Rect available_space_; + // Visible space of |shelf_container_view| in ScrollableShelfView's local + // coordinates. Different from |available_space_|, |visible_space_| only + // contains app icons and is mirrored for horizontal shelf under RTL. + gfx::Rect visible_space_; + ShelfView* shelf_view_ = nullptr; gfx::Vector2dF scroll_offset_;
diff --git a/ash/shelf/scrollable_shelf_view_unittest.cc b/ash/shelf/scrollable_shelf_view_unittest.cc index 988d32f..415a6d1 100644 --- a/ash/shelf/scrollable_shelf_view_unittest.cc +++ b/ash/shelf/scrollable_shelf_view_unittest.cc
@@ -125,11 +125,11 @@ const views::View* last_visible_icon = view_model->view_at(scrollable_shelf_view_->last_tappable_app_index()); const gfx::Rect icon_bounds = last_visible_icon->GetBoundsInScreen(); - const gfx::Rect shelf_container_bounds = - scrollable_shelf_view_->shelf_container_view()->GetBoundsInScreen(); + gfx::Rect visible_space = scrollable_shelf_view_->visible_space(); + views::View::ConvertRectToScreen(scrollable_shelf_view_, &visible_space); EXPECT_EQ(icon_bounds.right() + ShelfConfig::Get()->scrollable_shelf_ripple_padding(), - shelf_container_bounds.right()); + visible_space.right()); EXPECT_FALSE(scrollable_shelf_view_->ShouldAdjustForTest()); }
diff --git a/ash/shelf/shelf_container_view.cc b/ash/shelf/shelf_container_view.cc index d5282d05..72ce9e69 100644 --- a/ash/shelf/shelf_container_view.cc +++ b/ash/shelf/shelf_container_view.cc
@@ -31,29 +31,6 @@ PreferredSizeChanged(); } -void ShelfContainerView::Layout() { - // Should not use ShelfView::GetPreferredSize in replace of - // CalculateIdealSize. Because ShelfView::CalculatePreferredSize relies on the - // bounds of app icon. Meanwhile, the icon's bounds may be updated by - // animation. - const gfx::Rect ideal_bounds = gfx::Rect(CalculateIdealSize()); - - const gfx::Rect local_bounds = GetLocalBounds(); - gfx::Rect shelf_view_bounds = - local_bounds.Contains(ideal_bounds) ? local_bounds : ideal_bounds; - - // Offsets |shelf_view_bounds| to ensure the sufficient space for the ripple - // ring of the first shelf item. - if (shelf_view_->shelf()->IsHorizontalAlignment()) - shelf_view_bounds.Offset( - ShelfConfig::Get()->scrollable_shelf_ripple_padding(), 0); - else - shelf_view_bounds.Offset( - 0, ShelfConfig::Get()->scrollable_shelf_ripple_padding()); - - shelf_view_->SetBoundsRect(shelf_view_bounds); -} - const char* ShelfContainerView::GetClassName() const { return "ShelfContainerView"; }
diff --git a/ash/shelf/shelf_container_view.h b/ash/shelf/shelf_container_view.h index f83e1e326..01dedcc6 100644 --- a/ash/shelf/shelf_container_view.h +++ b/ash/shelf/shelf_container_view.h
@@ -27,7 +27,6 @@ // views::View: gfx::Size CalculatePreferredSize() const override; void ChildPreferredSizeChanged(views::View* child) override; - void Layout() override; const char* GetClassName() const override; protected:
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 7a15611..fe371a7 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -312,12 +312,12 @@ Shell::Get()->app_list_controller()->RemoveObserver(this); if (Shell::Get()->overview_controller()) Shell::Get()->overview_controller()->RemoveObserver(this); - Shell::Get()->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); } void ShelfLayoutManager::InitObservers() { Shell::Get()->AddShellObserver(this); - Shell::Get()->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); Shell::Get()->overview_controller()->AddObserver(this); Shell::Get()->app_list_controller()->AddObserver(this); Shell::Get() @@ -610,9 +610,8 @@ return SHELF_BACKGROUND_LOGIN; } - const bool in_split_view_mode = - Shell::Get()->split_view_controller() && - Shell::Get()->split_view_controller()->InSplitViewMode(); + const bool in_split_view_mode = SplitViewController::Get() && + SplitViewController::Get()->InSplitViewMode(); const bool maximized = in_split_view_mode || state_.window_state == WorkspaceWindowState::kFullscreen ||
diff --git a/ash/shell.cc b/ash/shell.cc index ca0c2c1b..5d61872f 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -135,7 +135,6 @@ #include "ash/wm/overview/overview_controller.h" #include "ash/wm/resize_shadow_controller.h" #include "ash/wm/screen_pinning_controller.h" -#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/system_gesture_event_filter.h" #include "ash/wm/system_modal_container_event_filter.h" #include "ash/wm/system_modal_container_layout_manager.h" @@ -775,10 +774,6 @@ // destruction of its owned RootWindowControllers relies on the value. window_tree_host_manager_->Shutdown(); - // Destroy |SplitViewController| and |RootWindowController| at about the same - // time, as we plan for |RootWindowController| to own a |SplitViewController|. - // TODO(crbug.com/970013): Actually carry out that plan. - split_view_controller_.reset(); // Depends on |focus_controller_|, so must be destroyed before. window_tree_host_manager_.reset(); @@ -1107,10 +1102,6 @@ system_notification_controller_ = std::make_unique<SystemNotificationController>(); - // Create |SplitViewController| and |RootWindowController| at about the same - // time, as we plan for |RootWindowController| to own a |SplitViewController|. - // TODO(crbug.com/970013): Actually carry out that plan. - split_view_controller_ = std::make_unique<SplitViewController>(); window_tree_host_manager_->InitHosts(); // Create virtual keyboard after WindowTreeHostManager::InitHosts() since
diff --git a/ash/shell.h b/ash/shell.h index 15ca000..20f304c 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -173,7 +173,6 @@ class ShutdownControllerImpl; class SmsObserver; class SnapController; -class SplitViewController; class StickyKeysController; class SystemGestureEventFilter; class SystemModalContainerEventFilter; @@ -457,9 +456,6 @@ ShutdownControllerImpl* shutdown_controller() { return shutdown_controller_.get(); } - SplitViewController* split_view_controller() { - return split_view_controller_.get(); - } StickyKeysController* sticky_keys_controller() { return sticky_keys_controller_.get(); } @@ -767,9 +763,6 @@ std::unique_ptr<DockedMagnifierControllerImpl> docked_magnifier_controller_; - // The split view controller for Chrome OS. - std::unique_ptr<SplitViewController> split_view_controller_; - std::unique_ptr<SnapController> snap_controller_; // |native_cursor_manager_| is owned by |cursor_manager_|, but we keep a
diff --git a/ash/system/message_center/arc/arc_notification_view.h b/ash/system/message_center/arc/arc_notification_view.h index 14ccfe7..0fe506ac 100644 --- a/ash/system/message_center/arc/arc_notification_view.h +++ b/ash/system/message_center/arc/arc_notification_view.h
@@ -56,7 +56,7 @@ void OnSnoozeButtonPressed(const ui::Event& event) override; void UpdateCornerRadius(int top_radius, int bottom_radius) override; - // message_center::SlideOutController::Delegate: + // views::SlideOutControllerDelegate: void OnSlideChanged(bool in_progress) override; // Overridden from views::View:
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index 5b24629..8bfc038 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -108,8 +108,7 @@ // default side. The window which was dragged to either side to begin // splitview will remain untouched. Skip that window if it appears in the // mru list. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode() && mru_window_list.size() > 2u) { if (mru_window_list[0] ==
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc index 3ef6215..21c60fe 100644 --- a/ash/system/overview/overview_button_tray_unittest.cc +++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -388,8 +388,7 @@ // Enter splitview mode. Snap |window1| to the left, this will be the default // splitview window. Shell::Get()->overview_controller()->StartOverview(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); ASSERT_EQ(window1.get(), split_view_controller->GetDefaultSnappedWindow());
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc index a07fdf2..b7306d4 100644 --- a/ash/wm/base_state.cc +++ b/ash/wm/base_state.cc
@@ -187,7 +187,7 @@ gfx::Rect bounds_in_parent; if (ShouldAllowSplitView()) { bounds_in_parent = - Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInParent( + SplitViewController::Get()->GetSnappedWindowBoundsInParent( window, (state_type == WindowStateType::kLeftSnapped) ? SplitViewController::LEFT : SplitViewController::RIGHT);
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc index a332db8..3f1f03b 100644 --- a/ash/wm/desks/desks_controller.cc +++ b/ash/wm/desks/desks_controller.cc
@@ -236,8 +236,7 @@ Shell::Get()->overview_controller()->EndOverview( OverviewSession::EnterExitOverviewType::kImmediateExit); } - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->EndSplitView( SplitViewController::EndReason::kDesksChange); @@ -286,8 +285,7 @@ // We are removing the active desk, which may have split view active. // We will restore the split view state of the newly activated desk at the // end of the animation. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->EndSplitView( SplitViewController::EndReason::kDesksChange); @@ -714,8 +712,7 @@ // Exit split view if active, before activating the new desk. We will // restore the split view state of the newly activated desk at the end. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->EndSplitView( SplitViewController::EndReason::kDesksChange);
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index b78dea8..b71dd36 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -1611,8 +1611,7 @@ auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(win2.get(), SplitViewController::RIGHT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); @@ -1649,8 +1648,7 @@ ASSERT_EQ(2u, desks_controller->desks().size()); auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(win2.get(), SplitViewController::RIGHT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); @@ -1726,8 +1724,7 @@ &win3_delegate, /*id=*/-1, gfx::Rect(big))); OverviewController* overview_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(overview_controller->StartOverview()); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); EXPECT_FALSE(CanSnapInSplitview(win2.get())); @@ -1781,8 +1778,7 @@ Desk* desk_2 = desks_controller->desks()[1].get(); auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(win2.get(), SplitViewController::RIGHT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); @@ -1813,8 +1809,7 @@ ASSERT_EQ(2u, desks_controller->desks().size()); Desk* desk_2 = desks_controller->desks()[1].get(); auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); EXPECT_EQ(nullptr, split_view_controller->right_window()); @@ -1838,8 +1833,7 @@ ASSERT_EQ(2u, desks_controller->desks().size()); Desk* desk_2 = desks_controller->desks()[1].get(); auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); EXPECT_EQ(win1.get(), split_view_controller->left_window()); EXPECT_EQ(nullptr, split_view_controller->right_window()); @@ -1868,8 +1862,7 @@ auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(win1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(win2.get(), SplitViewController::RIGHT); auto* desk_1_backdrop_controller = @@ -1951,8 +1944,7 @@ EXPECT_TRUE(CanSnapInSplitview(window.get())); // Snap the window in this orientation. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); EXPECT_EQ(window.get(), split_view_controller->left_window()); EXPECT_TRUE(split_view_controller->InSplitViewMode()); @@ -2055,7 +2047,7 @@ TEST_F(DesksWithSplitViewTest, SwitchToDeskWithSnappedActiveWindow) { auto* desks_controller = DesksController::Get(); auto* overview_controller = Shell::Get()->overview_controller(); - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); // Two virtual desks: |desk_1| (active) and |desk_2|. NewDesk();
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc index e05a65f3..077332a 100644 --- a/ash/wm/immersive_fullscreen_controller_unittest.cc +++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -727,10 +727,9 @@ // Top-of-window views will not be revealed for snapped window in splitview // mode either. - Shell::Get()->split_view_controller()->SnapWindow(window(), - SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window(), SplitViewController::LEFT); EXPECT_TRUE(WindowState::Get(window())->IsSnapped()); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); AttemptReveal(MODALITY_GESTURE_SCROLL); EXPECT_FALSE(controller()->IsRevealed()); }
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc index 9c455cb5..77bfb34 100644 --- a/ash/wm/overview/overview_controller.cc +++ b/ash/wm/overview/overview_controller.cc
@@ -154,7 +154,7 @@ // in the overview grid for the display where the overview button was long // pressed, and the first window in that overview grid is snappable. - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); // Exit split view mode if we are already in it. if (split_view_controller->InSplitViewMode()) { // In some cases the window returned by window_util::GetActiveWindow will be @@ -460,7 +460,7 @@ // in case of |SplitViewController::State::kBothSnapped|, that function will // insert one of the two snapped windows to overview. const SplitViewController::State split_view_state = - Shell::Get()->split_view_controller()->state(); + SplitViewController::Get()->state(); should_focus_overview_ = split_view_state == SplitViewController::State::kNoSnap || split_view_state == SplitViewController::State::kBothSnapped; @@ -504,7 +504,7 @@ bool OverviewController::CanEnterOverview() { // Prevent toggling overview during the split view divider snap animation. - if (Shell::Get()->split_view_controller()->IsDividerAnimating()) + if (SplitViewController::Get()->IsDividerAnimating()) return false; // Don't allow a window overview if the user session is not active (e.g. @@ -521,8 +521,7 @@ bool OverviewController::CanEndOverview( OverviewSession::EnterExitOverviewType type) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); // Prevent toggling overview during the split view divider snap animation. if (split_view_controller->IsDividerAnimating()) return false;
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index fc61acdc..4d36025 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -252,8 +252,7 @@ } } - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (!split_view_controller->InSplitViewMode()) return work_area; @@ -305,7 +304,7 @@ gfx::Rect GetGridBoundsInScreenForSplitview( aura::Window* window, base::Optional<IndicatorState> indicator_state = base::nullopt) { - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); auto state = split_view_controller->state(); // If we are in splitview mode already just use the given state, otherwise @@ -361,7 +360,7 @@ split_view_drag_indicators->current_indicator_state() == IndicatorState::kDragArea && !IsCurrentScreenOrientationLandscape() && - !Shell::Get()->split_view_controller()->InSplitViewMode()) { + !SplitViewController::Get()->InSplitViewMode()) { desks_widget_root_bounds.Offset(0, overview_grid_screen_bounds.height() * kHighlightScreenPrimaryAxisRatio + @@ -476,7 +475,7 @@ OverviewGrid::~OverviewGrid() = default; void OverviewGrid::Shutdown() { - Shell::Get()->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); ScreenRotationAnimator::GetForRootWindow(root_window_)->RemoveObserver(this); Shell::Get()->wallpaper_controller()->RemoveObserver(this); grid_event_handler_.reset(); @@ -497,8 +496,7 @@ !Shell::Get()->tablet_mode_controller()->InTabletMode(); // OverviewGrid in splitscreen does not include the window to be activated. - if (!window_list_.empty() || - Shell::Get()->split_view_controller()->InSplitViewMode()) { + if (!window_list_.empty() || SplitViewController::Get()->InSplitViewMode()) { // The following instance self-destructs when shutdown animation ends. new ShutdownAnimationFpsCounterObserver( root_window_->layer()->GetCompositor(), single_animation_in_clamshell); @@ -517,7 +515,7 @@ for (const auto& window : window_list_) window->PrepareForOverview(); - Shell::Get()->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); if (Shell::Get()->tablet_mode_controller()->InTabletMode()) ScreenRotationAnimator::GetForRootWindow(root_window_)->AddObserver(this); @@ -917,7 +915,7 @@ void OverviewGrid::OnDisplayMetricsChanged() { // In case of split view mode, the grid bounds and item positions will be // updated in |OnSplitViewDividerPositionChanged|. - if (Shell::Get()->split_view_controller()->InSplitViewMode()) + if (SplitViewController::Get()->InSplitViewMode()) return; SetBoundsAndUpdatePositions( GetGridBoundsInScreen(root_window_, /*divider_changed=*/false), @@ -932,8 +930,7 @@ if (!overview_controller->InOverviewSession()) return; - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); const bool unsnappable_window_activated = state == SplitViewController::State::kNoSnap && split_view_controller->end_reason() == @@ -1086,7 +1083,7 @@ }); SkRegion occluded_region; - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode()) { // Snapped windows and the split view divider are not included in // |target_bounds| or |window_list_|, but can occlude other windows, so add
diff --git a/ash/wm/overview/overview_grid_unittest.cc b/ash/wm/overview/overview_grid_unittest.cc index fa7a471..05bf35d8 100644 --- a/ash/wm/overview/overview_grid_unittest.cc +++ b/ash/wm/overview/overview_grid_unittest.cc
@@ -226,12 +226,12 @@ wm::ActivateWindow(window1.get()); Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); - Shell::Get()->split_view_controller()->SnapWindow(window1.get(), - SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window1.get(), + SplitViewController::LEFT); // Snap |window2| and check that |window3| is maximized. - Shell::Get()->split_view_controller()->SnapWindow(window2.get(), - SplitViewController::RIGHT); + SplitViewController::Get()->SnapWindow(window2.get(), + SplitViewController::RIGHT); EXPECT_TRUE(WindowState::Get(window3.get())->IsMaximized()); // Tests that |window3| is not animated even though its bounds are larger than
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 149313f..c644bcc 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -277,8 +277,7 @@ // target state in |SplitViewController::OnOverviewModeEnding|. // Unify the mechanism to control it and remove ifs. if (Shell::Get()->tablet_mode_controller()->InTabletMode() && - !Shell::Get()->split_view_controller()->InSplitViewMode() && - reset_transform) { + !SplitViewController::Get()->InSplitViewMode() && reset_transform) { MaximizeIfSnapped(GetWindow()); } @@ -552,7 +551,7 @@ visible = false; } else { const SplitViewController::State state = - Shell::Get()->split_view_controller()->state(); + SplitViewController::Get()->state(); visible = state == SplitViewController::State::kLeftSnapped || state == SplitViewController::State::kRightSnapped; } @@ -659,9 +658,9 @@ aura::Window* dragged_window = GetWindow(); aura::Window* dragged_widget_window = item_widget_->GetNativeWindow(); aura::Window* parent_window = dragged_widget_window->parent(); - if (Shell::Get()->split_view_controller()->InSplitViewMode()) { + if (SplitViewController::Get()->InSplitViewMode()) { aura::Window* snapped_window = - Shell::Get()->split_view_controller()->GetDefaultSnappedWindow(); + SplitViewController::Get()->GetDefaultSnappedWindow(); if (snapped_window->parent() == parent_window && dragged_window->parent() == parent_window) { parent_window->StackChildBelow(dragged_window, snapped_window);
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 940cc9f8..7a968e114 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -188,7 +188,7 @@ UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_); - Shell::Get()->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); display::Screen::GetScreen()->AddObserver(this); base::RecordAction(base::UserMetricsAction("WindowSelector_Overview")); @@ -217,7 +217,7 @@ // Stop observing split view state changes before restoring window focus. // Otherwise the activation of the window triggers OnSplitViewStateChanged() // that will call into this function again. - Shell::Get()->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); size_t remaining_items = 0; for (std::unique_ptr<OverviewGrid>& overview_grid : grid_list_) { @@ -274,7 +274,7 @@ if (!IsEmpty()) return; - if (Shell::Get()->split_view_controller()->InTabletSplitViewMode()) + if (SplitViewController::Get()->InTabletSplitViewMode()) UpdateNoWindowsWidget(); else EndOverview(); @@ -393,7 +393,7 @@ const gfx::PointF& location_in_screen, bool is_touch_dragging) { if (Shell::Get()->overview_controller()->IsInStartAnimation() || - Shell::Get()->split_view_controller()->IsDividerAnimating()) { + SplitViewController::Get()->IsDividerAnimating()) { return; } highlight_controller_->SetFocusHighlightVisibility(false); @@ -583,7 +583,7 @@ // We do not want an active window in overview. It will cause blatantly // broken behavior as in the video linked in crbug.com/992223. wm::ActivateWindow( - Shell::Get()->split_view_controller()->GetDefaultSnappedWindow()); + SplitViewController::Get()->GetDefaultSnappedWindow()); } } } @@ -627,7 +627,7 @@ // Do not cancel overview mode if the window activation happens when split // view mode is also active. SplitViewController will do the right thing to // handle the window activation change. - if (Shell::Get()->split_view_controller()->InSplitViewMode()) + if (SplitViewController::Get()->InSplitViewMode()) return; // Do not cancel overview mode if the window activation was caused while @@ -760,7 +760,7 @@ } // In case of split view mode, the no windows widget bounds will be updated in // |OnSplitViewDividerPositionChanged|. - if (Shell::Get()->split_view_controller()->InSplitViewMode()) + if (SplitViewController::Get()->InSplitViewMode()) return; RefreshNoWindowsWidgetBounds(/*animate=*/false); } @@ -789,9 +789,8 @@ // If the new window is added when splitscreen is active, do nothing. // SplitViewController will do the right thing to snap the window or end // overview mode. - if (Shell::Get()->split_view_controller()->InSplitViewMode() && - new_window->GetRootWindow() == Shell::Get() - ->split_view_controller() + if (SplitViewController::Get()->InSplitViewMode() && + new_window->GetRootWindow() == SplitViewController::Get() ->GetDefaultSnappedWindow() ->GetRootWindow()) { return;
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index c7838c02..d36e43d 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -1502,8 +1502,8 @@ EnterTabletMode(); ToggleOverview(); ASSERT_TRUE(overview_controller()->InOverviewSession()); - Shell::Get()->split_view_controller()->SnapWindow(window.get(), - SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window.get(), + SplitViewController::LEFT); ASSERT_TRUE(overview_controller()->InOverviewSession()); SendKey(ui::VKEY_ESCAPE); EXPECT_TRUE(overview_controller()->InOverviewSession()); @@ -1636,7 +1636,7 @@ // Tests that when snapping a window to the left in splitview, the no windows // indicator shows up in the middle of the right side of the screen. - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); no_windows_widget = overview_session()->no_windows_widget_for_testing(); ASSERT_TRUE(no_windows_widget); @@ -1663,7 +1663,7 @@ std::unique_ptr<aura::Window> window(CreateTestWindow()); ToggleOverview(); - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); EXPECT_TRUE(overview_session()->no_windows_widget_for_testing()); @@ -2800,7 +2800,7 @@ } SplitViewController* split_view_controller() { - return Shell::Get()->split_view_controller(); + return SplitViewController::Get(); } protected: @@ -3191,7 +3191,7 @@ } SplitViewController* split_view_controller() { - return Shell::Get()->split_view_controller(); + return SplitViewController::Get(); } bool IsDividerAnimating() { @@ -3770,7 +3770,7 @@ EXPECT_TRUE(overview_controller()->InOverviewSession()); EndSplitView(); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(overview_controller()->InOverviewSession()); // Test that ToggleOverview() can end overview if we're not in split view @@ -3783,10 +3783,10 @@ ToggleOverview(); overview_item1 = GetOverviewItemForWindow(window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(overview_controller()->InOverviewSession()); Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_FALSE(overview_controller()->InOverviewSession()); // Test that closing all windows in overview can end overview if we're not in @@ -4392,8 +4392,8 @@ ToggleOverview(); // Snap a window to the left and test dragging the divider towards the right // edge of the screen. - Shell::Get()->split_view_controller()->SnapWindow(window1.get(), - SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window1.get(), + SplitViewController::LEFT); OverviewGrid* grid = overview_session()->grid_list()[0].get(); ASSERT_TRUE(grid); @@ -4417,8 +4417,8 @@ ToggleOverview(); // Snap a window to the right and test dragging the divider towards the left // edge of the screen. - Shell::Get()->split_view_controller()->SnapWindow(window1.get(), - SplitViewController::RIGHT); + SplitViewController::Get()->SnapWindow(window1.get(), + SplitViewController::RIGHT); grid = overview_session()->grid_list()[0].get(); ASSERT_TRUE(grid);
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index 3535c9c..be00154 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -48,8 +48,7 @@ } // namespace bool CanCoverAvailableWorkspace(aura::Window* window) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode()) return CanSnapInSplitview(window); return WindowState::Get(window)->IsMaximizedOrFullscreenOrPinned();
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc index 9463ed4..3dba108e 100644 --- a/ash/wm/overview/overview_window_drag_controller.cc +++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -130,7 +130,7 @@ OverviewItem* item, bool is_touch_dragging) : overview_session_(overview_session), - split_view_controller_(Shell::Get()->split_view_controller()), + split_view_controller_(SplitViewController::Get()), item_(item), on_desks_bar_item_size_(GetItemSizeWhenOnDesksBar(item)), display_count_(Shell::GetAllRootWindows().size()), @@ -138,7 +138,7 @@ should_allow_split_view_(ShouldAllowSplitView()), virtual_desks_bar_enabled_(GetVirtualDesksBarEnabled(item)) { DCHECK(!Shell::Get()->overview_controller()->IsInStartAnimation()); - DCHECK(!Shell::Get()->split_view_controller()->IsDividerAnimating()); + DCHECK(!SplitViewController::Get()->IsDividerAnimating()); } OverviewWindowDragController::~OverviewWindowDragController() = default; @@ -684,7 +684,7 @@ DCHECK_NE(snap_position, SplitViewController::NONE); // |item_| will be deleted after SplitViewController::SnapWindow(). - DCHECK(!Shell::Get()->split_view_controller()->IsDividerAnimating()); + DCHECK(!SplitViewController::Get()->IsDividerAnimating()); aura::Window* window = item_->GetWindow(); split_view_controller_->SnapWindow(window, snap_position, /*use_divider_spawn_animation=*/true);
diff --git a/ash/wm/overview/overview_window_drag_controller_unittest.cc b/ash/wm/overview/overview_window_drag_controller_unittest.cc index f5e39e0..a45066d 100644 --- a/ash/wm/overview/overview_window_drag_controller_unittest.cc +++ b/ash/wm/overview/overview_window_drag_controller_unittest.cc
@@ -310,7 +310,7 @@ } SplitViewController* split_view_controller() { - return Shell::Get()->split_view_controller(); + return SplitViewController::Get(); } OverviewSession* overview_session() {
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index 25d4339..1975747e 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -137,7 +137,7 @@ // activated. // TODO(sammiequon): This does not handle the case if either the snapped // window or this window is an always on top window. - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); if (ShouldUseTabletModeGridLayout() && split_view_controller->InSplitViewMode()) { aura::Window* snapped_window =
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index e642109..34051e1 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -12,6 +12,7 @@ #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/presentation_time_recorder.h" #include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" #include "ash/scoped_animation_disabler.h" #include "ash/screen_util.h" #include "ash/session/session_controller_impl.h" @@ -272,6 +273,12 @@ int ending_position_; }; +// static +SplitViewController* SplitViewController::Get() { + DCHECK(Shell::GetPrimaryRootWindowController()); + return Shell::GetPrimaryRootWindowController()->split_view_controller(); +} + SplitViewController::SplitViewController() { Shell::Get()->accessibility_controller()->AddObserver(this); display::Screen::GetScreen()->AddObserver(this); @@ -284,7 +291,11 @@ } SplitViewController::~SplitViewController() { + if (Shell::Get()->tablet_mode_controller()) + Shell::Get()->tablet_mode_controller()->RemoveObserver(this); display::Screen::GetScreen()->RemoveObserver(this); + if (Shell::Get()->accessibility_controller()) + Shell::Get()->accessibility_controller()->RemoveObserver(this); EndSplitView(); }
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h index 7ecc77f3..fe6de29 100644 --- a/ash/wm/splitview/split_view_controller.h +++ b/ash/wm/splitview/split_view_controller.h
@@ -94,6 +94,13 @@ kBothSnapped, }; + // For now, there is only one |SplitViewController|, regardless of whether the + // |ash::features::kMultiDisplayOverviewAndSplitView| feature flag is enabled. + // TODO(crbug.com/970013): When the feature flag is enabled, there shall be a + // |SplitViewController| for each root window. Instead of Get, this function + // shall be ForWindow, similar to |RootWindowController::ForWindow|. + static SplitViewController* Get(); + SplitViewController(); ~SplitViewController() override;
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index 39a30d2..f6fd5c8 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -197,7 +197,7 @@ } SplitViewController* split_view_controller() { - return Shell::Get()->split_view_controller(); + return SplitViewController::Get(); } SplitViewDivider* split_view_divider() {
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc index a40739b..65192bb 100644 --- a/ash/wm/splitview/split_view_divider.cc +++ b/ash/wm/splitview/split_view_divider.cc
@@ -75,7 +75,7 @@ class DividerView : public views::View, public views::ViewTargeterDelegate { public: explicit DividerView(SplitViewDivider* divider) - : controller_(Shell::Get()->split_view_controller()), divider_(divider) { + : controller_(SplitViewController::Get()), divider_(divider) { divider_view_ = new views::View(); divider_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); divider_view_->layer()->SetColor(kSplitviewDividerColor);
diff --git a/ash/wm/splitview/split_view_divider_handler_view.cc b/ash/wm/splitview/split_view_divider_handler_view.cc index 96fc7c2..a20c6020 100644 --- a/ash/wm/splitview/split_view_divider_handler_view.cc +++ b/ash/wm/splitview/split_view_divider_handler_view.cc
@@ -124,7 +124,7 @@ spawning_animation_.reset(); SetVisible(true); selection_animation_->UpdateWhiteHandlerBounds(); - if (Shell::Get()->split_view_controller()->is_resizing()) + if (SplitViewController::Get()->is_resizing()) selection_animation_->Show(); else selection_animation_->Hide();
diff --git a/ash/wm/splitview/split_view_drag_indicators.cc b/ash/wm/splitview/split_view_drag_indicators.cc index a9b357c4..2c321fc 100644 --- a/ash/wm/splitview/split_view_drag_indicators.cc +++ b/ash/wm/splitview/split_view_drag_indicators.cc
@@ -169,7 +169,7 @@ void OnIndicatorTypeChanged(IndicatorState indicator_state, IndicatorState previous_indicator_state) { // In split view, the labels never show, and they do not need to be updated. - if (Shell::Get()->split_view_controller()->InSplitViewMode()) + if (SplitViewController::Get()->InSplitViewMode()) return; // On transition to a state with no indicators, any label that is showing @@ -377,7 +377,7 @@ if (IsPreviewAreaState(indicator_state_) || nix_preview_inset) { // Get the preview area bounds from the split view controller. preview_area_bounds = - Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInScreen( + SplitViewController::Get()->GetSnappedWindowBoundsInScreen( GetWidget()->GetNativeWindow(), preview_state == IndicatorState::kPreviewAreaLeft ? SplitViewController::LEFT
diff --git a/ash/wm/splitview/split_view_drag_indicators_unittest.cc b/ash/wm/splitview/split_view_drag_indicators_unittest.cc index fee3fe3..c5eb799 100644 --- a/ash/wm/splitview/split_view_drag_indicators_unittest.cc +++ b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
@@ -64,7 +64,7 @@ } SplitViewController* split_view_controller() { - return Shell::Get()->split_view_controller(); + return SplitViewController::Get(); } IndicatorState indicator_state() {
diff --git a/ash/wm/splitview/split_view_highlight_view.cc b/ash/wm/splitview/split_view_highlight_view.cc index dfab8f3..bcdcb5a 100644 --- a/ash/wm/splitview/split_view_highlight_view.cc +++ b/ash/wm/splitview/split_view_highlight_view.cc
@@ -233,7 +233,7 @@ SplitViewDragIndicators::IsPreviewAreaOnLeftTopOfScreen( previous_indicator_state); DoSplitviewOpacityAnimation( - layer(), Shell::Get()->split_view_controller()->InSplitViewMode() + layer(), SplitViewController::Get()->InSplitViewMode() ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT : (was_this_the_preview ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN @@ -244,10 +244,10 @@ SetColor(SplitViewDragIndicators::IsCannotSnapState(indicator_state) ? SK_ColorBLACK : SK_ColorWHITE); - DoSplitviewOpacityAnimation( - layer(), Shell::Get()->split_view_controller()->InSplitViewMode() - ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT - : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN); + DoSplitviewOpacityAnimation(layer(), + SplitViewController::Get()->InSplitViewMode() + ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT + : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN); } } // namespace ash
diff --git a/ash/wm/splitview/split_view_test_api.cc b/ash/wm/splitview/split_view_test_api.cc index 5c05d03b..5e66fc5 100644 --- a/ash/wm/splitview/split_view_test_api.cc +++ b/ash/wm/splitview/split_view_test_api.cc
@@ -4,7 +4,6 @@ #include "ash/public/cpp/split_view_test_api.h" -#include "ash/shell.h" #include "ash/wm/splitview/split_view_controller.h" namespace ash { @@ -28,11 +27,11 @@ position = SplitViewController::RIGHT; break; } - Shell::Get()->split_view_controller()->SnapWindow(window, position); + SplitViewController::Get()->SnapWindow(window, position); } void SplitViewTestApi::SwapWindows() { - Shell::Get()->split_view_controller()->SwapWindows(); + SplitViewController::Get()->SwapWindows(); } } // namespace ash
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc index 14b4957..12ededd 100644 --- a/ash/wm/splitview/split_view_utils.cc +++ b/ash/wm/splitview/split_view_utils.cc
@@ -241,8 +241,7 @@ // could snap windows that were not in split view. Also, a window may have // become full screen, and if so, then it would be better not to reactivate // split view. See https://crbug.com/944134. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (refresh_snapped_windows) { const MruWindowTracker::WindowList windows =
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index 993497e6..3169b0a 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -943,7 +943,7 @@ // there is a window snapped on one side but no window snapped on the other // side, then overview mode should be started (to be seen on the side with // no snapped window). - const auto state = Shell::Get()->split_view_controller()->state(); + const auto state = SplitViewController::Get()->state(); if (state == SplitViewController::State::kLeftSnapped || state == SplitViewController::State::kRightSnapped) { Shell::Get()->overview_controller()->StartOverview();
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc index f120c87..b53ee88 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -1138,8 +1138,7 @@ // Test that if the active window is not snapped before tablet mode, then split // view is not activated. TEST_P(TabletModeControllerTest, StartTabletActiveNoSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window = CreateTestWindow(); tablet_mode_controller()->SetEnabledForTest(true); EXPECT_EQ(SplitViewController::State::kNoSnap, @@ -1150,8 +1149,7 @@ // Test that if the active window is snapped on the left before tablet mode, // then split view is activated with the active window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft(); tablet_mode_controller()->SetEnabledForTest(true); EXPECT_EQ(SplitViewController::State::kLeftSnapped, @@ -1164,8 +1162,7 @@ // Test that if the active window is snapped on the right before tablet mode, // then split view is activated with the active window on the right. TEST_P(TabletModeControllerTest, StartTabletActiveRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedRight(); tablet_mode_controller()->SetEnabledForTest(true); EXPECT_EQ(SplitViewController::State::kRightSnapped, @@ -1179,8 +1176,7 @@ // the previous window is snapped on the right, then split view is activated // with the active window on the left and the previous window on the right. TEST_P(TabletModeControllerTest, StartTabletActiveLeftSnapPreviousRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> right_window = CreateDesktopWindowSnappedRight(); @@ -1198,8 +1194,7 @@ // and the previous window is snapped on the left, then split view is activated // with the active window on the right and the previous window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveRightSnapPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> right_window = CreateDesktopWindowSnappedRight(); @@ -1218,8 +1213,7 @@ // is not activated. TEST_P(TabletModeControllerTest, StartTabletActiveArcLeftSnapPreviousRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); left_window->SetProperty(aura::client::kAppType, static_cast<int>(AppType::ARC_APP)); @@ -1238,8 +1232,7 @@ // window), then split view is activated with the active window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveLeftSnapPreviousArcRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> right_window = CreateDesktopWindowSnappedRight(); @@ -1261,8 +1254,7 @@ // window snapped on the left, then split view is activated with the parent // snapped on the left. TEST_P(TabletModeControllerTest, StartTabletActiveTransientChildOfLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> parent = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> child = CreateTestWindow(gfx::Rect(), aura::client::WINDOW_TYPE_POPUP); @@ -1280,8 +1272,7 @@ // previous window is snapped on the left, then split view is activated with the // previous window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveAppListPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft(); Shell::Get()->app_list_controller()->ShowAppList(); ASSERT_TRUE(wm::IsActiveWindow( @@ -1298,8 +1289,7 @@ // previous window is snapped on the left, then split view is activated with the // previous window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveDraggedPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> dragged_window = CreateTestWindow(); std::unique_ptr<aura::Window> snapped_window = CreateDesktopWindowSnappedLeft(); @@ -1320,8 +1310,7 @@ // with the previous window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveHiddenFromOverviewPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window_hidden_from_overview = CreateTestWindow(); window_hidden_from_overview->SetProperty(kHideInOverviewKey, true); @@ -1341,8 +1330,7 @@ // split view is activated with the parent on the left. TEST_P(TabletModeControllerTest, StartTabletActiveDraggedPreviousTransientChildOfLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> dragged_window = CreateTestWindow(); std::unique_ptr<aura::Window> parent = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> child = @@ -1366,8 +1354,7 @@ // window is snapped on the right, then split view is not activated. TEST_P(TabletModeControllerTest, StartTabletActiveDesktopOnlyLeftSnapPreviousRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); aura::test::TestWindowDelegate left_window_delegate; std::unique_ptr<aura::Window> left_window(CreateTestWindowInShellWithDelegate( &left_window_delegate, /*id=*/-1, /*bounds=*/gfx::Rect(0, 0, 400, 400))); @@ -1395,8 +1382,7 @@ // previous window is snapped on the left, then split view is not activated. TEST_P(TabletModeControllerTest, StartTabletActiveDesktopOnlyRightSnapPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); aura::test::TestWindowDelegate right_window_delegate; std::unique_ptr<aura::Window> right_window( @@ -1426,8 +1412,7 @@ // the active window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveLeftSnapPreviousDesktopOnlyRightSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> left_window = CreateDesktopWindowSnappedLeft(); aura::test::TestWindowDelegate right_window_delegate; std::unique_ptr<aura::Window> right_window( @@ -1459,8 +1444,7 @@ // the active window on the right. TEST_P(TabletModeControllerTest, StartTabletActiveRightSnapPreviousDesktopOnlyLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); aura::test::TestWindowDelegate left_window_delegate; std::unique_ptr<aura::Window> left_window(CreateTestWindowInShellWithDelegate( &left_window_delegate, /*id=*/-1, /*bounds=*/gfx::Rect(0, 0, 400, 400))); @@ -1501,8 +1485,7 @@ // the left before tablet mode, then split view is activated with the active // window on the left. TEST_P(TabletModeControllerTest, StartTabletActiveLeftSnapPreviousLeftSnap) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); std::unique_ptr<aura::Window> window1 = CreateDesktopWindowSnappedLeft(); std::unique_ptr<aura::Window> window2 = CreateDesktopWindowSnappedLeft(); wm::ActivateWindow(window1.get());
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc index 6c28bc0..794e9bb 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -95,7 +95,7 @@ } // namespace TabletModeWindowDragDelegate::TabletModeWindowDragDelegate() - : split_view_controller_(Shell::Get()->split_view_controller()), + : split_view_controller_(SplitViewController::Get()), split_view_drag_indicators_(std::make_unique<SplitViewDragIndicators>()) { }
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc index 8ff0ac89..bea2323 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -132,7 +132,7 @@ return left_window ? work_area.height() - left_window_bounds.height() : right_window_bounds.height(); default: - return Shell::Get()->split_view_controller()->GetDefaultDividerPosition( + return SplitViewController::Get()->GetDefaultDividerPosition( left_window ? left_window : right_window); } } @@ -144,8 +144,7 @@ if (windows.empty()) return; - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); // If split view mode is already active, use its own divider position. if (!split_view_controller->InSplitViewMode()) split_view_controller->InitDividerPositionForTransition(divider_position); @@ -245,7 +244,7 @@ } AddWindowCreationObservers(); display::Screen::GetScreen()->AddObserver(this); - Shell::Get()->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); Shell::Get()->session_controller()->AddObserver(this); Shell::Get()->overview_controller()->AddObserver(this); accounts_since_entering_tablet_.insert( @@ -286,14 +285,13 @@ // single split case to match the clamshell split view behavior. (there is // no both snapped state or single split state in clamshell split view). The // windows will still be kept snapped though. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (split_view_controller->InSplitViewMode()) { OverviewController* overview_controller = Shell::Get()->overview_controller(); if (!overview_controller->InOverviewSession() || overview_controller->overview_session()->IsEmpty()) { - Shell::Get()->split_view_controller()->EndSplitView( + SplitViewController::Get()->EndSplitView( SplitViewController::EndReason::kExitTabletMode); overview_controller->EndOverview(); } @@ -303,7 +301,7 @@ for (aura::Window* window : added_windows_) window->RemoveObserver(this); added_windows_.clear(); - Shell::Get()->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); Shell::Get()->session_controller()->RemoveObserver(this); Shell::Get()->overview_controller()->RemoveObserver(this); display::Screen::GetScreen()->RemoveObserver(this); @@ -361,7 +359,7 @@ if (canceled) return; - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); // Maximize all snapped windows upon exiting overview mode except snapped // windows in splitview mode. Note the snapped window might not be tracked in @@ -383,7 +381,7 @@ SplitViewController::State state) { if (state != SplitViewController::State::kNoSnap) return; - switch (Shell::Get()->split_view_controller()->end_reason()) { + switch (SplitViewController::Get()->end_reason()) { case SplitViewController::EndReason::kNormal: case SplitViewController::EndReason::kUnsnappableWindowActivated: case SplitViewController::EndReason::kPipExpanded: @@ -516,8 +514,7 @@ void TabletModeWindowManager::OnActiveUserSessionChanged( const AccountId& account_id) { - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); // There is only one SplitViewController object for all user sessions, but // functionally, each user session independently can be in split view or not.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc index 90348363..40c24f9 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -1837,7 +1837,7 @@ // After transition, we should be in single split screen. CreateTabletModeWindowManager(); EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); // 6. Tablet -> Clamshell. Since clamshell splitscreen is not enabled, oveview @@ -1845,7 +1845,7 @@ // state. DestroyTabletModeWindowManager(); EXPECT_FALSE(overview_controller->InOverviewSession()); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); // Create another normal state window to test additional scenarios. @@ -1861,13 +1861,13 @@ // 8. Tablet -> Clamshell. If the two windows are in splitscreen in tablet // mode, after transition they will restore to their old window states. - Shell::Get()->split_view_controller()->SnapWindow(window.get(), - SplitViewController::LEFT); - Shell::Get()->split_view_controller()->SnapWindow(window2.get(), - SplitViewController::RIGHT); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + SplitViewController::Get()->SnapWindow(window.get(), + SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window2.get(), + SplitViewController::RIGHT); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); DestroyTabletModeWindowManager(); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); EXPECT_FALSE(WindowState::Get(window2.get())->IsSnapped()); @@ -1876,16 +1876,16 @@ const WMEvent event2(WM_EVENT_SNAP_RIGHT); WindowState::Get(window2.get())->OnWMEvent(&event2); CreateTabletModeWindowManager(); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); // 10. Tablet -> Clamshell. If overview and splitview are both active, they // will be both ended after the transition. overview_controller->StartOverview(); EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); DestroyTabletModeWindowManager(); EXPECT_FALSE(overview_controller->InOverviewSession()); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); } // The class to test TabletModeWindowManagerTest related functionalities when @@ -1952,14 +1952,14 @@ // After transition, we should be in single split screen. CreateTabletModeWindowManager(); EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); // 6. Tablet -> Clamshell. Since there is only 1 window, splitview and // overview will be both ended. The window will be kept snapped. DestroyTabletModeWindowManager(); EXPECT_FALSE(overview_controller->InOverviewSession()); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); // Create another normal state window to test additional scenarios. @@ -1974,22 +1974,22 @@ // 8. Tablet -> Clamshell. If tablet splitscreen is active with two snapped // windows, the two windows will remain snapped in clamshell mode. - Shell::Get()->split_view_controller()->SnapWindow(window.get(), - SplitViewController::LEFT); - Shell::Get()->split_view_controller()->SnapWindow(window2.get(), - SplitViewController::RIGHT); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + SplitViewController::Get()->SnapWindow(window.get(), + SplitViewController::LEFT); + SplitViewController::Get()->SnapWindow(window2.get(), + SplitViewController::RIGHT); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_FALSE(overview_controller->InOverviewSession()); DestroyTabletModeWindowManager(); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); EXPECT_TRUE(WindowState::Get(window2.get())->IsSnapped()); - EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_FALSE(SplitViewController::Get()->InSplitViewMode()); EXPECT_FALSE(overview_controller->InOverviewSession()); // 9. Clamshell -> Tablet. If two window are snapped to two sides of the // screen, they will carry over to splitscreen in tablet mode. CreateTabletModeWindowManager(); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped()); EXPECT_TRUE(WindowState::Get(window2.get())->IsSnapped()); @@ -1997,15 +1997,15 @@ // 10. Tablet -> Clamshell. If overview and splitview are both active, after // transition, they will remain both active. overview_controller->StartOverview(); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); DestroyTabletModeWindowManager(); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); // 11. Clamshell -> Tablet. The same as 10. CreateTabletModeWindowManager(); - EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); + EXPECT_TRUE(SplitViewController::Get()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); } @@ -2016,8 +2016,7 @@ gfx::Rect rect(10, 10, 200, 50); std::unique_ptr<aura::Window> window( CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect)); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); OverviewController* overview_controller = Shell::Get()->overview_controller(); // First test 1 window case.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc index f8feb49e..570ff101 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_state.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -85,17 +85,13 @@ } if (state_object->GetStateType() == WindowStateType::kLeftSnapped) { - return Shell::Get() - ->split_view_controller() - ->GetSnappedWindowBoundsInParent(state_object->window(), - SplitViewController::LEFT); + return SplitViewController::Get()->GetSnappedWindowBoundsInParent( + state_object->window(), SplitViewController::LEFT); } if (state_object->GetStateType() == WindowStateType::kRightSnapped) { - return Shell::Get() - ->split_view_controller() - ->GetSnappedWindowBoundsInParent(state_object->window(), - SplitViewController::RIGHT); + return SplitViewController::Get()->GetSnappedWindowBoundsInParent( + state_object->window(), SplitViewController::RIGHT); } gfx::Rect bounds_in_parent;
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index 9fa60d4..b462556 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc
@@ -233,7 +233,7 @@ // overview mode. The default snap position is the position where the window // was first snapped. See |default_snap_position_| in SplitViewController for // more detail. - auto* split_view_controller = Shell::Get()->split_view_controller(); + auto* split_view_controller = SplitViewController::Get(); if (split_view_controller->InTabletSplitViewMode() && window == split_view_controller->GetDefaultSnappedWindow()) { return true;
diff --git a/ash/wm/wm_shadow_controller_delegate.cc b/ash/wm/wm_shadow_controller_delegate.cc index c201afa..bbaa2019 100644 --- a/ash/wm/wm_shadow_controller_delegate.cc +++ b/ash/wm/wm_shadow_controller_delegate.cc
@@ -23,8 +23,7 @@ bool WmShadowControllerDelegate::ShouldShowShadowForWindow( const aura::Window* window) { // Hide the shadow if it is one of the splitscreen snapped windows. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (split_view_controller && split_view_controller->IsWindowInSplitView(window)) { return false;
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc index 5682c74..83e3a75 100644 --- a/ash/wm/workspace/backdrop_controller.cc +++ b/ash/wm/workspace/backdrop_controller.cc
@@ -81,8 +81,7 @@ // For the active desk, only use the windows snapped in SplitViewController if // SplitView mode is active. - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); if (desks_util::IsActiveDeskContainer(desk_container) && split_view_controller->InSplitViewMode()) { aura::Window* left_window = split_view_controller->left_window(); @@ -113,7 +112,7 @@ : container_(container) { DCHECK(container_); auto* shell = Shell::Get(); - shell->split_view_controller()->AddObserver(this); + SplitViewController::Get()->AddObserver(this); shell->overview_controller()->AddObserver(this); shell->accessibility_controller()->AddObserver(this); shell->wallpaper_controller()->AddObserver(this); @@ -129,7 +128,7 @@ shell->wallpaper_controller()->RemoveObserver(this); if (shell->overview_controller()) shell->overview_controller()->RemoveObserver(this); - shell->split_view_controller()->RemoveObserver(this); + SplitViewController::Get()->RemoveObserver(this); // TODO(oshima): animations won't work right with mus: // http://crbug.com/548396. Hide(/*destroy=*/true); @@ -428,8 +427,7 @@ // TODO(afakhry): Define the correct behavior and revise this in a follow-up // CL. aura::Window* window = GetTopmostWindowWithBackdrop(); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); SplitViewController::State state = split_view_controller->state(); if ((state == SplitViewController::State::kLeftSnapped && window == split_view_controller->left_window()) || @@ -444,8 +442,7 @@ gfx::Rect BackdropController::GetBackdropBounds() { DCHECK(!BackdropShouldFullscreen()); - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); SplitViewController::State state = split_view_controller->state(); DCHECK(state == SplitViewController::State::kLeftSnapped || state == SplitViewController::State::kRightSnapped);
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 576b96e..5736a9e 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1814,8 +1814,7 @@ return window; }; - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); + SplitViewController* split_view_controller = SplitViewController::Get(); const gfx::Rect bounds(0, 0, 400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
diff --git a/base/BUILD.gn b/base/BUILD.gn index 3c92548..96d11be 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2490,7 +2490,7 @@ "android/unguessable_token_android_unittest.cc", "at_exit_unittest.cc", "atomicops_unittest.cc", - "auto_reset_unittests.cc", + "auto_reset_unittest.cc", "barrier_closure_unittest.cc", "base64_unittest.cc", "base64url_unittest.cc",
diff --git a/base/auto_reset.h b/base/auto_reset.h index 0ab0af7..d8ce87b6 100644 --- a/base/auto_reset.h +++ b/base/auto_reset.h
@@ -7,8 +7,6 @@ #include <utility> -#include "base/macros.h" - // base::AutoReset<> is useful for setting a variable to a new value only within // a particular scope. An base::AutoReset<> object resets a variable to its // original value upon destruction, making it an alternative to writing @@ -20,19 +18,23 @@ namespace base { -template<typename T> +template <typename T> class AutoReset { public: - AutoReset(T* scoped_variable, T new_value) + template <typename U> + AutoReset(T* scoped_variable, U&& new_value) : scoped_variable_(scoped_variable), - original_value_(std::move(*scoped_variable)) { - *scoped_variable_ = std::move(new_value); - } + original_value_( + std::exchange(*scoped_variable_, std::forward<U>(new_value))) {} AutoReset(AutoReset&& other) - : scoped_variable_(other.scoped_variable_), - original_value_(std::move(other.original_value_)) { - other.scoped_variable_ = nullptr; + : scoped_variable_(std::exchange(other.scoped_variable_, nullptr)), + original_value_(std::move(other.original_value_)) {} + + AutoReset& operator=(AutoReset&& rhs) { + scoped_variable_ = std::exchange(rhs.scoped_variable_, nullptr); + original_value_ = std::move(rhs.original_value_); + return *this; } ~AutoReset() { @@ -40,20 +42,9 @@ *scoped_variable_ = std::move(original_value_); } - AutoReset& operator=(AutoReset&& rhs) { - if (this != &rhs) { - scoped_variable_ = rhs.scoped_variable_; - rhs.scoped_variable_ = nullptr; - original_value_ = std::move(rhs.original_value_); - } - return *this; - } - private: T* scoped_variable_; T original_value_; - - DISALLOW_COPY_AND_ASSIGN(AutoReset); }; } // namespace base
diff --git a/base/auto_reset_unittests.cc b/base/auto_reset_unittest.cc similarity index 100% rename from base/auto_reset_unittests.cc rename to base/auto_reset_unittest.cc
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index c0dd1ec..a405d67 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -205,6 +205,7 @@ } } namespace printing { +class PrintJobWorker; class PrinterQuery; } namespace rlz_lib { @@ -352,6 +353,7 @@ friend class memory_instrumentation::OSMetrics; friend class module_installer::ScopedAllowModulePakLoad; friend class mojo::CoreLibraryInitializer; + friend class printing::PrintJobWorker; friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703 friend class ui::MaterialDesignController; friend class web::WebSubThread;
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index e479d21..93ad68a 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -2039,6 +2039,12 @@ "/Ob0", # Disable all inlining (on by default). "/GF", # Enable string pooling (off by default). ] + + if (target_cpu == "arm64") { + # Disable omitting frame pointers for no_optimize build because stack + # trace on Windows ARM64 relies on it. + cflags += [ "/Oy-" ] + } } else if (is_android && !android_full_debug) { # On Android we kind of optimize some things that don't affect debugging # much even when optimization is disabled to get the binary size down.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 64226d8..876c992 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8899905896794786240 \ No newline at end of file +8899880327732877040 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index d037ab1b..63856f3 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8899912590972143056 \ No newline at end of file +8899879555102631152 \ No newline at end of file
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc index ee9c8e2f..4c48b4b 100644 --- a/cc/metrics/frame_sequence_tracker.cc +++ b/cc/metrics/frame_sequence_tracker.cc
@@ -125,16 +125,15 @@ void FrameSequenceTrackerCollection::NotifyBeginImplFrame( const viz::BeginFrameArgs& args) { - for (auto& tracker : frame_trackers_) { + RecreateTrackers(args); + for (auto& tracker : frame_trackers_) tracker.second->ReportBeginImplFrame(args); - } } void FrameSequenceTrackerCollection::NotifyBeginMainFrame( const viz::BeginFrameArgs& args) { - for (auto& tracker : frame_trackers_) { + for (auto& tracker : frame_trackers_) tracker.second->ReportBeginMainFrame(args); - } } void FrameSequenceTrackerCollection::NotifyImplFrameCausedNoDamage( @@ -185,6 +184,24 @@ }); } +void FrameSequenceTrackerCollection::RecreateTrackers( + const viz::BeginFrameArgs& args) { + std::vector<FrameSequenceTrackerType> recreate_trackers; + for (const auto& tracker : frame_trackers_) { + if (tracker.second->ShouldReportMetricsNow(args)) + recreate_trackers.push_back(tracker.first); + } + + for (const auto& tracker_type : recreate_trackers) { + // StopSequence put the tracker in the |removal_trackers_|, which will + // report its throughput data when its frame is presented. + StopSequence(tracker_type); + // The frame sequence is still active, so create a new tracker to keep + // tracking this sequence. + StartSequence(tracker_type); + } +} + FrameSequenceTracker* FrameSequenceTrackerCollection::GetTrackerForTesting( FrameSequenceTrackerType type) { if (!frame_trackers_.contains(type)) @@ -268,6 +285,9 @@ args.sequence_number); impl_throughput_.frames_expected += begin_impl_frame_data_.previous_sequence_delta; + + if (first_frame_timestamp_.is_null()) + first_frame_timestamp_ = args.frame_time; } void FrameSequenceTracker::ReportBeginMainFrame( @@ -487,6 +507,14 @@ return dict; } +bool FrameSequenceTracker::ShouldReportMetricsNow( + const viz::BeginFrameArgs& args) const { + if (!first_frame_timestamp_.is_null() && + args.frame_time - first_frame_timestamp_ >= time_delta_to_report_) + return true; + return false; +} + base::Optional<int> FrameSequenceTracker::ThroughputData::ReportHistogram( FrameSequenceTrackerType sequence_type, const char* thread_name,
diff --git a/cc/metrics/frame_sequence_tracker.h b/cc/metrics/frame_sequence_tracker.h index bc57f51..5004aa00 100644 --- a/cc/metrics/frame_sequence_tracker.h +++ b/cc/metrics/frame_sequence_tracker.h
@@ -96,6 +96,8 @@ private: friend class FrameSequenceTrackerTest; + void RecreateTrackers(const viz::BeginFrameArgs& args); + const bool is_single_threaded_; // The callsite can use the type to manipulate the tracker. base::flat_map<FrameSequenceTrackerType, @@ -167,6 +169,9 @@ TerminationStatus termination_status() const { return termination_status_; } + // Returns true if we should ask this tracker to report its throughput data. + bool ShouldReportMetricsNow(const viz::BeginFrameArgs& args) const; + private: friend class FrameSequenceTrackerCollection; friend class FrameSequenceTrackerTest; @@ -272,6 +277,13 @@ // Keeps track of the last sequence-number that produced a frame from the // main-thread. uint64_t last_submitted_main_sequence_ = 0; + + // The time when this tracker is created, or the time when it was previously + // scheduled to report histogram. + base::TimeTicks first_frame_timestamp_; + + // Report the throughput metrics every 5 seconds. + const base::TimeDelta time_delta_to_report_ = base::TimeDelta::FromSeconds(5); }; } // namespace cc
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc index a2f081f..53d9b62 100644 --- a/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -37,9 +37,10 @@ FrameSequenceTrackerType::kTouchScroll); } - viz::BeginFrameArgs CreateBeginFrameArgs(uint64_t source_id, - uint64_t sequence_number) { - auto now = base::TimeTicks::Now(); + viz::BeginFrameArgs CreateBeginFrameArgs( + uint64_t source_id, + uint64_t sequence_number, + base::TimeTicks now = base::TimeTicks::Now()) { auto interval = base::TimeDelta::FromMilliseconds(16); auto deadline = now + interval; return viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, source_id, @@ -164,6 +165,17 @@ "Graphics.Smoothness.Throughput.SlowerThread.TouchScroll", 3u); } + base::TimeDelta TimeDeltaToReort() const { + return tracker_->time_delta_to_report_; + } + + unsigned NumberOfTrackers() const { + return collection_.frame_trackers_.size(); + } + unsigned NumberOfRemovalTrackers() const { + return collection_.removal_trackers_.size(); + } + protected: uint32_t number_of_frames_checkerboarded() const { return tracker_->checkerboarding_.frames_checkerboarded; @@ -331,4 +343,26 @@ ReportMetrics(); } +TEST_F(FrameSequenceTrackerTest, ReportMetricsAtFixedInterval) { + const uint64_t source = 1; + uint64_t sequence = 0; + base::TimeDelta first_time_delta = base::TimeDelta::FromSeconds(1); + auto args = CreateBeginFrameArgs(source, ++sequence, + base::TimeTicks::Now() + first_time_delta); + + // args.frame_time is less than 5s of the tracker creation time, so won't + // schedule this tracker to report its throughput. + collection_.NotifyBeginImplFrame(args); + EXPECT_EQ(NumberOfTrackers(), 1u); + EXPECT_EQ(NumberOfRemovalTrackers(), 0u); + + // Now args.frame_time is 5s since the tracker creation time, so this tracker + // should be scheduled to report its throughput. + args = CreateBeginFrameArgs(source, ++sequence, + args.frame_time + TimeDeltaToReort()); + collection_.NotifyBeginImplFrame(args); + EXPECT_EQ(NumberOfTrackers(), 1u); + EXPECT_EQ(NumberOfRemovalTrackers(), 1u); +} + } // namespace cc
diff --git a/cc/paint/element_id.cc b/cc/paint/element_id.cc index 15d7883..69d3237 100644 --- a/cc/paint/element_id.cc +++ b/cc/paint/element_id.cc
@@ -26,7 +26,7 @@ res->EndDictionary(); } -ElementIdType ElementId::GetInternalValue() const { +ElementIdType ElementId::GetStableId() const { return id_; }
diff --git a/cc/paint/element_id.h b/cc/paint/element_id.h index 59e0158..05ecd23 100644 --- a/cc/paint/element_id.h +++ b/cc/paint/element_id.h
@@ -61,7 +61,7 @@ void AddToTracedValue(base::trace_event::TracedValue* res) const; std::unique_ptr<base::Value> AsValue() const; - ElementIdType GetInternalValue() const; + ElementIdType GetStableId() const; std::string ToString() const;
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc index 6560daea..b84952f 100644 --- a/cc/trees/effect_node.cc +++ b/cc/trees/effect_node.cc
@@ -138,7 +138,7 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const { value->SetInteger("backdrop_mask_element_id", - backdrop_mask_element_id.GetInternalValue()); + backdrop_mask_element_id.GetStableId()); value->SetInteger("id", id); value->SetInteger("parent_id", parent_id); value->SetInteger("stable_id", stable_id);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index a624cef..6facf98 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -3908,7 +3908,7 @@ ElementId current_native_scrolling_element = scroll_state->data()->current_native_scrolling_element(); - if (current_native_scrolling_element.GetInternalValue() != 0) { + if (current_native_scrolling_element.GetStableId() != 0) { auto& scroll_tree = active_tree_->property_trees()->scroll_tree; scrolling_node = scroll_tree.FindNodeFromElementId(current_native_scrolling_element);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomSheetContent.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomSheetContent.java index 5548929..eb2d7fa7 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomSheetContent.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomSheetContent.java
@@ -85,11 +85,6 @@ } @Override - public boolean isPeekStateEnabled() { - return true; - } - - @Override public boolean wrapContentEnabled() { return true; }
diff --git a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml index ab83e2c..c9928dc 100644 --- a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml +++ b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
@@ -6,6 +6,7 @@ <org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/tab_group_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -15,23 +16,27 @@ android:layout_width="match_parent" android:layout_height="@dimen/bottom_sheet_peek_height" android:orientation="horizontal" - android:gravity="center_vertical" - android:clickable="true"> + android:gravity="center_vertical"> <org.chromium.ui.widget.ChromeImageView android:id="@+id/toolbar_left_button" style="@style/BottomToolbarButton" android:src="@drawable/ic_expand_more_black_24dp" app:tint="@color/standard_mode_tint" android:contentDescription="@string/accessibility_bottom_tab_grid_close_tab_sheet" /> - <TextView - android:id="@+id/title" - android:layout_height="wrap_content" - android:layout_width="0dp" - android:layout_weight="1" - android:singleLine="true" - android:ellipsize="end" - android:textAppearance="@style/TextAppearance.BlackTitle1" - android:gravity="center"/> + <EditText + tools:ignore="LabelFor" + android:id="@+id/title" + android:cursorVisible="false" + android:background="@android:color/transparent" + android:layout_height="@dimen/bottom_sheet_peek_height" + android:layout_width="0dp" + android:layout_weight="1" + android:singleLine="true" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.BlackTitle1" + android:inputType="text|textNoSuggestions" + android:imeOptions="actionDone" + android:gravity="center"/> <org.chromium.ui.widget.ChromeImageView android:id="@+id/toolbar_right_button" style="@style/BottomToolbarButton"
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java index 2adcfc41..5f82dde 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
@@ -9,6 +9,7 @@ import android.content.SharedPreferences; import android.view.View; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import org.chromium.base.ApplicationStatus; @@ -149,6 +150,7 @@ * @param title The tab group title to store. */ public static void storeTabGroupTitle(int tabRootId, String title) { + assert tabRootId != Tab.INVALID_TAB_ID; getSharedPreferences().edit().putString(String.valueOf(tabRootId), title).apply(); } @@ -157,6 +159,7 @@ * @param tabRootId The tab root ID whose related tab group title will be deleted. */ public static void deleteTabGroupTitle(int tabRootId) { + assert tabRootId != Tab.INVALID_TAB_ID; getSharedPreferences().edit().remove(String.valueOf(tabRootId)).apply(); } @@ -165,7 +168,9 @@ * @param tabRootId The tab root ID whose related tab group title will be fetched. * @return The stored title of the target tab group, default value is null. */ + @Nullable public static String getTabGroupTitle(int tabRootId) { + assert tabRootId != Tab.INVALID_TAB_ID; return getSharedPreferences().getString(String.valueOf(tabRootId), null); }
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 4923f92..c8b1ae8 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
@@ -38,7 +38,8 @@ TabContentManager tabContentManager, TabCreatorManager tabCreatorManager, ViewGroup containerView, TabSwitcherMediator.ResetHandler resetHandler, TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider, - TabGridDialogMediator.AnimationParamsProvider animationParamsProvider) { + TabGridDialogMediator.AnimationParamsProvider animationParamsProvider, + TabGroupTitleEditor tabGroupTitleEditor) { mComponentName = animationParamsProvider == null ? "TabGridDialogFromStrip" : "TabGridDialogInSwitcher"; @@ -51,7 +52,8 @@ mMediator = new TabGridDialogMediator(context, this, mToolbarPropertyModel, tabModelSelector, tabCreatorManager, resetHandler, animationParamsProvider, - mTabSelectionEditorCoordinator.getController(), mComponentName); + mTabSelectionEditorCoordinator.getController(), tabGroupTitleEditor, + mComponentName); mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null,
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 2218c11..b73c06ab 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
@@ -9,6 +9,8 @@ import android.content.Context; import android.content.res.ColorStateList; import android.support.v7.content.res.AppCompatResources; +import android.text.Editable; +import android.text.TextWatcher; import android.view.View; import androidx.annotation.Nullable; @@ -32,6 +34,7 @@ import org.chromium.chrome.browser.widget.ScrimView; import org.chromium.chrome.tab_ui.R; import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.modelutil.PropertyModel; import java.util.List; @@ -89,18 +92,22 @@ private final DialogController mDialogController; private final TabSwitcherMediator.ResetHandler mTabSwitcherResetHandler; private final AnimationParamsProvider mAnimationParamsProvider; + private final TabGroupTitleEditor mTabGroupTitleEditor; private final DialogHandler mTabGridDialogHandler; private final TabSelectionEditorCoordinator .TabSelectionEditorController mTabSelectionEditorController; private final String mComponentName; + private KeyboardVisibilityDelegate.KeyboardVisibilityListener mKeyboardVisibilityListener; private int mCurrentTabId = Tab.INVALID_TAB_ID; + private boolean mIsUpdatingTitle; + private String mCurrentGroupModifiedTitle; TabGridDialogMediator(Context context, DialogController dialogController, PropertyModel model, TabModelSelector tabModelSelector, TabCreatorManager tabCreatorManager, TabSwitcherMediator.ResetHandler tabSwitcherResetHandler, AnimationParamsProvider animationParamsProvider, TabSelectionEditorCoordinator.TabSelectionEditorController tabSelectionEditorController, - String componentName) { + TabGroupTitleEditor tabGroupTitleEditor, String componentName) { mContext = context; mModel = model; mTabModelSelector = tabModelSelector; @@ -108,6 +115,7 @@ mDialogController = dialogController; mTabSwitcherResetHandler = tabSwitcherResetHandler; mAnimationParamsProvider = animationParamsProvider; + mTabGroupTitleEditor = tabGroupTitleEditor; mTabGridDialogHandler = new DialogHandler(); mTabSelectionEditorController = tabSelectionEditorController; mComponentName = componentName; @@ -188,12 +196,15 @@ assert mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter() instanceof TabGroupModelFilter; - // Setup toolbar property model. + // Setup toolbar button click listeners. setupToolbarClickHandlers(); // Setup dialog selection editor. setupDialogSelectionEditor(); + // Setup toolbar edit text. + setupToolbarEditText(); + // Setup ScrimView observer. setupScrimViewObserver(); } @@ -208,6 +219,7 @@ } } mTabSelectionEditorController.hide(); + saveCurrentGroupModifiedTitle(); mDialogController.resetWithListOfTabs(null); } @@ -243,6 +255,8 @@ mTabModelObserver); } mTabModelSelector.removeObserver(mTabModelSelectorObserver); + KeyboardVisibilityDelegate.getInstance().removeKeyboardVisibilityListener( + mKeyboardVisibilityListener); } boolean isVisible() { @@ -263,6 +277,13 @@ hideDialog(true); return; } + assert mTabGroupTitleEditor != null; + Tab currentTab = mTabModelSelector.getTabById(mCurrentTabId); + String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(currentTab.getRootId()); + if (storedTitle != null && relatedTabs.size() > 1) { + mModel.set(TabGridPanelProperties.HEADER_TITLE, storedTitle); + return; + } mModel.set(TabGridPanelProperties.HEADER_TITLE, mContext.getResources().getQuantityString( R.plurals.bottom_tab_grid_title_placeholder, tabsCount, tabsCount)); @@ -298,6 +319,36 @@ mTabSelectionEditorController.configureToolbar(actionButtonText, actionProvider, 1, null); } + private void setupToolbarEditText() { + mKeyboardVisibilityListener = isShowing -> { + mModel.set(TabGridPanelProperties.TITLE_CURSOR_VISIBILITY, isShowing); + if (!isShowing) { + saveCurrentGroupModifiedTitle(); + } + }; + KeyboardVisibilityDelegate.getInstance().addKeyboardVisibilityListener( + mKeyboardVisibilityListener); + + TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + if (!mIsUpdatingTitle) return; + mCurrentGroupModifiedTitle = s.toString(); + } + }; + mModel.set(TabGridPanelProperties.TITLE_TEXT_WATCHER, textWatcher); + + View.OnFocusChangeListener onFocusChangeListener = + (v, hasFocus) -> mIsUpdatingTitle = hasFocus; + mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER, onFocusChangeListener); + } + private void setupScrimViewObserver() { ScrimView.ScrimObserver scrimObserver = new ScrimView.ScrimObserver() { @Override @@ -357,6 +408,18 @@ .getRelatedTabList(tabId); } + private void saveCurrentGroupModifiedTitle() { + if (mCurrentGroupModifiedTitle == null) return; + assert mTabGroupTitleEditor != null; + assert mCurrentTabId != Tab.INVALID_TAB_ID; + + Tab currentTab = mTabModelSelector.getTabById(mCurrentTabId); + mTabGroupTitleEditor.storeTabGroupTitle(currentTab.getRootId(), mCurrentGroupModifiedTitle); + mTabGroupTitleEditor.updateTabGroupTitle(currentTab, mCurrentGroupModifiedTitle); + mModel.set(TabGridPanelProperties.HEADER_TITLE, mCurrentGroupModifiedTitle); + mCurrentGroupModifiedTitle = null; + } + TabListMediator.TabGridDialogHandler getTabGridDialogHandler() { return mTabGridDialogHandler; } @@ -387,4 +450,20 @@ void setCurrentTabIdForTest(int tabId) { mCurrentTabId = tabId; } + + @VisibleForTesting + KeyboardVisibilityDelegate.KeyboardVisibilityListener + getKeyboardVisibilityListenerForTesting() { + return mKeyboardVisibilityListener; + } + + @VisibleForTesting + boolean getIsUpdatingTitleForTesting() { + return mIsUpdatingTitle; + } + + @VisibleForTesting + String getCurrentGroupModifiedTitleForTesting() { + return mCurrentGroupModifiedTitle; + } }
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 73f9b31..40ddf4e6 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
@@ -174,6 +174,7 @@ mScrimView = new ScrimView(context, null, mTabGridDialogParentView); mPopupWindow = new PopupWindow(mTabGridDialogParentView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mPopupWindow.setFocusable(true); updateDialogWithOrientation(context, context.getResources().getConfiguration().orientation); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java index 504c649..0168d2c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.tasks.tab_management; import android.content.res.ColorStateList; +import android.text.TextWatcher; +import android.view.View; import android.view.View.OnClickListener; import org.chromium.chrome.browser.widget.ScrimView; @@ -60,10 +62,18 @@ public static final PropertyModel .WritableObjectPropertyKey<OnClickListener> MENU_CLICK_LISTENER = new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyModel.WritableObjectPropertyKey<TextWatcher> TITLE_TEXT_WATCHER = + new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyModel + .WritableObjectPropertyKey<View.OnFocusChangeListener> TITLE_TEXT_ON_FOCUS_LISTENER = + new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyModel.WritableBooleanPropertyKey TITLE_CURSOR_VISIBILITY = + new PropertyModel.WritableBooleanPropertyKey(); 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_PARAMS, UNGROUP_BAR_STATUS, DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE, - INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER}; + INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER, + TITLE_TEXT_ON_FOCUS_LISTENER, TITLE_CURSOR_VISIBILITY}; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java index be62ff0..b362ef7 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java
@@ -20,6 +20,9 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.PRIMARY_COLOR; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.SCRIMVIEW_OBSERVER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT; +import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_CURSOR_VISIBILITY; +import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER; +import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_WATCHER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.UNGROUP_BAR_STATUS; import android.support.v7.widget.LinearLayoutManager; @@ -117,6 +120,13 @@ viewHolder.contentView.setVisibility(View.VISIBLE); } else if (MENU_CLICK_LISTENER == propertyKey) { viewHolder.toolbarView.setMenuButtonOnClickListener(model.get(MENU_CLICK_LISTENER)); + } else if (TITLE_TEXT_WATCHER == propertyKey) { + viewHolder.toolbarView.setTitleTextOnChangedListener(model.get(TITLE_TEXT_WATCHER)); + } else if (TITLE_TEXT_ON_FOCUS_LISTENER == propertyKey) { + viewHolder.toolbarView.setTitleTextOnFocusChangeListener( + model.get(TITLE_TEXT_ON_FOCUS_LISTENER)); + } else if (TITLE_CURSOR_VISIBILITY == propertyKey) { + viewHolder.toolbarView.setTitleCursorVisibility(model.get(TITLE_CURSOR_VISIBILITY)); } } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetContent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetContent.java index ba7f16e..3453737 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetContent.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetContent.java
@@ -6,6 +6,7 @@ import android.view.View; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.ContentPriority; import org.chromium.chrome.tab_ui.R; @@ -54,8 +55,8 @@ } @Override - public boolean isPeekStateEnabled() { - return false; + public int getPeekHeight() { + return BottomSheet.HeightMode.DISABLED; } @Override
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 c3ceef34..db6262cd 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
@@ -88,9 +88,9 @@ // and the dialog here. mTabGridSheetCoordinator = null; - mTabGridDialogCoordinator = - new TabGridDialogCoordinator(mContext, tabModelSelector, tabContentManager, - activity, activity.getCompositorViewHolder(), null, null, null); + mTabGridDialogCoordinator = new TabGridDialogCoordinator(mContext, tabModelSelector, + tabContentManager, activity, activity.getCompositorViewHolder(), null, null, + null, mTabStripCoordinator.getTabGroupTitleEditor()); } else { mTabGridSheetCoordinator = new TabGridSheetCoordinator(mContext, activity.getBottomSheetController(),
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java index 204c89bc..4cc1f3c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
@@ -7,13 +7,14 @@ import android.content.Context; import android.content.res.ColorStateList; import android.support.v4.widget.TextViewCompat; +import android.text.TextWatcher; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; -import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.tab_ui.R; @@ -28,7 +29,7 @@ private ChromeImageView mLeftButton; private ChromeImageView mMenuButton; private ViewGroup mContainerView; - private TextView mTitleTextView; + private EditText mTitleTextView; private LinearLayout mMainContent; public TabGroupUiToolbarView(Context context, AttributeSet attrs) { @@ -43,7 +44,7 @@ mRightButton = findViewById(R.id.toolbar_right_button); mMenuButton = findViewById(R.id.toolbar_menu_button); mContainerView = (ViewGroup) findViewById(R.id.toolbar_container_view); - mTitleTextView = (TextView) findViewById(R.id.title); + mTitleTextView = (EditText) findViewById(R.id.title); mMainContent = findViewById(R.id.main_content); } @@ -59,6 +60,18 @@ mMenuButton.setOnClickListener(listener); } + void setTitleTextOnChangedListener(TextWatcher textWatcher) { + mTitleTextView.addTextChangedListener(textWatcher); + } + + void setTitleTextOnFocusChangeListener(OnFocusChangeListener listener) { + mTitleTextView.setOnFocusChangeListener(listener); + } + + void setTitleCursorVisibility(boolean isVisible) { + mTitleTextView.setCursorVisible(isVisible); + } + ViewGroup getViewContainer() { return mContainerView; } @@ -100,6 +113,8 @@ if (!isDialog) { // We don't support toolbar menu for TabGridSheet. mMainContent.removeView(mMenuButton); + // We don't support tab group naming for TabGridSheet. + mTitleTextView.setFocusable(false); return; } Context context = getContext(); @@ -108,7 +123,7 @@ (int) context.getResources().getDimension(R.dimen.tab_group_toolbar_topic_margin); MarginLayoutParams params = (MarginLayoutParams) mTitleTextView.getLayoutParams(); params.setMarginStart(topicMargin); - mTitleTextView.setGravity(Gravity.START); + mTitleTextView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); TextViewCompat.setTextAppearance( mTitleTextView, org.chromium.chrome.R.style.TextAppearance_BlackHeadline); }
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 d3c839a9..9eacbea3 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
@@ -235,6 +235,13 @@ } /** + * @return The editor {@link TabGroupTitleEditor} that is used to update tab group title. + */ + TabGroupTitleEditor getTabGroupTitleEditor() { + return mMediator.getTabGroupTitleEditor(); + } + + /** * @see TabListMediator#resetWithListOfTabs(List, boolean, boolean) */ boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode, boolean mruMode) {
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 d8da896b..e176c58 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
@@ -329,7 +329,7 @@ public void onTitleUpdated(Tab updatedTab) { int index = mModel.indexFromId(updatedTab.getId()); if (index == TabModel.INVALID_TAB_INDEX) return; - mModel.get(index).model.set(TabProperties.TITLE, mTitleProvider.getTitle(updatedTab)); + mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(updatedTab)); } @Override @@ -340,6 +340,8 @@ private final TabModelObserver mTabModelObserver; + private TabGroupTitleEditor mTabGroupTitleEditor; + private TabGroupModelFilter.Observer mTabGroupObserver; /** @@ -668,6 +670,35 @@ } }; + if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { + mTabGroupTitleEditor = new TabGroupTitleEditor(mTabModelSelector) { + @Override + protected void updateTabGroupTitle(Tab tab, String title) { + // Only update title in PropertyModel for tab switcher. + if (!mActionsOnAllRelatedTabs) return; + Tab currentGroupSelectedTab = + TabGroupUtils.getSelectedTabInGroupForTab(mTabModelSelector, tab); + int index = mModel.indexFromId(currentGroupSelectedTab.getId()); + if (index == TabModel.INVALID_TAB_INDEX) return; + mModel.get(index).model.set(TabProperties.TITLE, title); + } + + @Override + protected void deleteTabGroupTitle(int tabRootId) { + TabGroupUtils.deleteTabGroupTitle(tabRootId); + } + + @Override + protected String getTabGroupTitle(int tabRootId) { + return TabGroupUtils.getTabGroupTitle(tabRootId); + } + + @Override + protected void storeTabGroupTitle(int tabRootId, String title) { + TabGroupUtils.storeTabGroupTitle(tabRootId, title); + } + }; + } mTabGridItemTouchHelperCallback = new TabGridItemTouchHelperCallback(mModel, mTabModelSelector, mTabClosedListener, mTabGridDialogHandler, mComponentName, mActionsOnAllRelatedTabs); @@ -861,7 +892,7 @@ mModel.get(index).model.set( TabProperties.CREATE_GROUP_LISTENER, getCreateGroupButtonListener(tab, isSelected)); mModel.get(index).model.set(TabProperties.IS_SELECTED, isSelected); - mModel.get(index).model.set(TabProperties.TITLE, mTitleProvider.getTitle(tab)); + mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(tab)); updateFaviconForTab(tab, null); boolean forceUpdate = isSelected && !quickMode; @@ -916,6 +947,15 @@ } /** + * Exposes a {@link TabGroupTitleEditor} to modify the title of a tab group. + * @return The {@link TabGroupTitleEditor} used to modify the title of a tab group. + */ + @Nullable + TabGroupTitleEditor getTabGroupTitleEditor() { + return mTabGroupTitleEditor; + } + + /** * Destroy any members that needs clean up. */ public void destroy() { @@ -940,6 +980,9 @@ if (mComponentCallbacks != null) { mContext.unregisterComponentCallbacks(mComponentCallbacks); } + if (mTabGroupTitleEditor != null) { + mTabGroupTitleEditor.destroy(); + } } private void addTabInfoToModel(final Tab tab, int index, boolean isSelected) { @@ -970,7 +1013,7 @@ PropertyModel tabInfo = new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID) .with(TabProperties.TAB_ID, tab.getId()) - .with(TabProperties.TITLE, mTitleProvider.getTitle(tab)) + .with(TabProperties.TITLE, getLatestTitleForTab(tab)) .with(TabProperties.FAVICON, mTabListFaviconProvider.getDefaultFaviconDrawable( tab.isIncognito())) @@ -1051,6 +1094,18 @@ return createGroupButtonOnClickListener; } + @VisibleForTesting + String getLatestTitleForTab(Tab tab) { + String originalTitle = mTitleProvider.getTitle(tab); + if (!mActionsOnAllRelatedTabs || mTabGroupTitleEditor == null) return originalTitle; + // If the group degrades to a single tab, delete the stored title. + if (getRelatedTabsForId(tab.getId()).size() <= 1) { + return originalTitle; + } + String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(tab.getRootId()); + return storedTitle == null ? originalTitle : storedTitle; + } + int selectedTabId() { if (mNextTabId != Tab.INVALID_TAB_ID) { return mNextTabId;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java index 4012109e..dd394710 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -95,19 +95,6 @@ mMediator = new TabSwitcherMediator(this, containerViewModel, tabModelSelector, fullscreenManager, container, mTabSelectionEditorCoordinator.getController(), mode); - if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { - mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector, - tabContentManager, tabCreatorManager, container, this, mMediator, - this::getTabGridDialogAnimationParams); - - mUndoGroupSnackbarController = - new UndoGroupSnackbarController(context, tabModelSelector, snackbarManageable); - - mMediator.setTabGridDialogController(mTabGridDialogCoordinator.getDialogController()); - } else { - mTabGridDialogCoordinator = null; - mUndoGroupSnackbarController = null; - } mMultiThumbnailCardProvider = new MultiThumbnailCardProvider(context, tabContentManager, tabModelSelector); @@ -129,6 +116,21 @@ mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel, mTabListCoordinator.getContainerView(), TabListContainerViewBinder::bind); + if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { + mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector, + tabContentManager, tabCreatorManager, container, this, mMediator, + this::getTabGridDialogAnimationParams, + mTabListCoordinator.getTabGroupTitleEditor()); + + mUndoGroupSnackbarController = + new UndoGroupSnackbarController(context, tabModelSelector, snackbarManageable); + + mMediator.setTabGridDialogController(mTabGridDialogCoordinator.getDialogController()); + } else { + mTabGridDialogCoordinator = null; + mUndoGroupSnackbarController = null; + } + if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled() && mode == TabListCoordinator.TabListMode.GRID && !FeatureUtilities.isStartSurfaceEnabled()) {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java index 32ea41b..47467a5 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
@@ -10,15 +10,17 @@ import android.os.Build; import android.provider.Settings; import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.MediumTest; +import android.support.test.filters.SmallTest; import android.support.v4.content.ContextCompat; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.TextView; import org.junit.Assert; import org.junit.Test; @@ -51,7 +53,7 @@ private TabGridDialogParent mTabGridDialogParent; private ChromeImageView mRightButton; private ChromeImageView mLeftButton; - private TextView mTitleTextView; + private EditText mTitleTextView; private View mMainContent; private ViewGroup mTabGridDialogParentView; @@ -81,7 +83,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetCollapseClickListener() { AtomicBoolean leftButtonClicked = new AtomicBoolean(); @@ -97,7 +99,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetAddClickListener() { AtomicBoolean rightButtonClicked = new AtomicBoolean(); @@ -113,7 +115,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetHeaderTitle() { String title = "1024 tabs"; @@ -121,11 +123,11 @@ mModel.set(TabGridPanelProperties.HEADER_TITLE, title); - Assert.assertEquals(title, mTitleTextView.getText()); + Assert.assertEquals(title, mTitleTextView.getText().toString()); } @Test - @MediumTest + @SmallTest @UiThreadTest public void testContentTopMargin() { // Since setting content top margin is only used in sheet, we can assume that the parent is @@ -143,7 +145,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetPrimaryColor() { int color = ContextCompat.getColor(getActivity(), R.color.modern_blue_300); @@ -157,7 +159,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetTint() { ColorStateList tint = ColorUtils.getThemedToolbarIconTint(getActivity(), true); @@ -177,7 +179,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetScrimViewObserver() { AtomicBoolean scrimViewClicked = new AtomicBoolean(); @@ -204,7 +206,7 @@ } @Test - @MediumTest + @SmallTest public void testSetDialogVisibility() { Assert.assertFalse(mTabGridDialogParent.getPopupWindowForTesting().isShowing()); Assert.assertNull(mTabGridDialogParent.getCurrentDialogAnimatorForTesting()); @@ -237,7 +239,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetAnimationParams() { // Initially, the show animation set is empty. @@ -269,7 +271,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetUngroupbarStatus() { // Default status for ungroup bar is hidden. @@ -288,7 +290,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetDialogBackgroundResource() { int normalResourceId = R.drawable.tab_grid_dialog_background; @@ -304,7 +306,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetUngroupbarBackgroundColor() { int normalColorId = R.color.tab_grid_dialog_background_color; @@ -320,7 +322,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetUngroupbarHoveredBackgroundColor() { int normalColorId = R.color.tab_grid_card_selected_color; @@ -337,7 +339,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetUngroupbarTextAppearance() { int normalStyleId = R.style.TextAppearance_BlueTitle2; @@ -353,7 +355,7 @@ } @Test - @MediumTest + @SmallTest @UiThreadTest public void testSetMainContentVisibility() { mContentView.setVisibility(View.INVISIBLE); @@ -364,6 +366,59 @@ Assert.assertEquals(View.VISIBLE, mContentView.getVisibility()); } + @Test + @SmallTest + @UiThreadTest + public void testSetTitleTextWatcher() { + String title = "cool tabs"; + AtomicBoolean titleTextUpdated = new AtomicBoolean(); + titleTextUpdated.set(false); + + TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void afterTextChanged(Editable editable) { + titleTextUpdated.set(true); + } + }; + mModel.set(TabGridPanelProperties.TITLE_TEXT_WATCHER, textWatcher); + + mTitleTextView.setText(title); + Assert.assertTrue(titleTextUpdated.get()); + } + + @Test + @SmallTest + @UiThreadTest + public void testSetTitleTextOnFocusListener() { + AtomicBoolean textFocusChanged = new AtomicBoolean(); + textFocusChanged.set(false); + Assert.assertFalse(mTitleTextView.isFocused()); + + View.OnFocusChangeListener listener = (view, b) -> textFocusChanged.set(true); + mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER, listener); + mTitleTextView.requestFocus(); + + Assert.assertTrue(mTitleTextView.isFocused()); + Assert.assertTrue(textFocusChanged.get()); + } + + @Test + @SmallTest + @UiThreadTest + public void testSetCursorVisibility() { + mTitleTextView.setCursorVisible(false); + + mModel.set(TabGridPanelProperties.TITLE_CURSOR_VISIBILITY, true); + + Assert.assertTrue(mTitleTextView.isCursorVisible()); + } + @Override public void tearDownTest() throws Exception { mMCP.destroy();
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java index 9dc410f..0fad718 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -10,6 +10,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doNothing; @@ -17,11 +18,15 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; +import android.text.Editable; +import android.text.TextWatcher; import android.view.View; +import android.widget.EditText; import org.junit.After; import org.junit.Before; @@ -51,6 +56,7 @@ import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.modelutil.PropertyModel; import java.util.ArrayList; @@ -72,6 +78,7 @@ private static final String DIALOG_TITLE1 = "1 Tab"; private static final String DIALOG_TITLE2 = "2 Tabs"; private static final String REMOVE_BUTTON_STRING = "Remove"; + private static final String CUSTOMIZED_DIALOG_TITLE = "Cool Tabs"; private static final int TAB1_ID = 456; private static final int TAB2_ID = 789; private static final int TAB3_ID = 123; @@ -108,6 +115,12 @@ TabModel mTabModel; @Mock TabSelectionEditorCoordinator.TabSelectionEditorController mTabSelectionEditorController; + @Mock + TabGroupTitleEditor mTabGroupTitleEditor; + @Mock + EditText mTitleTextView; + @Mock + Editable mEditable; @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @@ -167,11 +180,13 @@ doReturn(REMOVE_BUTTON_STRING) .when(mContext) .getString(R.string.tab_grid_dialog_selection_mode_remove); + doReturn(mEditable).when(mTitleTextView).getText(); + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mEditable).toString(); mModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS); mMediator = new TabGridDialogMediator(mContext, mDialogController, mModel, mTabModelSelector, mTabCreatorManager, mTabSwitcherResetHandler, - mAnimationParamsProvider, mTabSelectionEditorController, ""); + mAnimationParamsProvider, mTabSelectionEditorController, mTabGroupTitleEditor, ""); } @After @@ -242,6 +257,111 @@ } @Test + public void onTitleTextChange_WithoutFocus() { + TextWatcher textWatcher = mModel.get(TabGridPanelProperties.TITLE_TEXT_WATCHER); + // Mock tab1 is the current tab for the dialog. + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + assertThat(mEditable.toString(), equalTo(CUSTOMIZED_DIALOG_TITLE)); + + textWatcher.afterTextChanged(mEditable); + + // TabGroupTitleEditor should not react to text change when there is no focus. + verify(mTabGroupTitleEditor, never()).storeTabGroupTitle(anyInt(), any(String.class)); + verify(mTabGroupTitleEditor, never()).updateTabGroupTitle(any(Tab.class), anyString()); + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(TAB1_TITLE)); + assertThat(mMediator.getCurrentGroupModifiedTitleForTesting(), equalTo(null)); + } + + @Test + public void onTitleTextChange_WithFocus() { + TextWatcher textWatcher = mModel.get(TabGridPanelProperties.TITLE_TEXT_WATCHER); + // Mock tab1 is the current tab for the dialog. + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + assertThat(mEditable.toString(), equalTo(CUSTOMIZED_DIALOG_TITLE)); + + // Focus on title TextView. + View.OnFocusChangeListener listener = + mModel.get(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER); + listener.onFocusChange(mTitleTextView, true); + + textWatcher.afterTextChanged(mEditable); + + assertThat(mMediator.getCurrentGroupModifiedTitleForTesting(), + equalTo(CUSTOMIZED_DIALOG_TITLE)); + } + + @Test + public void onTitleTextFocusChange() { + View.OnFocusChangeListener listener = + mModel.get(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER); + assertThat(mMediator.getIsUpdatingTitleForTesting(), equalTo(false)); + + listener.onFocusChange(mTitleTextView, true); + + assertThat(mMediator.getIsUpdatingTitleForTesting(), equalTo(true)); + } + + @Test + public void onKeyBoardVisibilityChanged_ChangeCursorVisibility() { + KeyboardVisibilityDelegate.KeyboardVisibilityListener listener = + mMediator.getKeyboardVisibilityListenerForTesting(); + mModel.set(TabGridPanelProperties.TITLE_CURSOR_VISIBILITY, false); + + listener.keyboardVisibilityChanged(true); + assertThat(mModel.get(TabGridPanelProperties.TITLE_CURSOR_VISIBILITY), equalTo(true)); + + listener.keyboardVisibilityChanged(false); + assertThat(mModel.get(TabGridPanelProperties.TITLE_CURSOR_VISIBILITY), equalTo(false)); + } + + @Test + public void onKeyBoardVisibilityChanged_StoreGroupTitle() { + KeyboardVisibilityDelegate.KeyboardVisibilityListener keyboardVisibilityListener = + mMediator.getKeyboardVisibilityListenerForTesting(); + TextWatcher textWatcher = mModel.get(TabGridPanelProperties.TITLE_TEXT_WATCHER); + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + + // Mock that keyboard shows and group title is updated. + keyboardVisibilityListener.keyboardVisibilityChanged(true); + View.OnFocusChangeListener onFocusChangeListener = + mModel.get(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER); + onFocusChangeListener.onFocusChange(mTitleTextView, true); + textWatcher.afterTextChanged(mEditable); + assertThat(mMediator.getCurrentGroupModifiedTitleForTesting(), + equalTo(CUSTOMIZED_DIALOG_TITLE)); + + keyboardVisibilityListener.keyboardVisibilityChanged(false); + + verify(mTabGroupTitleEditor).storeTabGroupTitle(eq(TAB1_ID), eq(CUSTOMIZED_DIALOG_TITLE)); + verify(mTabGroupTitleEditor).updateTabGroupTitle(eq(mTab1), eq(CUSTOMIZED_DIALOG_TITLE)); + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); + } + + @Test + public void onKeyBoardVisibilityChanged_NoFocus_NotStoreGroupTitle() { + KeyboardVisibilityDelegate.KeyboardVisibilityListener keyboardVisibilityListener = + mMediator.getKeyboardVisibilityListenerForTesting(); + TextWatcher textWatcher = mModel.get(TabGridPanelProperties.TITLE_TEXT_WATCHER); + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + + // Mock that keyboard shows but title edit text is not focused. + keyboardVisibilityListener.keyboardVisibilityChanged(true); + textWatcher.afterTextChanged(mEditable); + assertThat(mMediator.getIsUpdatingTitleForTesting(), equalTo(false)); + + keyboardVisibilityListener.keyboardVisibilityChanged(false); + + verify(mTabGroupTitleEditor, never()).storeTabGroupTitle(anyInt(), anyString()); + verify(mTabGroupTitleEditor, never()).updateTabGroupTitle(any(Tab.class), anyString()); + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(TAB1_TITLE)); + } + + @Test public void tabAddition() { Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); // Mock that the animation params is not null. @@ -255,13 +375,13 @@ @Test public void tabClosure_NotLast_NotCurrent() { - // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed. + // Mock that tab1 and tab2 are in the same group, but tab2 just gets closed. doReturn(new ArrayList<>(Arrays.asList(mTab1))) .when(mTabGroupModelFilter) .getRelatedTabList(TAB2_ID); - // Assume tab1 is the current tab for the dialog. + // Mock tab1 is the current tab for the dialog. mMediator.setCurrentTabIdForTest(TAB1_ID); - // Assume dialog title is null and the dialog is showing. + // Mock dialog title is null and the dialog is showing. mModel.set(TabGridPanelProperties.HEADER_TITLE, null); mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); @@ -275,13 +395,13 @@ @Test public void tabClosure_NotLast_Current() { - // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed. + // Mock that tab1 and tab2 are in the same group, but tab2 just gets closed. doReturn(new ArrayList<>(Arrays.asList(mTab1))) .when(mTabGroupModelFilter) .getRelatedTabList(TAB2_ID); - // Assume tab2 is the current tab for the dialog. + // Mock tab2 is the current tab for the dialog. mMediator.setCurrentTabIdForTest(TAB2_ID); - // Assume dialog title is null and the dialog is showing. + // Mock dialog title is null and the dialog is showing. mModel.set(TabGridPanelProperties.HEADER_TITLE, null); mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); @@ -295,11 +415,11 @@ @Test public void tabClosure_Last_Current() { - // Assume that tab1 is the last tab in the group and it just gets closed. + // Mock that tab1 is the last tab in the group and it just gets closed. doReturn(new ArrayList<>()).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); // As last tab in the group, tab1 is definitely the current tab for the dialog. mMediator.setCurrentTabIdForTest(TAB1_ID); - // Assume the dialog is showing and the source animation params is not null. + // Mock the dialog is showing and the source animation params is not null. mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, mAnimationParams); mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); @@ -316,13 +436,13 @@ @Test public void tabClosure_NotLast_Current_WithDialogHidden() { - // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed. + // Mock that tab1 and tab2 are in the same group, but tab2 just gets closed. doReturn(new ArrayList<>(Arrays.asList(mTab1))) .when(mTabGroupModelFilter) .getRelatedTabList(TAB2_ID); - // Assume tab2 is the current tab for the dialog. + // Mock tab2 is the current tab for the dialog. mMediator.setCurrentTabIdForTest(TAB2_ID); - // Assume dialog title is null and the dialog is hidden. + // Mock dialog title is null and the dialog is hidden. mModel.set(TabGridPanelProperties.HEADER_TITLE, null); mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); @@ -338,6 +458,81 @@ } @Test + public void tabClosure_NonRootTab_StillGroupAfterClosure_WithStoredTitle() { + // Mock that tab1, tab2 and newTab are in the same group and tab1 is the root tab. + Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2, newTab)); + createTabGroup(tabgroup, TAB1_ID); + + // Mock that newTab just get closed. + List<Tab> tabgroupAfterClosure = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + doReturn(tabgroupAfterClosure).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); + doReturn(tabgroupAfterClosure).when(mTabGroupModelFilter).getRelatedTabList(TAB2_ID); + + // Mock that newTab is the current tab for the dialog. + mMediator.setCurrentTabIdForTest(TAB3_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB1_ID); + + assertThat(mTabGroupTitleEditor.getTabGroupTitle(mTab1.getRootId()), + equalTo(CUSTOMIZED_DIALOG_TITLE)); + mTabModelObserverCaptor.getValue().willCloseTab(newTab, false); + + // Dialog title should still be the stored title. + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); + } + + @Test + public void tabClosure_RootTab_StillGroupAfterClosure_WithStoredTitle() { + // Mock that tab1, tab2 and newTab are in the same group and newTab is the root tab. + Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2, newTab)); + createTabGroup(tabgroup, TAB3_ID); + + // Mock that newTab just get closed. + List<Tab> tabgroupAfterClosure = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + doReturn(tabgroupAfterClosure).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); + doReturn(tabgroupAfterClosure).when(mTabGroupModelFilter).getRelatedTabList(TAB2_ID); + + // Mock that newTab is the current tab for the dialog. + mMediator.setCurrentTabIdForTest(TAB3_ID); + + // Mock that we have a stored title stored with reference to root ID of newTab. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB3_ID); + + mTabModelObserverCaptor.getValue().willCloseTab(newTab, false); + + // Dialog title should still be the stored title even if the root tab is closed. + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); + } + + @Test + public void tabClosure_SingleTabAfterClosure_WithStoredTitle() { + // Mock that tab1, tab2 are in the same group and tab1 is the root tab. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); + + // Mock that tab2 just get closed. + List<Tab> tabgroupAfterClosure = new ArrayList<>(Arrays.asList(mTab1)); + doReturn(tabgroupAfterClosure).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); + + // Mock that tab2 is the current tab for the dialog. + mMediator.setCurrentTabIdForTest(TAB2_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB1_ID); + + mTabModelObserverCaptor.getValue().willCloseTab(mTab2, false); + + // Even if there is a stored title for tab1, it is now a single tab, so we won't show the + // stored title. + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1)); + } + + @Test public void tabClosureUndone() { // Mock that the dialog is showing. mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); @@ -351,6 +546,28 @@ } @Test + public void tabClosureUndone_WithStoredTitle() { + // Mock that the dialog is showing. + mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); + mModel.set(TabGridPanelProperties.HEADER_TITLE, null); + mMediator.setCurrentTabIdForTest(TAB1_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB1_ID); + + // Mock that tab1 and tab2 are in the same group, and we are undoing tab2. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); + mTabModelObserverCaptor.getValue().tabClosureUndone(mTab2); + + // If current group has a stored title, dialog title should be set to stored title when + // undoing a closure. + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); + verify(mTabSwitcherResetHandler).resetWithTabList(mTabGroupModelFilter, false, false); + } + + @Test public void tabClosureUndone_WithDialogHidden() { // Mock that the dialog is hidden. mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); @@ -403,6 +620,41 @@ } @Test + public void hideDialog_StoreModifiedGroupTitle() { + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + + // Mock that we have a modified group title before dialog is hidden. + TextWatcher textWatcher = mModel.get(TabGridPanelProperties.TITLE_TEXT_WATCHER); + View.OnFocusChangeListener onFocusChangeListener = + mModel.get(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER); + onFocusChangeListener.onFocusChange(mTitleTextView, true); + textWatcher.afterTextChanged(mEditable); + assertThat(mMediator.getCurrentGroupModifiedTitleForTesting(), + equalTo(CUSTOMIZED_DIALOG_TITLE)); + + mMediator.hideDialog(false); + + verify(mTabGroupTitleEditor).storeTabGroupTitle(eq(TAB1_ID), eq(CUSTOMIZED_DIALOG_TITLE)); + verify(mTabGroupTitleEditor).updateTabGroupTitle(eq(mTab1), eq(CUSTOMIZED_DIALOG_TITLE)); + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); + } + + @Test + public void hideDialog_NoModifiedGroupTitle() { + mMediator.setCurrentTabIdForTest(TAB1_ID); + mModel.set(TabGridPanelProperties.HEADER_TITLE, TAB1_TITLE); + + mMediator.hideDialog(false); + + // When title is not updated, don't store title when hide dialog. + verify(mTabGroupTitleEditor, never()).storeTabGroupTitle(anyInt(), anyString()); + verify(mTabGroupTitleEditor, never()).updateTabGroupTitle(any(Tab.class), anyString()); + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(TAB1_TITLE)); + } + + @Test public void hideDialog_onReset() { mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, true); @@ -417,14 +669,40 @@ mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); mModel.set(TabGridPanelProperties.HEADER_TITLE, null); + // Mock that tab1 and tab2 are in a group. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); - mMediator.onReset(Arrays.asList(mTab1)); + mMediator.onReset(tabgroup); assertThat(mModel.get(TabGridPanelProperties.IS_DIALOG_VISIBLE), equalTo(true)); // Animation source Rect should be updated with specific Rect. assertThat(mModel.get(TabGridPanelProperties.ANIMATION_PARAMS), equalTo(mAnimationParams)); // Dialog title should be updated. - assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1)); + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(DIALOG_TITLE2)); + } + + @Test + public void showDialog_FromGTS_WithStoredTitle() { + // Mock that the dialog is hidden and animation source Rect and header title are all null. + mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); + mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); + mModel.set(TabGridPanelProperties.HEADER_TITLE, null); + // Mock that tab1 and tab2 are in a group. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB1_ID); + + mMediator.onReset(tabgroup); + + assertThat(mModel.get(TabGridPanelProperties.IS_DIALOG_VISIBLE), equalTo(true)); + // Animation source Rect should be updated with specific Rect. + assertThat(mModel.get(TabGridPanelProperties.ANIMATION_PARAMS), equalTo(mAnimationParams)); + // Dialog title should be updated with stored title. + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); } @Test @@ -433,19 +711,51 @@ // the animationParamsProvider is null. mMediator = new TabGridDialogMediator(mContext, mDialogController, mModel, mTabModelSelector, mTabCreatorManager, mTabSwitcherResetHandler, null, - mTabSelectionEditorController, ""); + mTabSelectionEditorController, mTabGroupTitleEditor, ""); + // Mock that the dialog is hidden and animation source Rect and header title are all null. mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); mModel.set(TabGridPanelProperties.HEADER_TITLE, null); + // Mock that tab1 and tab2 are in a group. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); - mMediator.onReset(Arrays.asList(mTab1)); + mMediator.onReset(tabgroup); assertThat(mModel.get(TabGridPanelProperties.IS_DIALOG_VISIBLE), equalTo(true)); // Animation params should not be specified. assertThat(mModel.get(TabGridPanelProperties.ANIMATION_PARAMS), equalTo(null)); // Dialog title should be updated. - assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1)); + assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(DIALOG_TITLE2)); + } + + @Test + public void showDialog_FromStrip_WithStoredTitle() { + // For strip we don't play zoom-in/zoom-out for show/hide dialog, and thus + // the animationParamsProvider is null. + mMediator = new TabGridDialogMediator(mContext, mDialogController, mModel, + mTabModelSelector, mTabCreatorManager, mTabSwitcherResetHandler, null, + mTabSelectionEditorController, mTabGroupTitleEditor, ""); + // Mock that the dialog is hidden and animation source Rect and header title are all null. + mModel.set(TabGridPanelProperties.IS_DIALOG_VISIBLE, false); + mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); + mModel.set(TabGridPanelProperties.HEADER_TITLE, null); + // Mock that tab1 and tab2 are in a group. + List<Tab> tabgroup = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabgroup, TAB1_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + doReturn(CUSTOMIZED_DIALOG_TITLE).when(mTabGroupTitleEditor).getTabGroupTitle(TAB1_ID); + + mMediator.onReset(tabgroup); + + assertThat(mModel.get(TabGridPanelProperties.IS_DIALOG_VISIBLE), equalTo(true)); + // Animation params should not be specified. + assertThat(mModel.get(TabGridPanelProperties.ANIMATION_PARAMS), equalTo(null)); + // Dialog title should be updated with stored title. + assertThat( + mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE)); } @Test @@ -459,9 +769,17 @@ private Tab prepareTab(int id, String title) { Tab tab = mock(Tab.class); doReturn(id).when(tab).getId(); + doReturn(id).when(tab).getRootId(); doReturn("").when(tab).getUrl(); doReturn(title).when(tab).getTitle(); doReturn(true).when(tab).isIncognito(); return tab; } + + private void createTabGroup(List<Tab> tabs, int rootId) { + for (Tab tab : tabs) { + when(mTabGroupModelFilter.getRelatedTabList(tab.getId())).thenReturn(tabs); + doReturn(rootId).when(tab).getRootId(); + } + } } \ No newline at end of file
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 ecc7fd79..d6db552 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
@@ -28,6 +28,8 @@ import android.app.Activity; import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; @@ -38,6 +40,8 @@ import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; +import androidx.annotation.IntDef; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -51,6 +55,7 @@ import org.robolectric.annotation.Config; import org.chromium.base.Callback; +import org.chromium.base.ContextUtils; import org.chromium.base.UserDataHost; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -78,6 +83,8 @@ import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -96,12 +103,24 @@ private static final String TAB2_TITLE = "Tab2"; private static final String TAB3_TITLE = "Tab3"; private static final String NEW_TITLE = "New title"; + private static final String CUSTOMIZED_DIALOG_TITLE1 = "Cool Tabs"; + private static final String TAB_GROUP_TITLES_FILE_NAME = "tab_group_titles"; private static final int TAB1_ID = 456; private static final int TAB2_ID = 789; private static final int TAB3_ID = 123; private static final int POSITION1 = 0; private static final int POSITION2 = 1; + @IntDef({TabListMediatorType.TAB_SWITCHER, TabListMediatorType.TAB_STRIP, + TabListMediatorType.TAB_GRID_DIALOG}) + @Retention(RetentionPolicy.SOURCE) + public @interface TabListMediatorType { + int TAB_SWITCHER = 0; + int TAB_STRIP = 1; + int TAB_GRID_DIALOG = 2; + int NUM_ENTRIES = 3; + } + @Mock TabContentManager mTabContentManager; @Mock @@ -142,6 +161,16 @@ Profile mProfile; @Mock Tracker mTracker; + @Mock + TabListMediator.TitleProvider mTitleProvider; + @Mock + SharedPreferences mSharedPreferences; + @Mock + SharedPreferences.Editor mEditor; + @Mock + SharedPreferences.Editor mPutStringEditor; + @Mock + SharedPreferences.Editor mRemoveEditor; @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @Captor @@ -165,6 +194,7 @@ private RecyclerView.ViewHolder mDummyViewHolder2; private View mItemView1 = mock(View.class); private View mItemView2 = mock(View.class); + private TabGroupModelFilter.Observer mMediatorTabGroupModelFilterObserver; @Before public void setUp() { @@ -173,6 +203,8 @@ MockitoAnnotations.initMocks(this); + FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false); + FeatureUtilities.setStartSurfaceEnabledForTesting(false); mTab1 = prepareTab(TAB1_ID, TAB1_TITLE); mTab2 = prepareTab(TAB2_ID, TAB2_TITLE); mViewHolder1 = prepareViewHolder(TAB1_ID, POSITION1); @@ -223,20 +255,29 @@ .openTabGridDialog(any(Tab.class)); doNothing().when(mContext).registerComponentCallbacks(mComponentCallbacksCaptor.capture()); doReturn(mGridLayoutManager).when(mRecyclerView).getLayoutManager(); + doReturn(mSharedPreferences) + .when(mContext) + .getSharedPreferences(TAB_GROUP_TITLES_FILE_NAME, Context.MODE_PRIVATE); + doReturn(mEditor).when(mSharedPreferences).edit(); + doReturn(mRemoveEditor).when(mEditor).remove(any(String.class)); + doReturn(mPutStringEditor).when(mEditor).putString(any(String.class), any(String.class)); mModel = new TabListModel(); mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - false, null, null, mGridCardOnClickListenerProvider, null, + mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, + mTabListFaviconProvider, false, null, null, mGridCardOnClickListenerProvider, null, getClass().getSimpleName(), 0); mMediator.registerOrientationListener(mGridLayoutManager); TrackerFactory.setTrackerForTests(mTracker); + ContextUtils.initApplicationContextForTests(mContext); } @After public void tearDown() { RecordUserAction.setDisabledForTests(false); RecordHistogram.setDisabledForTests(false); + FeatureUtilities.setTabGroupsAndroidEnabledForTesting(null); + FeatureUtilities.setStartSurfaceEnabledForTesting(null); } @Test @@ -245,18 +286,41 @@ } @Test - public void updatesTitle() { + public void updatesTitle_WithoutStoredTitle() { initAndAssertAllProperties(); assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); - doReturn(NEW_TITLE).when(mTab1).getTitle(); + doReturn(NEW_TITLE).when(mTitleProvider).getTitle(mTab1); mTabObserverCaptor.getValue().onTitleUpdated(mTab1); assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(NEW_TITLE)); } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void updatesTitle_WithStoredTitle_TabGroup() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + + // Mock that tab1 and new tab are in the same group with root ID as TAB1_ID. + Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, newTab)); + createTabGroup(tabs, TAB1_ID); + + // Mock that we have a stored title stored with reference to root ID of tab1. + when(mSharedPreferences.getString(String.valueOf(mTab1.getRootId()), null)) + .thenReturn(CUSTOMIZED_DIALOG_TITLE1); + assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + + mTabObserverCaptor.getValue().onTitleUpdated(mTab1); + + assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(CUSTOMIZED_DIALOG_TITLE1)); + } + + @Test public void updatesFavicon_SingleTab_GTS() { initAndAssertAllProperties(); mMediator.setActionOnAllRelatedTabsForTesting(true); @@ -339,11 +403,8 @@ } @Test - @Features.DisableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, - ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void sendsMoveTabSignalCorrectlyWithoutGroup() { initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false); TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); doReturn(mEmptyTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); @@ -356,8 +417,8 @@ @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void sendsMoveTabSignalCorrectlyWithGroup() { - initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(true); @@ -372,10 +433,7 @@ @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void sendsMoveTabSignalCorrectlyWithinGroup() { - initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); - - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); getItemTouchHelperCallback().onMove(mRecyclerView, mViewHolder1, mViewHolder2); @@ -386,16 +444,14 @@ @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void sendsMergeTabSignalCorrectly() { - initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); - mMediator.setActionOnAllRelatedTabsForTesting(true); + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(true); itemTouchHelperCallback.setHoveredTabIndexForTesting(POSITION1); itemTouchHelperCallback.setSelectedTabIndexForTesting(POSITION2); itemTouchHelperCallback.getMovementFlags(mRecyclerView, mDummyViewHolder1); - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mAdapter).when(mRecyclerView).getAdapter(); // Simulate the drop action. @@ -411,7 +467,7 @@ @Features.DisableFeatures({TAB_GROUPS_ANDROID, TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void neverSendsMergeTabSignal_Without_Group() { initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false); + mMediator.setActionOnAllRelatedTabsForTesting(true); TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(true); @@ -419,14 +475,12 @@ itemTouchHelperCallback.setSelectedTabIndexForTesting(POSITION2); itemTouchHelperCallback.getMovementFlags(mRecyclerView, mDummyViewHolder1); - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mAdapter).when(mRecyclerView).getAdapter(); // Simulate the drop action. itemTouchHelperCallback.onSelectedChanged( mDummyViewHolder1, ItemTouchHelper.ACTION_STATE_IDLE); - verify(mTabGroupModelFilter, never()).mergeTabsToGroup(anyInt(), anyInt()); verify(mGridLayoutManager, never()).removeView(any(View.class)); } @@ -434,9 +488,8 @@ @Features.EnableFeatures({TAB_GROUPS_ANDROID}) @Features.DisableFeatures({TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) public void neverSendsMergeTabSignal_With_Group_Without_Group_Improvement() { - initAndAssertAllProperties(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); - mMediator.setActionOnAllRelatedTabsForTesting(true); + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(true); itemTouchHelperCallback.setHoveredTabIndexForTesting(POSITION1); @@ -460,16 +513,13 @@ // clang-format off public void sendsUngroupSignalCorrectly() { // clang-format on - initAndAssertAllProperties(); - setUpForTabGroupOperation(); - FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(false); itemTouchHelperCallback.setUnGroupTabIndexForTesting(POSITION1); itemTouchHelperCallback.getMovementFlags(mRecyclerView, mDummyViewHolder1); - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mAdapter).when(mRecyclerView).getAdapter(); doReturn(1).when(mAdapter).getItemCount(); @@ -702,18 +752,17 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMergeIntoGroup() { - setUpForTabGroupOperation(); - // Setup the mediator with a CreateGroupButtonProvider. - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName(), 0); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume that moveTab in TabModel is finished. Selected tab in the group becomes mTab1. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); doReturn(mTab2).when(mTabModel).getTabAt(POSITION1); doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1); - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); // Assume that reset in TabGroupModelFilter is finished. doReturn(new ArrayList<>(Arrays.asList(mTab1, mTab2))) @@ -728,7 +777,7 @@ assertNotNull(mModel.get(0).model.get(TabProperties.FAVICON)); assertNotNull(mModel.get(1).model.get(TabProperties.FAVICON)); - mTabGroupModelFilterObserverCaptor.getValue().didMergeTabToGroup(mTab1, TAB2_ID); + mMediatorTabGroupModelFilterObserver.didMergeTabToGroup(mTab1, TAB2_ID); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -737,12 +786,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_GTS_Moved_Tab_Selected() { - setUpForTabGroupOperation(); - // Setup the mediator with a CreateGroupButtonProvider. - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName(), 0); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume that two tabs are in the same group before ungroup. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2)); @@ -757,7 +806,7 @@ doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION2); doReturn(2).when(mTabGroupModelFilter).getCount(); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION1); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -769,12 +818,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_GTS_Origin_Tab_Selected() { - setUpForTabGroupOperation(); - // Setup the mediator with a CreateGroupButtonProvider. - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName(), 0); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume that two tabs are in the same group before ungroup. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); @@ -789,7 +838,7 @@ doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION2); doReturn(2).when(mTabGroupModelFilter).getCount(); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab2, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab2, POSITION1); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -801,8 +850,13 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_GTS_LastTab() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + // Assume that tab1 is a single tab. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); mMediator.resetWithListOfTabs(tabs, false, false); @@ -811,7 +865,7 @@ doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); // Ungroup the single tab. - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION1); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -819,13 +873,13 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_Dialog() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); - // Setup the mediator with a DialogHandler. - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - false, null, null, null, mTabGridDialogHandler, getClass().getSimpleName(), 0); // Assume that filter is already updated. doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION1); @@ -835,7 +889,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION1); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -844,13 +898,13 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_Dialog_LastTab() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); - // Setup the mediator with a DialogHandler. - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - false, null, null, null, mTabGridDialogHandler, getClass().getSimpleName(), 0); // Assume that tab1 is a single tab. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); mMediator.resetWithListOfTabs(tabs, false, false); @@ -859,18 +913,19 @@ doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); // Ungroup the single tab. - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION1); verify(mTabGridDialogHandler).updateDialogContent(Tab.INVALID_TAB_ID); } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMoveOutOfGroup_Strip() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_STRIP); - mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - false, null, null, null, null, getClass().getSimpleName(), 0); // Assume that filter is already updated. doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION1); @@ -880,7 +935,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION1); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -923,8 +978,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMovementWithGroup_Forward() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume that moveTab in TabModel is finished. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); @@ -935,7 +994,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabGroup(mTab2, POSITION2, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabGroup(mTab2, POSITION2, POSITION1); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -943,8 +1002,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMovementWithGroup_Backward() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume that moveTab in TabModel is finished. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); @@ -955,7 +1018,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabGroup(mTab1, POSITION1, POSITION2); + mMediatorTabGroupModelFilterObserver.didMoveTabGroup(mTab1, POSITION1, POSITION2); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -963,8 +1026,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMovementWithinGroup_Forward() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); // Assume that moveTab in TabModel is finished. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); @@ -977,8 +1044,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveWithinGroup( - mTab2, POSITION2, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveWithinGroup(mTab2, POSITION2, POSITION1); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -986,8 +1052,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void tabMovementWithinGroup_Backward() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); // Assume that moveTab in TabModel is finished. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); @@ -1000,8 +1070,7 @@ assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); - mTabGroupModelFilterObserverCaptor.getValue().didMoveWithinGroup( - mTab1, POSITION1, POSITION2); + mMediatorTabGroupModelFilterObserver.didMoveWithinGroup(mTab1, POSITION1, POSITION2); assertThat(mModel.size(), equalTo(2)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -1009,8 +1078,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void undoGrouped_One_Adjacent_Tab() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume there are 3 tabs in TabModel, mTab2 just grouped with mTab1; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE); @@ -1024,7 +1097,7 @@ doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION2); doReturn(tab3).when(mTabGroupModelFilter).getTabAt(2); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab2, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab2, POSITION1); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.indexFromId(TAB1_ID), equalTo(0)); @@ -1033,8 +1106,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void undoForwardGrouped_One_Tab() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume there are 3 tabs in TabModel, tab3 just grouped with mTab1; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE); @@ -1048,7 +1125,7 @@ doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION2); doReturn(tab3).when(mTabGroupModelFilter).getTabAt(2); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(tab3, POSITION1); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(tab3, POSITION1); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.indexFromId(TAB1_ID), equalTo(0)); @@ -1057,8 +1134,12 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off public void undoBackwardGrouped_One_Tab() { - setUpForTabGroupOperation(); + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); // Assume there are 3 tabs in TabModel, mTab1 just grouped with mTab2; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE); @@ -1072,7 +1153,7 @@ doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION2); doReturn(tab3).when(mTabGroupModelFilter).getTabAt(2); - mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION2); + mMediatorTabGroupModelFilterObserver.didMoveTabOutOfGroup(mTab1, POSITION2); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.indexFromId(TAB1_ID), equalTo(0)); @@ -1159,6 +1240,121 @@ assertThat(mMediator.indexOfTab(TAB2_ID), equalTo(1)); } + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void getLatestTitle_NotGTS() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_GRID_DIALOG); + // Mock that we have a stored title stored with reference to root ID of tab1. + when(mSharedPreferences.getString(String.valueOf(mTab1.getRootId()), null)) + .thenReturn(CUSTOMIZED_DIALOG_TITLE1); + assertThat(mMediator.getTabGroupTitleEditor().getTabGroupTitle(mTab1.getRootId()), + equalTo(CUSTOMIZED_DIALOG_TITLE1)); + + // Mock that tab1 and tab2 are in the same group and group root id is TAB1_ID. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabs, TAB1_ID); + + // Even if we have a stored title, we only show it in tab switcher. + assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(TAB1_TITLE)); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void getLatestTitle_SingleTab_GTS() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + // Mock that we have a stored title stored with reference to root ID of tab1. + when(mSharedPreferences.getString(String.valueOf(mTab1.getRootId()), null)) + .thenReturn(CUSTOMIZED_DIALOG_TITLE1); + assertThat(mMediator.getTabGroupTitleEditor().getTabGroupTitle(mTab1.getRootId()), + equalTo(CUSTOMIZED_DIALOG_TITLE1)); + + // Mock that tab1 is a single tab. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); + createTabGroup(tabs, TAB1_ID); + + // We never show stored title for single tab. + assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(TAB1_TITLE)); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void getLatestTitle_Stored_GTS() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + // Mock that we have a stored title stored with reference to root ID of tab1. + when(mSharedPreferences.getString(String.valueOf(mTab1.getRootId()), null)) + .thenReturn(CUSTOMIZED_DIALOG_TITLE1); + assertThat(mMediator.getTabGroupTitleEditor().getTabGroupTitle(mTab1.getRootId()), + equalTo(CUSTOMIZED_DIALOG_TITLE1)); + + // Mock that tab1 and tab2 are in the same group and group root id is TAB1_ID. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabs, TAB1_ID); + + assertThat(mMediator.getLatestTitleForTab(mTab1), equalTo(CUSTOMIZED_DIALOG_TITLE1)); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void updateTabGroupTitle_GTS() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + assertThat(mModel.get(POSITION1).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + + // Mock that tab1 and newTab are in the same group and group root id is TAB1_ID. + Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, newTab)); + createTabGroup(tabs, TAB1_ID); + doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1); + doReturn(POSITION1).when(mTabGroupModelFilter).indexOf(mTab1); + + mMediator.getTabGroupTitleEditor().updateTabGroupTitle(mTab1, CUSTOMIZED_DIALOG_TITLE1); + + assertThat(mModel.get(POSITION1).model.get(TabProperties.TITLE), + equalTo(CUSTOMIZED_DIALOG_TITLE1)); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void tabGroupTitleEditor_storeTitle() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + TabGroupTitleEditor tabGroupTitleEditor = mMediator.getTabGroupTitleEditor(); + + tabGroupTitleEditor.storeTabGroupTitle(mTab1.getRootId(), CUSTOMIZED_DIALOG_TITLE1); + + verify(mEditor).putString( + eq(String.valueOf(mTab1.getRootId())), eq(CUSTOMIZED_DIALOG_TITLE1)); + verify(mPutStringEditor).apply(); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + // clang-format off + public void tabGroupTitleEditor_deleteTitle() { + // clang-format on + setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); + TabGroupTitleEditor tabGroupTitleEditor = mMediator.getTabGroupTitleEditor(); + + tabGroupTitleEditor.deleteTabGroupTitle(mTab1.getRootId()); + + verify(mEditor).remove(eq(String.valueOf(mTab1.getRootId()))); + verify(mRemoveEditor).apply(); + } + private void initAndAssertAllProperties() { List<Tab> tabs = new ArrayList<>(); for (int i = 0; i < mTabModel.getCount(); i++) { @@ -1204,9 +1400,11 @@ when(tab.getView()).thenReturn(mock(View.class)); when(tab.getUserDataHost()).thenReturn(new UserDataHost()); doReturn(id).when(tab).getId(); + doReturn(id).when(tab).getRootId(); doReturn("").when(tab).getUrl(); doReturn(title).when(tab).getTitle(); doReturn(true).when(tab).isIncognito(); + doReturn(title).when(mTitleProvider).getTitle(tab); return tab; } @@ -1232,7 +1430,7 @@ 0f, 0f, 0f, mProfile); } - private void setUpForTabGroupOperation() { + private void setUpForTabGroupOperation(@TabListMediatorType int type) { doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getTabModelFilter(true); doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getTabModelFilter(false); @@ -1240,10 +1438,29 @@ .when(mTabGroupModelFilter) .addTabGroupObserver(mTabGroupModelFilterObserverCaptor.capture()); + TabListMediator.TabGridDialogHandler handler = + type == TabListMediatorType.TAB_GRID_DIALOG ? mTabGridDialogHandler : null; + boolean actionOnRelatedTabs = type == TabListMediatorType.TAB_SWITCHER; + FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); + mMediator = new TabListMediator(mContext, mModel, mTabModelSelector, - mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - true, null, null, null, null, getClass().getSimpleName(), 0); + mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, + mTabListFaviconProvider, actionOnRelatedTabs, null, null, null, handler, + getClass().getSimpleName(), 0); + + // There are two TabGroupModelFilter.Observer added when initializing TabListMediator, one + // from TabListMediator and the other from TabGroupTitleEditor. Here we only test the one + // from TabListMediator. + mMediatorTabGroupModelFilterObserver = + mTabGroupModelFilterObserverCaptor.getAllValues().get(0); initAndAssertAllProperties(); } + + private void createTabGroup(List<Tab> tabs, int rootId) { + for (Tab tab : tabs) { + when(mTabGroupModelFilter.getRelatedTabList(tab.getId())).thenReturn(tabs); + doReturn(rootId).when(tab).getRootId(); + } + } }
diff --git a/chrome/android/java/res/layout/ephemeral_tab_toolbar.xml b/chrome/android/java/res/layout/ephemeral_tab_toolbar.xml index 0bfcc57..8f5ae7d 100644 --- a/chrome/android/java/res/layout/ephemeral_tab_toolbar.xml +++ b/chrome/android/java/res/layout/ephemeral_tab_toolbar.xml
@@ -7,14 +7,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - android:paddingBottom="30dp" android:layout_width="match_parent" - android:layout_height="86dp"> + android:layout_height="100dp" + android:paddingBottom="30dp"> <LinearLayout android:id="@+id/toolbar" android:layout_width="match_parent" - android:layout_height="@dimen/toolbar_height_no_shadow" + android:layout_height="@dimen/preview_tab_toolbar_height" android:orientation="vertical"> <View @@ -23,16 +23,16 @@ <RelativeLayout android:layout_width="match_parent" - android:layout_height="48dp" + android:layout_height="62dp" android:orientation="horizontal"> <org.chromium.ui.widget.ChromeImageView android:id="@+id/favicon" android:layout_width="48dp" android:layout_height="48dp" - android:layout_centerVertical="true" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" + android:layout_marginTop="12dp" android:padding="12dp" android:src="@drawable/ic_chrome" app:tint="@color/default_icon_color_blue" @@ -57,19 +57,41 @@ android:layout_centerVertical="true" android:padding="12dp" android:src="@drawable/open_in_new_tab" - app:tint="@color/default_icon_color" - tools:ignore="ContentDescription" /> + android:contentDescription="@string/contextmenu_open_in_new_tab" + app:tint="@color/default_icon_color" /> <TextView android:id="@+id/ephemeral_tab_text" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="12dp" + android:layout_marginTop="16dp" android:layout_toStartOf="@id/open_in_new_tab" android:layout_toEndOf="@id/favicon" android:ellipsize="end" android:singleLine="true" - android:textAppearance="@style/TextAppearance.BlackTitle1" /> + android:textAppearance="@style/TextAppearance.BlackBodyDefault" /> + + <org.chromium.ui.widget.ChromeImageView + android:id="@+id/security_icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_below="@id/ephemeral_tab_text" + android:layout_toEndOf="@id/favicon" + android:layout_marginTop="4dp" + app:tint="@color/default_icon_color" /> + + <TextView + android:id="@+id/ephemeral_tab_caption" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_toStartOf="@id/open_in_new_tab" + android:layout_toEndOf="@id/security_icon" + android:layout_below="@id/ephemeral_tab_text" + android:layout_marginLeft="4dp" + android:ellipsize="start" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.BlackHint2" /> + </RelativeLayout> <View @@ -90,6 +112,6 @@ android:id="@+id/shadow" android:layout_width="match_parent" android:layout_height="@dimen/action_bar_shadow_height" - android:layout_marginTop="@dimen/toolbar_height_no_shadow"/> + android:layout_marginTop="@dimen/preview_tab_toolbar_height"/> </FrameLayout>
diff --git a/chrome/android/java/res/layout/navigation_sheet_toolbar.xml b/chrome/android/java/res/layout/navigation_sheet_toolbar.xml index f6c5ad7..92a00ba 100644 --- a/chrome/android/java/res/layout/navigation_sheet_toolbar.xml +++ b/chrome/android/java/res/layout/navigation_sheet_toolbar.xml
@@ -6,8 +6,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:paddingBottom="@dimen/navigation_sheet_toolbar_bottom_padding"> + android:layout_marginTop="8dp"> <ImageView android:id="@+id/drag_handlebar" android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index c60bb3d..9215347 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -136,6 +136,9 @@ <!-- Overlay panel dimensions --> <dimen name="overlay_panel_bar_height_legacy">56dp</dimen> <dimen name="overlay_panel_bar_height">70dp</dimen> + + <!-- Preview tab dimensions --> + <dimen name="preview_tab_toolbar_height">70dp</dimen> <dimen name="preview_tab_favicon_size">24dp</dimen> <!-- Autofill keyboard accessory dimensions --> @@ -673,10 +676,10 @@ <dimen name="navigation_bubble_text_bottom_padding">5dp</dimen> <dimen name="navigation_bubble_text_start_padding">2dp</dimen> <dimen name="navigation_bubble_text_end_padding">8dp</dimen> - <dimen name="navigation_sheet_toolbar_bottom_padding">44dp</dimen> <dimen name="navigation_sheet_content_top_padding">18dp</dimen> <dimen name="navigation_sheet_content_bottom_padding">4dp</dimen> <dimen name="navigation_sheet_content_wrap_padding">12dp</dimen> + <dimen name="navigation_sheet_peek_height">64dp</dimen> <!-- ChromeTextInputLayout dimensions --> <dimen name="text_input_layout_padding_start">3dp</dimen>
diff --git a/chrome/android/java/res_download/layout/download_manager_section_header.xml b/chrome/android/java/res_download/layout/download_manager_section_header.xml index 9ab6962..9eec352 100644 --- a/chrome/android/java/res_download/layout/download_manager_section_header.xml +++ b/chrome/android/java/res_download/layout/download_manager_section_header.xml
@@ -6,7 +6,6 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content"> <View @@ -28,25 +27,4 @@ android:maxLines="1" android:textAppearance="@style/TextAppearance.BlackTitle1"/> - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@+id/date" - android:paddingStart="@dimen/list_item_default_margin" - android:textAppearance="@style/TextAppearance.BlackHint2" - android:maxLines="1" /> - - <Space - android:id="@+id/bottom_space" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_below="@+id/title" /> - - <include layout="@layout/list_menu_button" - android:layout_width="48dp" - android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" /> - </RelativeLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java index 5401c19..b048cf5d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java
@@ -60,6 +60,12 @@ public void onVisibilityChanged(boolean isVisible) {} /** + * Called when the SSL state changes. + */ + + public void onSSLStateUpdated() {} + + /** * Called once the WebContents has been seen. */ public void onContentViewSeen() {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java index 4bd5329..8b82c5d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -197,6 +197,11 @@ } @Override + public void visibleSSLStateChanged() { + mContentDelegate.onSSLStateUpdated(); + } + + @Override public void enterFullscreenModeForTab(boolean prefersNavigationBar) { mIsFullscreen = true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java index 5dda11b..e2009f8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -7,6 +7,8 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Handler; +import android.support.annotation.DrawableRes; +import android.text.TextUtils; import org.chromium.base.Callback; import org.chromium.chrome.R; @@ -17,18 +19,19 @@ import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.favicon.FaviconUtils; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.ssl.SecurityStateModel; import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.ui.widget.RoundedIconGenerator; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; import org.chromium.components.embedder_support.view.ContentView; +import org.chromium.components.security_state.ConnectionSecurityLevel; import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_public.browser.NavigationHandle; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.PageTransition; -import java.net.MalformedURLException; -import java.net.URL; - /** * Central class for ephemeral tab, responsible for spinning off other classes necessary to display * the preview tab UI. @@ -42,6 +45,7 @@ private final BottomSheetController mBottomSheetController; private final FaviconLoader mFaviconLoader; private OverlayPanelContent mPanelContent; + private WebContentsObserver mWebContentsObserver; private EphemeralTabSheetContent mSheetContent; private boolean mIsIncognito; private String mUrl; @@ -81,9 +85,10 @@ getContent().loadUrl(url, true); getContent().updateBrowserControlsState(true); + if (mWebContentsObserver == null) mWebContentsObserver = createWebContentsObserver(); mSheetContent.attachWebContents( getContent().getWebContents(), (ContentView) getContent().getContainerView()); - mSheetContent.setTitleText(title); + mSheetContent.updateTitle(title); mBottomSheetController.requestShowContent(mSheetContent, true); // TODO(donnd): Collect UMA with OverlayPanel.StateChangeReason.CLICK. @@ -109,6 +114,11 @@ mPanelContent.destroy(); mPanelContent = null; } + + if (mWebContentsObserver != null) { + mWebContentsObserver.destroy(); + mWebContentsObserver = null; + } } private void openInNewTab() { @@ -136,6 +146,40 @@ mSheetContent.startFaviconAnimation(drawable); } + private WebContentsObserver createWebContentsObserver() { + return new WebContentsObserver(mPanelContent.getWebContents()) { + @Override + public void titleWasSet(String title) { + mSheetContent.updateTitle(title); + } + + @Override + public void didFinishNavigation(NavigationHandle navigation) { + if (navigation.hasCommitted() && navigation.isInMainFrame()) { + mSheetContent.updateURL(mPanelContent.getWebContents().getVisibleUrl()); + } + } + }; + } + + @DrawableRes + private static int getSecurityIconResource(@ConnectionSecurityLevel int securityLevel) { + switch (securityLevel) { + case ConnectionSecurityLevel.NONE: + case ConnectionSecurityLevel.WARNING: + return R.drawable.omnibox_info; + case ConnectionSecurityLevel.DANGEROUS: + return R.drawable.omnibox_https_invalid; + case ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT: + case ConnectionSecurityLevel.SECURE: + case ConnectionSecurityLevel.EV_SECURE: + return R.drawable.omnibox_https_valid; + default: + assert false; + } + return 0; + } + /** * Observes the ephemeral tab web contents and loads the associated favicon. */ @@ -144,16 +188,18 @@ @Override public void onMainFrameLoadStarted(String url, boolean isExternalUrl) { - try { - String newHost = new URL(url).getHost(); - String curHost = mCurrentUrl == null ? null : new URL(mCurrentUrl).getHost(); - if (!newHost.equals(curHost)) { - mCurrentUrl = url; - mFaviconLoader.loadFavicon(url, (drawable) -> onFaviconAvailable(drawable)); - } - } catch (MalformedURLException e) { - assert false : "Malformed URL should not be passed."; - } + if (TextUtils.equals(mCurrentUrl, url)) return; + + mCurrentUrl = url; + mFaviconLoader.loadFavicon(url, (drawable) -> onFaviconAvailable(drawable)); + } + + @Override + public void onSSLStateUpdated() { + int securityLevel = SecurityStateModel.getSecurityLevelForWebContents( + mPanelContent.getWebContents()); + mSheetContent.setSecurityIcon(getSecurityIconResource(securityLevel)); + mSheetContent.updateURL(mPanelContent.getWebContents().getVisibleUrl()); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java index 294b5f29..86a6dd7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java
@@ -7,6 +7,7 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; +import android.support.annotation.DrawableRes; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; @@ -24,6 +25,7 @@ import org.chromium.chrome.browser.ui.widget.FadingShadowView; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.components.embedder_support.view.ContentView; +import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.content_public.browser.RenderCoordinates; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.ActivityWindowAndroid; @@ -32,6 +34,8 @@ * Represents ephemeral tab content and the toolbar, which can be included inside the bottom sheet. */ public class EphemeralTabSheetContent implements BottomSheet.BottomSheetContent { + private static final float PEEK_TOOLBAR_HEIGHT_MULTIPLE = 2.f; + private final Context mContext; private final Runnable mOpenNewTabCallback; private final Runnable mToolbarClickCallback; @@ -87,7 +91,7 @@ mSheetContentView.addView(mThinWebView.getView()); int topPadding = - mContext.getResources().getDimensionPixelSize(R.dimen.toolbar_height_no_shadow); + mContext.getResources().getDimensionPixelSize(R.dimen.preview_tab_toolbar_height); mSheetContentView.setPadding(0, topPadding, 0, 0); } @@ -127,9 +131,21 @@ } /** Sets the ephemeral tab title text. */ - public void setTitleText(String text) { + public void updateTitle(String title) { TextView toolbarText = mToolbarView.findViewById(R.id.ephemeral_tab_text); - toolbarText.setText(text); + toolbarText.setText(title); + } + + /** Sets the ephemeral tab URL. */ + public void updateURL(String url) { + TextView caption = mToolbarView.findViewById(R.id.ephemeral_tab_caption); + caption.setText(UrlFormatter.formatUrlForSecurityDisplayOmitScheme(url)); + } + + /** Sets the security icon. */ + public void setSecurityIcon(@DrawableRes int resId) { + ImageView securityIcon = mToolbarView.findViewById(R.id.security_icon); + securityIcon.setImageResource(resId); } /** Sets the progress percentage on the progress bar. */ @@ -178,8 +194,10 @@ } @Override - public boolean isPeekStateEnabled() { - return true; + public int getPeekHeight() { + int toolbarHeight = + mContext.getResources().getDimensionPixelSize(R.dimen.toolbar_height_no_shadow); + return (int) (toolbarHeight * PEEK_TOOLBAR_HEIGHT_MULTIPLE); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java index bc4e1976..42e576b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java
@@ -54,9 +54,6 @@ /** Whether or not rename feature should be shown in UI. */ public final boolean isRenameEnabled; - /** Whether or not section headers should be shown in UI. */ - public final boolean showSectionHeaders; - /** Constructor. */ private DownloadManagerUiConfig(Builder builder) { isOffTheRecord = builder.mIsOffTheRecord; @@ -69,7 +66,6 @@ maxThumbnailScaleFactor = builder.mMaxThumbnailScaleFactor; justNowThresholdSeconds = builder.mJustNowThresholdSeconds; isRenameEnabled = builder.mIsRenameEnabled; - showSectionHeaders = builder.mShowSectionHeaders; } /** Helper class for building a {@link DownloadManagerUiConfig}. */ @@ -89,7 +85,6 @@ private float mMaxThumbnailScaleFactor = 1.5f; /* hdpi scale factor. */ private long mJustNowThresholdSeconds; private boolean mIsRenameEnabled; - private boolean mShowSectionHeaders; public Builder() { readParamsFromFinch(); @@ -140,11 +135,6 @@ return this; } - public Builder setShowSectionHeaders(boolean showSectionHeaders) { - mShowSectionHeaders = showSectionHeaders; - return this; - } - public DownloadManagerUiConfig build() { return new DownloadManagerUiConfig(this); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java index cbb1fe3..824c72a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -31,7 +31,6 @@ import org.chromium.chrome.browser.download.home.list.DateOrderedListCoordinator.DeleteController; import org.chromium.chrome.browser.download.home.metrics.OfflineItemStartupLogger; import org.chromium.chrome.browser.download.home.metrics.UmaUtils; -import org.chromium.chrome.browser.download.home.metrics.UmaUtils.ImagesMenuAction; import org.chromium.chrome.browser.download.home.metrics.UmaUtils.ViewAction; import org.chromium.chrome.browser.widget.ThumbnailProvider; import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest; @@ -195,15 +194,11 @@ mModel.getProperties().set(ListProperties.CALLBACK_RESUME, this ::onResumeItem); mModel.getProperties().set(ListProperties.CALLBACK_CANCEL, this ::onCancelItem); mModel.getProperties().set(ListProperties.CALLBACK_SHARE, this ::onShareItem); - mModel.getProperties().set(ListProperties.CALLBACK_SHARE_ALL, this ::onShareItems); mModel.getProperties().set(ListProperties.CALLBACK_REMOVE, this ::onDeleteItem); - mModel.getProperties().set(ListProperties.CALLBACK_REMOVE_ALL, this ::onDeleteItems); mModel.getProperties().set(ListProperties.PROVIDER_VISUALS, this ::getVisuals); mModel.getProperties().set(ListProperties.CALLBACK_SELECTION, this ::onSelection); mModel.getProperties().set(ListProperties.CALLBACK_RENAME, mUiConfig.isRenameEnabled ? this::onRenameItem : null); - mModel.getProperties().set( - ListProperties.CALLBACK_START_SELECTION, this ::onStartSelection); } /** Tears down this mediator. */ @@ -285,14 +280,6 @@ mSelectionDelegate.toggleSelectionForItem(item); } - private void onStartSelection() { - // We are hard coding that this is coming from the Photos section, as that is the only - // one that supports a section menu. If that changes we need to support a wider array - // of metrics. - UmaUtils.recordImagesMenuAction(ImagesMenuAction.MENU_START_SELECTING); - mSelectionDelegate.setSelectionModeEnabledForZeroItems(true); - } - private void onOpenItem(OfflineItem item) { UmaUtils.recordItemAction(ViewAction.OPEN); mProvider.openItem(item); @@ -323,22 +310,6 @@ shareItemsInternal(CollectionUtil.newHashSet(item)); } - private void onShareItems(List<OfflineItem> items) { - // We are hard coding that this is coming from the Photos section, as that is the only - // one that supports a section menu. If that changes we need to support a wider array - // of metrics. - UmaUtils.recordImagesMenuAction(ImagesMenuAction.MENU_SHARE_ALL); - shareItemsInternal(items); - } - - private void onDeleteItems(List<OfflineItem> items) { - // We are hard coding that this is coming from the Photos section, as that is the only - // one that supports a section menu. If that changes we need to support a wider array - // of metrics. - UmaUtils.recordImagesMenuAction(ImagesMenuAction.MENU_DELETE_ALL); - deleteItemsInternal(items); - } - private void onRenameItem(OfflineItem item) { UmaUtils.recordItemAction(ViewAction.MENU_RENAME); mRenameController.rename(item.title, (newName, renameCallback) -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java index 6feec725..a917fcd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java
@@ -47,17 +47,9 @@ private final Map<Date, DateGroup> mDateGroups = new TreeMap<>((lhs, rhs) -> { return rhs.compareTo(lhs); }); - // Whether we should hide the section headers and only show the ones that show a new date. Title - // and menu button are not present. - private final boolean mHideSectionHeaders; - // Whether we shouldn't have any headers. Meant to be used for prefetch tab. private boolean mHideAllHeaders; - // Meant to be used when a non-all chip is selected. Shouldn't have titles, only have dates. Can - // have menu button. - private boolean mHideTitleFromSectionHeaders; - /** * Creates an DateOrderedList instance that will reflect {@code source}. * @param source The source of data for this list. @@ -70,7 +62,6 @@ mModel = model; mConfig = config; mJustNowProvider = justNowProvider; - mHideSectionHeaders = !mConfig.showSectionHeaders; source.addObserver(this); onItemsAdded(source.getItems()); } @@ -81,7 +72,6 @@ */ public void onFilterTypeSelected(@Filters.FilterType int filter) { mHideAllHeaders = filter == Filters.FilterType.PREFETCHED; - mHideTitleFromSectionHeaders = filter != Filters.FilterType.NONE; } // OfflineItemFilterObserver implementation. @@ -124,19 +114,14 @@ } else { addOrUpdateItemToDateGroups(item); - int sectionHeaderIndex = -1; for (int i = 0; i < mModel.size(); i++) { ListItem listItem = mModel.get(i); - if (listItem instanceof SectionHeaderListItem) sectionHeaderIndex = i; if (!(listItem instanceof OfflineItemListItem)) continue; OfflineItemListItem existingItem = (OfflineItemListItem) listItem; if (item.id.equals(existingItem.item.id)) { existingItem.item = item; mModel.update(i, existingItem); - if (oldItem.state != item.state) { - updateSectionHeader(sectionHeaderIndex, i); - } break; } } @@ -155,16 +140,6 @@ dateGroup.addOrUpdateItem(item); } - private void updateSectionHeader(int sectionHeaderIndex, int offlineItemIndex) { - if (sectionHeaderIndex < 0 || mHideSectionHeaders) return; - - SectionHeaderListItem sectionHeader = - (SectionHeaderListItem) mModel.get(sectionHeaderIndex); - OfflineItem offlineItem = ((OfflineItemListItem) mModel.get(offlineItemIndex)).item; - sectionHeader.items.set(offlineItemIndex - sectionHeaderIndex - 1, offlineItem); - mModel.update(sectionHeaderIndex, sectionHeader); - } - // Flattens out the hierarchical data and adds items to the model in the order they should be // displayed. Date headers and section headers are added wherever necessary. The existing items // in the model are replaced by the new set of items computed. @@ -180,16 +155,10 @@ Section section = dateGroup.sections.get(filter); // Add a section header. - if (!mHideAllHeaders && (!mHideSectionHeaders || sectionIndex == 0)) { - SectionHeaderListItem sectionHeaderItem = new SectionHeaderListItem(filter, - date.getTime(), sectionIndex == 0 /* showDate */, - date.equals(JUST_NOW_DATE) /* isJustNow */, + if (!mHideAllHeaders && sectionIndex == 0) { + SectionHeaderListItem sectionHeaderItem = new SectionHeaderListItem( + date.getTime(), date.equals(JUST_NOW_DATE) /* isJustNow */, sectionIndex == 0 && dateIndex > 0 /* showDivider */); - if (!mHideSectionHeaders) { - sectionHeaderItem.showTitle = !mHideTitleFromSectionHeaders; - sectionHeaderItem.showMenu = filter == OfflineItemFilter.IMAGE; - sectionHeaderItem.items = new ArrayList<>(section.items); - } listItems.add(sectionHeaderItem); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java index 9aa4dde..0c6ed1c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java
@@ -10,14 +10,10 @@ import org.chromium.chrome.browser.download.home.StableIds; import org.chromium.components.offline_items_collection.OfflineItem; -import java.util.Calendar; import java.util.Date; -import java.util.List; /** An abstract class that represents a variety of possible list items to show in downloads home. */ public abstract class ListItem { - private static final long DATE_SEPARATOR_HASH_CODE_OFFSET = 10; - private static final long SECTION_SEPARATOR_HASH_CODE_OFFSET = 100; private static final long SECTION_HEADER_HASH_CODE_OFFSET = 1000; public final long stableId; @@ -56,51 +52,27 @@ super(stableId); this.date = date; } - - /** - * Creates a {@link DateListItem} instance around a particular calendar day. This will - * automatically generate the {@link ListItem#stableId} from {@code calendar}. - * @param calendar - */ - public DateListItem(Calendar calendar) { - this(generateStableIdForDayOfYear(calendar), calendar.getTime()); - } - - @VisibleForTesting - static long generateStableIdForDayOfYear(Calendar calendar) { - return (calendar.get(Calendar.YEAR) << 16) + calendar.get(Calendar.DAY_OF_YEAR); - } } /** A {@link ListItem} representing a section header. */ public static class SectionHeaderListItem extends DateListItem { - public final int filter; - public boolean showDate; - public boolean showTitle; - public boolean showMenu; public boolean isJustNow; public boolean showDivider; - public List<OfflineItem> items; /** - * Creates a {@link SectionHeaderListItem} instance for a given {@code filter} and - * {@code timestamp}. + * Creates a {@link SectionHeaderListItem} instance for a given {@code timestamp}. */ - public SectionHeaderListItem(int filter, long timestamp, boolean showDate, - boolean isJustNow, boolean showDivider) { - super(isJustNow && showDate ? StableIds.JUST_NOW_SECTION - : generateStableId(timestamp, filter), + public SectionHeaderListItem(long timestamp, boolean isJustNow, boolean showDivider) { + super(isJustNow ? StableIds.JUST_NOW_SECTION : generateStableId(timestamp), new Date(timestamp)); - this.filter = filter; - this.showDate = showDate; this.isJustNow = isJustNow; this.showDivider = showDivider; } @VisibleForTesting - static long generateStableId(long timestamp, int filter) { + static long generateStableId(long timestamp) { long hash = new Date(timestamp).hashCode(); - return hash + filter + SECTION_HEADER_HASH_CODE_OFFSET; + return hash + SECTION_HEADER_HASH_CODE_OFFSET; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java index 7ac8b30..83f62941 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java
@@ -12,8 +12,6 @@ import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; -import java.util.List; - /** * The properties required to build a {@link ListItem} which contain two types of properties for the * download manager: (1) A set of properties that act directly on the list view itself. (2) A set of @@ -57,18 +55,10 @@ WritableObjectPropertyKey<Callback<OfflineItem>> CALLBACK_SHARE = new WritableObjectPropertyKey<>(); - /** The callback for when a UI action should share all selected {@link OfflineItem}s. */ - WritableObjectPropertyKey < Callback < List<OfflineItem>>> CALLBACK_SHARE_ALL = - new WritableObjectPropertyKey<>(); - /** The callback for when a UI action should remove a {@link OfflineItem}. */ WritableObjectPropertyKey<Callback<OfflineItem>> CALLBACK_REMOVE = new WritableObjectPropertyKey<>(); - /** The callback for when a UI action should remove all selected {@link OfflineItem}s. */ - WritableObjectPropertyKey < Callback < List<OfflineItem>>> CALLBACK_REMOVE_ALL = - new WritableObjectPropertyKey<>(); - /** The callback for when a UI action should rename a {@link OfflineItem}. */ WritableObjectPropertyKey<Callback<OfflineItem>> CALLBACK_RENAME = new WritableObjectPropertyKey<>(); @@ -83,16 +73,7 @@ /** Whether or not selection mode is currently active. */ WritableBooleanPropertyKey SELECTION_MODE_ACTIVE = new WritableBooleanPropertyKey(); - /** - * The callback to trigger when a UI action starts general selection mode. This is different - * from {@link #CALLBACK_SELECTION} in that it should be triggered when the UI enters selection - * mode without any particularly attached {@link ListItem}. - */ - WritableObjectPropertyKey<Runnable> CALLBACK_START_SELECTION = - new WritableObjectPropertyKey<>(); - PropertyKey[] ALL_KEYS = new PropertyKey[] {ENABLE_ITEM_ANIMATIONS, CALLBACK_OPEN, - CALLBACK_PAUSE, CALLBACK_RESUME, CALLBACK_CANCEL, CALLBACK_SHARE, CALLBACK_SHARE_ALL, - CALLBACK_REMOVE, CALLBACK_REMOVE_ALL, CALLBACK_RENAME, PROVIDER_VISUALS, - CALLBACK_SELECTION, SELECTION_MODE_ACTIVE, CALLBACK_START_SELECTION}; + CALLBACK_PAUSE, CALLBACK_RESUME, CALLBACK_CANCEL, CALLBACK_SHARE, CALLBACK_REMOVE, + CALLBACK_RENAME, PROVIDER_VISUALS, CALLBACK_SELECTION, SELECTION_MODE_ACTIVE}; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java index 0a65012..9309d8df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.download.home.list.holder; -import android.content.Context; -import android.content.res.Resources; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -13,38 +11,17 @@ import org.chromium.chrome.browser.download.home.list.ListItem; import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderListItem; -import org.chromium.chrome.browser.download.home.list.ListProperties; -import org.chromium.chrome.browser.download.home.list.ListUtils; import org.chromium.chrome.browser.download.home.list.UiUtils; -import org.chromium.chrome.browser.ui.widget.ListMenuButton; import org.chromium.chrome.download.R; -import org.chromium.components.offline_items_collection.OfflineItem; -import org.chromium.components.offline_items_collection.OfflineItemState; import org.chromium.ui.modelutil.PropertyModel; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * A {@link ViewHolder} specifically meant to display a section header. */ -public class SectionTitleViewHolder extends ListItemViewHolder implements ListMenuButton.Delegate { +public class SectionTitleViewHolder extends ListItemViewHolder { private final View mDivider; private final TextView mDate; - private final TextView mTitle; - private final ListMenuButton mMore; - private final View mTopSpace; - private final View mBottomSpace; - private Runnable mShareCallback; - private Runnable mDeleteCallback; - private Runnable mShareAllCallback; - private Runnable mDeleteAllCallback; - private Runnable mSelectCallback; - - private boolean mHasMultipleItems; - private boolean mCanSelectItems; /** Create a new {@link SectionTitleViewHolder} instance. */ public static SectionTitleViewHolder create(ViewGroup parent) { @@ -57,110 +34,17 @@ super(view); mDivider = view.findViewById(R.id.divider); mDate = (TextView) view.findViewById(R.id.date); - mTitle = (TextView) view.findViewById(R.id.title); - mMore = (ListMenuButton) view.findViewById(R.id.more); - mTopSpace = view.findViewById(R.id.top_space); - mBottomSpace = view.findViewById(R.id.bottom_space); - if (mMore != null) mMore.setDelegate(this); } // ListItemViewHolder implementation. @Override public void bind(PropertyModel properties, ListItem item) { SectionHeaderListItem sectionItem = (SectionHeaderListItem) item; - mTitle.setText(ListUtils.getTextForSection(sectionItem.filter)); - if (sectionItem.showDate) { - mDate.setText(sectionItem.isJustNow ? itemView.getContext().getResources().getString( - R.string.download_manager_just_now) - : UiUtils.dateToHeaderString(sectionItem.date)); - } + mDate.setText(sectionItem.isJustNow ? itemView.getContext().getResources().getString( + R.string.download_manager_just_now) + : UiUtils.dateToHeaderString(sectionItem.date)); - updateTopBottomSpacing(sectionItem.showMenu); mDivider.setVisibility(sectionItem.showDivider ? ViewGroup.VISIBLE : ViewGroup.GONE); - mDate.setVisibility(sectionItem.showDate ? View.VISIBLE : View.GONE); - mTitle.setVisibility((sectionItem.showTitle ? View.VISIBLE : View.GONE)); - if (mMore != null) mMore.setVisibility(sectionItem.showMenu ? View.VISIBLE : View.GONE); - - if (sectionItem.items != null) { - mHasMultipleItems = sectionItem.items.size() > 1; - mCanSelectItems = !getCompletedItems(sectionItem.items).isEmpty(); - } - - if (sectionItem.showMenu && mMore != null) { - assert sectionItem.items.size() > 0; - mShareCallback = () - -> properties.get(ListProperties.CALLBACK_SHARE) - .onResult(sectionItem.items.get(0)); - mDeleteCallback = () - -> properties.get(ListProperties.CALLBACK_REMOVE) - .onResult(sectionItem.items.get(0)); - - mShareAllCallback = () - -> properties.get(ListProperties.CALLBACK_SHARE_ALL) - .onResult(getCompletedItems(sectionItem.items)); - mDeleteAllCallback = () - -> properties.get(ListProperties.CALLBACK_REMOVE_ALL) - .onResult(sectionItem.items); - mSelectCallback = properties.get(ListProperties.CALLBACK_START_SELECTION); - - mMore.setClickable(!properties.get(ListProperties.SELECTION_MODE_ACTIVE)); - } - } - - @Override - public ListMenuButton.Item[] getItems() { - Context context = itemView.getContext(); - if (mHasMultipleItems) { - return new ListMenuButton.Item[] { - new ListMenuButton.Item(context, R.string.select, mCanSelectItems), - new ListMenuButton.Item(context, R.string.share_group, mCanSelectItems), - new ListMenuButton.Item(context, R.string.delete_group, true)}; - } else { - return new ListMenuButton.Item[] { - new ListMenuButton.Item(context, R.string.share, mCanSelectItems), - new ListMenuButton.Item(context, R.string.delete, true)}; - } - } - - @Override - public void onItemSelected(ListMenuButton.Item item) { - if (item.getTextId() == R.string.select) { - mSelectCallback.run(); - } else if (item.getTextId() == R.string.share) { - mShareCallback.run(); - } else if (item.getTextId() == R.string.delete) { - mDeleteCallback.run(); - } else if (item.getTextId() == R.string.share_group) { - mShareAllCallback.run(); - } else if (item.getTextId() == R.string.delete_group) { - mDeleteAllCallback.run(); - } - } - - private void updateTopBottomSpacing(boolean showMenu) { - Resources resources = itemView.getContext().getResources(); - ViewGroup.LayoutParams topSpaceParams = mTopSpace.getLayoutParams(); - ViewGroup.LayoutParams bottomSpaceParams = mBottomSpace.getLayoutParams(); - - topSpaceParams.height = resources.getDimensionPixelSize(showMenu - ? R.dimen.download_manager_section_title_padding_image - : R.dimen.download_manager_section_title_padding_top); - bottomSpaceParams.height = resources.getDimensionPixelSize(showMenu - ? R.dimen.download_manager_section_title_padding_image - : R.dimen.download_manager_section_title_padding_bottom); - - mTopSpace.setLayoutParams(topSpaceParams); - mBottomSpace.setLayoutParams(bottomSpaceParams); - } - - private static List<OfflineItem> getCompletedItems(Collection<OfflineItem> items) { - List<OfflineItem> completedItems = new ArrayList<>(); - for (OfflineItem item : items) { - if (item.state != OfflineItemState.COMPLETE) continue; - completedItems.add(item); - } - - return completedItems; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/metrics/UmaUtils.java index 46330b2b..ac9f5b9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/metrics/UmaUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/metrics/UmaUtils.java
@@ -56,18 +56,6 @@ } // Please treat this list as append only and keep it in sync with - // Android.DownloadManager.List.Section.Menu.Actions in enums.xml. - @IntDef({ImagesMenuAction.MENU_START_SELECTING, ImagesMenuAction.MENU_SHARE_ALL, - ImagesMenuAction.MENU_DELETE_ALL}) - @Retention(RetentionPolicy.SOURCE) - public @interface ImagesMenuAction { - int MENU_START_SELECTING = 0; - int MENU_SHARE_ALL = 1; - int MENU_DELETE_ALL = 2; - int NUM_ENTRIES = 3; - } - - // Please treat this list as append only and keep it in sync with // Android.Download.Rename.Dialog.Action in enums.xml. @IntDef({RenameDialogAction.RENAME_DIALOG_CONFIRM, RenameDialogAction.RENAME_DIALOG_CANCEL, RenameDialogAction.RENAME_DIALOG_OTHER, @@ -86,34 +74,6 @@ } /** - * Called to record metrics for the given images section menu action. - * @param action The given menu action. - */ - public static void recordImagesMenuAction(@ImagesMenuAction int action) { - String userActionSuffix; - switch (action) { - case ImagesMenuAction.MENU_START_SELECTING: - userActionSuffix = "StartSelecting"; - break; - case ImagesMenuAction.MENU_SHARE_ALL: - userActionSuffix = "ShareAll"; - break; - case ImagesMenuAction.MENU_DELETE_ALL: - userActionSuffix = "DeleteAll"; - break; - default: - assert false : "Unexpected action " + action + " passed to recordImagesMenuAction."; - return; - } - - RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.List.Section.Menu.Images.Action", action, - ImagesMenuAction.NUM_ENTRIES); - RecordUserAction.record( - "Android.DownloadManager.List.Selection.Menu.Images.Action." + userActionSuffix); - } - - /** * Called to record metrics for the given list item action. * @param action The given list item action. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java index 196e101..7499b473 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
@@ -48,13 +48,6 @@ int countSpecializedHandlers(List<ResolveInfo> infos); /** - * Returns the package name of the first valid WebAPK in {@link infos}. - * @param infos ResolveInfos to search. - * @return The package name of the first valid WebAPK. Null if no valid WebAPK was found. - */ - String findFirstWebApkPackageName(List<ResolveInfo> infos); - - /** * Start an activity for the intent. Used for intents that must be handled externally. * @param intent The intent we want to send. * @param proxy Whether we need to proxy the intent through AuthenticatedProxyActivity (this is @@ -163,4 +156,10 @@ * @return Whether the Intent points to an app that we trust and that launched Chrome. */ boolean isIntentForTrustedCallingApp(Intent intent); + + /** + * @param packageName The package to check. + * @return Whether the package is a valid WebAPK package. + */ + boolean isValidWebApk(String packageName); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java index 2d56240..5b33682f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -299,11 +299,6 @@ } @Override - public String findFirstWebApkPackageName(List<ResolveInfo> infos) { - return WebApkValidator.findFirstWebApkPackage(mApplicationContext, infos); - } - - @Override public void startActivity(Intent intent, boolean proxy) { try { forcePdfViewerAsIntentHandlerIfNeeded(intent); @@ -644,4 +639,9 @@ public boolean isIntentForTrustedCallingApp(Intent intent) { return false; } + + @Override + public boolean isValidWebApk(String packageName) { + return WebApkValidator.isValidWebApk(ContextUtils.getApplicationContext(), packageName); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java index 1b73c28c..1d534d1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -9,6 +9,7 @@ import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.SystemClock; @@ -44,6 +45,7 @@ import java.lang.annotation.RetentionPolicy; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -74,21 +76,6 @@ @VisibleForTesting static final String EXTRA_MARKET_REFERRER = "market_referrer"; - @IntDef({WebApkLaunchDecision.LAUNCHED, WebApkLaunchDecision.LAUNCH_FAILED, - WebApkLaunchDecision.ALREADY_IN_WEBAPK, - WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER}) - public @interface WebApkLaunchDecision { - int LAUNCHED = 0; - int LAUNCH_FAILED = 1; - - // User is either in target WebAPK or in CCT launched by the target WebAPK. - int ALREADY_IN_WEBAPK = 2; - - // The WebAPK either cannot handle intent or there are multiple non-browser apps which - // can handle the intent. - int WEBAPK_NOT_SOLE_INTENT_HANDLER = 3; - } - // These values are persisted in histograms. Please do not renumber. Append only. @IntDef({AiaIntent.FALLBACK_USED, AiaIntent.SERP, AiaIntent.OTHER}) @Retention(RetentionPolicy.SOURCE) @@ -186,18 +173,34 @@ && (params.getRedirectHandler() == null // For instance, if this is a chained fallback URL, we ignore it. || !params.getRedirectHandler().shouldNotOverrideUrlLoading())) { - if (InstantAppsHandler.isIntentToInstantApp(targetIntent)) { - RecordHistogram.recordEnumeratedHistogram( - "Android.InstantApps.DirectInstantAppsIntent", AiaIntent.FALLBACK_USED, - AiaIntent.NUM_ENTRIES); - } - - result = clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params); + result = handleFallbackUrl(params, targetIntent, browserFallbackUrl); } if (DEBUG) printDebugShouldOverrideUrlLoadingResult(result); return result; } + private @OverrideUrlLoadingResult int handleFallbackUrl( + ExternalNavigationParams params, Intent targetIntent, String browserFallbackUrl) { + if (InstantAppsHandler.isIntentToInstantApp(targetIntent)) { + RecordHistogram.recordEnumeratedHistogram("Android.InstantApps.DirectInstantAppsIntent", + AiaIntent.FALLBACK_USED, AiaIntent.NUM_ENTRIES); + } + // Launch WebAPK if it can handle the URL. + try { + Intent intent = Intent.parseUri(browserFallbackUrl, Intent.URI_INTENT_SCHEME); + sanitizeQueryIntentActivitiesIntent(intent); + List<ResolveInfo> resolvingInfos = mDelegate.queryIntentActivities(intent); + if (!shouldStayInWebApkCCT(params, resolvingInfos) + && !isAlreadyInTargetWebApk(resolvingInfos, params) + && launchWebApkIfSoleIntentHandler(resolvingInfos, intent)) { + return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; + } + } catch (Exception e) { + if (DEBUG) Log.i(TAG, "Could not parse fallback url as intent"); + } + return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params); + } + private void printDebugShouldOverrideUrlLoadingResult(int result) { String resultString; switch (result) { @@ -475,46 +478,14 @@ */ private int handleUnresolvableIntent( ExternalNavigationParams params, Intent targetIntent, String browserFallbackUrl) { - if (browserFallbackUrl != null) { - return handleFallbackUrl(params, targetIntent, browserFallbackUrl); - } + // Fallback URL will be handled by the caller of shouldOverrideUrlLoadingInternal. + if (browserFallbackUrl != null) return OverrideUrlLoadingResult.NO_OVERRIDE; if (targetIntent.getPackage() != null) return handleWithMarketIntent(params, targetIntent); if (DEBUG) Log.i(TAG, "Could not find an external activity to use"); return OverrideUrlLoadingResult.NO_OVERRIDE; } - private @OverrideUrlLoadingResult int handleFallbackUrl( - ExternalNavigationParams params, Intent intent, String browserFallbackUrl) { - // Launch WebAPK if it can handle the URL. - if (!TextUtils.isEmpty(intent.getPackage()) - || (intent.getSelector() != null - && !TextUtils.isEmpty(intent.getSelector().getPackage()))) { - try { - intent = Intent.parseUri(browserFallbackUrl, Intent.URI_INTENT_SCHEME); - } catch (Exception e) { - if (DEBUG) Log.i(TAG, "Could not parse fallback url"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - } - sanitizeQueryIntentActivitiesIntent(intent); - List<ResolveInfo> resolvingInfos = mDelegate.queryIntentActivities(intent); - switch (launchWebApkIfSoleIntentHandler(params, resolvingInfos, intent)) { - case WebApkLaunchDecision.ALREADY_IN_WEBAPK: - if (DEBUG) Log.i(TAG, "Already in WebAPK"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - case WebApkLaunchDecision.LAUNCH_FAILED: - if (DEBUG) Log.i(TAG, "WebAPK launch failed"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - case WebApkLaunchDecision.LAUNCHED: - if (DEBUG) Log.i(TAG, "Launched WebAPK"); - return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; - case WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER: - break; - } - } - return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params); - } - private @OverrideUrlLoadingResult int handleWithMarketIntent( ExternalNavigationParams params, Intent intent) { String marketReferrer = IntentUtils.safeGetStringExtra(intent, EXTRA_MARKET_REFERRER); @@ -698,6 +669,60 @@ return OverrideUrlLoadingResult.NO_OVERRIDE; } + /** + * If some third-party app launched Chrome with an intent, and the URL got redirected, and the + * user explicitly chose Chrome over other intent handlers, stay in Chrome unless there was a + * new intent handler after redirection or Chrome cannot handle it any more. + * Custom tabs are an exception to this rule, since at no point, the user sees an intent picker + * and "picking Chrome" is handled inside the support library. + */ + private boolean shouldKeepIntentRedirectInChrome(ExternalNavigationParams params, + boolean incomingIntentRedirect, Intent targetIntent, boolean isExternalProtocol) { + if (params.getRedirectHandler() != null && incomingIntentRedirect && !isExternalProtocol + && !params.getRedirectHandler().isFromCustomTabIntent() + && !params.getRedirectHandler().hasNewResolver(targetIntent)) { + if (DEBUG) Log.i(TAG, "Custom tab redirect no handled"); + return true; + } + return false; + } + + /** + * Returns whether the activity belongs to a WebAPK and the URL is within the scope of the + * WebAPK. The WebAPK's main activity is a bouncer that redirects to WebApkActivity in Chrome. + * In order to avoid bouncing indefinitely, we should not override the navigation if we are + * currently showing the WebAPK (params#nativeClientPackageName()) that we will redirect to. + */ + private boolean isAlreadyInTargetWebApk( + List<ResolveInfo> resolveInfos, ExternalNavigationParams params) { + String currentName = params.nativeClientPackageName(); + if (currentName == null) return false; + for (ResolveInfo resolveInfo : resolveInfos) { + ActivityInfo info = resolveInfo.activityInfo; + if (info != null && currentName.equals(info.packageName)) { + if (DEBUG) Log.i(TAG, "Already in WebAPK"); + return true; + } + } + return false; + } + + private boolean launchExternalIntent(Intent targetIntent, boolean shouldProxyForInstantApps) { + try { + if (!mDelegate.startActivityIfNeeded(targetIntent, shouldProxyForInstantApps)) { + if (DEBUG) Log.i(TAG, "The current Activity was the only targeted Activity."); + return false; + } + } catch (ActivityNotFoundException e) { + // The targeted app must have been uninstalled/disabled since we queried for Activities + // to handle this intent. + if (DEBUG) Log.i(TAG, "Activity not found."); + return false; + } + if (DEBUG) Log.i(TAG, "startActivityIfNeeded"); + return true; + } + private @OverrideUrlLoadingResult int shouldOverrideUrlLoadingInternal( ExternalNavigationParams params, Intent targetIntent, @Nullable String browserFallbackUrl) { @@ -814,45 +839,22 @@ targetIntent, params, browserFallbackUrl, shouldProxyForInstantApps); } - // Some third-party app launched Chrome with an intent, and the URL got redirected. The - // user has explicitly chosen Chrome over other intent handlers, so stay in Chrome - // unless there was a new intent handler after redirection or Chrome cannot handle it - // any more. - // Custom tabs are an exception to this rule, since at no point, the user sees an intent - // picker and "picking Chrome" is handled inside the support library. - if (params.getRedirectHandler() != null && incomingIntentRedirect) { - if (!isExternalProtocol && !params.getRedirectHandler().isFromCustomTabIntent() - && !params.getRedirectHandler().hasNewResolver(targetIntent)) { - if (DEBUG) Log.i(TAG, "Custom tab redirect no handled"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - } - } - - switch (launchWebApkIfSoleIntentHandler(params, resolvingInfos, targetIntent)) { - case WebApkLaunchDecision.ALREADY_IN_WEBAPK: - if (DEBUG) Log.i(TAG, "Already in WebAPK"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - case WebApkLaunchDecision.LAUNCH_FAILED: - if (DEBUG) Log.i(TAG, "WebAPK launch failed"); - return OverrideUrlLoadingResult.NO_OVERRIDE; - case WebApkLaunchDecision.LAUNCHED: - if (DEBUG) Log.i(TAG, "Launched WebAPK"); - return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; - case WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER: - break; - } - - try { - if (mDelegate.startActivityIfNeeded(targetIntent, shouldProxyForInstantApps)) { - // Assume the browser can handle it if there's no activity for this intent. - if (DEBUG) Log.i(TAG, "startActivityIfNeeded"); - return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; - } - } catch (ActivityNotFoundException e) { - if (DEBUG) Log.i(TAG, "Activity not found."); + if (shouldKeepIntentRedirectInChrome( + params, incomingIntentRedirect, targetIntent, isExternalProtocol)) { return OverrideUrlLoadingResult.NO_OVERRIDE; } + if (shouldStayInWebApkCCT(params, resolvingInfos)) { + return OverrideUrlLoadingResult.NO_OVERRIDE; + } + if (isAlreadyInTargetWebApk(resolvingInfos, params)) { + return OverrideUrlLoadingResult.NO_OVERRIDE; + } else if (launchWebApkIfSoleIntentHandler(resolvingInfos, targetIntent)) { + return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; + } + if (launchExternalIntent(targetIntent, shouldProxyForInstantApps)) { + return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; + } return OverrideUrlLoadingResult.NO_OVERRIDE; } @@ -1022,50 +1024,36 @@ tab.getActivity().getIntent(), Browser.EXTRA_APPLICATION_ID); if (appId == null) return false; - try { - Intent.parseUri(params.getUrl(), Intent.URI_INTENT_SCHEME); - } catch (URISyntaxException ex) { - return false; - } - return !ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(handlers, appId) + boolean webApkHasSpecializedHandler = + ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(handlers, appId) .isEmpty(); + if (webApkHasSpecializedHandler) return false; + if (DEBUG) Log.i(TAG, "Staying in WebApk CCT."); + return true; } /** * Launches WebAPK if the WebAPK is the sole non-browser handler for the given intent. - * Returns whether a WebAPK was launched and if it was not launched returns why. + * @return Whether a WebAPK was launched. */ - private @WebApkLaunchDecision int launchWebApkIfSoleIntentHandler( - ExternalNavigationParams params, List<ResolveInfo> resolvingInfos, Intent intent) { - if (shouldStayInWebApkCCT(params, resolvingInfos)) { - return WebApkLaunchDecision.ALREADY_IN_WEBAPK; - } - - String targetWebApkPackageName = mDelegate.findFirstWebApkPackageName(resolvingInfos); - - // We can't rely on this falling through to startActivityIfNeeded and behaving - // correctly for WebAPKs. This is because the target of the intent is the WebApk's main - // activity but that's just a bouncer which will redirect to WebApkActivity in chrome. - // To avoid bouncing indefinitely, don't override the navigation if we are currently - // showing the WebApk |params.webApkPackageName()| that we will redirect to. - if (targetWebApkPackageName != null - && targetWebApkPackageName.equals(params.nativeClientPackageName())) { - return WebApkLaunchDecision.ALREADY_IN_WEBAPK; - } - - if (targetWebApkPackageName == null - || mDelegate.countSpecializedHandlers(resolvingInfos) != 1) { - return WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER; - } - - intent.setPackage(targetWebApkPackageName); + private boolean launchWebApkIfSoleIntentHandler( + List<ResolveInfo> resolvingInfos, Intent targetIntent) { + ArrayList<String> packages = + ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter( + resolvingInfos, null); + if (packages.size() != 1 || !mDelegate.isValidWebApk(packages.get(0))) return false; + Intent webApkIntent = new Intent(targetIntent); + webApkIntent.setPackage(packages.get(0)); try { - if (mDelegate.startActivityIfNeeded(intent, false)) { - return WebApkLaunchDecision.LAUNCHED; - } + mDelegate.startActivity(webApkIntent, false); + if (DEBUG) Log.i(TAG, "Launched WebAPK"); + return true; } catch (ActivityNotFoundException e) { + // The WebApk must have been uninstalled/disabled since we queried for Activities to + // handle this intent. + if (DEBUG) Log.i(TAG, "WebAPK launch failed"); + return false; } - return WebApkLaunchDecision.LAUNCH_FAILED; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java index 6c68a6b6..439013d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
@@ -293,11 +293,13 @@ } @Override - public boolean isPeekStateEnabled() { + public int getPeekHeight() { // Makes peek state as 'not present' when bottom sheet is in expanded state (i.e. animating // from expanded to close state). It avoids the sheet animating in two distinct steps, which // looks awkward. - return !mBottomSheetController.get().getBottomSheet().isSheetOpen(); + return !mBottomSheetController.get().getBottomSheet().isSheetOpen() + ? getSizePx(mParentView.getContext(), R.dimen.navigation_sheet_peek_height) + : BottomSheet.HeightMode.DISABLED; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java index d7405795..f9f4bf7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
@@ -12,6 +12,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.WebContentsFactory; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -194,10 +195,14 @@ } private static String getUrlFromIntent(Intent intent) { - if (Intent.ACTION_VIEW.equals(intent.getAction()) - || Intent.ACTION_MAIN.equals(intent.getAction())) { + String action = intent.getAction(); + if (Intent.ACTION_VIEW.equals(action) || Intent.ACTION_MAIN.equals(action) + || (action == null + && ChromeTabbedActivity.MAIN_LAUNCHER_ACTIVITY_NAME.equals( + intent.getComponent().getClassName()))) { // TODO(alexclarke): For ACTION_MAIN maybe refactor TabPersistentStore so we can - // instantiate (a subset of that) here to extract the URL. + // instantiate (a subset of that) here to extract the URL if it's not set in the + // intent. return IntentHandler.getUrlFromIntent(intent); } else { return null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java index df9632d..3bc9c19b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
@@ -52,8 +52,8 @@ } @Override - public boolean isPeekStateEnabled() { - return false; + public int getPeekHeight() { + return BottomSheet.HeightMode.DISABLED; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/micro/MicrotransactionView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/micro/MicrotransactionView.java index c83f1a7..799e7b02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/micro/MicrotransactionView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/micro/MicrotransactionView.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.HeightMode; /** Microtransaction UI. */ /* package */ class MicrotransactionView implements BottomSheetContent { @@ -113,8 +114,8 @@ } @Override - public boolean isPeekStateEnabled() { - return mIsPeekStateEnabled; + public int getPeekHeight() { + return mIsPeekStateEnabled ? HeightMode.DEFAULT : HeightMode.DISABLED; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/DevicePickerBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/DevicePickerBottomSheetContent.java index 9829c66..35abb8c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/DevicePickerBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/DevicePickerBottomSheetContent.java
@@ -105,9 +105,9 @@ } @Override - public boolean isPeekStateEnabled() { + public int getPeekHeight() { // Return false to ensure that the entire bottom sheet is shown. - return false; + return BottomSheet.HeightMode.DISABLED; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java index c988892..92948d0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -74,7 +74,6 @@ private static Map<String, Boolean> sFlags = new HashMap<>(); private static Boolean sHasGoogleAccountAuthenticator; private static Boolean sHasRecognitionIntentHandler; - private static Boolean sIsTabGroupsAndroidEnabled; private static Boolean sIsTabToGtsAnimationEnabled; private static String sReachedCodeProfilerTrialGroup; @@ -480,22 +479,15 @@ || ChromeFeatureList.isEnabled( ChromeFeatureList.TAB_GROUPS_ANDROID)) && TabManagementModuleProvider.getDelegate() != null - && ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID)); + && ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID) + && isHighEndPhone()); } /** * @return Whether the tab group feature is enabled and available for use. */ public static boolean isTabGroupsAndroidEnabled() { - if (sIsTabGroupsAndroidEnabled == null) { - ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance(); - - sIsTabGroupsAndroidEnabled = preferenceManager.readBoolean( - ChromePreferenceManager.TAB_GROUPS_ANDROID_ENABLED_KEY, false); - sIsTabGroupsAndroidEnabled &= isHighEndPhone(); - } - - return sIsTabGroupsAndroidEnabled; + return isFlagEnabled(ChromePreferenceManager.TAB_GROUPS_ANDROID_ENABLED_KEY, false); } /** @@ -504,7 +496,16 @@ */ @VisibleForTesting public static void setTabGroupsAndroidEnabledForTesting(@Nullable Boolean available) { - sIsTabGroupsAndroidEnabled = available; + sFlags.put(ChromePreferenceManager.TAB_GROUPS_ANDROID_ENABLED_KEY, available); + } + + /** + * Toggles whether the StartSurface is enabled for testing. Should be reset back to null after + * the test has finished. + */ + @VisibleForTesting + public static void setStartSurfaceEnabledForTesting(@Nullable Boolean isEnabled) { + sFlags.put(ChromePreferenceManager.START_SURFACE_ENABLED_KEY, isEnabled); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index 56e3218..6b77aeaca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -81,6 +81,28 @@ int SCROLLING = 4; } + /** The different possible height modes for a given state. */ + @IntDef({HeightMode.DEFAULT, HeightMode.WRAP_CONTENT, HeightMode.DISABLED}) + @Retention(RetentionPolicy.SOURCE) + public @interface HeightMode { + /** + * The sheet will use the stock behavior for the {@link SheetState} this is used for. + * Typically this means a pre-defined height ratio, peek being the exception that uses the + * feature's toolbar height. + */ + int DEFAULT = 0; + /** + * The sheet will set its height so the content is completely visible. This mode cannot + * be used for the peek state. + */ + int WRAP_CONTENT = -1; + /** + * The state this mode is used for will be disabled. For example, disabling the peek state + * would cause the sheet to automatically expand when triggered. + */ + int DISABLED = -2; + } + /** The different reasons that the sheet's state can change. */ @IntDef({StateChangeReason.NONE, StateChangeReason.SWIPE, StateChangeReason.BACK_PRESS, StateChangeReason.TAP_SCRIM, StateChangeReason.NAVIGATION, @@ -157,10 +179,10 @@ private ValueAnimator mSettleAnimator; /** The width of the view that contains the bottom sheet. */ - private float mContainerWidth; + private int mContainerWidth; /** The height of the view that contains the bottom sheet. */ - private float mContainerHeight; + private int mContainerHeight; /** The desired height of the current content view. */ private float mContentDesiredHeight = HEIGHT_UNSPECIFIED; @@ -266,11 +288,6 @@ boolean swipeToDismissEnabled(); /** - * @return Whether the peek state is enabled. - */ - boolean isPeekStateEnabled(); - - /** * @return Whether the bottom sheet should wrap its content, i.e. its height in the FULL * state is the minimum height required such that the content is visible. If this * behavior is enabled, the HALF state of the sheet is disabled. @@ -296,6 +313,16 @@ } /** + * @return The height of the peeking state for the content in px or one of the values in + * {@link HeightMode}. If {@link HeightMode#DEFAULT}, the system expects + * {@link #getToolbarView} to be non-null, where it will then use its height as the + * peeking height. + */ + default int getPeekHeight() { + return HeightMode.DEFAULT; + } + + /** * TODO(jinsukkim): Revise the API in favor of those specifying the height and its behavior * for each state. * @return Height of the sheet in half state with respect to the container height. @@ -423,8 +450,7 @@ */ public boolean handleBackPress() { if (isSheetOpen()) { - int sheetState = - mSheetContent.isPeekStateEnabled() ? SheetState.PEEK : SheetState.HIDDEN; + int sheetState = getMinSwipableSheetState(); setSheetState(sheetState, true, StateChangeReason.BACK_PRESS); return true; } @@ -503,8 +529,7 @@ * @param root The container of the bottom sheet. * @param tabProvider A means of accessing the active tab. * @param fullscreenManager A fullscreen manager for persisting browser controls and - * determining\ - * their offset. + * determining their offset. * @param window Android window for getting insets. * @param keyboardDelegate Delegate for hiding the keyboard. */ @@ -527,6 +552,9 @@ mBottomSheetContentContainer.setBottomSheet(this); mBottomSheetContentContainer.setBackgroundResource(R.drawable.top_round); + mContainerWidth = root.getWidth(); + mContainerHeight = root.getHeight(); + // Listen to height changes on the root. root.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { private int mPreviousKeyboardHeight; @@ -536,8 +564,8 @@ int oldLeft, int oldTop, int oldRight, int oldBottom) { // Compute the new height taking the keyboard into account. // TODO(mdjones): Share this logic with LocationBarLayout: crbug.com/725725. - float previousWidth = mContainerWidth; - float previousHeight = mContainerHeight; + int previousWidth = mContainerWidth; + int previousHeight = mContainerHeight; mContainerWidth = right - left; mContainerHeight = bottom - top; @@ -617,7 +645,7 @@ // open over the fullscreen video. See crbug.com/740499. if (mFullscreenManager != null && mFullscreenManager.getPersistentFullscreenMode() && isSheetOpen()) { - setSheetState(SheetState.PEEK, false); + setSheetState(getMinSwipableSheetState(), false); } else { if (isRunningSettleAnimation()) return; setSheetState(mCurrentState, false); @@ -736,9 +764,26 @@ * @return The minimum sheet state that the user can swipe to. i.e. flinging down will either * close the sheet or peek it. */ - private @SheetState int getMinSwipableSheetState() { - return swipeToDismissEnabled() || !mSheetContent.isPeekStateEnabled() ? SheetState.HIDDEN - : SheetState.PEEK; + @SheetState + int getMinSwipableSheetState() { + return swipeToDismissEnabled() || !isPeekStateEnabled() ? SheetState.HIDDEN + : SheetState.PEEK; + } + + /** + * Get the state that the bottom sheet should open to with the provided content. + * @return The minimum opened state for the current content. + */ + @SheetState + int getOpeningState() { + if (mSheetContent == null) { + return SheetState.HIDDEN; + } else if (isPeekStateEnabled()) { + return SheetState.PEEK; + } else if (!shouldSkipHalfState()) { + return SheetState.HALF; + } + return SheetState.FULL; } @Override @@ -889,7 +934,9 @@ * @return Get the height in px that the peeking bar is offset due to the browser controls. */ private float getOffsetFromBrowserControls() { - if (mSheetContent != null && !mSheetContent.hideOnScroll()) return 0; + if (mSheetContent == null || mSheetContent.hideOnScroll() || !isPeekStateEnabled()) { + return 0; + } float peekHeight = getPeekRatio() * mContainerHeight; return peekHeight * mFullscreenManager.getBrowserControlHiddenRatio(); @@ -906,7 +953,7 @@ // browser controls do. float translationY = (mContainerHeight - mCurrentOffsetPx) + getOffsetFromBrowserControls(); - if (MathUtils.areFloatsEqual(translationY, getTranslationY())) return; + if (isSheetOpen() && MathUtils.areFloatsEqual(translationY, getTranslationY())) return; setTranslationY(translationY); @@ -917,11 +964,19 @@ mSheetContainer.addView(this); } - float peekHeight = getSheetHeightForState(SheetState.PEEK); - boolean isAtPeekingHeight = MathUtils.areFloatsEqual(getCurrentOffsetPx(), peekHeight); - if (isSheetOpen() && (getCurrentOffsetPx() < peekHeight || isAtPeekingHeight)) { + // Do open/close computation based on the minimum allowed state by the sheet's content. + float minScrollableHeight = getSheetHeightForState(getMinSwipableSheetState()); + boolean isAtMinHeight = MathUtils.areFloatsEqual(getCurrentOffsetPx(), minScrollableHeight); + boolean heightLessThanPeek = getCurrentOffsetPx() < minScrollableHeight; + // Trigger the onSheetClosed event when the sheet is moving toward the hidden state if peek + // is disabled. This should be fine since touch is disabled when the sheet's target is + // hidden. + boolean triggerCloseWithHidden = !isPeekStateEnabled() && mTargetState == SheetState.HIDDEN; + + if (isSheetOpen() && (heightLessThanPeek || isAtMinHeight || triggerCloseWithHidden)) { onSheetClosed(reason); - } else if (!isSheetOpen() && getCurrentOffsetPx() > peekHeight) { + } else if (!isSheetOpen() && mTargetState != SheetState.HIDDEN + && getCurrentOffsetPx() > minScrollableHeight) { onSheetOpened(reason); } @@ -977,11 +1032,27 @@ return 0; } + /** @return Whether the peeking state for the sheet's content is enabled. */ + private boolean isPeekStateEnabled() { + return mSheetContent != null && mSheetContent.getPeekHeight() != HeightMode.DISABLED; + } + /** * @return The ratio of the height of the screen that the peeking state is. */ public float getPeekRatio() { - if (mContainerHeight <= 0) return 0; + if (mContainerHeight <= 0 || !isPeekStateEnabled()) return 0; + + // If the content has a custom peek ratio set, use that instead of computing one. + if (mSheetContent != null && mSheetContent.getPeekHeight() != HeightMode.DEFAULT) { + assert mSheetContent.getPeekHeight() + != HeightMode.WRAP_CONTENT : "The peek mode can't wrap content."; + float ratio = mSheetContent.getPeekHeight() / (float) mContainerHeight; + assert ratio > 0 && ratio <= 1 : "Custom peek ratios must be in the range of (0, 1]."; + return ratio; + } + assert getToolbarView() != null : "Using default peek height requires a non-null toolbar"; + View toolbarView = getToolbarView(); int toolbarHeight = toolbarView.getHeight(); if (toolbarHeight == 0) { @@ -993,7 +1064,7 @@ toolbarHeight = layoutParams.height; } else { toolbarView.measure( - MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mContainerWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( (int) mContainerHeight, MeasureSpec.AT_MOST)); toolbarHeight = toolbarView.getMeasuredHeight(); @@ -1070,8 +1141,9 @@ o.onSheetOffsetChanged(mLastOffsetRatioSent, getCurrentOffsetPx()); } - if (MathUtils.areFloatsEqual( - offsetWithBrowserControls, getSheetHeightForState(SheetState.PEEK))) { + if (isPeekStateEnabled() + && MathUtils.areFloatsEqual( + offsetWithBrowserControls, getSheetHeightForState(SheetState.PEEK))) { for (BottomSheetObserver o : mObservers) o.onSheetFullyPeeked(); } } @@ -1079,6 +1151,7 @@ /** * @see #setSheetState(int, boolean, int) */ + @VisibleForTesting public void setSheetState(@SheetState int state, boolean animate) { setSheetState(state, animate, StateChangeReason.NONE); } @@ -1093,8 +1166,7 @@ * observers that a more specific event has occurred, otherwise * STATE_CHANGE_REASON_NONE can be used. */ - public void setSheetState( - @SheetState int state, boolean animate, @StateChangeReason int reason) { + void setSheetState(@SheetState int state, boolean animate, @StateChangeReason int reason) { assert state != SheetState.NONE; // Setting state to SCROLLING is not a valid operation. This can happen only when @@ -1104,9 +1176,7 @@ return; } - if (state == SheetState.HALF && shouldSkipHalfState()) { - state = SheetState.FULL; - } + if (state == SheetState.HALF && shouldSkipHalfState()) state = SheetState.FULL; mTargetState = state; @@ -1226,8 +1296,8 @@ } mSheetContent.getContentView().measure( - MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec((int) mContainerHeight, MeasureSpec.AT_MOST)); + MeasureSpec.makeMeasureSpec(mContainerWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mContainerHeight, MeasureSpec.AT_MOST)); mContentDesiredHeight = mSheetContent.getContentView().getMeasuredHeight(); } @@ -1286,7 +1356,7 @@ int prevState = nextState; for (@SheetState int i = getMinSwipableSheetState(); i <= SheetState.FULL; i++) { if (i == SheetState.HALF && shouldSkipHalfState) continue; - if (i == SheetState.PEEK && !mSheetContent.isPeekStateEnabled()) continue; + if (i == SheetState.PEEK && !isPeekStateEnabled()) continue; prevState = nextState; nextState = i; // The values in PanelState are ascending, they should be kept that way in order for
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java index d19d5eb..00663b64 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -142,10 +142,7 @@ public void onScrimClick() { if (!mBottomSheet.isSheetOpen()) return; mBottomSheet.setSheetState( - mBottomSheet.getCurrentSheetContent().isPeekStateEnabled() - ? BottomSheet.SheetState.PEEK - : BottomSheet.SheetState.HIDDEN, - true, StateChangeReason.TAP_SCRIM); + mBottomSheet.getMinSwipableSheetState(), true, StateChangeReason.TAP_SCRIM); } @Override @@ -223,7 +220,7 @@ mIsSuppressed = false; if (mBottomSheet.getCurrentSheetContent() != null) { - mBottomSheet.setSheetState(BottomSheet.SheetState.PEEK, true); + mBottomSheet.setSheetState(mBottomSheet.getOpeningState(), true); } else { // In the event the previous content was hidden, try to show the next one. showNextContent(true); @@ -322,7 +319,7 @@ BottomSheetContent nextContent = mContentQueue.poll(); mBottomSheet.showContent(nextContent); - mBottomSheet.setSheetState(BottomSheet.SheetState.PEEK, animate); + mBottomSheet.setSheetState(mBottomSheet.getOpeningState(), animate); } /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index a4e7ee5..328cdfb 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -170,9 +170,6 @@ <message name="IDS_DELETE" desc="Label for a delete button. Used in multiple contexts. [CHAR-LIMIT=20]"> Delete </message> - <message name="IDS_DELETE_GROUP" desc="Label for button that deletes a group of items. [CHAR-LIMIT=20]"> - Delete group - </message> <message name="IDS_REMOVE" desc="Label for a button to remove an item (e.g. a bookmark) from a list. [CHAR-LIMIT=20]"> Remove </message> @@ -230,9 +227,6 @@ <message name="IDS_SHARE" desc="Content description for a button to share item(s). [CHAR-LIMIT=20]"> Share </message> - <message name="IDS_SHARE_GROUP" desc="Content description for a button to share a group item(s). [CHAR-LIMIT=20]"> - Share group - </message> <message name="IDS_SEARCH" desc="The label for a search button."> Search </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java index dd960489..ac3c682 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -8,6 +8,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -1599,6 +1600,14 @@ return ri; } + private static ResolveInfo newSpecializedResolveInfo( + String packageName, IntentActivity activity) { + ResolveInfo info = newResolveInfo(packageName); + info.filter = new IntentFilter(Intent.ACTION_VIEW); + info.filter.addDataAuthority(activity.mUrlPrefix, null); + return info; + } + private static WebappInfo newWebappInfoFromScope(String scope) { Intent webappIntent = WebappTestHelper.createMinimalWebappIntent("" /* id */, "" /* url */); webappIntent.putExtra(ShortcutHelper.EXTRA_SCOPE, scope); @@ -1660,7 +1669,8 @@ } for (IntentActivity intentActivity : mIntentActivities) { if (dataString.startsWith(intentActivity.urlPrefix())) { - list.add(newResolveInfo(intentActivity.packageName())); + list.add(newSpecializedResolveInfo( + intentActivity.packageName(), intentActivity)); } } if (!list.isEmpty()) return list; @@ -1716,17 +1726,6 @@ return count; } - @Override - public String findFirstWebApkPackageName(List<ResolveInfo> infos) { - List<IntentActivity> matchingIntentActivities = findMatchingIntentActivities(infos); - for (IntentActivity intentActivity : matchingIntentActivities) { - if (intentActivity.isWebApk()) { - return intentActivity.packageName(); - } - } - return null; - } - private ArrayList<IntentActivity> findMatchingIntentActivities(List<ResolveInfo> infos) { ArrayList<IntentActivity> outList = new ArrayList<IntentActivity>(); for (ResolveInfo info : infos) { @@ -1823,6 +1822,16 @@ return mIsCallingAppTrusted; } + @Override + public boolean isValidWebApk(String packageName) { + for (IntentActivity activity : mIntentActivities) { + if (activity.packageName().equals(packageName)) { + return activity.isWebApk(); + } + } + return false; + } + public void reset() { startActivityIntent = null; startIncognitoIntentCalled = false;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java index 6444c736..cb9e5445 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
@@ -16,6 +16,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.UrlUtils; @@ -33,7 +34,6 @@ import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.test.util.UiRestriction; @@ -138,10 +138,11 @@ NavigationSheetCoordinator sheet = (NavigationSheetCoordinator) showPopup(controller); ListView listview = sheet.getContentView().findViewById(R.id.navigation_entries); - CriteriaHelper.pollUiThread(sheet::isExpanded); + CriteriaHelper.pollUiThread(() -> listview.getChildCount() >= 2); Assert.assertEquals(INVALID_NAVIGATION_INDEX, controller.mNavigatedIndex); - TouchCommon.singleClickView(listview.getChildAt(1)); + ThreadUtils.runOnUiThreadBlocking(() -> listview.getChildAt(1).callOnClick()); + CriteriaHelper.pollUiThread(sheet::isHidden); CriteriaHelper.pollUiThread( Criteria.equals(NAVIGATION_INDEX_2, () -> controller.mNavigatedIndex));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java index d58ccce8..a4b9bb8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.init; +import android.content.ComponentName; import android.content.Intent; import android.net.Uri; import android.support.test.filters.SmallTest; @@ -38,6 +39,11 @@ private static final String INVALID_SCHEME = "javascript:alert()"; private static final Intent VIEW_INTENT = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(SITE_A)); + private static final Intent CHROME_MAIN_COMPONENT_INTENT = + new Intent() + .setComponent(new ComponentName("com.google.android.apps.chrome", + "com.google.android.apps.chrome.Main")) + .setData(Uri.parse(SITE_A)); private static final Intent INCOGNITO_VIEW_INTENT = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(SITE_A)) @@ -97,6 +103,14 @@ @Test @SmallTest @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS) + public void testShouldLoadTab_AllowChromeMainComponentIntentWithUrl() { + Assert.assertTrue(createStartupTabPreloader(CHROME_MAIN_COMPONENT_INTENT, sChromeTabCreator) + .shouldLoadTab()); + } + + @Test + @SmallTest + @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS) public void testShouldLoadTab_AllowMainIntentsWithUrl() { Assert.assertTrue( createStartupTabPreloader(MAIN_INTENT_WITH_URL, sChromeTabCreator).shouldLoadTab());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java index 6dac1ad..d88930a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -125,7 +125,7 @@ @Restriction(RESTRICTION_TYPE_SVR) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testScreenTapsNotRegistered_WebXr() throws InterruptedException { @@ -210,7 +210,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testControllerClicksRegisteredOnDaydream_WebXr() { EmulatedVrController controller = new EmulatedVrController(mTestRule.getActivity()); @@ -246,7 +246,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testControllerExposedAsGamepadOnDaydream_WebXr() { EmulatedVrController controller = new EmulatedVrController(mTestRule.getActivity()); @@ -397,7 +397,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testScreenTapsRegisteredOnCardboard_WebXr() { mWebXrVrTestFramework.loadUrlAndAwaitInitialization( @@ -435,7 +435,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testTransientScreenTapsRegisteredOnCardboard_WebXr() { mWebXrVrTestFramework.loadUrlAndAwaitInitialization( @@ -482,7 +482,7 @@ @MediumTest @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testPresentationLocksFocus_WebXr() { presentationLocksFocusImpl(WebXrVrTestFramework.getFileUrlForHtmlTestFile( @@ -519,7 +519,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) public void testAppButtonExitsPresentation_WebXr() { appButtonExitsPresentationImpl( WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"), @@ -572,7 +572,7 @@ @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) public void testAppButtonNoopsWhenBrowsingDisabled_WebXr() throws ExecutionException { appButtonNoopsTestImpl(WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"), mWebXrVrTestFramework); @@ -589,7 +589,7 @@ XrActivityRestriction.SupportedActivity.CCT}) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) public void testAppButtonNoopsWhenBrowsingNotSupported_WebXr() throws ExecutionException { appButtonNoopsTestImpl(WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"), @@ -671,7 +671,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) public void testAppButtonAfterPageStopsSubmitting_WebXr() { appButtonAfterPageStopsSubmittingImpl( WebXrVrTestFramework.getFileUrlForHtmlTestFile("webxr_page_submits_once"), @@ -698,7 +698,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testWebXrInputSourceHasGamepad() { webxrGamepadSupportImpl(true /* daydream */); @@ -714,7 +714,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testWebXrInputSourceWithoutGamepad_Cardboard() { webxrGamepadSupportImpl(false /* daydream */); @@ -763,7 +763,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) public void testAppButtonLongPressDisplaysPermissions() throws InterruptedException { testAppButtonLongPressDisplaysPermissionsImpl(); @@ -778,7 +778,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.CTA}) public void testAppButtonLongPressDisplaysPermissionsIncognito() throws InterruptedException { @@ -852,7 +852,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) // TODO(https://crbug.com/901494): Make this run everywhere when permissions are // unbroken. @XrActivityRestriction({XrActivityRestriction.SupportedActivity.CTA}) @@ -865,7 +865,7 @@ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE) @CommandLineFlags .Remove({"enable-webvr"}) - @CommandLineFlags.Add({"enable-features=WebXR"}) + @CommandLineFlags.Add({"enable-features=WebXR,WebXrGamepadModule"}) @XrActivityRestriction({XrActivityRestriction.SupportedActivity.CTA}) public void testInSessionPermissionRequestsIncognito() { mWebXrVrTestFramework.openIncognitoTab("about:blank");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java index 7b6cba49..677f019 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -183,11 +183,11 @@ */ @Test @MediumTest - @CommandLineFlags.Remove({"enable-webvr"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWebXrDisabledWithoutFlagSet() { - // TODO(bsheedy): Remove this test once WebXR is on by default without - // requiring an origin trial. + @CommandLineFlags + .Add({"disable-features=WebXR"}) + @CommandLineFlags.Remove({"enable-webvr"}) + @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) + public void testWebXrDisabledWithoutFlagSet() { apiDisabledWithoutFlagSetImpl(WebXrVrTestFramework.getFileUrlForHtmlTestFile( "test_webxr_disabled_without_flag_set"), mWebXrVrTestFramework);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java index 1398ed0..6993a46f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
@@ -85,9 +85,9 @@ mHighPriorityContent = new TestBottomSheetContent( mActivityTestRule.getActivity(), ContentPriority.HIGH, false); - mPeekableContent = new TestBottomSheetContent(mActivityTestRule.getActivity(), true); - mNonPeekableContent = - new TestBottomSheetContent(mActivityTestRule.getActivity(), false); + mPeekableContent = new TestBottomSheetContent(mActivityTestRule.getActivity()); + mNonPeekableContent = new TestBottomSheetContent(mActivityTestRule.getActivity()); + mNonPeekableContent.setPeekHeight(BottomSheet.HeightMode.DISABLED); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java index 1b618a8..33ff028 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.widget.bottomsheet; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import android.support.test.filters.MediumTest; @@ -21,6 +22,8 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.util.MathUtils; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.HeightMode; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.SheetState; import org.chromium.chrome.test.BottomSheetTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.ui.test.util.UiRestriction; @@ -29,96 +32,143 @@ /** This class tests the functionality of the {@link BottomSheetObserver}. */ @RunWith(ChromeJUnit4ClassRunner.class) -@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // ChromeHome is only enabled on phones +@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // Bottom sheet is only used on phones. public class BottomSheetObserverTest { @Rule public BottomSheetTestRule mBottomSheetTestRule = new BottomSheetTestRule(); private BottomSheetTestRule.Observer mObserver; + private TestBottomSheetContent mSheetContent; @Before public void setUp() throws Exception { - mBottomSheetTestRule.startMainActivityOnBottomSheet(BottomSheet.SheetState.PEEK); + mBottomSheetTestRule.startMainActivityOnBottomSheet(SheetState.HIDDEN); ThreadUtils.runOnUiThreadBlocking(() -> { - mBottomSheetTestRule.getBottomSheet().showContent(new TestBottomSheetContent( - mBottomSheetTestRule.getActivity(), BottomSheet.ContentPriority.HIGH, false)); + mSheetContent = new TestBottomSheetContent( + mBottomSheetTestRule.getActivity(), BottomSheet.ContentPriority.HIGH, false); + mBottomSheetTestRule.getBottomSheet().showContent(mSheetContent); }); mObserver = mBottomSheetTestRule.getObserver(); } + /** Test that the onSheetClosed event is triggered if the sheet is closed without animation. */ + @Test + @MediumTest + public void testCloseEventCalled_noAnimation() throws TimeoutException { + runCloseEventTest(false, true); + } + /** - * Test that the onSheetClosed event is triggered if the sheet is closed without animation. + * Test that the onSheetClosed event is triggered if the sheet is closed without animation and + * without a peeking state. */ @Test @MediumTest - public void testCloseEventCalledNoAnimation() throws TimeoutException { - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.FULL, false); + public void testCloseEventCalled_noAnimationNoPeekState() throws TimeoutException { + runCloseEventTest(false, false); + } + + /** Test that the onSheetClosed event is triggered if the sheet is closed with animation. */ + @Test + @MediumTest + public void testCloseEventCalled_withAnimation() throws TimeoutException { + runCloseEventTest(true, true); + } + + /** + * Test that the onSheetClosed event is triggered if the sheet is closed with animation but + * without a peeking state. + */ + @Test + @MediumTest + public void testCloseEventCalled_withAnimationNoPeekState() throws TimeoutException { + runCloseEventTest(true, false); + } + + /** + * Run different versions of the onSheetClosed event test. + * @param animationEnabled Whether to run the test with animation. + * @param peekStateEnabled Whether the sheet's content has a peek state. + */ + private void runCloseEventTest(boolean animationEnabled, boolean peekStateEnabled) + throws TimeoutException { + mBottomSheetTestRule.setSheetState(SheetState.FULL, false); + + mSheetContent.setPeekHeight(peekStateEnabled ? HeightMode.DEFAULT : HeightMode.DISABLED); CallbackHelper closedCallbackHelper = mObserver.mClosedCallbackHelper; int initialOpenedCount = mObserver.mOpenedCallbackHelper.getCallCount(); int closedCallbackCount = closedCallbackHelper.getCallCount(); - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.PEEK, false); + mBottomSheetTestRule.setSheetState( + peekStateEnabled ? SheetState.PEEK : SheetState.HIDDEN, animationEnabled); closedCallbackHelper.waitForCallback(closedCallbackCount, 1); assertEquals(initialOpenedCount, mObserver.mOpenedCallbackHelper.getCallCount()); } + /** Test that the onSheetOpened event is triggered if the sheet is opened without animation. */ + @Test + @MediumTest + public void testOpenedEventCalled_noAnimation() throws TimeoutException { + runOpenEventTest(false, true); + } + /** - * Test that the onSheetClosed event is triggered if the sheet is closed with animation. + * Test that the onSheetOpened event is triggered if the sheet is opened without animation and + * without a peeking state. */ @Test @MediumTest - public void testCloseEventCalledWithAnimation() throws TimeoutException { - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.FULL, false); + public void testOpenedEventCalled_noAnimationNoPeekState() throws TimeoutException { + runOpenEventTest(false, false); + } + /** Test that the onSheetOpened event is triggered if the sheet is opened with animation. */ + @Test + @MediumTest + public void testOpenedEventCalled_withAnimation() throws TimeoutException { + runOpenEventTest(true, true); + } + + /** + * Test that the onSheetOpened event is triggered if the sheet is opened with animation and + * without a peek state. + */ + @Test + @MediumTest + public void testOpenedEventCalled_withAnimationNoPeekState() throws TimeoutException { + runOpenEventTest(true, false); + } + + /** + * Run different versions of the onSheetOpened event test. + * @param animationEnabled Whether to run the test with animation. + * @param peekStateEnabled Whether the sheet's content has a peek state. + */ + private void runOpenEventTest(boolean animationEnabled, boolean peekStateEnabled) + throws TimeoutException { + mSheetContent.setPeekHeight(peekStateEnabled ? HeightMode.DEFAULT : HeightMode.DISABLED); + + CallbackHelper openedCallbackHelper = mObserver.mOpenedCallbackHelper; + int openedCallbackCount = openedCallbackHelper.getCallCount(); CallbackHelper closedCallbackHelper = mObserver.mClosedCallbackHelper; + int initialClosedCount = closedCallbackHelper.getCallCount(); - int initialOpenedCount = mObserver.mOpenedCallbackHelper.getCallCount(); + mBottomSheetTestRule.setSheetState( + mBottomSheetTestRule.getBottomSheet().getOpeningState(), false); - int closedCallbackCount = closedCallbackHelper.getCallCount(); - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.PEEK, true); - closedCallbackHelper.waitForCallback(closedCallbackCount, 1); + assertNotEquals("Sheet should not be hidden.", + mBottomSheetTestRule.getBottomSheet().getSheetState(), SheetState.HIDDEN); + if (!peekStateEnabled) { + assertNotEquals("Sheet should be above the peeking state when peek is disabled.", + mBottomSheetTestRule.getBottomSheet().getSheetState(), SheetState.PEEK); + } - assertEquals(initialOpenedCount, mObserver.mOpenedCallbackHelper.getCallCount()); - } - - /** - * Test that the onSheetOpened event is triggered if the sheet is opened without animation. - */ - @Test - @MediumTest - public void testOpenedEventCalledNoAnimation() throws TimeoutException { - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.PEEK, false); - - CallbackHelper openedCallbackHelper = mObserver.mOpenedCallbackHelper; - - int initialClosedCount = mObserver.mClosedCallbackHelper.getCallCount(); - - int openedCallbackCount = openedCallbackHelper.getCallCount(); - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.FULL, false); + mBottomSheetTestRule.setSheetState(SheetState.FULL, animationEnabled); openedCallbackHelper.waitForCallback(openedCallbackCount, 1); - assertEquals(initialClosedCount, mObserver.mClosedCallbackHelper.getCallCount()); - } - - /** - * Test that the onSheetOpened event is triggered if the sheet is opened with animation. - */ - @Test - @MediumTest - public void testOpenedEventCalledWithAnimation() throws TimeoutException { - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.PEEK, false); - - CallbackHelper openedCallbackHelper = mObserver.mOpenedCallbackHelper; - - int initialClosedCount = mObserver.mClosedCallbackHelper.getCallCount(); - - int openedCallbackCount = openedCallbackHelper.getCallCount(); - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.FULL, true); - openedCallbackHelper.waitForCallback(openedCallbackCount, 1); - - assertEquals(initialClosedCount, mObserver.mClosedCallbackHelper.getCallCount()); + assertEquals(initialClosedCount, closedCallbackHelper.getCallCount()); } /** @@ -127,7 +177,7 @@ @Test @MediumTest public void testOffsetChangedEvent() throws TimeoutException { - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.FULL, false); + mBottomSheetTestRule.setSheetState(SheetState.FULL, false); CallbackHelper callbackHelper = mObserver.mOffsetChangedCallbackHelper; BottomSheet bottomSheet = mBottomSheetTestRule.getBottomSheet(); @@ -199,8 +249,8 @@ callbackHelper.waitForCallback(callCount); // HALF state is forbidden when wrapping the content. - mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.HALF, false); - assertEquals(BottomSheet.SheetState.FULL, bottomSheet.getSheetState()); + mBottomSheetTestRule.setSheetState(SheetState.HALF, false); + assertEquals(SheetState.FULL, bottomSheet.getSheetState()); // Check the offset. assertEquals(wrappedContentHeight + bottomSheet.getToolbarShadowHeight(),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java index 1baecf9..5fe0e1d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java
@@ -30,20 +30,19 @@ /** Whether this content is browser specific. */ private boolean mHasCustomLifecycle; - /** Whether this content's peek state is enabled. */ - private boolean mPeekStateEnabled; + /** The peek height of this content. */ + private int mPeekHeight; /** * @param context A context to inflate views with. * @param priority The content's priority. * @param hasCustomLifecycle Whether the content is browser specific. - * @param peekStateEnabled Whether the content's peek state is enabled. */ - public TestBottomSheetContent(Context context, @ContentPriority int priority, - boolean hasCustomLifecycle, boolean peekStateEnabled) { + public TestBottomSheetContent( + Context context, @ContentPriority int priority, boolean hasCustomLifecycle) { + mPeekHeight = BottomSheet.HeightMode.DEFAULT; mPriority = priority; mHasCustomLifecycle = hasCustomLifecycle; - mPeekStateEnabled = peekStateEnabled; TestThreadUtils.runOnUiThreadBlocking(() -> { mToolbarView = new View(context); ViewGroup.LayoutParams params = @@ -61,20 +60,9 @@ /** * @param context A context to inflate views with. - * @param priority The content's priority. - * @param hasCustomLifecycle Whether the content is browser specific. */ - public TestBottomSheetContent( - Context context, @ContentPriority int priority, boolean hasCustomLifecycle) { - this(context, priority, hasCustomLifecycle, true); - } - - /** - * @param context A context to inflate views with. - * @param peekStateEnabled Whether the content's peek state is enabled. - */ - public TestBottomSheetContent(Context context, boolean peekStateEnabled) { - this(/*TestBottomSheetContent(*/ context, ContentPriority.LOW, false, peekStateEnabled); + public TestBottomSheetContent(Context context) { + this(/*TestBottomSheetContent(*/ context, ContentPriority.LOW, false); } @Override @@ -106,9 +94,13 @@ return false; } + public void setPeekHeight(int height) { + mPeekHeight = height; + } + @Override - public boolean isPeekStateEnabled() { - return mPeekStateEnabled; + public int getPeekHeight() { + return mPeekHeight; } @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java index 33b23d6..caa73b7 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java
@@ -84,7 +84,6 @@ /** * Action List * 1. Set(item1 @ 1:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 1:00 1/1/2018 ] */ @Test @@ -94,15 +93,14 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), item1); } /** * Action List * 1. Set(item1 @ 2:00 1/1/2018, [ DATE @ 0:00 1/1/2018, - * item2 @ 1:00 1/1/2018) SECTION @ Video, + * item2 @ 1:00 1/1/2018) * item1 @ 2:00 1/1/2018, * item2 @ 1:00 1/1/2018 ] */ @@ -114,8 +112,7 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(3, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 1), item2); } @@ -123,9 +120,7 @@ /** * Action List * 1. Set(item1 @ 2:00 1/1/2018 Video, [ DATE @ 0:00 1/1/2018, - * item2 @ 1:00 1/1/2018 Audio) SECTION @ Video, - * item1 @ 2:00 1/1/2018, - * SECTION @ Audio, + * item2 @ 1:00 1/1/2018 Audio) item1 @ 2:00 1/1/2018, * item2 @ 1:00 1/1/2018 ] */ @Test @@ -135,73 +130,16 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); - Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + Assert.assertEquals(3, mModel.size()); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.AUDIO, false, false); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); - } - - /** - * Action List - * 1. Set(item1 @ 2:00 1/1/2018 Video, [ DATE @ 0:00 1/1/2018, - * item2 @ 1:00 1/1/2018 Image) SECTION @ Video, - * item1 @ 2:00 1/1/2018, - * SECTION @ Image, - * item2 @ 1:00 1/1/2018 ] - */ - @Test - public void testShowMenuButtonForImageSectionWithoutDate() { - OfflineItem item1 = buildItem("1", buildCalendar(2018, 1, 1, 2), OfflineItemFilter.VIDEO); - OfflineItem item2 = buildItem("2", buildCalendar(2018, 1, 1, 1), OfflineItemFilter.IMAGE); - when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); - DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); - - Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); - Assert.assertFalse(((SectionHeaderListItem) mModel.get(0)).showMenu); - - assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.IMAGE, false, false); - Assert.assertTrue(((SectionHeaderListItem) mModel.get(2)).showMenu); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); - } - - /** - * Action List - * 1. Set(item1 @ 2:00 1/1/2018 Image, [ DATE @ 0:00 1/1/2018, - * item2 @ 1:00 1/1/2018 Page) SECTION @ Image, - * item1 @ 2:00 1/1/2018, - * SECTION @ Page, - * item2 @ 1:00 1/1/2018 ] - */ - @Test - public void testShowMenuButtonForImageSectionWithDate() { - OfflineItem item1 = buildItem("1", buildCalendar(2018, 1, 1, 2), OfflineItemFilter.IMAGE); - OfflineItem item2 = buildItem("2", buildCalendar(2018, 1, 1, 1), OfflineItemFilter.PAGE); - when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); - DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); - - Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.IMAGE, true, false); - Assert.assertTrue(((SectionHeaderListItem) mModel.get(0)).showMenu); - - assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.PAGE, false, false); - Assert.assertFalse(((SectionHeaderListItem) mModel.get(2)).showMenu); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 1), item2); } /** * Action List * 1. Set(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * IN_PROGRESS) SECTION @ Video, + * IN_PROGRESS) * item1 @ 1:00 1/1/2018 ] */ @Test @@ -212,16 +150,16 @@ DateOrderedListMutator list = createMutatorWithJustNowProvider(); Assert.assertEquals(2, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), item1); } /** * Action List * 1. Set(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * Video IN_PROGRESS, SECTION @ Video, + * Video IN_PROGRESS, * item2 @ 1:00 1/1/2018 item1 @ 1:00 1/1/2018, - * Audio COMPLETE Recent) SECTION @ Audio, + * Audio COMPLETE Recent) * item2 @ 1:00 1/1/2018 ] */ @Test @@ -234,26 +172,25 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = createMutatorWithJustNowProvider(); - Assert.assertEquals(4, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + Assert.assertEquals(3, mModel.size()); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), item1); - assertJustNowSection(mModel.get(2), OfflineItemFilter.AUDIO, false, false); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 1), item2); } /** * Action List * 1. Set(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * PAUSED) SECTION @ Video, + * PAUSED) * item1 @ 1:00 1/1/2018 ] * 2. Update(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * Resume --> IN_PROGRESS) SECTION @ Video, + * Resume --> IN_PROGRESS) * item1 @ 1:00 1/1/2018 ] * 3. Update(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * COMPLETE, completion time now) SECTION @ Video, + * COMPLETE, completion time now) * item1 @ 1:00 1/1/2018 ] * 4. Update(item1 @ 1:00 1/1/2018 [ DATE Just Now, - * COMPLETE, completion time 1/1/2017) SECTION @ Video, + * COMPLETE, completion time 1/1/2017) * item1 @ 1:00 1/1/2018 ] */ @Test @@ -265,7 +202,7 @@ mModel.addObserver(mObserver); Assert.assertEquals(2, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), item1); // Resume the download. @@ -275,7 +212,7 @@ list.onItemUpdated(item1, update1); Assert.assertEquals(2, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), update1); // Complete the download. @@ -286,7 +223,7 @@ list.onItemUpdated(update1, update2); Assert.assertEquals(2, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), update2); // Too much time has passed since completion of the download. @@ -297,17 +234,16 @@ list.onItemUpdated(update2, update3); Assert.assertEquals(2, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), update3); } /** * Action List * 1. Set(item1 @ 1:00 2/1/2018 [ DATE Just Now, - * Video IN_PROGRESS, SECTION @ Video, + * Video IN_PROGRESS, * item2 @ 1:00 1/1/2018 item1 @ 1:00 2/1/2018, * Audio COMPLETE) DATE 1/1/2018 - * SECTION @ Audio, * item2 @ 1:00 1/1/2018 ] */ @Test @@ -319,20 +255,19 @@ DateOrderedListMutator list = createMutatorWithJustNowProvider(); Assert.assertEquals(4, mModel.size()); - assertJustNowSection(mModel.get(0), OfflineItemFilter.VIDEO, true, false); + assertJustNowSection(mModel.get(0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 2, 1, 1), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.AUDIO, true, true); + assertSectionHeader(mModel.get(2), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); } /** * Action List * 1. Set(item1 @ 0:00 1/2/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 0:00 1/1/2018) SECTION @ Video, + * item2 @ 0:00 1/1/2018) * item1 @ 0:00 1/2/2018, * DATE @ 0:00 1/1/2018, - * SECTION @ Audio, + * * item2 @ 0:00 1/1/2018 ] */ @Test @@ -343,18 +278,16 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 0), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.AUDIO, true, true); + assertSectionHeader(mModel.get(2), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 0), item2); } /** * Action List * 1. Set(item1 @ 4:00 1/1/2018, [ DATE @ 0:00 1/1/2018, - * item2 @ 5:00 1/1/2018) SECTION @ Video, + * item2 @ 5:00 1/1/2018) * item2 @ 5:00 1/1/2018, * item1 @ 4:00 1/1/2018 ] */ @@ -366,8 +299,7 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(3, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 5), item2); assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item1); } @@ -375,10 +307,9 @@ /** * Action List * 1. Set(item1 @ 4:00 1/2/2018 Video, [ DATE @ 0:00 1/2/2018, - * item2 @ 5:00 1/1/2018 Video) SECTION @ Video, + * item2 @ 5:00 1/1/2018 Video) * item2 @ 4:00 1/2/2018, * DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 5:00 1/1/2018 ] */ @Test @@ -389,21 +320,18 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, true); + assertSectionHeader(mModel.get(2), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 5), item2); } /** * Action List * 1. Set(item1 @ 4:00 1/2/2018 Video, [ DATE @ 0:00 1/2/2018, - * item2 @ 5:00 1/1/2018 Page ) SECTION @ Video, + * item2 @ 5:00 1/1/2018 Page ) * item2 @ 4:00 1/2/2018, * DATE @ 0:00 1/1/2018, - * SECTION @ Page, * item1 @ 5:00 1/1/2018 ] */ @Test @@ -414,21 +342,18 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.PAGE, true, true); + assertSectionHeader(mModel.get(2), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 5), item2); } /** * Action List * 1. Set(item1 @ 4:00 1/1/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 3:00 1/2/2018) SECTION @ Video, + * item2 @ 3:00 1/2/2018) * item2 @ 3:00 1/2/2018, * DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 4:00 1/1/2018 ] */ @Test @@ -439,11 +364,9 @@ DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 3), item2); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, true); + assertSectionHeader(mModel.get(2), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 4), item1); } @@ -452,7 +375,6 @@ * 1. Set() [ ] * * 2. Add(item1 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 4:00 1/1/2018 ] */ @Test @@ -472,17 +394,13 @@ /** * Action List * 1. Set(item1 @ 1:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item1 @ 1:00 1/2/2018 ] * 2. Add(item2 @ 2:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item2 @ 2:00 1/2/2018 * item1 @ 1:00 1/2/2018 ] * 3. Add(item3 @ 2:00 1/3/2018) [ DATE @ 0:00 1/3/2018, - * SECTION @ Video, * item3 @ 2:00 1/3/2018 * DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item2 @ 2:00 1/2/2018 * item1 @ 1:00 1/2/2018 ] */ @@ -516,20 +434,16 @@ /** * Action List * 1. Set(item1 @ 4:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item1 @ 4:00 1/2/2018 ] * * 2. Add(item2 @ 3:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item1 @ 4:00 1/2/2018 * item2 @ 3:00 1/2/2018 ] * * 3. Add(item3 @ 4:00 1/1/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item1 @ 4:00 1/2/2018 * item2 @ 3:00 1/2/2018, * DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item3 @ 4:00 1/1/2018 */ @Test @@ -562,7 +476,7 @@ /** * Action List * 1. Set(item1 @ 2:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, + * * item1 @ 2:00 1/2/2018 ] * * 2. Remove(item1) [ ] @@ -583,12 +497,11 @@ /** * Action List * 1. Set(item1 @ 3:00 1/2/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 2:00 1/2/2018) SECTION @ Video, + * item2 @ 2:00 1/2/2018) * item1 @ 3:00 1/2/2018, * item2 @ 2:00 1/2/2018 ] * * 2. Remove(item1) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item2 @ 2:00 1/2/2018 ] */ @Test @@ -603,20 +516,18 @@ list.onItemsRemoved(CollectionUtil.newArrayList(item1)); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 2), item2); } /** * Action List * 1. Set(item1 @ 3:00 1/2/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 2:00 1/2/2018) SECTION @ Video, + * item2 @ 2:00 1/2/2018) * item1 @ 3:00 1/2/2018, * item2 @ 2:00 1/2/2018 ] * * 2. Remove(item2) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item1 @ 3:00 1/2/2018 ] */ @Test @@ -631,52 +542,19 @@ list.onItemsRemoved(CollectionUtil.newArrayList(item2)); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 3), item1); } /** * Action List - * 1. Set(item1 @ 3:00 1/2/2018 Video, [ DATE @ 0:00 1/2/2018, - * item2 @ 2:00 1/2/2018 Image) SECTION @ Video, - * item1 @ 3:00 1/2/2018, - * SECTION @ Image, - * item2 @ 2:00 1/2/2018 ] - * - * 2. Remove(item1) [ DATE @ 0:00 1/2/2018, - * SECTION @ Image, - * item2 @ 2:00 1/2/2018 ] - */ - @Test - public void testRemoveOnlyItemInSection() { - OfflineItem item1 = buildItem("1", buildCalendar(2018, 1, 2, 3), OfflineItemFilter.VIDEO); - OfflineItem item2 = buildItem("2", buildCalendar(2018, 1, 2, 2), OfflineItemFilter.IMAGE); - when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); - DateOrderedListMutator list = createMutatorWithoutJustNowProvider(); - mModel.addObserver(mObserver); - Assert.assertEquals(4, mModel.size()); - - when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item2)); - list.onItemsRemoved(CollectionUtil.newArrayList(item1)); - - Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.IMAGE, true, false); - assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 2), item2); - } - - /** - * Action List * 1. Set(item1 @ 3:00 1/3/2018, [ DATE @ 0:00 1/3/2018, - * item2 @ 2:00 1/2/2018) SECTION @ Video, + * item2 @ 2:00 1/2/2018) * item1 @ 3:00 1/3/2018, * DATE @ 0:00 1/2/2018, - * SECTION @ Video, * item2 @ 2:00 1/2/2018 ] * * 2. Remove(item2) [ DATE @ 0:00 1/3/2018, - * SECTION @ Video, * item1 @ 3:00 1/3/2018 ] */ @Test @@ -691,8 +569,7 @@ list.onItemsRemoved(CollectionUtil.newArrayList(item2)); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 3, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 3, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 3, 3), item1); } @@ -701,11 +578,11 @@ * 1. Set() [ ] * * 2. Add(item1 @ 6:00 1/1/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 4:00 1/1/2018, SECTION @ Video, + * item2 @ 4:00 1/1/2018, * item3 @ 10:00 1/2/2018, item4 @ 12:00 1/2/2018, * item4 @ 12:00 1/2/2018) item3 @ 10:00 1/2/2018 * DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item1 @ 6:00 1/1/2018, * item2 @ 4:00 1/1/2018 ] */ @@ -725,12 +602,10 @@ list.onItemsAdded(CollectionUtil.newArrayList(item1, item2, item3, item4)); Assert.assertEquals(6, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 12), item4); assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 10), item3); - assertSectionHeader( - mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, true); + assertSectionHeader(mModel.get(3), buildCalendar(2018, 1, 1, 0), true); assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 6), item1); assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 1, 4), item2); } @@ -740,16 +615,13 @@ * 1. Set() [ ] * * 2. Add(item3 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item3 @ 4:00 1/1/2018 ] * * 3. Add(item1 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 4:00 1/1/2018, * item3 @ 4:00 1/1/2018 ] * * 4. Add(item2 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 4:00 1/1/2018, * item2 @ 4:00 1/1/2018, * item3 @ 4:00 1/1/2018 ] @@ -788,12 +660,12 @@ /** * Action List * 1. Set(item1 @ 6:00 IN_PROGRESS 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item1 @ 3:00 1/1/2018 IN_PROGRESS] * * 2. Update(item1 @ 6:00 COMPLETE 1/1/2018) * - * 3. Add(item2 @ 4:00 IN_PROGRESS 1/1/2018) [ SECTION @ Video, + * 3. Add(item2 @ 4:00 IN_PROGRESS 1/1/2018) [ * DATE @ 0:00 1/1/2018, * item1 @ 6:00 1/1/2018 COMPLETE, * item2 @ 4:00 1/1/2018 IN_PROGRESS] @@ -810,8 +682,7 @@ list.onItemsAdded(CollectionUtil.newArrayList(item1)); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 6), item1); // Complete the download. @@ -825,8 +696,7 @@ list.onItemsAdded(CollectionUtil.newArrayList(item2)); Assert.assertEquals(3, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 6), update1); assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item2); } @@ -834,16 +704,16 @@ /** * Action List * 2. Set(item1 @ 6:00 1/1/2018, [ DATE @ 0:00 1/2/2018, - * item2 @ 4:00 1/1/2018, SECTION @ Video, + * item2 @ 4:00 1/1/2018, * item3 @ 10:00 1/2/2018, item4 @ 12:00 1/2/2018, * item4 @ 12:00 1/2/2018) item3 @ 10:00 1/2/2018 * DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item1 @ 6:00 1/1/2018, * item2 @ 4:00 1/1/2018 ] * * 2. Remove(item2, [ DATE @ 0:00 1/1/2018, - * item3, SECTION @ Video, + * item3, * item4) item1 @ 6:00 1/1/2018 ] */ @Test @@ -862,20 +732,19 @@ list.onItemsRemoved(CollectionUtil.newArrayList(item2, item3, item4)); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 6), item1); } /** * Action List * 1. Set(item1 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item1 @ 4:00 1/1/2018 ] * * 2. Update (item1, * newItem1 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * newItem1 @ 4:00 1/1/2018 ] */ @Test @@ -893,20 +762,19 @@ list.onItemUpdated(item1, newItem1); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), newItem1); } /** * Action List * 1. Set(item1 @ 5:00 1/1/2018, [ DATE @ 0:00 1/1/2018, - * item2 @ 4:00 1/1/2018) SECTION @ Video, + * item2 @ 4:00 1/1/2018) * item1 @ 5:00 1/1/2018, * item2 @ 4:00 1/1/2018 * 2. Update (item1, * newItem1 @ 3:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item2 @ 4:00 1/1/2018, * newItem1 @ 3:00 1/1/2018 ] */ @@ -926,8 +794,7 @@ list.onItemUpdated(item1, newItem1); Assert.assertEquals(3, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), item2); assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 3), newItem1); } @@ -935,14 +802,13 @@ /** * Action List * 1. Set(item1 @ 5:00 1/1/2018, [ DATE @ 0:00 1/1/2018, - * item2 @ 4:00 1/1/2018) SECTION @ Video, + * item2 @ 4:00 1/1/2018) * item1 @ 5:00 1/1/2018, * item2 @ 4:00 1/1/2018 * 2. Update (item1, * newItem1 @ 3:00 1/1/2018 Image) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, + * * item2 @ 4:00 1/1/2018, - * SECTION @ Image, * newItem1 @ 3:00 1/1/2018 ] */ @Test @@ -960,24 +826,19 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(newItem1, item2)); list.onItemUpdated(item1, newItem1); - Assert.assertEquals(4, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.VIDEO, true, false); + Assert.assertEquals(3, mModel.size()); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), item2); - assertSectionHeader( - mModel.get(2), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.IMAGE, false, false); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 3), newItem1); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 3), newItem1); } /** * Action List * 1. Set(item1 @ 4:00 1/1/2018) [ DATE @ 0:00 1/1/2018, - * SECTION @ Video, * item1 @ 4:00 1/1/2018 ] * * 2. Update (item1, * newItem1 @ 6:00 1/2/2018) [ DATE @ 0:00 1/2/2018, - * SECTION @ Video, * newItem1 @ 6:00 1/2/2018 ] */ @Test @@ -995,8 +856,7 @@ list.onItemUpdated(item1, newItem1); Assert.assertEquals(2, mModel.size()); - assertSectionHeader( - mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.VIDEO, true, false); + assertSectionHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0), false); assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 6), newItem1); } @@ -1017,19 +877,18 @@ } private DateOrderedListMutator createMutatorWithoutJustNowProvider() { - DownloadManagerUiConfig config = - new DownloadManagerUiConfig.Builder().setShowSectionHeaders(true).build(); - return new DateOrderedListMutator(mSource, mModel, config, new JustNowProvider(config) { + DownloadManagerUiConfig config = new DownloadManagerUiConfig.Builder().build(); + JustNowProvider justNowProvider = new JustNowProvider(config) { @Override public boolean isJustNowItem(OfflineItem item) { return false; } - }); + }; + return new DateOrderedListMutator(mSource, mModel, config, justNowProvider); } private DateOrderedListMutator createMutatorWithJustNowProvider() { - DownloadManagerUiConfig config = - new DownloadManagerUiConfig.Builder().setShowSectionHeaders(true).build(); + DownloadManagerUiConfig config = new DownloadManagerUiConfig.Builder().build(); return new DateOrderedListMutator(mSource, mModel, config, new JustNowProvider(config)); } @@ -1047,33 +906,20 @@ Assert.assertEquals(offlineItem, ((OfflineItemListItem) item).item); } - private static void assertSectionHeader(ListItem item, Calendar calendar, - @OfflineItemFilter int filter, boolean showDate, boolean showDivider) { + private static void assertSectionHeader(ListItem item, Calendar calendar, boolean showDivider) { Assert.assertTrue(item instanceof SectionHeaderListItem); SectionHeaderListItem sectionHeader = (SectionHeaderListItem) item; assertDatesAreEqual(sectionHeader.date, calendar); - Assert.assertEquals(filter, sectionHeader.filter); Assert.assertEquals( - SectionHeaderListItem.generateStableId(calendar.getTimeInMillis(), filter), - item.stableId); - Assert.assertEquals(sectionHeader.showDate, showDate); + SectionHeaderListItem.generateStableId(calendar.getTimeInMillis()), item.stableId); Assert.assertEquals(sectionHeader.showDivider, showDivider); } - private static void assertJustNowSection( - ListItem item, @OfflineItemFilter int filter, boolean showDate, boolean showDivider) { + private static void assertJustNowSection(ListItem item, boolean showDivider) { Assert.assertTrue(item instanceof SectionHeaderListItem); SectionHeaderListItem sectionHeader = (SectionHeaderListItem) item; - Assert.assertEquals(filter, sectionHeader.filter); Assert.assertTrue(sectionHeader.isJustNow); - Assert.assertEquals(sectionHeader.showDate, showDate); Assert.assertEquals(sectionHeader.showDivider, showDivider); - if (showDate) { - Assert.assertEquals(StableIds.JUST_NOW_SECTION, item.stableId); - } else { - Assert.assertEquals(SectionHeaderListItem.generateStableId( - new Date(Long.MAX_VALUE).getTime(), filter), - item.stableId); - } + Assert.assertEquals(StableIds.JUST_NOW_SECTION, item.stableId); } }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 16938cb..29a7cd7 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -765,6 +765,8 @@ "media/webrtc/window_icon_util_chromeos.cc", "media/webrtc/window_icon_util_mac.mm", "media/webrtc/window_icon_util_win.cc", + "memory/chrome_browser_main_extra_parts_memory.cc", + "memory/chrome_browser_main_extra_parts_memory.h", "memory/enterprise_memory_limit_evaluator.cc", "memory/enterprise_memory_limit_evaluator.h", "memory/enterprise_memory_limit_pref_observer.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index a2948865..790f469c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3077,11 +3077,6 @@ flag_descriptions::kChromeColorsCustomColorPickerDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kChromeColorsCustomColorPicker)}, - {"grid-layout-for-ntp-shortcuts", - flag_descriptions::kGridLayoutForNtpShortcutsName, - flag_descriptions::kGridLayoutForNtpShortcutsDescription, kOsDesktop, - FEATURE_VALUE_TYPE(features::kGridLayoutForNtpShortcuts)}, - {"ntp-customization-menu-v2", flag_descriptions::kNtpCustomizationMenuV2Name, flag_descriptions::kNtpCustomizationMenuV2Description, kOsDesktop, @@ -4365,7 +4360,7 @@ {"safety-tips", flag_descriptions::kSafetyTipName, flag_descriptions::kSafetyTipDescription, kOsAll, - FEATURE_VALUE_TYPE(features::kSafetyTipUI)}, + FEATURE_VALUE_TYPE(security_state::features::kSafetyTipUI)}, #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) {"animated-avatar-button", flag_descriptions::kAnimatedAvatarButtonName,
diff --git a/chrome/browser/android/vr/arcore_device/arcore.h b/chrome/browser/android/vr/arcore_device/arcore.h index 5870424..0f7231a9 100644 --- a/chrome/browser/android/vr/arcore_device/arcore.h +++ b/chrome/browser/android/vr/arcore_device/arcore.h
@@ -45,6 +45,9 @@ // when the camera image was updated successfully. virtual mojom::VRPosePtr Update(bool* camera_updated) = 0; + // Return latest estimate for the floor height. + virtual float GetEstimatedFloorHeight() = 0; + // Returns information about all planes detected in the current frame. virtual mojom::XRPlaneDetectionDataPtr GetDetectedPlanesData() = 0; @@ -55,6 +58,15 @@ const mojom::XRRayPtr& ray, std::vector<mojom::XRHitResultPtr>* hit_results) = 0; + virtual base::Optional<uint32_t> SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray) = 0; + + virtual mojom::XRHitTestSubscriptionResultsDataPtr + GetHitTestSubscriptionResults(const device::mojom::VRPosePtr& pose) = 0; + + virtual void UnsubscribeFromHitTest(uint32_t subscription_id) = 0; + virtual base::Optional<uint32_t> CreateAnchor( const mojom::VRPosePtr& pose) = 0; virtual base::Optional<uint32_t> CreateAnchor(const mojom::VRPosePtr& pose,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc index d7e3146..4c1164b14 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -44,6 +44,8 @@ constexpr std::array<float, 6> kDisplayCoordinatesForTransform = { 0.f, 0.f, 1.f, 0.f, 0.f, 1.f}; +constexpr uint32_t kInputSourceId = 1; + gfx::Transform ConvertUvsToTransformMatrix(const std::vector<float>& uvs) { // We're creating a matrix that transforms viewport UV coordinates (for a // screen-filling quad, origin at bottom left, u=1 at right, v=1 at top) to @@ -367,15 +369,17 @@ have_camera_image_ = true; mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); - // Check if floor height estimate has changed. The estimate might eventually - // be provided by |arcore_| - for now, use hard-coded value. - if (floor_height_estimate_changed_) { + // Check if floor height estimate has changed. + float new_floor_height_estimate = arcore_->GetEstimatedFloorHeight(); + if (!floor_height_estimate_ || + *floor_height_estimate_ != new_floor_height_estimate) { + floor_height_estimate_ = new_floor_height_estimate; + frame_data->stage_parameters_updated = true; frame_data->stage_parameters = mojom::VRStageParameters::New(); frame_data->stage_parameters->standing_transform = gfx::Transform(); frame_data->stage_parameters->standing_transform.Translate3d( - 0, floor_height_estimate_, 0); - floor_height_estimate_changed_ = false; + 0, *floor_height_estimate_, 0); } frame_data->frame_id = webxr_->StartFrameAnimating(); @@ -583,6 +587,46 @@ hit_test_requests_.push_back(std::move(request)); } +void ArCoreGl::SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider::SubscribeToHitTestCallback + callback) { + DVLOG(2) << __func__ << ": ray origin=" << ray->origin.ToString() + << ", ray direction=" << ray->direction.ToString(); + + // Input source state information is known to ArCoreGl and not to ArCore - + // check if we recognize the input source id. + + if (native_origin_information->is_input_source_id()) { + if (native_origin_information->get_input_source_id() != kInputSourceId) { + DVLOG(1) << __func__ << ": incorrect input source ID passed"; + std::move(callback).Run( + device::mojom::SubscribeToHitTestResult::FAILURE_GENERIC, 0); + return; + } + } + + base::Optional<uint32_t> maybe_subscription_id = arcore_->SubscribeToHitTest( + std::move(native_origin_information), std::move(ray)); + + if (maybe_subscription_id) { + DVLOG(2) << __func__ << ": subscription_id=" << *maybe_subscription_id; + std::move(callback).Run(device::mojom::SubscribeToHitTestResult::SUCCESS, + *maybe_subscription_id); + } else { + DVLOG(1) << __func__ << ": subscription failed"; + std::move(callback).Run( + device::mojom::SubscribeToHitTestResult::FAILURE_GENERIC, 0); + } +} + +void ArCoreGl::UnsubscribeFromHitTest(uint32_t subscription_id) { + DVLOG(2) << __func__; + + arcore_->UnsubscribeFromHitTest(subscription_id); +} + void ArCoreGl::CreateAnchor(mojom::VRPosePtr anchor_pose, CreateAnchorCallback callback) { DVLOG(2) << __func__; @@ -646,6 +690,10 @@ input_states_.push_back(std::move(input_state)); frame_data->pose->input_state = std::move(input_states_); } + + // Get results for hit test subscriptions. + frame_data->hit_test_subscription_results = + arcore_->GetHitTestSubscriptionResults(frame_data->pose); } // The timing requirements for hit-test are documented here: @@ -699,7 +747,7 @@ device::mojom::XRInputSourceState::New(); // Only one controller is supported, so the source id can be static. - state->source_id = 1; + state->source_id = kInputSourceId; state->primary_input_pressed = screen_touch_active_; if (!screen_touch_active_ && screen_touch_pending_) {
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h index 6607816..e2576a3 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -8,6 +8,7 @@ #include <memory> #include <utility> #include <vector> + #include "base/cancelable_callback.h" #include "base/containers/queue.h" #include "base/macros.h" @@ -110,6 +111,14 @@ mojom::XRRayPtr, mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback) override; + void SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider::SubscribeToHitTestCallback + callback) override; + + void UnsubscribeFromHitTest(uint32_t subscription_id) override; + void CreateAnchor(mojom::VRPosePtr anchor_pose, CreateAnchorCallback callback) override; void CreatePlaneAnchor(mojom::VRPosePtr anchor_pose, @@ -218,11 +227,8 @@ mojom::VRDisplayInfoPtr display_info_; bool display_info_changed_ = false; - // True if floor height estimate should be passed to blink via XRFrameData - // returned by subsequent call to |GetFrameData()|. - bool floor_height_estimate_changed_ = true; // Currently estimated floor height. - float floor_height_estimate_ = 1.2; + base::Optional<float> floor_height_estimate_; std::vector<device::mojom::XRInputSourceStatePtr> input_states_; gfx::PointF screen_last_touch_;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc index fa0cdb33..7263644 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -67,10 +67,22 @@ return result; } +constexpr float kDefaultFloorHeightEstimation = 1.2; + } // namespace namespace device { +HitTestSubscriptionData::HitTestSubscriptionData( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray) + : native_origin_information(std::move(native_origin_information)), + ray(std::move(ray)) {} + +HitTestSubscriptionData::HitTestSubscriptionData( + HitTestSubscriptionData&& other) = default; +HitTestSubscriptionData::~HitTestSubscriptionData() = default; + ArCoreImpl::ArCoreImpl() : gl_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} @@ -589,17 +601,239 @@ return result; } +float ArCoreImpl::GetEstimatedFloorHeight() { + return kDefaultFloorHeightEstimation; +} + +base::Optional<uint32_t> ArCoreImpl::SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray) { + // First, check if we recognize the type of the native origin. + + if (native_origin_information->is_reference_space_category()) { + // Reference spaces are implicitly recognized and don't carry an ID. + } else if (native_origin_information->is_input_source_id()) { + // Input source IDs are verified in the higher layer as ArCoreImpl does + // not carry input source state. + } else if (native_origin_information->is_plane_id()) { + // Validate that we know which plane's space the hit test is interested in + // tracking. + if (plane_id_to_plane_object_.count( + PlaneId(native_origin_information->get_plane_id())) == 0) { + return base::nullopt; + } + } else if (native_origin_information->is_anchor_id()) { + // Validate that we know which anchor's space the hit test is interested + // in tracking. + if (anchor_id_to_anchor_object_.count( + AnchorId(native_origin_information->get_anchor_id())) == 0) { + return base::nullopt; + } + } else { + NOTREACHED(); + return base::nullopt; + } + + auto maybe_subscription_id = CreateHitTestSubscriptionId(); + if (!maybe_subscription_id) { + return base::nullopt; + } + + hit_test_subscription_id_to_data_.emplace( + *maybe_subscription_id, + HitTestSubscriptionData{std::move(native_origin_information), + std::move(ray)}); + + return maybe_subscription_id->GetUnsafeValue(); +} + +mojom::XRHitTestSubscriptionResultsDataPtr +ArCoreImpl::GetHitTestSubscriptionResults( + const device::mojom::VRPosePtr& pose) { + mojom::XRHitTestSubscriptionResultsDataPtr result = + mojom::XRHitTestSubscriptionResultsData::New(); + + for (auto& subscription_id_and_data : hit_test_subscription_id_to_data_) { + // First, check if we can find the current transformation for a ray. If not, + // skip processing this subscription. + auto maybe_mojo_from_native_origin = GetMojoFromNativeOrigin( + subscription_id_and_data.second.native_origin_information, pose); + + if (!maybe_mojo_from_native_origin) { + continue; + } + + // Since we have a transform, let's use it to obtain hit test results. + result->results.push_back(GetHitTestSubscriptionResult( + HitTestSubscriptionId(subscription_id_and_data.first), + *subscription_id_and_data.second.ray, *maybe_mojo_from_native_origin)); + } + + return result; +} + +device::mojom::XRHitTestSubscriptionResultDataPtr +ArCoreImpl::GetHitTestSubscriptionResult( + HitTestSubscriptionId id, + const mojom::XRRay& native_origin_ray, + const gfx::Transform& mojo_from_native_origin) { + // Transform the ray according to the latest transform based on the XRSpace + // used in hit test subscription. + + gfx::Point3F origin = native_origin_ray.origin; + mojo_from_native_origin.TransformPoint(&origin); + + gfx::Vector3dF direction = native_origin_ray.direction; + mojo_from_native_origin.TransformVector(&direction); + + std::vector<mojom::XRHitResultPtr> hit_results; + RequestHitTest(origin, direction, &hit_results); + + return mojom::XRHitTestSubscriptionResultData::New(id.GetUnsafeValue(), + std::move(hit_results)); +} + +base::Optional<gfx::Transform> ArCoreImpl::GetMojoFromReferenceSpace( + device::mojom::XRReferenceSpaceCategory category, + const device::mojom::VRPosePtr& mojo_from_viewer) { + switch (category) { + case device::mojom::XRReferenceSpaceCategory::LOCAL: + return gfx::Transform{}; + case device::mojom::XRReferenceSpaceCategory::LOCAL_FLOOR: { + auto result = gfx::Transform{}; + result.Translate3d(0, -GetEstimatedFloorHeight(), 0); + return result; + } + case device::mojom::XRReferenceSpaceCategory::VIEWER: + return mojo::ConvertTo<gfx::Transform>(mojo_from_viewer); + case device::mojom::XRReferenceSpaceCategory::BOUNDED_FLOOR: + return base::nullopt; + case device::mojom::XRReferenceSpaceCategory::UNBOUNDED: + return base::nullopt; + } +} + +base::Optional<gfx::Transform> ArCoreImpl::GetMojoFromNativeOrigin( + const mojom::XRNativeOriginInformationPtr& native_origin_information, + const device::mojom::VRPosePtr& mojo_from_viewer) { + if (native_origin_information->is_input_source_id()) { + if (!mojo_from_viewer->input_state) { + return base::nullopt; + } + + // Linear search should be fine for ARCore device as it only has one input + // source (for now). + for (auto& input_source_state : *mojo_from_viewer->input_state) { + if (input_source_state->source_id == + native_origin_information->get_input_source_id()) { + if (!input_source_state->description->pointer_offset) { + return base::nullopt; + } + + auto view_from_pointer = + *input_source_state->description->pointer_offset; + + auto mojo_from_view = mojo::ConvertTo<gfx::Transform>(mojo_from_viewer); + + return mojo_from_view * view_from_pointer; + } + } + + return base::nullopt; + } else if (native_origin_information->is_reference_space_category()) { + return GetMojoFromReferenceSpace( + native_origin_information->get_reference_space_category(), + mojo_from_viewer); + } else if (native_origin_information->is_plane_id()) { + auto plane_it = plane_id_to_plane_object_.find( + PlaneId(native_origin_information->get_plane_id())); + if (plane_it == plane_id_to_plane_object_.end()) { + return base::nullopt; + } + + // Naked pointer is fine as we don't own the object and ArAsPlane does not + // increase the refcount. + ArPlane* plane = ArAsPlane(plane_it->second.get()); + + internal::ScopedArCoreObject<ArPose*> ar_pose; + ArPose_create( + arcore_session_.get(), nullptr, + internal::ScopedArCoreObject<ArPose*>::Receiver(ar_pose).get()); + ArPlane_getCenterPose(arcore_session_.get(), plane, ar_pose.get()); + mojom::VRPosePtr mojo_pose = + GetMojomPoseFromArPose(arcore_session_.get(), std::move(ar_pose)); + + return mojo::ConvertTo<gfx::Transform>(mojo_pose); + } else if (native_origin_information->is_anchor_id()) { + auto anchor_it = anchor_id_to_anchor_object_.find( + AnchorId(native_origin_information->get_anchor_id())); + if (anchor_it == anchor_id_to_anchor_object_.end()) { + return base::nullopt; + } + + internal::ScopedArCoreObject<ArPose*> ar_pose; + ArPose_create( + arcore_session_.get(), nullptr, + internal::ScopedArCoreObject<ArPose*>::Receiver(ar_pose).get()); + + ArAnchor_getPose(arcore_session_.get(), anchor_it->second.get(), + ar_pose.get()); + mojom::VRPosePtr mojo_pose = + GetMojomPoseFromArPose(arcore_session_.get(), std::move(ar_pose)); + + return mojo::ConvertTo<gfx::Transform>(mojo_pose); + } else { + NOTREACHED(); + return base::nullopt; + } +} // namespace device + +void ArCoreImpl::UnsubscribeFromHitTest(uint32_t subscription_id) { + auto it = hit_test_subscription_id_to_data_.find( + HitTestSubscriptionId(subscription_id)); + if (it == hit_test_subscription_id_to_data_.end()) { + return; + } + + hit_test_subscription_id_to_data_.erase(it); +} + +base::Optional<HitTestSubscriptionId> +ArCoreImpl::CreateHitTestSubscriptionId() { + if (next_id_ == std::numeric_limits<uint32_t>::max()) { + return base::nullopt; + } + + uint32_t current_id = next_id_++; + + return HitTestSubscriptionId(current_id); +} + bool ArCoreImpl::RequestHitTest( const mojom::XRRayPtr& ray, std::vector<mojom::XRHitResultPtr>* hit_results) { - DVLOG(2) << __func__ << ": ray origin=" << ray->origin.ToString() - << ", direction=" << ray->direction.ToString(); + DCHECK(ray); + return RequestHitTest(ray->origin, ray->direction, hit_results); +} + +bool ArCoreImpl::RequestHitTest( + const gfx::Point3F& origin, + const gfx::Vector3dF& direction, + std::vector<mojom::XRHitResultPtr>* hit_results) { + DVLOG(2) << __func__ << ": origin=" << origin.ToString() + << ", direction=" << direction.ToString(); DCHECK(hit_results); DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); DCHECK(arcore_frame_.is_valid()); + // ArCore returns hit-results in sorted order, thus providing the guarantee + // of sorted results promised by the WebXR spec for requestHitTest(). + std::array<float, 3> origin_array = {origin.x(), origin.y(), origin.z()}; + std::array<float, 3> direction_array = {direction.x(), direction.y(), + direction.z()}; + internal::ScopedArCoreObject<ArHitResultList*> arcore_hit_result_list; ArHitResultList_create( arcore_session_.get(), @@ -611,14 +845,9 @@ return false; } - // ArCore returns hit-results in sorted order, thus providing the guarantee - // of sorted results promised by the WebXR spec for requestHitTest(). - float origin[3] = {ray->origin.x(), ray->origin.y(), ray->origin.z()}; - float direction[3] = {ray->direction.x(), ray->direction.y(), - ray->direction.z()}; - - ArFrame_hitTestRay(arcore_session_.get(), arcore_frame_.get(), origin, - direction, arcore_hit_result_list.get()); + ArFrame_hitTestRay(arcore_session_.get(), arcore_frame_.get(), + origin_array.data(), direction_array.data(), + arcore_hit_result_list.get()); int arcore_hit_result_list_size = 0; ArHitResultList_getSize(arcore_session_.get(), arcore_hit_result_list.get(),
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.h b/chrome/browser/android/vr/arcore_device/arcore_impl.h index 21fd467b..a1377b4 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.h
@@ -91,6 +91,18 @@ using PlaneId = util::IdTypeU32<class PlaneTag>; using AnchorId = util::IdTypeU32<class AnchorTag>; +using HitTestSubscriptionId = util::IdTypeU32<class HitTestSubscriptionTag>; + +struct HitTestSubscriptionData { + mojom::XRNativeOriginInformationPtr native_origin_information; + mojom::XRRayPtr ray; + + HitTestSubscriptionData( + mojom::XRNativeOriginInformationPtr native_origin_information, + mojom::XRRayPtr ray); + HitTestSubscriptionData(HitTestSubscriptionData&& other); + ~HitTestSubscriptionData(); +}; // This class should be created and accessed entirely on a Gl thread. class ArCoreImpl : public ArCore { @@ -115,9 +127,25 @@ void Pause() override; void Resume() override; + float GetEstimatedFloorHeight() override; + bool RequestHitTest(const mojom::XRRayPtr& ray, std::vector<mojom::XRHitResultPtr>* hit_results) override; + // Helper. + bool RequestHitTest(const gfx::Point3F& origin, + const gfx::Vector3dF& direction, + std::vector<mojom::XRHitResultPtr>* hit_results); + + base::Optional<uint32_t> SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr nativeOriginInformation, + mojom::XRRayPtr ray) override; + + mojom::XRHitTestSubscriptionResultsDataPtr GetHitTestSubscriptionResults( + const device::mojom::VRPosePtr& pose) override; + + void UnsubscribeFromHitTest(uint32_t subscription_id) override; + base::Optional<uint32_t> CreateAnchor( const device::mojom::VRPosePtr& pose) override; base::Optional<uint32_t> CreateAnchor(const device::mojom::VRPosePtr& pose, @@ -184,6 +212,9 @@ std::map<AnchorId, device::internal::ScopedArCoreObject<ArAnchor*>> anchor_id_to_anchor_object_; + std::map<HitTestSubscriptionId, HitTestSubscriptionData> + hit_test_subscription_id_to_data_; + // Returns tuple containing plane id and a boolean signifying that the plane // was created. The result will be a nullopt in case the ID should be assigned // but next ID would result in an integer overflow. @@ -192,6 +223,23 @@ base::Optional<std::pair<AnchorId, bool>> CreateOrGetAnchorId( void* anchor_address); + base::Optional<HitTestSubscriptionId> CreateHitTestSubscriptionId(); + + // Returns hit test subscription results for a single subscription given + // current XRSpace transformation. + device::mojom::XRHitTestSubscriptionResultDataPtr + GetHitTestSubscriptionResult(HitTestSubscriptionId id, + const mojom::XRRay& ray, + const gfx::Transform& ray_transformation); + + base::Optional<gfx::Transform> GetMojoFromNativeOrigin( + const mojom::XRNativeOriginInformationPtr& native_origin_information, + const device::mojom::VRPosePtr& pose); + + base::Optional<gfx::Transform> GetMojoFromReferenceSpace( + device::mojom::XRReferenceSpaceCategory category, + const device::mojom::VRPosePtr& pose); + // Executes |fn| for each still tracked, non-subsumed plane present in // |arcore_planes_|. template <typename FunctionType>
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.cc b/chrome/browser/android/vr/arcore_device/fake_arcore.cc index c3919a2..b1519527 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.cc +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
@@ -196,6 +196,10 @@ return pose; } +float FakeArCore::GetEstimatedFloorHeight() { + return 2.0; +} + bool FakeArCore::RequestHitTest( const mojom::XRRayPtr& ray, std::vector<mojom::XRHitResultPtr>* hit_results) { @@ -207,6 +211,23 @@ return true; } +base::Optional<uint32_t> FakeArCore::SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr nativeOriginInformation, + mojom::XRRayPtr ray) { + NOTREACHED(); + return base::nullopt; +} + +mojom::XRHitTestSubscriptionResultsDataPtr +FakeArCore::GetHitTestSubscriptionResults( + const device::mojom::VRPosePtr& pose) { + return nullptr; +} + +void FakeArCore::UnsubscribeFromHitTest(uint32_t subscription_id) { + NOTREACHED(); +} + mojom::XRPlaneDetectionDataPtr FakeArCore::GetDetectedPlanesData() { std::vector<mojom::XRPlaneDataPtr> result;
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.h b/chrome/browser/android/vr/arcore_device/fake_arcore.h index 6735393f..0b9860f 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.h +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.h
@@ -31,12 +31,24 @@ const base::span<const float> uvs) override; gfx::Transform GetProjectionMatrix(float near, float far) override; mojom::VRPosePtr Update(bool* camera_updated) override; + void Pause() override; void Resume() override; + float GetEstimatedFloorHeight() override; + bool RequestHitTest(const mojom::XRRayPtr& ray, std::vector<mojom::XRHitResultPtr>* hit_results) override; + base::Optional<uint32_t> SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr nativeOriginInformation, + mojom::XRRayPtr ray) override; + + mojom::XRHitTestSubscriptionResultsDataPtr GetHitTestSubscriptionResults( + const device::mojom::VRPosePtr& pose) override; + + void UnsubscribeFromHitTest(uint32_t subscription_id) override; + mojom::XRPlaneDetectionDataPtr GetDetectedPlanesData() override; mojom::XRAnchorsDataPtr GetAnchorsData() override;
diff --git a/chrome/browser/android/vr/arcore_device/type_converters.cc b/chrome/browser/android/vr/arcore_device/type_converters.cc index f27ef30..535c4d6 100644 --- a/chrome/browser/android/vr/arcore_device/type_converters.cc +++ b/chrome/browser/android/vr/arcore_device/type_converters.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/android/vr/arcore_device/type_converters.h" +#include "ui/gfx/transform_util.h" + namespace mojo { device::mojom::XRPlaneOrientation @@ -18,4 +20,20 @@ } } +gfx::Transform TypeConverter<gfx::Transform, device::mojom::VRPosePtr>::Convert( + const device::mojom::VRPosePtr& pose) { + gfx::DecomposedTransform decomposed; + if (pose->orientation) { + decomposed.quaternion = *pose->orientation; + } + + if (pose->position) { + decomposed.translate[0] = pose->position->x(); + decomposed.translate[1] = pose->position->y(); + decomposed.translate[2] = pose->position->z(); + } + + return gfx::ComposeTransform(decomposed); +} + } // namespace mojo
diff --git a/chrome/browser/android/vr/arcore_device/type_converters.h b/chrome/browser/android/vr/arcore_device/type_converters.h index c8cf665..3cf27d5 100644 --- a/chrome/browser/android/vr/arcore_device/type_converters.h +++ b/chrome/browser/android/vr/arcore_device/type_converters.h
@@ -7,6 +7,7 @@ #include "chrome/browser/android/vr/arcore_device/arcore_sdk.h" #include "device/vr/public/mojom/vr_service.mojom.h" +#include "ui/gfx/transform.h" namespace mojo { @@ -15,6 +16,11 @@ static device::mojom::XRPlaneOrientation Convert(ArPlaneType plane_type); }; +template <> +struct TypeConverter<gfx::Transform, device::mojom::VRPosePtr> { + static gfx::Transform Convert(const device::mojom::VRPosePtr& pose); +}; + } // namespace mojo #endif // CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_TYPE_CONVERTERS_H_
diff --git a/chrome/browser/autofill/autofill_provider_browsertest.cc b/chrome/browser/autofill/autofill_provider_browsertest.cc index 35b20b2..e2ea63c3 100644 --- a/chrome/browser/autofill/autofill_provider_browsertest.cc +++ b/chrome/browser/autofill/autofill_provider_browsertest.cc
@@ -283,38 +283,50 @@ EXPECT_EQ("\"SUBMISSION_FINISHED\"", message); } -IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest, - LabelTagChangeImpactFormComparingWithFlagOn) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillSkipComparingInferredLabels); +class AutofillProviderBrowserTestWithSkipFlagOn + : public AutofillProviderBrowserTest { + public: + AutofillProviderBrowserTestWithSkipFlagOn() { + feature_list_.InitAndEnableFeature( + features::kAutofillSkipComparingInferredLabels); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +class AutofillProviderBrowserTestWithSkipFlagOff + : public AutofillProviderBrowserTest { + public: + AutofillProviderBrowserTestWithSkipFlagOff() { + feature_list_.InitAndDisableFeature( + features::kAutofillSkipComparingInferredLabels); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOn, + LabelTagChangeImpactFormComparing) { SetLabelChangeExpectationAndTriggerQuery(); ChangeLabelAndCheckResult("label_id", false /*expect_forms_same*/); } -IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest, - InferredLabelChangeNotImpactFormComparingWithFlagOn) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillSkipComparingInferredLabels); +IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOn, + InferredLabelChangeNotImpactFormComparing) { SetLabelChangeExpectationAndTriggerQuery(); ChangeLabelAndCheckResult("p_id", true /*expect_forms_same*/); } -IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest, - LabelTagChangeImpactFormComparingWithFlagOff) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - features::kAutofillSkipComparingInferredLabels); +IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOff, + LabelTagChangeImpactFormComparing) { SetLabelChangeExpectationAndTriggerQuery(); ChangeLabelAndCheckResult("label_id", false /*expect_forms_same*/); } -IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest, - InferredLabelChangeImpactFormComparingWithFlagOff) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - features::kAutofillSkipComparingInferredLabels); +IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOff, + InferredLabelChangeImpactFormComparing) { SetLabelChangeExpectationAndTriggerQuery(); ChangeLabelAndCheckResult("p_id", false /*expect_forms_same*/); }
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 6bad9bc..33ea655 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -8,7 +8,9 @@ </outputs> <release seq="1"> <structures> - <structure name="IDR_SIGNIN_SHARED_CSS_HTML" file="resources\signin\signin_shared_css.html" preprocess="true" allowexternalscript="true" type="chrome_html" /> + <if expr="is_win or is_macosx or desktop_linux"> + <structure name="IDR_SIGNIN_SHARED_CSS_HTML" file="resources\signin\signin_shared_css.html" preprocess="true" allowexternalscript="true" type="chrome_html" /> + </if> <if expr="not is_android"> <structure name="IDR_INCOGNITO_TAB_HTML" file="resources\ntp4\incognito_tab.html" flattenhtml="true" type="chrome_html" /> <structure name="IDR_GUEST_TAB_HTML" file="resources\ntp4\guest_tab.html" flattenhtml="true" type="chrome_html" /> @@ -322,18 +324,20 @@ <include name="IDR_SITE_ENGAGEMENT_JS" file="resources\engagement\site_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" /> <include name="IDR_SITE_ENGAGEMENT_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\engagement\site_engagement_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_URL_MOJOM_LITE_JS" file="${root_gen_dir}\url\mojom\url.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> - <include name="IDR_SYNC_DISABLED_CONFIRMATION_HTML" file="resources\signin\sync_confirmation\sync_disabled_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SYNC_DISABLED_CONFIRMATION_JS" file="resources\signin\sync_confirmation\sync_disabled_confirmation.js" type="BINDATA" /> - <include name="IDR_SYNC_CONFIRMATION_HTML" file="resources\signin\sync_confirmation\sync_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SYNC_CONFIRMATION_JS" file="resources\signin\sync_confirmation\sync_confirmation.js" type="BINDATA" /> - <include name="IDR_SYNC_CONFIRMATION_BROWSER_PROXY_HTML" file="resources\signin\sync_confirmation\sync_confirmation_browser_proxy.html" type="BINDATA" /> - <include name="IDR_SYNC_CONFIRMATION_BROWSER_PROXY_JS" file="resources\signin\sync_confirmation\sync_confirmation_browser_proxy.js" type="BINDATA" /> - <include name="IDR_SYNC_CONFIRMATION_APP_HTML" file="resources\signin\sync_confirmation\sync_confirmation_app.html" type="BINDATA" flattenhtml="true" allowexternalscript="true" /> - <include name="IDR_SYNC_CONFIRMATION_APP_JS" file="resources\signin\sync_confirmation\sync_confirmation_app.js" type="BINDATA" /> - <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_HTML" file="resources\signin\signin_email_confirmation\signin_email_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_JS" file="resources\signin\signin_email_confirmation\signin_email_confirmation.js" type="BINDATA" /> - <include name="IDR_SIGNIN_ERROR_HTML" file="resources\signin\signin_error\signin_error.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SIGNIN_ERROR_JS" file="resources\signin\signin_error\signin_error.js" type="BINDATA" /> + <if expr="is_win or is_macosx or desktop_linux"> + <include name="IDR_SYNC_DISABLED_CONFIRMATION_HTML" file="resources\signin\sync_confirmation\sync_disabled_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_SYNC_DISABLED_CONFIRMATION_JS" file="resources\signin\sync_confirmation\sync_disabled_confirmation.js" type="BINDATA" /> + <include name="IDR_SYNC_CONFIRMATION_HTML" file="resources\signin\sync_confirmation\sync_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_SYNC_CONFIRMATION_JS" file="resources\signin\sync_confirmation\sync_confirmation.js" type="BINDATA" /> + <include name="IDR_SYNC_CONFIRMATION_BROWSER_PROXY_HTML" file="resources\signin\sync_confirmation\sync_confirmation_browser_proxy.html" type="BINDATA" /> + <include name="IDR_SYNC_CONFIRMATION_BROWSER_PROXY_JS" file="resources\signin\sync_confirmation\sync_confirmation_browser_proxy.js" type="BINDATA" /> + <include name="IDR_SYNC_CONFIRMATION_APP_HTML" file="resources\signin\sync_confirmation\sync_confirmation_app.html" type="BINDATA" flattenhtml="true" allowexternalscript="true" /> + <include name="IDR_SYNC_CONFIRMATION_APP_JS" file="resources\signin\sync_confirmation\sync_confirmation_app.js" type="BINDATA" /> + <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_HTML" file="resources\signin\signin_email_confirmation\signin_email_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_JS" file="resources\signin\signin_email_confirmation\signin_email_confirmation.js" type="BINDATA" /> + <include name="IDR_SIGNIN_ERROR_HTML" file="resources\signin\signin_error\signin_error.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_SIGNIN_ERROR_JS" file="resources\signin\signin_error\signin_error.js" type="BINDATA" /> + </if> <include name="IDR_USB_ENUMERATION_OPTIONS_MOJOM_LITE_JS" file="${root_gen_dir}\services\device\public\mojom\usb_enumeration_options.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> <include name="IDR_USB_DEVICE_MANAGER_CLIENT_MOJOM_LITE_JS" file="${root_gen_dir}\services\device\public\mojom\usb_manager_client.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> <include name="IDR_USB_DEVICE_MANAGER_MOJOM_LITE_JS" file="${root_gen_dir}\services\device\public\mojom\usb_manager.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index a48dcf5..164df34 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc
@@ -41,8 +41,6 @@ #include "build/branding_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/first_run/first_run.h" -#include "chrome/browser/memory/memory_pressure_monitor.h" -#include "chrome/browser/memory/swap_thrashing_monitor.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_shortcut_manager.h" #include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h" @@ -610,17 +608,6 @@ base::PostDelayedTask(FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&DetectFaultTolerantHeap), base::TimeDelta::FromMinutes(1)); - - // Start the swap thrashing monitor if it's enabled. - // - // TODO(sebmarchand): Delay the initialization of this monitor once we start - // using this feature by default, this is currently enabled at startup to make - // it easier to experiment with this monitor. - if (base::FeatureList::IsEnabled(features::kSwapThrashingMonitor)) - memory::SwapThrashingMonitor::Initialize(); - - if (base::FeatureList::IsEnabled(features::kNewMemoryPressureMonitor)) - memory_pressure_monitor_ = memory::MemoryPressureMonitor::Create(); } // static
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h index 382216c..70639aec 100644 --- a/chrome/browser/chrome_browser_main_win.h +++ b/chrome/browser/chrome_browser_main_win.h
@@ -19,10 +19,6 @@ class CommandLine; } -namespace memory { -class MemoryPressureMonitor; -} - // Handle uninstallation when given the appropriate the command-line switch. // If |chrome_still_running| is true a modal dialog will be shown asking the // user to close the other chrome instance. @@ -78,11 +74,6 @@ // Watches module load events and forwards them to the ModuleDatabase. std::unique_ptr<ModuleWatcher> module_watcher_; - // The memory pressure monitor. This is currently only being used to record - // metrics, the base::MemoryPressureMonitor is still being used to emit memory - // pressure signals. - std::unique_ptr<memory::MemoryPressureMonitor> memory_pressure_monitor_; - DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsWin); };
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 62a90a4..a89707a 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -72,6 +72,7 @@ #include "chrome/browser/media/webrtc/audio_debug_recordings_handler.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/webrtc_logging_controller.h" +#include "chrome/browser/memory/chrome_browser_main_extra_parts_memory.h" #include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h" #include "chrome/browser/metrics/chrome_feature_list_creator.h" #include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h" @@ -1251,6 +1252,8 @@ main_parts->AddParts(new ChromeBrowserMainExtraPartsProfiling); + main_parts->AddParts(new ChromeBrowserMainExtraPartsMemory); + chrome::AddMetricsExtraParts(main_parts.get()); return main_parts;
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc index 0f4cf5f5..8a22d3b 100644 --- a/chrome/browser/chrome_content_browser_client_browsertest.cc +++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" +#include "base/no_destructor.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/system/sys_info.h" @@ -234,10 +235,68 @@ contents->GetMainFrame()->GetProcess()->GetID())); } +enum class SitePerProcessMemoryThreshold { + kNone, + k128MB, + k768MB, +}; + +enum class SitePerProcessMode { + kDisabled, + kEnabled, + kIsolatedOrigin, +}; + +struct SitePerProcessMemoryThresholdBrowserTestParams { + SitePerProcessMemoryThreshold threshold; + SitePerProcessMode mode; +}; + +const url::Origin& GetTrialOrigin() { + static base::NoDestructor<url::Origin> origin{ + url::Origin::Create(GURL("http://foo.com/"))}; + return *origin; +} + // Helper class to run tests on a simulated 512MB low-end device. -class SitePerProcessMemoryThresholdBrowserTest : public InProcessBrowserTest { +class SitePerProcessMemoryThresholdBrowserTest + : public InProcessBrowserTest, + public ::testing::WithParamInterface< + SitePerProcessMemoryThresholdBrowserTestParams> { public: - SitePerProcessMemoryThresholdBrowserTest() = default; + SitePerProcessMemoryThresholdBrowserTest() { + switch (GetParam().threshold) { + case SitePerProcessMemoryThreshold::kNone: + break; + case SitePerProcessMemoryThreshold::k128MB: + threshold_feature_.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, + "128"}}); + break; + case SitePerProcessMemoryThreshold::k768MB: + threshold_feature_.InitAndEnableFeatureWithParameters( + features::kSitePerProcessOnlyForHighMemoryClients, + {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, + "768"}}); + break; + } + + switch (GetParam().mode) { + case SitePerProcessMode::kDisabled: + mode_feature_.InitAndDisableFeature(features::kSitePerProcess); + break; + case SitePerProcessMode::kEnabled: + mode_feature_.InitAndEnableFeature(features::kSitePerProcess); + break; + case SitePerProcessMode::kIsolatedOrigin: + mode_feature_.InitAndEnableFeatureWithParameters( + features::kIsolateOrigins, + {{features::kIsolateOriginsFieldTrialParamName, + GetTrialOrigin().Serialize()}}); + break; + } + } void SetUpCommandLine(base::CommandLine* command_line) override { InProcessBrowserTest::SetUpCommandLine(command_line); @@ -297,142 +356,83 @@ #endif private: + base::test::ScopedFeatureList threshold_feature_; + base::test::ScopedFeatureList mode_feature_; + DISALLOW_COPY_AND_ASSIGN(SitePerProcessMemoryThresholdBrowserTest); }; -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessEnabled_HighThreshold) { +using SitePerProcessMemoryThresholdBrowserTestNoIsolation = + SitePerProcessMemoryThresholdBrowserTest; +IN_PROC_BROWSER_TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolation, + NoIsolation) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; - // 512MB of physical memory that the test simulates is below the 768MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndEnableFeature(features::kSitePerProcess); - - // Despite enabled site-per-process trial, there should be no isolation - // because the device has too little memory. + // Isolation should be disabled given the set of parameters used to + // instantiate these tests. EXPECT_FALSE( content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); } -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessEnabled_LowThreshold) { +using SitePerProcessMemoryThresholdBrowserTestIsolation = + SitePerProcessMemoryThresholdBrowserTest; +IN_PROC_BROWSER_TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolation, + Isolation) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; - // 512MB of physical memory that the test simulates is above the 128MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndEnableFeature(features::kSitePerProcess); - - // site-per-process trial is enabled, and the memory threshold is above the - // memory present on the device. + // Isolation should be enabled given the set of parameters used to + // instantiate these tests. EXPECT_TRUE(content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); } -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessEnabled_NoThreshold) { - if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) - return; - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndEnableFeature(features::kSitePerProcess); - +INSTANTIATE_TEST_SUITE_P( + NoIsolation, + SitePerProcessMemoryThresholdBrowserTestNoIsolation, + testing::Values( #if defined(OS_ANDROID) - // Expect false on Android because 512MB physical memory triggered by - // kEnableLowEndDeviceMode in SetUpCommandLine() is below the 1024MB Android - // specific memory limit which disbles site isolation for all sites. - EXPECT_FALSE( - content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); -#else - EXPECT_TRUE(content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); + // Expect no isolation on Android because 512MB physical memory + // triggered by kEnableLowEndDeviceMode in SetUpCommandLine() is below + // the 1024MB Android specific memory limit which disables site + // isolation for all sites. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, SitePerProcessMode::kEnabled}, #endif -} + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kEnabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kDisabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kDisabled}, + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kDisabled})); -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessDisabled_HighThreshold) { +INSTANTIATE_TEST_SUITE_P(Isolation, + SitePerProcessMemoryThresholdBrowserTestIsolation, + testing::Values( +#if !defined(OS_ANDROID) + // See the note above regarding why this + // expectation is different on Android. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kEnabled}, +#endif + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kEnabled})); + +using SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin = + SitePerProcessMemoryThresholdBrowserTest; +IN_PROC_BROWSER_TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin, + TrialNoIsolatedOrigin) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; - // 512MB of physical memory that the test simulates is below the 768MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndDisableFeature(features::kSitePerProcess); - - // site-per-process trial is disabled, so isolation should be disabled - // (i.e. the memory threshold should be ignored). - EXPECT_FALSE( - content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); -} - -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessDisabled_LowThreshold) { - if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) - return; - - // 512MB of physical memory that the test simulates is above the 128MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndDisableFeature(features::kSitePerProcess); - - // site-per-process trial is disabled, so isolation should be disabled - // (i.e. the memory threshold should be ignored). - EXPECT_FALSE( - content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); -} - -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - SitePerProcessDisabled_NoThreshold) { - if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) - return; - - base::test::ScopedFeatureList site_per_process; - site_per_process.InitAndDisableFeature(features::kSitePerProcess); - - // site-per-process trial is disabled, so isolation should be disabled - // (i.e. the memory threshold should be ignored). - EXPECT_FALSE( - content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()); -} - -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - TrialIsolatedOrigins_HighThreshold) { - if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) - return; - - // 512MB of physical memory that the test simulates is below the 768MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}}); - - const url::Origin trial_origin = url::Origin::Create(GURL("http://foo.com/")); - base::test::ScopedFeatureList isolated_origins_feature; - isolated_origins_feature.InitAndEnableFeatureWithParameters( - features::kIsolateOrigins, {{features::kIsolateOriginsFieldTrialParamName, - trial_origin.Serialize()}}); SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); @@ -446,26 +446,16 @@ // Verify that the trial origin is not present. EXPECT_THAT(isolated_origins, - ::testing::Not(::testing::Contains(trial_origin))); + ::testing::Not(::testing::Contains(GetTrialOrigin()))); } -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - TrialIsolatedOrigins_LowThreshold) { +using SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin = + SitePerProcessMemoryThresholdBrowserTest; +IN_PROC_BROWSER_TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin, + TrialIsolatedOrigin) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; - // 512MB of physical memory that the test simulates is above the 128MB - // threshold. - base::test::ScopedFeatureList memory_feature; - memory_feature.InitAndEnableFeatureWithParameters( - features::kSitePerProcessOnlyForHighMemoryClients, - {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}}); - - const url::Origin trial_origin = url::Origin::Create(GURL("http://foo.com/")); - base::test::ScopedFeatureList isolated_origins_feature; - isolated_origins_feature.InitAndEnableFeatureWithParameters( - features::kIsolateOrigins, {{features::kIsolateOriginsFieldTrialParamName, - trial_origin.Serialize()}}); SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); @@ -475,36 +465,37 @@ ::testing::IsSubsetOf(isolated_origins)); // Verify that the trial origin is present. - EXPECT_THAT(isolated_origins, ::testing::Contains(trial_origin)); + EXPECT_THAT(isolated_origins, ::testing::Contains(GetTrialOrigin())); } -IN_PROC_BROWSER_TEST_F(SitePerProcessMemoryThresholdBrowserTest, - TrialIsolatedOrigins_NoThreshold) { - if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) - return; +INSTANTIATE_TEST_SUITE_P( + TrialNoIsolatedOrigin, + SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin, + testing::Values( +#if defined(OS_ANDROID) + // The 512MB the test simulates is below the global Android threshold of + // 1024MB, so the test origin should not be isolated. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kIsolatedOrigin}, +#endif + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k768MB, + SitePerProcessMode::kIsolatedOrigin})); - const url::Origin trial_origin = url::Origin::Create(GURL("http://foo.com/")); - base::test::ScopedFeatureList isolated_origins_feature; - isolated_origins_feature.InitAndEnableFeatureWithParameters( - features::kIsolateOrigins, {{features::kIsolateOriginsFieldTrialParamName, - trial_origin.Serialize()}}); - SiteIsolationPolicy::ApplyGlobalIsolatedOrigins(); - - auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance(); - std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(); - EXPECT_EQ(kExpectedTrialOrigins + expected_embedder_origins_.size(), - isolated_origins.size()); - EXPECT_THAT(expected_embedder_origins_, - ::testing::IsSubsetOf(isolated_origins)); - - if (kExpectedTrialOrigins > 0) { - // Verify that the trial origin is present. - EXPECT_THAT(isolated_origins, ::testing::Contains(trial_origin)); - } else { - EXPECT_THAT(isolated_origins, - ::testing::Not(::testing::Contains(trial_origin))); - } -} +INSTANTIATE_TEST_SUITE_P(TrialIsolatedOrigin, + SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin, + testing::Values( +#if defined(OS_ANDROID) + // See the note above regarding why this + // expectation is different on Android. + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::kNone, + SitePerProcessMode::kIsolatedOrigin}, +#endif + SitePerProcessMemoryThresholdBrowserTestParams{ + SitePerProcessMemoryThreshold::k128MB, + SitePerProcessMode::kIsolatedOrigin})); // Helper class to run tests with password-triggered site isolation initialized // via a regular field trial and *not* via a command-line override. It @@ -571,7 +562,7 @@ }; IN_PROC_BROWSER_TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, - BelowThreshold) { + DISABLED_BelowThreshold) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -603,7 +594,7 @@ } IN_PROC_BROWSER_TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, - AboveThreshold) { + DISABLED_AboveThreshold) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -636,7 +627,7 @@ // via field trials but force-enabled via command line, it takes effect even // when below the memory threshold. See https://crbug.com/1009828. IN_PROC_BROWSER_TEST_F(DisabledPasswordSiteIsolationFieldTrialTest, - CommandLineOverride_BelowThreshold) { + DISABLED_CommandLineOverride_BelowThreshold) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -670,7 +661,7 @@ // Similar to the test above, but with device memory being above memory // threshold. IN_PROC_BROWSER_TEST_F(DisabledPasswordSiteIsolationFieldTrialTest, - CommandLineOverride_AboveThreshold) { + DISABLED_CommandLineOverride_AboveThreshold) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -760,7 +751,7 @@ // the device is above the memory threshold, disabling it via the command line // takes precedence. IN_PROC_BROWSER_TEST_F(EnabledStrictOriginIsolationFieldTrialTest, - DisabledViaCommandLineOverride) { + DISABLED_DisabledViaCommandLineOverride) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -791,7 +782,7 @@ // via field trials but force-enabled via command line, it takes effect even // when below the memory threshold. See https://crbug.com/1009828. IN_PROC_BROWSER_TEST_F(DisabledStrictOriginIsolationFieldTrialTest, - EnabledViaCommandLineOverride_BelowThreshold) { + DISABLED_EnabledViaCommandLineOverride_BelowThreshold) { if (ShouldSkipBecauseOfConflictingCommandLineSwitches()) return; @@ -893,7 +884,9 @@ class PrefersColorSchemeTest : public testing::WithParamInterface<bool>, public InProcessBrowserTest { protected: - PrefersColorSchemeTest() : theme_client_(&test_theme_) {} + PrefersColorSchemeTest() : theme_client_(&test_theme_) { + feature_list_.InitWithFeatureState(features::kWebUIDarkMode, GetParam()); + } ~PrefersColorSchemeTest() { CHECK_EQ(&theme_client_, SetBrowserClientForTesting(original_client_)); @@ -934,6 +927,7 @@ const ui::NativeTheme* const theme_; }; + base::test::ScopedFeatureList feature_list_; ChromeContentBrowserClientWithWebTheme theme_client_; }; @@ -957,9 +951,6 @@ IN_PROC_BROWSER_TEST_P(PrefersColorSchemeTest, FeatureOverridesChromeSchemes) { test_theme_.SetDarkMode(true); - base::test::ScopedFeatureList features; - features.InitWithFeatureState(features::kWebUIDarkMode, GetParam()); - ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); bool matches; @@ -976,9 +967,6 @@ IN_PROC_BROWSER_TEST_P(PrefersColorSchemeTest, FeatureOverridesPdfUI) { test_theme_.SetDarkMode(true); - base::test::ScopedFeatureList features; - features.InitWithFeatureState(features::kWebUIDarkMode, GetParam()); - std::string pdf_extension_url(extensions::kExtensionScheme); pdf_extension_url.append(url::kStandardSchemeSeparator); pdf_extension_url.append(extension_misc::kPdfExtensionId);
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc index 8ed88c0..0ac7729 100644 --- a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc +++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -13,7 +13,6 @@ #include "components/dom_distiller/content/browser/distiller_page_web_contents.h" #include "components/dom_distiller/core/article_entry.h" #include "components/dom_distiller/core/distiller.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" @@ -22,12 +21,10 @@ namespace dom_distiller { DomDistillerContextKeyedService::DomDistillerContextKeyedService( - std::unique_ptr<DomDistillerStoreInterface> store, std::unique_ptr<DistillerFactory> distiller_factory, std::unique_ptr<DistillerPageFactory> distiller_page_factory, std::unique_ptr<DistilledPagePrefs> distilled_page_prefs) - : DomDistillerService(std::move(store), - std::move(distiller_factory), + : DomDistillerService(std::move(distiller_factory), std::move(distiller_page_factory), std::move(distilled_page_prefs)) {} @@ -62,8 +59,6 @@ base::FilePath database_dir( context->GetPath().Append(FILE_PATH_LITERAL("Articles"))); - auto dom_distiller_store = std::make_unique<DomDistillerStore>(); - std::unique_ptr<DistillerPageFactory> distiller_page_factory( new DistillerPageWebContentsFactory(context)); std::unique_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory( @@ -87,9 +82,9 @@ new DistilledPagePrefs(profile->GetPrefs())); DomDistillerContextKeyedService* service = - new DomDistillerContextKeyedService( - std::move(dom_distiller_store), std::move(distiller_factory), - std::move(distiller_page_factory), std::move(distilled_page_prefs)); + new DomDistillerContextKeyedService(std::move(distiller_factory), + std::move(distiller_page_factory), + std::move(distilled_page_prefs)); return service; }
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.h b/chrome/browser/dom_distiller/dom_distiller_service_factory.h index db65e63..e28ad13f 100644 --- a/chrome/browser/dom_distiller/dom_distiller_service_factory.h +++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.h
@@ -24,7 +24,6 @@ public DomDistillerService { public: DomDistillerContextKeyedService( - std::unique_ptr<DomDistillerStoreInterface> store, std::unique_ptr<DistillerFactory> distiller_factory, std::unique_ptr<DistillerPageFactory> distiller_page_factory, std::unique_ptr<DistilledPagePrefs> distilled_page_prefs);
diff --git a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc index 4e35444..006d5aa 100644 --- a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc +++ b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
@@ -28,7 +28,6 @@ #include "components/dom_distiller/core/distilled_page_prefs.h" #include "components/dom_distiller/core/distiller.h" #include "components/dom_distiller/core/dom_distiller_service.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/dom_distiller/core/dom_distiller_switches.h" #include "components/dom_distiller/core/fake_distiller.h" #include "components/dom_distiller/core/fake_distiller_page.h" @@ -84,17 +83,6 @@ "window.domAutomationController.send(" "typeof distiller == 'object')"; -ArticleEntry CreateEntry(const std::string& entry_id, - const std::string& page_url) { - ArticleEntry entry; - entry.set_entry_id(entry_id); - if (!page_url.empty()) { - ArticleEntryPage* page = entry.add_pages(); - page->set_url(page_url); - } - return entry; -} - void ExpectBodyHasThemeAndFont(content::WebContents* contents, const std::string& expected_theme, const std::string& expected_font) { @@ -128,7 +116,6 @@ auto distiller_page_factory = std::make_unique<MockDistillerPageFactory>(); auto* distiller_page_factory_raw = distiller_page_factory.get(); auto service = std::make_unique<DomDistillerContextKeyedService>( - std::make_unique<DomDistillerStore>(store_model_), std::move(distiller_factory), std::move(distiller_page_factory), std::make_unique<DistilledPagePrefs>( Profile::FromBrowserContext(context)->GetPrefs())); @@ -153,27 +140,12 @@ void PrefTest(bool is_error_page); // Database entries. - std::vector<ArticleEntry> store_model_; bool expect_distillation_ = false; bool expect_distiller_page_ = false; MockDistillerFactory* distiller_factory_ = nullptr; }; // The DomDistillerViewerSource renders untrusted content, so ensure no bindings -// are enabled when the article exists in the database. -IN_PROC_BROWSER_TEST_F(DomDistillerViewerSourceBrowserTest, - NoWebUIBindingsArticleExists) { - // Ensure there is one item in the database, which will trigger distillation. - const ArticleEntry entry = CreateEntry("DISTILLED", "http://example.com/1"); - store_model_.push_back(entry); - expect_distillation_ = true; - expect_distiller_page_ = true; - const GURL url = url_utils::GetDistillerViewUrlFromEntryId( - kDomDistillerScheme, entry.entry_id()); - ViewSingleDistilledPage(url, "text/html"); -} - -// The DomDistillerViewerSource renders untrusted content, so ensure no bindings // are enabled when the article is not found. IN_PROC_BROWSER_TEST_F(DomDistillerViewerSourceBrowserTest, NoWebUIBindingsArticleNotFound) {
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc index 5dfb413..b9fe9d10 100644 --- a/chrome/browser/download/download_browsertest.cc +++ b/chrome/browser/download/download_browsertest.cc
@@ -95,6 +95,7 @@ #include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/proto/csd.pb.h" #include "components/safe_browsing/safe_browsing_service_interface.h" +#include "components/security_state/core/features.h" #include "components/security_state/core/security_state.h" #include "components/services/quarantine/test_support.h" #include "content/public/browser/browser_task_traits.h" @@ -3886,9 +3887,11 @@ public: DownloadTestWithOptionalSafetyTipsFeature() { if (GetParam()) - feature_list_.InitAndEnableFeature(features::kSafetyTipUI); + feature_list_.InitAndEnableFeature( + security_state::features::kSafetyTipUI); else - feature_list_.InitAndDisableFeature(features::kSafetyTipUI); + feature_list_.InitAndDisableFeature( + security_state::features::kSafetyTipUI); } private:
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc index 40217cc..c5b8482a 100644 --- a/chrome/browser/download/download_offline_content_provider.cc +++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -422,7 +422,8 @@ observers_.RemoveObserver(observer); } -void DownloadOfflineContentProvider::OnManagerGoingDown() { +void DownloadOfflineContentProvider::OnManagerGoingDown( + SimpleDownloadManagerCoordinator* manager) { std::vector<DownloadItem*> all_items; GetAllDownloads(&all_items);
diff --git a/chrome/browser/download/download_offline_content_provider.h b/chrome/browser/download/download_offline_content_provider.h index 6047469..289a56a9 100644 --- a/chrome/browser/download/download_offline_content_provider.h +++ b/chrome/browser/download/download_offline_content_provider.h
@@ -108,7 +108,7 @@ // SimpleDownloadManagerCoordinator::Observer overrides void OnDownloadsInitialized(bool active_downloads_only) override; - void OnManagerGoingDown() override; + void OnManagerGoingDown(SimpleDownloadManagerCoordinator* manager) override; void GetAllDownloads(std::vector<DownloadItem*>* all_items); DownloadItem* GetDownload(const std::string& download_guid);
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc index 62328d8..b4696bd1 100644 --- a/chrome/browser/extensions/activity_log/activity_log.cc +++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -768,29 +768,19 @@ // we want to ensure the activity log is inactive unless the switch // or the app (covered by active_consumers_) is present. (has_listeners_ && has_switch); - const bool needs_db = has_consumer || has_switch; - const bool should_be_active = needs_db || has_consumer; + const bool should_be_active = has_consumer || has_switch; if (should_be_active == is_active_) return; bool has_db = db_enabled_ && database_policy_; - bool old_is_active = is_active_; + db_enabled_ = should_be_active; - if (should_be_active) { - if (needs_db && !has_db) { - db_enabled_ = true; - ChooseDatabasePolicy(); - } + if (should_be_active && !has_db) + ChooseDatabasePolicy(); - is_active_ = true; - } else { - if (has_db && !needs_db) - db_enabled_ = false; - is_active_ = false; - } + is_active_ = should_be_active; - DCHECK_NE(is_active_, old_is_active); for (content::RenderProcessHost::iterator iter( content::RenderProcessHost::AllHostsIterator()); !iter.IsAtEnd(); iter.Advance()) {
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc index ede8794..a2fabc3 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -400,17 +400,38 @@ "ContentSettings.ExtensionNonEmbeddedSettingSet", 2); } -IN_PROC_BROWSER_TEST_F(ExtensionContentSettingsApiTest, EmbeddedSettings) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(features::kPermissionDelegation); +class ExtensionContentSettingsApiTestWithPermissionDelegationDisabled + : public ExtensionContentSettingsApiTest { + public: + ExtensionContentSettingsApiTestWithPermissionDelegationDisabled() { + feature_list_.InitAndDisableFeature(features::kPermissionDelegation); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +class ExtensionContentSettingsApiTestWithPermissionDelegationEnabled + : public ExtensionContentSettingsApiTest { + public: + ExtensionContentSettingsApiTestWithPermissionDelegationEnabled() { + feature_list_.InitAndEnableFeature(features::kPermissionDelegation); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + ExtensionContentSettingsApiTestWithPermissionDelegationDisabled, + EmbeddedSettings) { const char kExtensionPath[] = "content_settings/embeddedsettings"; EXPECT_TRUE(RunExtensionSubtest(kExtensionPath, "test.html")) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionContentSettingsApiTest, - EmbeddedSettingsPermissionDelegation) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kPermissionDelegation); +IN_PROC_BROWSER_TEST_F( + ExtensionContentSettingsApiTestWithPermissionDelegationEnabled, + EmbeddedSettings) { const char kExtensionPath[] = "content_settings/embeddedsettings"; EXPECT_TRUE( RunExtensionSubtest(kExtensionPath, "test.html?permission_delegation"))
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc index 8d091f2..3e6af3e 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc +++ b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -64,15 +64,23 @@ DISALLOW_COPY_AND_ASSIGN(TestProcessManagerObserver); }; +class NativeMessagingApiTest : public ExtensionApiTest { + public: + NativeMessagingApiTest() { + feature_list_.InitAndEnableFeature(features::kOnConnectNative); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Disabled on Windows due to timeouts; see https://crbug.com/984897. #if defined(OS_WIN) #define MAYBE_NativeMessagingLaunch DISABLED_NativeMessagingLaunch #else #define MAYBE_NativeMessagingLaunch NativeMessagingLaunch #endif -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_NativeMessagingLaunch) { - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kOnConnectNative); +IN_PROC_BROWSER_TEST_F(NativeMessagingApiTest, MAYBE_NativeMessagingLaunch) { ProcessManager::SetEventPageIdleTimeForTesting(1); ProcessManager::SetEventPageSuspendingTimeForTesting(1); extensions::ScopedTestNativeMessagingHost test_host; @@ -113,10 +121,8 @@ // natively-initiated connections is not allowed. The test extension expects the // channel to be immediately closed with an error. IN_PROC_BROWSER_TEST_F( - ExtensionApiTest, + NativeMessagingApiTest, NativeMessagingLaunch_LaunchFromNativeUnsupportedByNativeHost) { - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kOnConnectNative); ProcessManager::SetEventPageIdleTimeForTesting(1); ProcessManager::SetEventPageSuspendingTimeForTesting(1); extensions::ScopedTestNativeMessagingHost test_host;
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc index 84549235..c697c4c 100644 --- a/chrome/browser/extensions/content_script_apitest.cc +++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -505,10 +505,19 @@ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } -IN_PROC_BROWSER_TEST_F(ContentScriptApiTest, +class ContentScriptApiTestWithTrustedDOMTypesEnabled + : public ContentScriptApiTest { + public: + ContentScriptApiTestWithTrustedDOMTypesEnabled() { + feature_list_.InitAndEnableFeature(features::kTrustedDOMTypes); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(ContentScriptApiTestWithTrustedDOMTypesEnabled, ContentScriptBypassPageTrustedTypes) { - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kTrustedDOMTypes); ASSERT_TRUE(StartEmbeddedTestServer()); extensions::ResultCatcher catcher; ASSERT_TRUE(RunExtensionTest("content_scripts/bypass_page_trusted_types"))
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 17195be4..b974987950 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2257,11 +2257,6 @@ "expiry_milestone": 82 }, { - "name": "grid-layout-for-ntp-shortcuts", - "owners": [ "kristipark", "ramyan" ], - "expiry_milestone": 78 - }, - { "name": "handwriting-gesture", "owners": [ "essential-inputs-team@google.com" ], "expiry_milestone": 80
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 8f2ff3d0..252d3b0 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2870,12 +2870,6 @@ "Enables the native DIAL Media Route Provider implementation to be used " "instead of the implementation in the Media Router component extension."; -const char kGridLayoutForNtpShortcutsName[] = - "Enable grid layout for NTP shortcuts"; -const char kGridLayoutForNtpShortcutsDescription[] = - "Enables better animations for the shortcuts, including improved " - "drag-and-drop."; - const char kNtpCustomizationMenuV2Name[] = "NTP customization menu version 2"; const char kNtpCustomizationMenuV2Description[] = "Use the second version of the NTP customization menu.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index d9b73ef..7ddc665 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1685,9 +1685,6 @@ extern const char kDialMediaRouteProviderName[]; extern const char kDialMediaRouteProviderDescription[]; -extern const char kGridLayoutForNtpShortcutsName[]; -extern const char kGridLayoutForNtpShortcutsDescription[]; - extern const char kNtpCustomizationMenuV2Name[]; extern const char kNtpCustomizationMenuV2Description[];
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc index 09b97310..a2feb74 100644 --- a/chrome/browser/geolocation/geolocation_browsertest.cc +++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -538,14 +538,23 @@ ExpectPosition(fake_latitude(), fake_longitude()); } -IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithFreshPosition) { - // When permission delegation is enabled, there isn't a way to have a pending - // permission prompt when permission has already been granted in another frame - // on the same page. That means that this test isn't relevant and can be - // deleted after the feature is enabled by default. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(features::kPermissionDelegation); +// When permission delegation is enabled, there isn't a way to have a pending +// permission prompt when permission has already been granted in another frame +// on the same page. That means that once the feature is enabled by default, +// tests which use this fixture are no longer relevant and can be deleted. +class GeolocationBrowserTestWithNoPermissionDelegation + : public GeolocationBrowserTest { + public: + GeolocationBrowserTestWithNoPermissionDelegation() { + feature_list_.InitAndDisableFeature(features::kPermissionDelegation); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(GeolocationBrowserTestWithNoPermissionDelegation, + IFramesWithFreshPosition) { set_html_for_tests("/geolocation/two_iframes.html"); ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT)); LoadIFrames(); @@ -599,12 +608,8 @@ ExpectPosition(cached_position_latitude, cached_position_lognitude); } -IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, CancelPermissionForFrame) { - // When permission delegation is removed, iframe requests are made for the top - // level frame. Navigating the iframe should not cancel the request. This - // test can be removed after the feature is enabled by default. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(features::kPermissionDelegation); +IN_PROC_BROWSER_TEST_F(GeolocationBrowserTestWithNoPermissionDelegation, + CancelPermissionForFrame) { set_html_for_tests("/geolocation/two_iframes.html"); ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT)); LoadIFrames();
diff --git a/chrome/browser/lookalikes/safety_tips/reputation_service.cc b/chrome/browser/lookalikes/safety_tips/reputation_service.cc index 7209553..5fe6099 100644 --- a/chrome/browser/lookalikes/safety_tips/reputation_service.cc +++ b/chrome/browser/lookalikes/safety_tips/reputation_service.cc
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/singleton.h" +#include "base/metrics/field_trial_params.h" #include "chrome/browser/lookalikes/lookalike_url_interstitial_page.h" #include "chrome/browser/lookalikes/lookalike_url_navigation_throttle.h" #include "chrome/browser/lookalikes/lookalike_url_service.h" @@ -17,15 +18,16 @@ #include "chrome/browser/lookalikes/safety_tips/safety_tips_config.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/chrome_features.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/safe_browsing/db/v4_protocol_manager_util.h" +#include "components/security_state/core/features.h" #include "url/url_constants.h" namespace { using chrome_browser_safety_tips::FlaggedPage; +using chrome_browser_safety_tips::UrlPattern; using lookalikes::DomainInfo; using lookalikes::LookalikeUrlNavigationThrottle; using lookalikes::LookalikeUrlService; @@ -34,9 +36,10 @@ using safety_tips::ReputationService; const base::FeatureParam<bool> kEnableLookalikeEditDistance{ - &features::kSafetyTipUI, "editdistance", false}; + &security_state::features::kSafetyTipUI, "editdistance", false}; const base::FeatureParam<bool> kEnableLookalikeEditDistanceSiteEngagement{ - &features::kSafetyTipUI, "editdistance_siteengagement", false}; + &security_state::features::kSafetyTipUI, "editdistance_siteengagement", + false}; bool ShouldTriggerSafetyTipFromLookalike( const GURL& url, @@ -162,6 +165,43 @@ return security_state::SafetyTipStatus::kNone; } +// Returns whether or not the Safety Tip should be suppressed for the given URL. +// Checks SafeBrowsing-style permutations of |url| against the component updater +// allowlist and returns whether the URL is explicitly allowed. Fails closed, so +// that warnings are suppressed if the component is unavailable. +bool ShouldSuppressWarning(const GURL& url) { + std::vector<std::string> patterns; + UrlToPatterns(url, &patterns); + + auto* proto = safety_tips::GetRemoteConfigProto(); + if (!proto) { + // This happens when the component hasn't downloaded yet. This should only + // happen for a short time after initial upgrade to M79. + // + // Disable all Safety Tips during that time. Otherwise, we would continue to + // flag on any known false positives until the client received the update. + return true; + } + + auto allowed_pages = proto->allowed_pattern(); + for (const auto& pattern : patterns) { + UrlPattern search_target; + search_target.set_pattern(pattern); + + auto lower = std::lower_bound( + allowed_pages.begin(), allowed_pages.end(), search_target, + [](const UrlPattern& a, const UrlPattern& b) -> bool { + return a.pattern() < b.pattern(); + }); + + if (lower != allowed_pages.end() && pattern == lower->pattern()) { + return true; + } + } + + return false; +} + } // namespace namespace safety_tips { @@ -219,6 +259,15 @@ const std::vector<DomainInfo>& engaged_sites) { const DomainInfo navigated_domain = lookalikes::GetDomainInfo(url); + // 0. Server-side warning suppression. + // If the URL is on the allowlist list, do nothing else. This is only used to + // mitigate false positives, so no further processing should be done. + if (ShouldSuppressWarning(url)) { + std::move(callback).Run(security_state::SafetyTipStatus::kNone, + IsIgnored(url), url, GURL()); + return; + } + // 1. Engagement check // Ensure that this URL is not already engaged. We can't use the synchronous // SiteEngagementService::IsEngagementAtLeast as it has side effects. This
diff --git a/chrome/browser/lookalikes/safety_tips/reputation_web_contents_observer.cc b/chrome/browser/lookalikes/safety_tips/reputation_web_contents_observer.cc index 10f8b41..b0cfd80 100644 --- a/chrome/browser/lookalikes/safety_tips/reputation_web_contents_observer.cc +++ b/chrome/browser/lookalikes/safety_tips/reputation_web_contents_observer.cc
@@ -11,7 +11,7 @@ #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/chrome_features.h" +#include "components/security_state/core/features.h" #include "content/public/browser/navigation_entry.h" namespace { @@ -159,10 +159,14 @@ // triggered when a committed navigation finishes. last_safety_tip_navigation_entry_id_ = web_contents()->GetController().GetLastCommittedEntry()->GetUniqueID(); + // Update the visible security state, since we downgrade indicator when a + // safety tip is triggered. This has to happen after + // last_safety_tip_navigation_entry_id_ is updated. + web_contents()->DidChangeVisibleSecurityState(); MaybeCallReputationCheckCallback(); - if (!base::FeatureList::IsEnabled(features::kSafetyTipUI)) { + if (!base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) { return; } ShowSafetyTipDialog(
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc index a5f1c41f..bb2bcf93 100644 --- a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc +++ b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc
@@ -4,15 +4,37 @@ #include "chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h" +#include <algorithm> +#include <memory> +#include <utility> + #include "chrome/browser/lookalikes/safety_tips/safety_tips_config.h" +namespace { + +// Retrieve existing config proto if set, or create a new one otherwise. +std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> GetConfig() { + auto* old = safety_tips::GetRemoteConfigProto(); + if (old) { + return std::make_unique<chrome_browser_safety_tips::SafetyTipsConfig>(*old); + } + + auto conf = std::make_unique<chrome_browser_safety_tips::SafetyTipsConfig>(); + // Any version ID will do. + conf->set_version_id(4); + return conf; +} + +} // namespace + +void InitializeSafetyTipConfig() { + safety_tips::SetRemoteConfigProto(GetConfig()); +} + void SetSafetyTipPatternsWithFlagType( std::vector<std::string> patterns, chrome_browser_safety_tips::FlaggedPage::FlagType type) { - std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> config_proto = - std::make_unique<chrome_browser_safety_tips::SafetyTipsConfig>(); - // Any version ID will do. - config_proto->set_version_id(4); + auto config_proto = GetConfig(); std::sort(patterns.begin(), patterns.end()); for (const auto& pattern : patterns) { chrome_browser_safety_tips::FlaggedPage* page = @@ -28,3 +50,14 @@ SetSafetyTipPatternsWithFlagType( patterns, chrome_browser_safety_tips::FlaggedPage::BAD_REP); } + +void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns) { + auto config_proto = GetConfig(); + std::sort(patterns.begin(), patterns.end()); + for (const auto& pattern : patterns) { + chrome_browser_safety_tips::UrlPattern* page = + config_proto->add_allowed_pattern(); + page->set_pattern(pattern); + } + safety_tips::SetRemoteConfigProto(std::move(config_proto)); +}
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h index 59143634..b8686f89 100644 --- a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h +++ b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h
@@ -6,9 +6,14 @@ #define CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIP_TEST_UTILS_H_ #include <string> +#include <vector> #include "chrome/browser/lookalikes/safety_tips/safety_tips.pb.h" +// Initialize component configuration. Necessary to enable Safety Tips for +// testing, as no heuristics trigger if the allowlist is inaccessible. +void InitializeSafetyTipConfig(); + // Sets the patterns included in component with the given flag type for tests. void SetSafetyTipPatternsWithFlagType( std::vector<std::string> pattern, @@ -18,4 +23,7 @@ // calls SetSafetyTipPatternsWithFlagType with BAD_REPUTATION as the type. void SetSafetyTipBadRepPatterns(std::vector<std::string> pattern); +// Sets allowlist patterns in the given proto for testing. +void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns); + #endif // CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIP_TEST_UTILS_H_
diff --git a/chrome/browser/media/media_engagement_autoplay_browsertest.cc b/chrome/browser/media/media_engagement_autoplay_browsertest.cc index b9920a0..eddeac1 100644 --- a/chrome/browser/media/media_engagement_autoplay_browsertest.cc +++ b/chrome/browser/media/media_engagement_autoplay_browsertest.cc
@@ -68,6 +68,13 @@ http_server_.ServeFilesFromSourceDirectory(kMediaEngagementTestDataPath); http_server_origin2_.ServeFilesFromSourceDirectory( kMediaEngagementTestDataPath); + + // Enable or disable MEI based on the test parameter. + if (GetParam()) { + scoped_feature_list_.InitWithFeatures(kFeatures, {}); + } else { + scoped_feature_list_.InitWithFeatures({}, kFeatures); + } } ~MediaEngagementAutoplayBrowserTest() override = default; @@ -82,13 +89,6 @@ ASSERT_TRUE(http_server_.Start()); ASSERT_TRUE(http_server_origin2_.Start()); - // Enable or disable MEI based on the test parameter. - if (GetParam()) { - scoped_feature_list_.InitWithFeatures(kFeatures, {}); - } else { - scoped_feature_list_.InitWithFeatures({}, kFeatures); - } - InProcessBrowserTest::SetUp(); // Clear any preloaded MEI data. @@ -367,11 +367,19 @@ ExpectAutoplayAllowedIfEnabled(); } -IN_PROC_BROWSER_TEST_P(MediaEngagementAutoplayBrowserTest, - BypassAutoplayHighEngagement_HTTPSOnly) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly); +class MediaEngagementAutoplayBrowserTestHttpsOnly + : public MediaEngagementAutoplayBrowserTest { + public: + MediaEngagementAutoplayBrowserTestHttpsOnly() { + feature_list_.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(MediaEngagementAutoplayBrowserTestHttpsOnly, + BypassAutoplayHighEngagement) { SetScores(PrimaryOrigin(), 20, 20); LoadTestPage("engagement_autoplay_test.html"); ExpectAutoplayDenied(); @@ -380,3 +388,7 @@ INSTANTIATE_TEST_SUITE_P(/* no prefix */, MediaEngagementAutoplayBrowserTest, testing::Bool()); + +INSTANTIATE_TEST_SUITE_P(/* no prefix */, + MediaEngagementAutoplayBrowserTestHttpsOnly, + testing::Bool());
diff --git a/chrome/browser/media/unified_autoplay_browsertest.cc b/chrome/browser/media/unified_autoplay_browsertest.cc index 7a8c6704..9af87f15 100644 --- a/chrome/browser/media/unified_autoplay_browsertest.cc +++ b/chrome/browser/media/unified_autoplay_browsertest.cc
@@ -60,11 +60,13 @@ // conflict with "AutoplayBrowserTest" in extensions code. class UnifiedAutoplayBrowserTest : public InProcessBrowserTest { public: + UnifiedAutoplayBrowserTest() { + scoped_feature_list_.InitAndEnableFeature(media::kUnifiedAutoplay); + } + ~UnifiedAutoplayBrowserTest() override = default; void SetUpOnMainThread() override { - scoped_feature_list_.InitAndEnableFeature(media::kUnifiedAutoplay); - host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(embedded_test_server()->Start()); @@ -417,13 +419,16 @@ class UnifiedAutoplaySettingBrowserTest : public UnifiedAutoplayBrowserTest { public: + UnifiedAutoplaySettingBrowserTest() { + scoped_feature_list_.InitWithFeatures( + {media::kAutoplayDisableSettings, media::kAutoplayWhitelistSettings}, + {}); + } + ~UnifiedAutoplaySettingBrowserTest() override = default; void SetUpOnMainThread() override { UnifiedAutoplayBrowserTest::SetUpOnMainThread(); - scoped_feature_list_.InitWithFeatures( - {media::kAutoplayDisableSettings, media::kAutoplayWhitelistSettings}, - {}); } bool AutoplayAllowed(const content::ToRenderFrameHost& adapter) {
diff --git a/chrome/browser/memory/chrome_browser_main_extra_parts_memory.cc b/chrome/browser/memory/chrome_browser_main_extra_parts_memory.cc new file mode 100644 index 0000000..728d5f2 --- /dev/null +++ b/chrome/browser/memory/chrome_browser_main_extra_parts_memory.cc
@@ -0,0 +1,46 @@ +// 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/memory/chrome_browser_main_extra_parts_memory.h" + +#include "base/memory/memory_pressure_monitor.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/memory/enterprise_memory_limit_pref_observer.h" + +#if defined(OS_WIN) +#include "chrome/browser/memory/swap_thrashing_monitor.h" +#endif + +ChromeBrowserMainExtraPartsMemory::ChromeBrowserMainExtraPartsMemory() = default; + +ChromeBrowserMainExtraPartsMemory::~ChromeBrowserMainExtraPartsMemory() = + default; + +void ChromeBrowserMainExtraPartsMemory::PostBrowserStart() { +#if defined(OS_WIN) + // Start the swap thrashing monitor if it's enabled. + // + // TODO(sebmarchand): Delay the initialization of this monitor once we start + // using this feature by default, this is currently enabled at startup to make + // it easier to experiment with this monitor. + if (base::FeatureList::IsEnabled(features::kSwapThrashingMonitor)) + memory::SwapThrashingMonitor::Initialize(); +#endif + + // The MemoryPressureMonitor might not be available in some tests. + if (base::MemoryPressureMonitor::Get() && + memory::EnterpriseMemoryLimitPrefObserver::PlatformIsSupported()) { + memory_limit_pref_observer_ = + std::make_unique<memory::EnterpriseMemoryLimitPrefObserver>( + g_browser_process->local_state()); + } +} + +void ChromeBrowserMainExtraPartsMemory::PostMainMessageLoopRun() { + // |memory_limit_pref_observer_| must be destroyed before its |pref_service_| + // is destroyed, as the observer's PrefChangeRegistrar's destructor uses the + // pref_service. + memory_limit_pref_observer_.reset(); +}
diff --git a/chrome/browser/memory/chrome_browser_main_extra_parts_memory.h b/chrome/browser/memory/chrome_browser_main_extra_parts_memory.h new file mode 100644 index 0000000..6cbdea4 --- /dev/null +++ b/chrome/browser/memory/chrome_browser_main_extra_parts_memory.h
@@ -0,0 +1,40 @@ +// 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_MEMORY_CHROME_BROWSER_MAIN_EXTRA_PARTS_MEMORY_H_ +#define CHROME_BROWSER_MEMORY_CHROME_BROWSER_MAIN_EXTRA_PARTS_MEMORY_H_ + +#include <memory> + +#include "base/macros.h" +#include "chrome/browser/chrome_browser_main_extra_parts.h" + +namespace memory { +class EnterpriseMemoryLimitPrefObserver; +} // namespace memory + +// Wrapper that owns and initialize the browser memory-related extra parts. +class ChromeBrowserMainExtraPartsMemory : public ChromeBrowserMainExtraParts { + public: + ChromeBrowserMainExtraPartsMemory(); + ~ChromeBrowserMainExtraPartsMemory() override; + + private: + // ChromeBrowserMainExtraParts overrides. + void PostBrowserStart() override; + void PostMainMessageLoopRun() override; + + // Tracks changes to the MemoryLimitMbEnabled enterprise policy, and + // starts/stops the EnterpriseMemoryLimitEvaluator accordingly. + // + // Only supported on some platforms, see + // EnterpriseMemoryLimitPrefObserver::PlatformIsSupported for the list of + // supported platforms. + std::unique_ptr<memory::EnterpriseMemoryLimitPrefObserver> + memory_limit_pref_observer_; + + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsMemory); +}; + +#endif // CHROME_BROWSER_MEMORY_CHROME_BROWSER_MAIN_EXTRA_PARTS_MEMORY_H_
diff --git a/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc b/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc index 0fe5ed9..4fd5d4f7 100644 --- a/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc +++ b/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc
@@ -7,8 +7,14 @@ #include "base/bind.h" #include "base/memory/memory_pressure_monitor.h" #include "base/util/memory_pressure/multi_source_memory_pressure_monitor.h" +#include "build/build_config.h" +#include "chrome/browser/resource_coordinator/utils.h" #include "chrome/common/pref_names.h" +#if !defined(OS_ANDROID) +#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h" +#endif + namespace memory { namespace { @@ -35,8 +41,20 @@ EnterpriseMemoryLimitPrefObserver::~EnterpriseMemoryLimitPrefObserver() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (evaluator_->IsRunning()) + if (evaluator_->IsRunning()) { +#if !defined(OS_ANDROID) + resource_coordinator::GetTabLifecycleUnitSource() + ->SetMemoryLimitEnterprisePolicyFlag(false); +#endif evaluator_->Stop(); + } +} + +bool EnterpriseMemoryLimitPrefObserver::PlatformIsSupported() { +#if defined(OS_WIN) || defined(OS_MACOSX) + return true; +#endif + return false; } // static @@ -59,6 +77,11 @@ } else if (evaluator_->IsRunning()) { evaluator_->Stop(); } + +#if !defined(OS_ANDROID) + resource_coordinator::GetTabLifecycleUnitSource() + ->SetMemoryLimitEnterprisePolicyFlag(pref->IsManaged()); +#endif } } // namespace memory
diff --git a/chrome/browser/memory/enterprise_memory_limit_pref_observer.h b/chrome/browser/memory/enterprise_memory_limit_pref_observer.h index a5cfecb..d2448b2 100644 --- a/chrome/browser/memory/enterprise_memory_limit_pref_observer.h +++ b/chrome/browser/memory/enterprise_memory_limit_pref_observer.h
@@ -20,6 +20,9 @@ explicit EnterpriseMemoryLimitPrefObserver(PrefService* pref_service); ~EnterpriseMemoryLimitPrefObserver(); + // Returns true if the current platform is supported, false otherwise. + static bool PlatformIsSupported(); + // Registers the TotalMemoryLimitMb pref with the provided PrefRegistry. // Should only be called by RegisterLocalState() in // chrome/browser/prefs/browser_prefs.cc.
diff --git a/chrome/browser/notifications/notification_interactive_uitest.cc b/chrome/browser/notifications/notification_interactive_uitest.cc index 9b324fa..e58a9ed9 100644 --- a/chrome/browser/notifications/notification_interactive_uitest.cc +++ b/chrome/browser/notifications/notification_interactive_uitest.cc
@@ -265,9 +265,8 @@ EXPECT_EQ("denied", QueryPermissionStatus(browser())); } -IN_PROC_BROWSER_TEST_F(NotificationsTest, TestPermissionEmbargo) { - base::test::ScopedFeatureList scoped_feature_list; - EnablePermissionsEmbargo(&scoped_feature_list); +IN_PROC_BROWSER_TEST_F(NotificationsTestWithPermissionsEmbargo, + TestPermissionEmbargo) { ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
diff --git a/chrome/browser/notifications/notification_interactive_uitest_support.cc b/chrome/browser/notifications/notification_interactive_uitest_support.cc index 564b439..f371521 100644 --- a/chrome/browser/notifications/notification_interactive_uitest_support.cc +++ b/chrome/browser/notifications/notification_interactive_uitest_support.cc
@@ -112,6 +112,7 @@ }; MessageCenterChangeObserver::MessageCenterChangeObserver() : impl_(new Impl) {} + MessageCenterChangeObserver::~MessageCenterChangeObserver() = default; bool MessageCenterChangeObserver::Wait() { @@ -128,9 +129,7 @@ return last_displayed_id_; } -void NotificationsTest::SetUpDefaultCommandLine( - base::CommandLine* command_line) { - InProcessBrowserTest::SetUpDefaultCommandLine(command_line); +NotificationsTest::NotificationsTest() { // Temporary change while the whole support class is changed to deal // with native notifications. crbug.com/714679 #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) @@ -306,17 +305,15 @@ return browser->tab_strip_model()->GetActiveWebContents(); } -void NotificationsTest::EnablePermissionsEmbargo( - base::test::ScopedFeatureList* scoped_feature_list) { +NotificationsTestWithPermissionsEmbargo :: + NotificationsTestWithPermissionsEmbargo() { #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) - scoped_feature_list->InitWithFeatures( - {features::kBlockPromptsIfDismissedOften, - features::kBlockPromptsIfIgnoredOften}, - {features::kNativeNotifications}); + feature_list_.InitWithFeatures({features::kBlockPromptsIfDismissedOften, + features::kBlockPromptsIfIgnoredOften}, + {features::kNativeNotifications}); #else - scoped_feature_list->InitWithFeatures( - {features::kBlockPromptsIfDismissedOften, - features::kBlockPromptsIfIgnoredOften}, - {}); + feature_list_.InitWithFeatures({features::kBlockPromptsIfDismissedOften, + features::kBlockPromptsIfIgnoredOften}, + {}); #endif // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) }
diff --git a/chrome/browser/notifications/notification_interactive_uitest_support.h b/chrome/browser/notifications/notification_interactive_uitest_support.h index b604d90..63b9262 100644 --- a/chrome/browser/notifications/notification_interactive_uitest_support.h +++ b/chrome/browser/notifications/notification_interactive_uitest_support.h
@@ -45,12 +45,9 @@ class NotificationsTest : public InProcessBrowserTest { public: - NotificationsTest() {} + NotificationsTest(); protected: - // InProcessBrowserTest overrides. - void SetUpDefaultCommandLine(base::CommandLine* command_line) override; - int GetNotificationCount(); int GetNotificationPopupCount(); @@ -86,10 +83,6 @@ GURL GetTestPageURL() const; content::WebContents* GetActiveWebContents(Browser* browser); - protected: - void EnablePermissionsEmbargo( - base::test::ScopedFeatureList* scoped_feature_list); - private: std::string RequestAndRespondToPermission( Browser* browser, @@ -98,4 +91,12 @@ base::test::ScopedFeatureList feature_list_; }; +class NotificationsTestWithPermissionsEmbargo : public NotificationsTest { + public: + NotificationsTestWithPermissionsEmbargo(); + + private: + base::test::ScopedFeatureList feature_list_; +}; + #endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_INTERACTIVE_UITEST_SUPPORT_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 826f0b6..8f1f4fe 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
@@ -915,12 +915,22 @@ blink::mojom::WebFeature::kHeavyAdIntervention, 1); } +class AdsPageLoadMetricsObserverResourceBrowserTestWithoutHeavyAdIntervention + : public AdsPageLoadMetricsObserverResourceBrowserTest { + public: + AdsPageLoadMetricsObserverResourceBrowserTestWithoutHeavyAdIntervention() { + feature_list_.InitAndDisableFeature(features::kHeavyAdIntervention); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Check that when the heavy ad feature is disabled we don't navigate // the frame. -IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest, - HeavyAdInterventionDisabled_ErrorPageNotLoaded) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(features::kHeavyAdIntervention); +IN_PROC_BROWSER_TEST_F( + AdsPageLoadMetricsObserverResourceBrowserTestWithoutHeavyAdIntervention, + ErrorPageNotLoaded) { base::HistogramTester histogram_tester; auto incomplete_resource_response = std::make_unique<net::test_server::ControllableHttpResponse>(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index b1c7e21a..047b2168 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -611,8 +611,8 @@ TouchToFillController* ChromePasswordManagerClient::GetOrCreateTouchToFillController() { if (!touch_to_fill_controller_) { - touch_to_fill_controller_ = - std::make_unique<TouchToFillController>(web_contents()); + touch_to_fill_controller_ = std::make_unique<TouchToFillController>( + web_contents(), GetFaviconService()); } return touch_to_fill_controller_.get();
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index 107e4b5..32800e40 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -2457,7 +2457,21 @@ CheckThatCredentialsStored("temp", "new_pw"); } -IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, +// This fixture disable autofill. If a password is autofilled, then all the +// Javascript changes are discarded and test below would not be able to feed a +// new password to the form. +class PasswordManagerBrowserTestWithAutofillDisabled + : public PasswordManagerBrowserTest { + public: + PasswordManagerBrowserTestWithAutofillDisabled() { + feature_list_.InitAndEnableFeature(features::kFillOnAccountSelect); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestWithAutofillDisabled, PasswordOverridenUpdateBubbleShown) { // At first let us save credentials to the PasswordManager. scoped_refptr<password_manager::TestPasswordStore> password_store = @@ -2471,12 +2485,6 @@ signin_form.password_value = base::ASCIIToUTF16("pw"); password_store->AddLogin(signin_form); - // Disable autofill. If a password is autofilled then all the Javacript - // changes are discarded. The test would not be able to feed the new password - // below. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kFillOnAccountSelect); - // Check that password update bubble is shown. NavigateToFile("/password/password_form.html"); NavigationObserver observer(WebContents());
diff --git a/chrome/browser/password_manager/touch_to_fill_controller.cc b/chrome/browser/password_manager/touch_to_fill_controller.cc index 2eb44e0..1431e267 100644 --- a/chrome/browser/password_manager/touch_to_fill_controller.cc +++ b/chrome/browser/password_manager/touch_to_fill_controller.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "chrome/browser/touch_to_fill/touch_to_fill_view.h" +#include "components/favicon/core/favicon_service.h" #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h" #include "components/password_manager/core/browser/origin_credential_store.h" #include "components/password_manager/core/browser/password_manager_driver.h" @@ -19,8 +20,22 @@ using password_manager::CredentialPair; using password_manager::PasswordManagerDriver; -TouchToFillController::TouchToFillController(content::WebContents* web_contents) - : web_contents_(web_contents) {} +namespace { + +void OnImageFetched(base::OnceCallback<void(const gfx::Image&)> callback, + const favicon_base::FaviconRawBitmapResult& bitmap_result) { + gfx::Image image; + if (bitmap_result.is_valid()) + image = gfx::Image::CreateFrom1xPNGBytes(bitmap_result.bitmap_data); + std::move(callback).Run(image); +} + +} // namespace + +TouchToFillController::TouchToFillController( + content::WebContents* web_contents, + favicon::FaviconService* favicon_service) + : web_contents_(web_contents), favicon_service_(favicon_service) {} TouchToFillController::~TouchToFillController() = default; @@ -47,8 +62,9 @@ password_manager::metrics_util::LogFilledCredentialIsFromAndroidApp( password_manager::IsValidAndroidFacetURI(credential.origin_url.spec())); - driver_->FillSuggestion(credential.username, credential.password); - std::exchange(driver_, nullptr)->TouchToFillDismissed(); + driver_->TouchToFillDismissed(); + std::exchange(driver_, nullptr) + ->FillSuggestion(credential.username, credential.password); } void TouchToFillController::OnDismiss() { @@ -61,3 +77,14 @@ gfx::NativeView TouchToFillController::GetNativeView() { return web_contents_->GetNativeView(); } + +void TouchToFillController::FetchFavicon( + const std::string& credential_origin, + int desired_size_in_pixel, + base::OnceCallback<void(const gfx::Image&)> callback) { + favicon_service_->GetRawFaviconForPageURL( + GURL(credential_origin), {favicon_base::IconType::kFavicon}, + desired_size_in_pixel, + /* fallback_to_host = */ true, + base::BindOnce(&OnImageFetched, std::move(callback)), &favicon_tracker_); +}
diff --git a/chrome/browser/password_manager/touch_to_fill_controller.h b/chrome/browser/password_manager/touch_to_fill_controller.h index a088ef5a..af8d850 100644 --- a/chrome/browser/password_manager/touch_to_fill_controller.h +++ b/chrome/browser/password_manager/touch_to_fill_controller.h
@@ -11,14 +11,20 @@ #include "base/containers/span.h" #include "base/memory/weak_ptr.h" +#include "base/task/cancelable_task_tracker.h" #include "chrome/browser/touch_to_fill/touch_to_fill_view.h" #include "chrome/browser/touch_to_fill/touch_to_fill_view_factory.h" +#include "components/favicon_base/favicon_types.h" #include "ui/gfx/native_widget_types.h" namespace content { class WebContents; } // namespace content +namespace favicon { +class FaviconService; +} // namespace favicon + namespace password_manager { class PasswordManagerDriver; struct CredentialPair; @@ -26,7 +32,8 @@ class TouchToFillController { public: - explicit TouchToFillController(content::WebContents* web_contents); + TouchToFillController(content::WebContents* web_contents, + favicon::FaviconService* favicon_service); TouchToFillController(const TouchToFillController&) = delete; TouchToFillController& operator=(const TouchToFillController&) = delete; ~TouchToFillController(); @@ -47,6 +54,12 @@ // The web page view containing the focused field. gfx::NativeView GetNativeView(); + // Obtains a favicon for the origin and invokes the callback with a favicon + // image or with an empty image if a favicon could not be retrieved. + void FetchFavicon(const std::string& credential_origin, + int desired_size_in_pixel, + base::OnceCallback<void(const gfx::Image&)> callback); + #if defined(UNIT_TEST) void set_view(std::unique_ptr<TouchToFillView> view) { view_ = std::move(view); @@ -63,6 +76,12 @@ // OnCredentialSelected() or OnDismissed() gets called. base::WeakPtr<password_manager::PasswordManagerDriver> driver_; + // The favicon service used to retrieve icons for a given origin. + favicon::FaviconService* favicon_service_ = nullptr; + + // Used to track requested favicons. On destruction, requests are cancelled. + base::CancelableTaskTracker favicon_tracker_; + // View used to communicate with the Android frontend. Lazily instantiated so // that it can be injected by tests. std::unique_ptr<TouchToFillView> view_;
diff --git a/chrome/browser/password_manager/touch_to_fill_controller_unittest.cc b/chrome/browser/password_manager/touch_to_fill_controller_unittest.cc index fc4a40d..88a46b2c 100644 --- a/chrome/browser/password_manager/touch_to_fill_controller_unittest.cc +++ b/chrome/browser/password_manager/touch_to_fill_controller_unittest.cc
@@ -68,7 +68,7 @@ private: MockTouchToFillView* mock_view_ = nullptr; MockPasswordManagerDriver driver_; - TouchToFillController touch_to_fill_controller_{nullptr}; + TouchToFillController touch_to_fill_controller_{nullptr, nullptr}; }; TEST_F(TouchToFillControllerTest, Show_And_Fill) {
diff --git a/chrome/browser/payments/has_enrolled_instrument_browsertest.cc b/chrome/browser/payments/has_enrolled_instrument_browsertest.cc index 64d95bf7..c0bc33b 100644 --- a/chrome/browser/payments/has_enrolled_instrument_browsertest.cc +++ b/chrome/browser/payments/has_enrolled_instrument_browsertest.cc
@@ -64,20 +64,6 @@ PlatformBrowserTest::SetUpOnMainThread(); } - std::unique_ptr<base::test::ScopedFeatureList> - EnableStrictHasEnrolledAutofillInstrument() { - auto features = std::make_unique<base::test::ScopedFeatureList>(); - features->InitWithFeatures( - /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}, - /*disabled_features=*/{ - features::kPaymentRequestSkipToGPay, -#if defined(OS_ANDROID) - ::chrome::android::kNoCreditCardAbort, -#endif // OS_ANDROID - }); - return features; - } - content::WebContents* GetActiveWebContents() { return chrome_test_utils::GetActiveWebContents(this); } @@ -94,6 +80,24 @@ DISALLOW_COPY_AND_ASSIGN(HasEnrolledInstrumentTest); }; +class HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument + : public HasEnrolledInstrumentTest { + public: + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument() { + feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}, + /*disabled_features=*/{ + features::kPaymentRequestSkipToGPay, +#if defined(OS_ANDROID) + ::chrome::android::kNoCreditCardAbort, +#endif + }); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoCard) { EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); @@ -103,28 +107,28 @@ EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + NoCard) { + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); - - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoBillingAddress) { @@ -139,28 +143,31 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + NoBillingAddress) { + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + autofill::test::GetCreditCard()); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, @@ -178,28 +185,33 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + HaveShippingNoBillingAddress) { + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + autofill::test::GetFullProfile()); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + autofill::test::GetCreditCard()); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, @@ -218,19 +230,25 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + HaveShippingAndBillingAddress) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + GetCardWithBillingAddress(address)); - EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(true, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(true, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); - } + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, InvalidCardNumber) { @@ -250,28 +268,36 @@ EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + InvalidCardNumber) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + autofill::CreditCard card = GetCardWithBillingAddress(address); + card.SetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NUMBER, + base::ASCIIToUTF16("1111111111111111")); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), card); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, ExpiredCard) { @@ -290,28 +316,35 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + ExpiredCard) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + autofill::CreditCard card = GetCardWithBillingAddress(address); + card.SetExpirationYear(2000); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), card); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } // TODO(https://crbug.com/994799): Unify autofill data validation and returned @@ -337,41 +370,50 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + HaveNoNameShippingAndBillingAddress) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + + address.SetRawInfo(autofill::ServerFieldType::NAME_FIRST, base::string16()); + address.SetRawInfo(autofill::ServerFieldType::NAME_MIDDLE, base::string16()); + address.SetRawInfo(autofill::ServerFieldType::NAME_LAST, base::string16()); + + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + GetCardWithBillingAddress(address)); // TODO(https://crbug.com/994799): Unify autofill data requirements between // desktop and Android. #if defined(OS_ANDROID) - // Android requires the billing address to have a name. - bool is_no_name_billing_address_valid = false; - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); + // Android requires the billing address to have a name. + bool is_no_name_billing_address_valid = false; + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); #else - // Desktop does not require the billing address to have a name. - bool is_no_name_billing_address_valid = true; + // Desktop does not require the billing address to have a name. + bool is_no_name_billing_address_valid = true; #endif // OS_ANDROID - EXPECT_EQ( - is_no_name_billing_address_valid, - content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); - EXPECT_EQ( - is_no_name_billing_address_valid, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(is_no_name_billing_address_valid, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(is_no_name_billing_address_valid, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - // Shipping address requires recipient name on all platforms. - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - } + // Shipping address requires recipient name on all platforms. + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, @@ -392,29 +434,37 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + HaveNoStreetShippingAndBillingAddress) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + address.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_STREET_ADDRESS, + base::string16()); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + GetCardWithBillingAddress(address)); - EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); - EXPECT_EQ(false, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), "show()")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestShipping:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show()")); + EXPECT_EQ( + not_supported_message(), + content::EvalJs(GetActiveWebContents(), "show({requestShipping:true})")); + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoEmailAddress) { @@ -434,23 +484,31 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + NoEmailAddress) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + address.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS, + base::string16()); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + GetCardWithBillingAddress(address)); - EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(true, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, InvalidEmailAddress) { @@ -470,23 +528,31 @@ EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument({requestPayerEmail:true})")); +} - { - auto features = EnableStrictHasEnrolledAutofillInstrument(); +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentTestWithStrictHasEnrolledAutofillInstrument, + InvalidEmailAddress) { + autofill::AutofillProfile address = autofill::test::GetFullProfile(); + address.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS, + base::ASCIIToUTF16("this-is-not-a-valid-email-address")); + test::AddAutofillProfile(GetActiveWebContents()->GetBrowserContext(), + address); + test::AddCreditCard(GetActiveWebContents()->GetBrowserContext(), + GetCardWithBillingAddress(address)); - EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument()")); - EXPECT_EQ(true, - content::EvalJs(GetActiveWebContents(), - "hasEnrolledInstrument({requestShipping:true})")); - EXPECT_EQ(false, content::EvalJs( - GetActiveWebContents(), - "hasEnrolledInstrument({requestPayerEmail:true})")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); + EXPECT_EQ(true, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestShipping:true})")); + EXPECT_EQ(false, + content::EvalJs(GetActiveWebContents(), + "hasEnrolledInstrument({requestPayerEmail:true})")); - EXPECT_EQ(not_supported_message(), - content::EvalJs(GetActiveWebContents(), - "show({requestPayerEmail:true})")); - } + EXPECT_EQ(not_supported_message(), + content::EvalJs(GetActiveWebContents(), + "show({requestPayerEmail:true})")); } } // namespace
diff --git a/chrome/browser/payments/has_enrolled_instrument_query_quota_browsertest.cc b/chrome/browser/payments/has_enrolled_instrument_query_quota_browsertest.cc index 3815a64..7004fe56 100644 --- a/chrome/browser/payments/has_enrolled_instrument_query_quota_browsertest.cc +++ b/chrome/browser/payments/has_enrolled_instrument_query_quota_browsertest.cc
@@ -57,23 +57,29 @@ return chrome_test_utils::GetActiveWebContents(this); } - protected: - base::test::ScopedFeatureList features_; - private: net::EmbeddedTestServer https_server_; DISALLOW_COPY_AND_ASSIGN(HasEnrolledInstrumentQueryQuotaTest); }; +class HasEnrolledInstrumentQueryQuotaTestNoFlags + : public HasEnrolledInstrumentQueryQuotaTest { + public: + HasEnrolledInstrumentQueryQuotaTestNoFlags() { + features_.InitWithFeatures( + /*enabled_features=*/{}, /*disabled_features=*/{ + features::kStrictHasEnrolledAutofillInstrument, + features::kWebPaymentsPerMethodCanMakePaymentQuota}); + } + + private: + base::test::ScopedFeatureList features_; +}; + // Payment options do not trigger query quota when the strict autofill data // check is disabled. Per-method query quota is also disabled in this test. -IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTest, NoFlags) { - features_.InitWithFeatures( - /*enabled_features=*/{}, /*disabled_features=*/{ - features::kStrictHasEnrolledAutofillInstrument, - features::kWebPaymentsPerMethodCanMakePaymentQuota}); - +IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTestNoFlags, NoFlags) { EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); EXPECT_EQ(false, @@ -81,13 +87,24 @@ "hasEnrolledInstrument({requestShipping:true})")); } +class HasEnrolledInstrumentQueryQuotaTestPerMethodQuota + : public HasEnrolledInstrumentQueryQuotaTest { + public: + HasEnrolledInstrumentQueryQuotaTestPerMethodQuota() { + features_.InitWithFeatures( + /*enabled_features=*/{features:: + kWebPaymentsPerMethodCanMakePaymentQuota}, + /*disabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}); + } + + private: + base::test::ScopedFeatureList features_; +}; + // Payment options do not trigger query quota when the strict autofill data // check is disabled. Per-method query quota is enabled in this test. -IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTest, PerMethodQuota) { - features_.InitWithFeatures( - /*enabled_features=*/{features::kWebPaymentsPerMethodCanMakePaymentQuota}, - /*disabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}); - +IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTestPerMethodQuota, + PerMethodQuota) { EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); EXPECT_EQ(false, @@ -95,15 +112,25 @@ "hasEnrolledInstrument({requestShipping:true})")); } +class HasEnrolledInstrumentQueryQuotaTestStrictAutofillDataCheck + : public HasEnrolledInstrumentQueryQuotaTest { + public: + HasEnrolledInstrumentQueryQuotaTestStrictAutofillDataCheck() { + features_.InitWithFeatures( + /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}, + /*disabled_features=*/{ + features::kWebPaymentsPerMethodCanMakePaymentQuota}); + } + + private: + base::test::ScopedFeatureList features_; +}; + // Payment options trigger query quota for Basic Card when the strict autofill // data check is enabled. Per-method query quota is disabled in this test. -IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTest, - StrictAutofillDataCheck) { - features_.InitWithFeatures( - /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument}, - /*disabled_features=*/{ - features::kWebPaymentsPerMethodCanMakePaymentQuota}); - +IN_PROC_BROWSER_TEST_F( + HasEnrolledInstrumentQueryQuotaTestStrictAutofillDataCheck, + StrictAutofillDataCheck) { EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); EXPECT_EQ("NotAllowedError: Exceeded query quota for hasEnrolledInstrument", @@ -111,14 +138,25 @@ "hasEnrolledInstrument({requestShipping:true})")); } +class HasEnrolledInstrumentQueryQuotaTestBothFlags + : public HasEnrolledInstrumentQueryQuotaTest { + public: + HasEnrolledInstrumentQueryQuotaTestBothFlags() { + features_.InitWithFeatures( + /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument, + features:: + kWebPaymentsPerMethodCanMakePaymentQuota}, + /*disabled_features=*/{}); + } + + private: + base::test::ScopedFeatureList features_; +}; + // Payment options trigger query quota for Basic Card when the strict autofill // data check is enabled. Per-method query quota is also enabled in this test. -IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTest, BothFlags) { - features_.InitWithFeatures( - /*enabled_features=*/{features::kStrictHasEnrolledAutofillInstrument, - features::kWebPaymentsPerMethodCanMakePaymentQuota}, - /*disabled_features=*/{}); - +IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentQueryQuotaTestBothFlags, + BothFlags) { EXPECT_EQ(false, content::EvalJs(GetActiveWebContents(), "hasEnrolledInstrument()")); EXPECT_EQ("NotAllowedError: Exceeded query quota for hasEnrolledInstrument",
diff --git a/chrome/browser/payments/payment_request_can_make_payment_browsertest.cc b/chrome/browser/payments/payment_request_can_make_payment_browsertest.cc index 000b8525..0d1bf078 100644 --- a/chrome/browser/payments/payment_request_can_make_payment_browsertest.cc +++ b/chrome/browser/payments/payment_request_can_make_payment_browsertest.cc
@@ -167,7 +167,6 @@ private: PaymentRequestTestController payment_request_controller_; - base::test::ScopedFeatureList feature_list_; syncer::TestSyncService sync_service_; std::unique_ptr<net::EmbeddedTestServer> https_server_; std::unique_ptr<autofill::EventWaiter<TestEvent>> event_waiter_; @@ -229,13 +228,23 @@ ExpectBodyContains({"false"}); } +class PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsDisabled + : public PaymentRequestCanMakePaymentQueryTest { + public: + PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsDisabled() { + feature_list_.InitAndDisableFeature( + payments::features::kReturnGooglePayInBasicCard); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Visa is required, and user has a masked visa instrument, and Google Pay cards // in basic-card is disabled. -IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryTest, - CanMakePayment_Supported_GooglePayCardsDisabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - payments::features::kReturnGooglePayInBasicCard); +IN_PROC_BROWSER_TEST_F( + PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsDisabled, + CanMakePayment_Supported) { NavigateTo("/payment_request_can_make_payment_query_test.html"); autofill::CreditCard card = autofill::test::GetMaskedServerCard(); card.SetNumber(base::ASCIIToUTF16("4111111111111111")); // We need a visa. @@ -252,13 +261,23 @@ ExpectBodyContains({"false"}); } +class PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsEnabled + : public PaymentRequestCanMakePaymentQueryTest { + public: + PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsEnabled() { + feature_list_.InitAndEnableFeature( + payments::features::kReturnGooglePayInBasicCard); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Visa is required, and user has a masked visa instrument, and Google Pay cards // in basic-card is enabled. -IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryTest, - CanMakePayment_Supported_GooglePayCardsEnabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - payments::features::kReturnGooglePayInBasicCard); +IN_PROC_BROWSER_TEST_F( + PaymentRequestCanMakePaymentQueryTestWithGooglePayCardsEnabled, + CanMakePayment_Supported) { NavigateTo("/payment_request_can_make_payment_query_test.html"); autofill::CreditCard card = autofill::test::GetMaskedServerCard(); card.SetNumber(base::ASCIIToUTF16("4111111111111111")); // We need a visa. @@ -371,8 +390,6 @@ } private: - base::test::ScopedFeatureList feature_list_; - DISALLOW_COPY_AND_ASSIGN(PaymentRequestCanMakePaymentQueryCCTest); }; @@ -597,13 +614,22 @@ ExpectBodyContains({"NotAllowedError"}); } +class PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuota + : public PaymentRequestCanMakePaymentQueryPMITest { + public: + PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuota() { + feature_list_.InitAndEnableFeature( + features::kWebPaymentsPerMethodCanMakePaymentQuota); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // If the device does not have any payment apps installed, canMakePayment() and // hasEnrolledInstrument() should return false for them. -IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITest, +IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuota, QueryQuotaForPaymentApps) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kWebPaymentsPerMethodCanMakePaymentQuota); NavigateTo("/payment_request_payment_method_identifier_test.html"); CallCanMakePayment(CheckFor::ALICE_PAY); @@ -664,17 +690,29 @@ ExpectBodyContains({"NotAllowedError"}); } +class + PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuotaAndServiceWorkerPayment + : public PaymentRequestCanMakePaymentQueryPMITest { + public: + PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuotaAndServiceWorkerPayment() { + feature_list_.InitWithFeatures( + /*enable_features=*/{::features::kServiceWorkerPaymentApps, + features:: + kWebPaymentsPerMethodCanMakePaymentQuota}, + /*disable_features=*/{}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Querying for payment apps in incognito returns result as normal mode to avoid // incognito mode detection. Multiple queries for different apps are rejected // with NotSupportedError to avoid user fingerprinting. -IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITest, - QueryQuotaForPaymentAppsInIncognitoMode) { +IN_PROC_BROWSER_TEST_F( + PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuotaAndServiceWorkerPayment, + QueryQuotaForPaymentAppsInIncognitoMode) { NavigateTo("/payment_request_payment_method_identifier_test.html"); - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - /*enable_features=*/{::features::kServiceWorkerPaymentApps, - features::kWebPaymentsPerMethodCanMakePaymentQuota}, - /*disable_features=*/{}); SetIncognito(true); @@ -703,11 +741,8 @@ // as in normal mode to avoid incognito mode detection. Multiple queries for // different payment methods are rejected with NotSupportedError to avoid user // fingerprinting. -IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITest, +IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITestWithPaymentQuota, NoQueryQuotaForPaymentAppsAndCardsInIncognito) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kWebPaymentsPerMethodCanMakePaymentQuota); NavigateTo("/payment_request_payment_method_identifier_test.html"); SetIncognito(true);
diff --git a/chrome/browser/permissions/permission_delegation_browsertest.cc b/chrome/browser/permissions/permission_delegation_browsertest.cc index bd74202..85267591 100644 --- a/chrome/browser/permissions/permission_delegation_browsertest.cc +++ b/chrome/browser/permissions/permission_delegation_browsertest.cc
@@ -21,11 +21,13 @@ public: PermissionDelegationBrowserTest() : geolocation_overrider_( - std::make_unique<device::ScopedGeolocationOverrider>(0, 0)) {} + std::make_unique<device::ScopedGeolocationOverrider>(0, 0)) { + scoped_feature_list_.InitAndEnableFeature(features::kPermissionDelegation); + } + ~PermissionDelegationBrowserTest() override = default; void SetUpOnMainThread() override { - scoped_feature_list_.InitAndEnableFeature(features::kPermissionDelegation); PermissionRequestManager* manager = PermissionRequestManager::FromWebContents(GetWebContents()); mock_permission_prompt_factory_.reset(
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc index 0adf3ce..b555578f8 100644 --- a/chrome/browser/permissions/permission_request_manager_browsertest.cc +++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -52,15 +52,17 @@ class PermissionRequestManagerBrowserTest : public InProcessBrowserTest { public: - PermissionRequestManagerBrowserTest() = default; + PermissionRequestManagerBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + features::kBlockRepeatedNotificationPermissionPrompts); + } + ~PermissionRequestManagerBrowserTest() override = default; void SetUpOnMainThread() override { PermissionRequestManager* manager = GetPermissionRequestManager(); mock_permission_prompt_factory_.reset( new MockPermissionPromptFactory(manager)); - scoped_feature_list_.InitAndEnableFeature( - features::kBlockRepeatedNotificationPermissionPrompts); host_resolver()->AddRule("*", "127.0.0.1"); }
diff --git a/chrome/browser/policy/e2e_test/.vpython b/chrome/browser/policy/e2e_test/.vpython index bc935fa..b68566c 100644 --- a/chrome/browser/policy/e2e_test/.vpython +++ b/chrome/browser/policy/e2e_test/.vpython
@@ -11,8 +11,8 @@ wheel: < name: "infra/celab/celab/windows-amd64" - # Source: https://ci.chromium.org/p/celab/builders/ci/Windows/b8902045658105865392 - version: "mHamQ8UpCgqQTQZyuKIFVlvYy3KSkDCsUSGXQtL5E-YC" + # Source: https://ci.chromium.org/p/celab/builders/ci/Windows/b8900225462594660384 + version: "Q1ebL0sPA1vX4tcIGj6d0IXxXa02M5CsBm3p0SbeGZUC" > # googleapiclient
diff --git a/chrome/browser/policy/e2e_test/run_tests.py b/chrome/browser/policy/e2e_test/run_tests.py index f74071c..220bc341 100644 --- a/chrome/browser/policy/e2e_test/run_tests.py +++ b/chrome/browser/policy/e2e_test/run_tests.py
@@ -31,6 +31,16 @@ default='*', help='Fully qualified names of TestCases to run (supports my.package.*)') parser.add_argument( + '--include', + metavar='<categoryA;...>', + default=None, + help='Categories of tests to include') + parser.add_argument( + '--exclude', + metavar='<categoryA;...>', + default=None, + help='Categories of tests to exclude') + parser.add_argument( '--noprogress', dest='show_progress', default=True, @@ -106,6 +116,10 @@ tests = ArgsParser.ParseTestsArg(args.tests) logging.debug('Found tests: %s', tests) + if args.include or args.exclude: + tests = ArgsParser.ProcessTestFilterArg(tests, args.include, args.exclude) + logging.debug('Got filtered tests: %s', tests) + hostFiles = ArgsParser.ParseHostsArg(args.hosts) logging.debug('Found hosts: %s', hostFiles)
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc index 13f9d7a..ab32d547 100644 --- a/chrome/browser/printing/print_job_worker.cc +++ b/chrome/browser/printing/print_job_worker.cc
@@ -22,11 +22,13 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/printing/print_job.h" #include "chrome/grit/generated_resources.h" +#include "components/crash/core/common/crash_keys.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "printing/backend/print_backend.h" #include "printing/print_job_constants.h" #include "printing/printed_document.h" #include "printing/printing_utils.h" @@ -39,6 +41,7 @@ #endif #if defined(OS_WIN) +#include "base/threading/thread_restrictions.h" #include "printing/printed_page_win.h" #endif @@ -203,6 +206,21 @@ void PrintJobWorker::UpdatePrintSettings(base::Value new_settings, SettingsCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + + std::unique_ptr<crash_keys::ScopedPrinterInfo> crash_key; + if (new_settings.FindIntKey(kSettingPrinterType).value() == kLocalPrinter) { +#if defined(OS_WIN) + // Blocking is needed here because Windows printer drivers are oftentimes + // not thread-safe and have to be accessed on the UI thread. + base::ScopedAllowBlocking allow_blocking; +#endif + scoped_refptr<PrintBackend> print_backend = + PrintBackend::CreateInstance(nullptr); + std::string printer_name = *new_settings.FindStringKey(kSettingDeviceName); + crash_key = std::make_unique<crash_keys::ScopedPrinterInfo>( + print_backend->GetPrinterDriverInfo(printer_name)); + } + PrintingContext::Result result = printing_context_->UpdatePrintSettings(std::move(new_settings)); GetSettingsDone(std::move(callback), result);
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index 11faf8e..9a556b5 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -1610,11 +1610,19 @@ ASSERT_EQ(0u, GetNotificationCount()); } -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, - PushEventIgnoresScheduledNotificationsForEnforcement) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kNotificationTriggers); +class PushMessagingBrowserTestWithNotificationTriggersEnabled + : public PushMessagingBrowserTest { + public: + PushMessagingBrowserTestWithNotificationTriggersEnabled() { + feature_list_.InitAndEnableFeature(features::kNotificationTriggers); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTestWithNotificationTriggersEnabled, + PushEventIgnoresScheduledNotificationsForEnforcement) { std::string script_result; ASSERT_NO_FATAL_FAILURE(SubscribeSuccessfully());
diff --git a/chrome/browser/resource_coordinator/tab_activity_watcher_browsertest.cc b/chrome/browser/resource_coordinator/tab_activity_watcher_browsertest.cc index 963f8a6..04dcba5 100644 --- a/chrome/browser/resource_coordinator/tab_activity_watcher_browsertest.cc +++ b/chrome/browser/resource_coordinator/tab_activity_watcher_browsertest.cc
@@ -68,7 +68,11 @@ // to UKM logs. class TabActivityWatcherTest : public InProcessBrowserTest { protected: - TabActivityWatcherTest() = default; + TabActivityWatcherTest() { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kTabRanker, + {{"disable_background_log_with_TabRanker", "false"}}); + } // TabActivityWatcherTest: void PreRunTestOnMainThread() override { @@ -79,9 +83,6 @@ void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); - scoped_feature_list_.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"disable_background_log_with_TabRanker", "false"}}); ASSERT_TRUE(embedded_test_server()->Start()); test_urls_ = {embedded_test_server()->GetURL("/title1.html"), embedded_test_server()->GetURL("/title2.html"), @@ -173,20 +174,31 @@ } std::vector<GURL> test_urls_; - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<UkmEntryChecker> ukm_entry_checker_; std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; private: + base::test::ScopedFeatureList scoped_feature_list_; + DISALLOW_COPY_AND_ASSIGN(TabActivityWatcherTest); }; +class TabActivityWatcherTestWithBackgroundLogDisabled + : public TabActivityWatcherTest { + public: + TabActivityWatcherTestWithBackgroundLogDisabled() { + feature_list_.InitAndEnableFeatureWithParameters( + features::kTabRanker, + {{"disable_background_log_with_TabRanker", "true"}}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests calculating tab scores using the Tab Ranker. -IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, CalculateReactivationScore) { - base::test::ScopedFeatureList scoped_feature_list_overrides; - scoped_feature_list_overrides.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"disable_background_log_with_TabRanker", "true"}}); +IN_PROC_BROWSER_TEST_F(TabActivityWatcherTestWithBackgroundLogDisabled, + CalculateReactivationScore) { // Use test clock so tabs have non-zero backgrounded times. base::SimpleTestTickClock test_clock; ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing(&test_clock); @@ -389,15 +401,23 @@ EXPECT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kFOCEntryName)); } -// Tests discarded tab is recorded correctly. -IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, - DiscardedTabGetsPreviousSourceId) { - base::test::ScopedFeatureList scoped_feature_list_overrides; - scoped_feature_list_overrides.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, - {"disable_background_log_with_TabRanker", "false"}}); +class TabActivityWatcherTestWithBackgroundLogEnabled + : public TabActivityWatcherTest { + public: + TabActivityWatcherTestWithBackgroundLogEnabled() { + feature_list_.InitAndEnableFeatureWithParameters( + features::kTabRanker, + {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, + {"disable_background_log_with_TabRanker", "false"}}); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Tests discarded tab is recorded correctly. +IN_PROC_BROWSER_TEST_F(TabActivityWatcherTestWithBackgroundLogEnabled, + DiscardedTabGetsPreviousSourceId) { ukm::SourceId ukm_source_id_for_tab_0 = 0; ukm::SourceId ukm_source_id_for_tab_1 = 0; @@ -506,19 +526,29 @@ } } -// Test the query time logging is correct. -IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, LogOldestNTabFeatures) { - // Set Feature params for this test. - // (1) background log is disabled, so that only query time logging and - // corresponding labels should be logged. - // (2) number of oldest tabs to log is set to 1, so that only 1 tab should be - // logged. - base::test::ScopedFeatureList scoped_feature_list_overrides; - scoped_feature_list_overrides.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, - {"disable_background_log_with_TabRanker", "true"}}); +class TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab + : public TabActivityWatcherTest { + public: + TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab() { + // Set Feature params for this test. + // (1) background log is disabled, so that only query time logging and + // corresponding labels should be logged. + // (2) number of oldest tabs to log is set to 1, so that only 1 tab should + // be logged. + feature_list_.InitAndEnableFeatureWithParameters( + features::kTabRanker, + {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, + {"disable_background_log_with_TabRanker", "true"}}); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Test the query time logging is correct. +IN_PROC_BROWSER_TEST_F( + TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab, + LogOldestNTabFeatures) { // Use test clock so tabs have non-zero backgrounded times. base::SimpleTestTickClock test_clock; ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing(&test_clock); @@ -610,13 +640,9 @@ } // Tests label id is recorded correctly for discarded tabs. -IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, DiscardedTabGetsCorrectLabelId) { - base::test::ScopedFeatureList scoped_feature_list_overrides; - scoped_feature_list_overrides.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, - {"disable_background_log_with_TabRanker", "true"}}); - +IN_PROC_BROWSER_TEST_F( + TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab, + DiscardedTabGetsCorrectLabelId) { ui_test_utils::NavigateToURL(browser(), test_urls_[0]); AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK); // No TabMetrics events are logged till now. @@ -692,14 +718,9 @@ // Tests label_id is incremented if the LogOldestNTabFeatures is called second // times without logging the label first. -IN_PROC_BROWSER_TEST_F(TabActivityWatcherTest, - TabsAlreadyHaveLabelIdGetIncrementalLabelIds) { - base::test::ScopedFeatureList scoped_feature_list_overrides; - scoped_feature_list_overrides.InitAndEnableFeatureWithParameters( - features::kTabRanker, - {{"number_of_oldest_tabs_to_log_with_TabRanker", "1"}, - {"disable_background_log_with_TabRanker", "true"}}); - +IN_PROC_BROWSER_TEST_F( + TabActivityWatcherTestWithBackgroundLogDisabledAndOnlyOneOldestTab, + TabsAlreadyHaveLabelIdGetIncrementalLabelIds) { ui_test_utils::NavigateToURL(browser(), test_urls_[0]); AddTabAtIndex(1, test_urls_[1], ui::PAGE_TRANSITION_LINK); // No TabMetrics events are logged till now.
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc index a9333d0e..d30b781 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
@@ -425,11 +425,18 @@ void TabLifecycleUnitSource::TabLifecycleUnit::SetIsHoldingWebLock( bool is_holding_weblock) { + // Unfreeze the tab if it receive a lock while being frozen. + if (is_holding_weblock && IsFrozenOrPendingFreeze(GetState())) + Unfreeze(); + is_holding_weblock_ = is_holding_weblock; } void TabLifecycleUnitSource::TabLifecycleUnit::SetIsHoldingIndexedDBLock( bool is_holding_indexeddb_lock) { + // Unfreeze the tab if it receive a lock while being frozen. + if (is_holding_indexeddb_lock && IsFrozenOrPendingFreeze(GetState())) + Unfreeze(); is_holding_indexeddb_lock_ = is_holding_indexeddb_lock; } @@ -602,12 +609,16 @@ // NOTE: These do not currently provide DecisionDetails! #if !defined(OS_CHROMEOS) if (reason == LifecycleUnitDiscardReason::URGENT) { - // Limit urgent discarding to once only. - if (GetDiscardCount() > 0) + // Limit urgent discarding to once only, unless discarding for the + // enterprise memory limit feature. + if (GetDiscardCount() > 0 && + !GetTabSource()->memory_limit_enterprise_policy()) return false; // Protect non-visible tabs from urgent discarding for a period of time. if (web_contents()->GetVisibility() != content::Visibility::VISIBLE) { base::TimeDelta time_in_bg = NowTicks() - GetWallTimeWhenHidden(); + // TODO(sebmarchand): Check if this should be lowered when the enterprise + // memory limit feature is set. if (time_in_bg < kBackgroundUrgentProtectionTime) return false; }
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc index 6b62c42..806bb9d 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
@@ -222,6 +222,10 @@ UpdateFocusedTab(); } +void TabLifecycleUnitSource::SetMemoryLimitEnterprisePolicyFlag(bool enabled) { + memory_limit_enterprise_policy_ = enabled; +} + void TabLifecycleUnitSource::OnFirstLifecycleUnitCreated() { // In production builds monitor the policy override of the lifecycles feature. // This class owns the monitor so it is okay to use base::Unretained. Note
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h index 8de7043..f26ead1 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -74,6 +74,13 @@ return tab_lifecycles_enterprise_policy_; } + // Returns the state of the MemoryLimitMbEnabled enterprise policy. + bool memory_limit_enterprise_policy() const { + return memory_limit_enterprise_policy_; + } + + void SetMemoryLimitEnterprisePolicyFlag(bool enabled); + protected: class TabLifecycleUnitHolder; @@ -187,6 +194,9 @@ // The enterprise policy for overriding the tab lifecycles feature. bool tab_lifecycles_enterprise_policy_ = true; + // The enterprise policy for setting a limit on total physical memory usage. + bool memory_limit_enterprise_policy_ = false; + // In official production builds this monitors policy settings and reflects // them in |tab_lifecycles_enterprise_policy_|. std::unique_ptr<TabLifecylesEnterprisePreferenceMonitor>
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc index 468baac..c82addd 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -373,6 +373,11 @@ LifecycleUnitDiscardReason::PROACTIVE); ExpectCanDiscardFalseTrivial(&tab_lifecycle_unit, LifecycleUnitDiscardReason::URGENT); + + // The tab should be discardable a second time when the memory limit + // enterprise policy is set. + GetTabLifecycleUnitSource()->SetMemoryLimitEnterprisePolicyFlag(true); + ExpectCanDiscardTrue(&tab_lifecycle_unit, LifecycleUnitDiscardReason::URGENT); } #endif // !defined(OS_CHROMEOS) @@ -990,4 +995,62 @@ tab_lifecycle_unit.SetIsHoldingIndexedDBLock(false); } +TEST_F(TabLifecycleUnitTest, TabUnfreezeOnWebLockAcquisition) { + TabLifecycleUnit tab_lifecycle_unit(GetTabLifecycleUnitSource(), &observers_, + usage_clock_.get(), web_contents_, + tab_strip_model_.get()); + TabLoadTracker::Get()->TransitionStateForTesting(web_contents_, + LoadingState::LOADED); + // Advance time enough that the tab is urgent discardable. + test_clock_.Advance(kBackgroundUrgentProtectionTime); + ExpectCanDiscardTrueAllReasons(&tab_lifecycle_unit); + + DecisionDetails decision_details; + EXPECT_TRUE(tab_lifecycle_unit.CanFreeze(&decision_details)); + + // Freeze the tab. + EXPECT_CALL(observer_, OnFrozenStateChange(web_contents_, true)); + tab_lifecycle_unit.Freeze(); + ::testing::Mock::VerifyAndClear(&observer_); + EXPECT_EQ(LifecycleUnitState::PENDING_FREEZE, tab_lifecycle_unit.GetState()); + + // Indicates that the tab has acquired a WebLock, this should unfreeze it. + EXPECT_CALL(observer_, OnFrozenStateChange(web_contents_, false)); + tab_lifecycle_unit.SetIsHoldingWebLock(true); + ::testing::Mock::VerifyAndClear(&observer_); + EXPECT_EQ(LifecycleUnitState::PENDING_UNFREEZE, + tab_lifecycle_unit.GetState()); + + tab_lifecycle_unit.SetIsHoldingWebLock(false); +} + +TEST_F(TabLifecycleUnitTest, TabUnfreezeOnIndexedDBLockAcquisition) { + TabLifecycleUnit tab_lifecycle_unit(GetTabLifecycleUnitSource(), &observers_, + usage_clock_.get(), web_contents_, + tab_strip_model_.get()); + TabLoadTracker::Get()->TransitionStateForTesting(web_contents_, + LoadingState::LOADED); + // Advance time enough that the tab is urgent discardable. + test_clock_.Advance(kBackgroundUrgentProtectionTime); + ExpectCanDiscardTrueAllReasons(&tab_lifecycle_unit); + + DecisionDetails decision_details; + EXPECT_TRUE(tab_lifecycle_unit.CanFreeze(&decision_details)); + + // Freeze the tab. + EXPECT_CALL(observer_, OnFrozenStateChange(web_contents_, true)); + tab_lifecycle_unit.Freeze(); + ::testing::Mock::VerifyAndClear(&observer_); + EXPECT_EQ(LifecycleUnitState::PENDING_FREEZE, tab_lifecycle_unit.GetState()); + + // Indicates that the tab has acquired a WebLock, this should unfreeze it. + EXPECT_CALL(observer_, OnFrozenStateChange(web_contents_, false)); + tab_lifecycle_unit.SetIsHoldingIndexedDBLock(true); + ::testing::Mock::VerifyAndClear(&observer_); + EXPECT_EQ(LifecycleUnitState::PENDING_UNFREEZE, + tab_lifecycle_unit.GetState()); + + tab_lifecycle_unit.SetIsHoldingIndexedDBLock(false); +} + } // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.js b/chrome/browser/resources/chromeos/login/oobe_dialog.js index 4702732d..86f3f56 100644 --- a/chrome/browser/resources/chromeos/login/oobe_dialog.js +++ b/chrome/browser/resources/chromeos/login/oobe_dialog.js
@@ -76,6 +76,14 @@ }, /** + * Scroll to the bottom of footer container. + */ + scrollToBottom: function() { + var el = this.$$('#footer-container'); + el.scrollTop = el.scrollHeight; + }, + + /** * This is called from oobe_welcome when this dialog is shown. */ show: function() {
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.css b/chrome/browser/resources/chromeos/login/oobe_eula.css index b78674a..548c85d 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.css +++ b/chrome/browser/resources/chromeos/login/oobe_eula.css
@@ -19,6 +19,7 @@ #installationSettings, #logging { font-size: 13px; + min-height: unset; } #crosEulaFrame {
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.js b/chrome/browser/resources/chromeos/login/oobe_eula.js index 939879b..8f44440 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.js +++ b/chrome/browser/resources/chromeos/login/oobe_eula.js
@@ -58,10 +58,10 @@ }, /** - * Flag that ensures that OOBE configuration is applied only once. + * Flag that ensures that eula screen set up once. * @private {boolean} */ - configuration_applied_: false, + initialized_: false, focus: function() { if (this.eulaLoadingScreenShown) { @@ -77,7 +77,19 @@ if (behavior.onBeforeShow) behavior.onBeforeShow.call(this); }); - window.setTimeout(this.applyOobeConfiguration_.bind(this), 0); + window.setTimeout(this.initializeScreen_.bind(this), 0); + }, + + /** + * Set up dialog before shown it for the first time. + * @private + */ + initializeScreen_: function() { + if (this.initialized_) + return; + this.$.eulaDialog.scrollToBottom(); + this.applyOobeConfiguration_(); + this.initialized_ = true; }, /** @@ -85,8 +97,6 @@ * @private */ applyOobeConfiguration_: function() { - if (this.configuration_applied_) - return; var configuration = Oobe.getInstance().getOobeConfiguration(); if (!configuration) return; @@ -96,7 +106,6 @@ if (configuration.eulaAutoAccept) { this.eulaAccepted_(); } - this.configuration_applied_ = true; }, /**
diff --git a/chrome/browser/resources/print_preview/data/model.js b/chrome/browser/resources/print_preview/data/model.js index 1d71350..e248222 100644 --- a/chrome/browser/resources/print_preview/data/model.js +++ b/chrome/browser/resources/print_preview/data/model.js
@@ -189,9 +189,9 @@ /** * Object containing current settings of Print Preview, for use by Polymer * controls. - * Initialize settings that are only available on some printers to - * unavailable, and settings that are provided by PDF generation to - * available. + * Initialize all settings to available so that more settings always stays + * in a collapsed state during startup, when document information and + * printer capabilities may arrive at slightly different times. * @type {!print_preview.Settings} */ settings: { @@ -243,7 +243,7 @@ value: true, /* color */ unavailableValue: false, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'isColorEnabled', @@ -256,7 +256,7 @@ height_microns: 279400, }, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'mediaSize', @@ -286,7 +286,7 @@ value: {}, unavailableValue: {}, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'dpi', @@ -326,7 +326,7 @@ value: true, unavailableValue: false, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'isDuplexEnabled', @@ -386,7 +386,7 @@ value: {}, unavailableValue: {}, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'vendorOptions', @@ -441,7 +441,7 @@ value: false, unavailableValue: false, valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'isPinEnabled', @@ -451,7 +451,7 @@ value: '', unavailableValue: '', valid: true, - available: false, + available: true, setByPolicy: false, setFromUi: false, key: 'pinValue',
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 2fd5e507..d6eaa9c 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -775,6 +775,18 @@ <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_JS" file="printing_page/cups_printers_entry_list.js" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_HTML" + file="printing_page/cups_printers_entry_list_behavior.html" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_JS" + file="printing_page/cups_printers_entry_list_behavior.js" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_HTML" + file="printing_page/cups_printers_entry_manager.html" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_JS" + file="printing_page/cups_printers_entry_manager.js" + type="chrome_html" /> <structure name="IDR_OS_SETTINGS_CUPS_PRINTERS_LIST_HTML" file="printing_page/cups_printers_list.html" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/printing_page/BUILD.gn b/chrome/browser/resources/settings/printing_page/BUILD.gn index e761995..acd3a3b 100644 --- a/chrome/browser/resources/settings/printing_page/BUILD.gn +++ b/chrome/browser/resources/settings/printing_page/BUILD.gn
@@ -22,6 +22,8 @@ ":cups_printers_browser_proxy", ":cups_printers_entry", ":cups_printers_entry_list", + ":cups_printers_entry_list_behavior", + ":cups_printers_entry_manager", ":cups_printers_list", ":cups_saved_printers", ":printing_browser_proxy", @@ -82,6 +84,9 @@ deps = [ ":cups_printer_types", ":cups_printers_browser_proxy", + ":cups_printers_entry_list_behavior", + ":cups_printers_entry_manager", + "//ui/webui/resources/js:list_property_update_behavior", "//ui/webui/resources/js:web_ui_listener_behavior", ] } @@ -102,6 +107,7 @@ deps = [ ":cups_nearby_printers", ":cups_printers_browser_proxy", + ":cups_printers_entry_manager", ":cups_saved_printers", "..:route", "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider", @@ -136,6 +142,22 @@ ] } + js_library("cups_printers_entry_list_behavior") { + deps = [ + ":cups_printer_types", + "//ui/webui/resources/js:list_property_update_behavior", + ] + } + + js_library("cups_printers_entry_manager") { + deps = [ + ":cups_printer_types", + ":cups_printers_browser_proxy", + "//ui/webui/resources/js:assert", + "//ui/webui/resources/js:cr", + ] + } + js_library("cups_printers_list") { deps = [ ":cups_printers_browser_proxy", @@ -149,7 +171,10 @@ deps = [ ":cups_printer_types", ":cups_printers_browser_proxy", + ":cups_printers_entry_list_behavior", + ":cups_printers_entry_manager", "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu", + "//ui/webui/resources/js:list_property_update_behavior", "//ui/webui/resources/js:web_ui_listener_behavior", ] }
diff --git a/chrome/browser/resources/settings/printing_page/cups_nearby_printers.html b/chrome/browser/resources/settings/printing_page/cups_nearby_printers.html index 923cb42..920ad26 100644 --- a/chrome/browser/resources/settings/printing_page/cups_nearby_printers.html +++ b/chrome/browser/resources/settings/printing_page/cups_nearby_printers.html
@@ -1,14 +1,17 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/list_property_update_behavior.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="cups_printer_types.html"> <link rel="import" href="cups_printers_browser_proxy.html"> <link rel="import" href="cups_printers_entry_list.html"> +<link rel="import" href="cups_printers_entry_list_behavior.html"> +<link rel="import" href="cups_printers_entry_manager.html"> <link rel="import" href="../settings_shared_css.html"> <dom-module id="settings-cups-nearby-printers"> <template> - <settings-cups-printers-entry-list printers="[[nearbyPrinters_]]" + <settings-cups-printers-entry-list printers="[[nearbyPrinters]]" search-term="[[searchTerm]]"> </settings-cups-printers-entry-list> </template>
diff --git a/chrome/browser/resources/settings/printing_page/cups_nearby_printers.js b/chrome/browser/resources/settings/printing_page/cups_nearby_printers.js index 9f6f7b6..b5c3644 100644 --- a/chrome/browser/resources/settings/printing_page/cups_nearby_printers.js +++ b/chrome/browser/resources/settings/printing_page/cups_nearby_printers.js
@@ -9,20 +9,16 @@ Polymer({ is: 'settings-cups-nearby-printers', - behaviors: [WebUIListenerBehavior], + // ListPropertyUpdateBehavior is used in CupsPrintersEntryListBehavior. + behaviors: [ + CupsPrintersEntryListBehavior, + ListPropertyUpdateBehavior, + WebUIListenerBehavior, + ], properties: { /** - * @type {!Array<!PrinterListEntry>} - * @private - */ - nearbyPrinters_: { - type: Array, - value: () => [], - }, - - /** - * Search term for filtering |nearbyPrinters_|. + * Search term for filtering |nearbyPrinters|. * @type {string} */ searchTerm: { @@ -30,6 +26,12 @@ value: '', }, + /** @type {?CupsPrinterInfo} */ + activePrinter: { + type: Object, + notify: true, + }, + /** * @type {number} * @private @@ -38,51 +40,12 @@ type: Number, value: -1, }, - - /** @type {?CupsPrinterInfo} */ - activePrinter: { - type: Object, - notify: true, - }, }, listeners: { 'add-automatic-printer': 'onAddAutomaticPrinter_', }, - /** @override */ - attached: function() { - settings.CupsPrintersBrowserProxyImpl.getInstance() - .startDiscoveringPrinters(); - this.addWebUIListener( - 'on-nearby-printers-changed', this.onNearbyPrintersChanged_.bind(this)); - }, - - /** - * @param {!Array<!CupsPrinterInfo>} automaticPrinters - * @param {!Array<!CupsPrinterInfo>} discoveredPrinters - * @private - */ - onNearbyPrintersChanged_: function(automaticPrinters, discoveredPrinters) { - if (!automaticPrinters && !discoveredPrinters) { - return; - } - - const printers = /** @type{!Array<!PrinterListEntry>} */ ([]); - - for (const printer of automaticPrinters) { - printers.push({printerInfo: printer, - printerType: PrinterType.AUTOMATIC}); - } - - for (const printer of discoveredPrinters) { - printers.push({printerInfo: printer, - printerType: PrinterType.DISCOVERED}); - } - - this.nearbyPrinters_ = printers; - }, - /** * @param {!CustomEvent<{item: !PrinterListEntry}>} e * @private @@ -106,12 +69,11 @@ * @private */ setActivePrinter_: function(item) { - this.activePrinterListEntryIndex_ = - this.nearbyPrinters_.findIndex( - printer => printer.printerInfo == item.printerInfo); + this.activePrinterListEntryIndex_ = this.nearbyPrinters.findIndex( + printer => printer.printerInfo.printerId == item.printerInfo.printerId); this.activePrinter = - this.get(['nearbyPrinters_', this.activePrinterListEntryIndex_]) + this.get(['nearbyPrinters', this.activePrinterListEntryIndex_]) .printerInfo; },
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.html b/chrome/browser/resources/settings/printing_page/cups_printers.html index 6777282..c5b866a 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers.html +++ b/chrome/browser/resources/settings/printing_page/cups_printers.html
@@ -16,6 +16,7 @@ <link rel="import" href="cups_add_printer_dialog.html"> <link rel="import" href="cups_edit_printer_dialog.html"> <link rel="import" href="cups_printer_shared_css.html"> +<link rel="import" href="cups_printers_entry_manager.html"> <link rel="import" href="cups_printers_list.html"> <link rel="import" href="cups_saved_printers.html"> <link rel="import" href="cups_nearby_printers.html"> @@ -142,7 +143,6 @@ <settings-cups-saved-printers id="savedPrinters" active-printer="{{activePrinter}}" - saved-printers="[[savedPrinters_]]" search-term="[[searchTerm]]"> </settings-cups-saved-printers> </div> @@ -197,7 +197,7 @@ </settings-cups-edit-printer-dialog> </template> - <cr-toast id="errorToast" duration="3000"> + <cr-toast id="errorToast" duration="3000" role="alert"> <div class="error-message" id="addPrinterDoneMessage"> [[addPrinterResultText_]] </div>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.js b/chrome/browser/resources/settings/printing_page/cups_printers.js index 8b39c62..ebd1009 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers.js +++ b/chrome/browser/resources/settings/printing_page/cups_printers.js
@@ -81,11 +81,16 @@ /** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */ networkConfig_: null, + /** @private {settings.printing.CupsPrintersEntryManager} */ + entryManager_: null, + /** @override */ created: function() { this.networkConfig_ = network_config.MojoInterfaceProviderImpl.getInstance() .getMojoServiceRemote(); + this.entryManager_ = + settings.printing.CupsPrintersEntryManager.getInstance(); }, /** @override */ @@ -110,7 +115,6 @@ this.updateCupsPrintersList_(); }, - /** * settings.RouteObserverBehavior * @param {!settings.Route} route @@ -119,10 +123,14 @@ currentRouteChanged: function(route) { if (route != settings.routes.CUPS_PRINTERS) { cr.removeWebUIListener('on-printers-changed'); + this.entryManager_.removeWebUIListeners(); return; } + + this.entryManager_.addWebUIListeners(); cr.addWebUIListener( 'on-printers-changed', this.onPrintersChanged_.bind(this)); + this.updateCupsPrintersList_(); }, /** @@ -152,13 +160,11 @@ const printerName = event.detail.printerName; switch (event.detail.resultCode) { case PrinterSetupResult.SUCCESS: - this.updateCupsPrintersList_(); this.addPrinterResultText_ = loadTimeData.getStringF('printerAddedSuccessfulMessage', printerName); break; case PrinterSetupResult.EDIT_SUCCESS: - this.updateCupsPrintersList_(); this.addPrinterResultText_ = loadTimeData.getStringF('printerEditedSuccessfulMessage', printerName); @@ -203,6 +209,7 @@ printer => /** @type {!PrinterListEntry} */({ printerInfo: printer, printerType: PrinterType.SAVED})); + this.entryManager_.setSavedPrintersList(this.savedPrinters_); } else { this.printers = cupsPrintersList.printerList; }
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js index 3fe5f69..573655d 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js +++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list.js
@@ -69,12 +69,14 @@ // |filteredPrinters_| is just |printers|. const updatedPrinters = this.searchTerm ? this.printers.filter( - item =>this.matchesSearchTerm_(item.printerInfo,this.searchTerm)) : + item => + this.matchesSearchTerm_(item.printerInfo, this.searchTerm)) : this.printers.slice(); updatedPrinters.sort(this.sortPrinters_); - this.updateList('filteredPrinters_', printer => printer.printerInfo, + this.updateList( + 'filteredPrinters_', printer => printer.printerInfo.printerId, updatedPrinters); this.showNoSearchResultsMessage_ =
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.html b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.html new file mode 100644 index 0000000..6f303194 --- /dev/null +++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.html
@@ -0,0 +1,2 @@ +<link rel="import" href="cups_printer_types.html"> +<script src="cups_printers_entry_list_behavior.js"></script> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.js b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.js new file mode 100644 index 0000000..9b557ff --- /dev/null +++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_list_behavior.js
@@ -0,0 +1,81 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Polymer behavior for observing CupsPrintersEntryManager events. + * Use this behavior if you want to receive a dynamically updated list of both + * saved and nearby printers. + */ + +/** @polymerBehavior */ +const CupsPrintersEntryListBehavior = { + properties: { + /** @private {!settings.printing.CupsPrintersEntryManager} */ + entryManager_: Object, + + /** @type {!Array<!PrinterListEntry>} */ + savedPrinters: { + type: Array, + value: () => [], + }, + + /** @type {!Array<!PrinterListEntry>} */ + nearbyPrinters: { + type: Array, + value: () => [], + }, + }, + + /** @override */ + created: function() { + this.entryManager_ = + settings.printing.CupsPrintersEntryManager.getInstance(); + }, + + /** @override */ + attached: function() { + this.entryManager_.addOnSavedPrintersChangedListener( + this.onSavedPrintersChanged_.bind(this)); + this.entryManager_.addOnNearbyPrintersChangedListener( + this.onNearbyPrintersChanged_.bind(this)); + + // Initialize saved and nearby printers list. + this.onSavedPrintersChanged_( + this.entryManager_.savedPrinters, [] /* printerAdded */, + [] /* printerRemoved */); + this.onNearbyPrintersChanged_(this.entryManager_.nearbyPrinters); + }, + + /** @override */ + detached: function() { + this.entryManager_.removeOnSavedPrintersChangedListener( + this.onSavedPrintersChanged_.bind(this)); + this.entryManager_.removeOnNearbyPrintersChangedListener( + this.onNearbyPrintersChanged_.bind(this)); + }, + + /** + * Non-empty/null fields indicate the applicable change to be notified. + * @param {!Array<!PrinterListEntry>} savedPrinters + * @param {!Array<!PrinterListEntry>} addedPrinters + * @param {!Array<!PrinterListEntry>} removedPrinters + * @private + */ + onSavedPrintersChanged_: function( + savedPrinters, addedPrinters, removedPrinters) { + this.updateList( + 'savedPrinters', printer => printer.printerInfo.printerId, + savedPrinters); + }, + + /** + * @param {!Array<!PrinterListEntry>} printerList + * @private + */ + onNearbyPrintersChanged_: function(printerList) { + this.updateList( + 'nearbyPrinters', printer => printer.printerInfo.printerId, + printerList); + } +}; \ No newline at end of file
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.html b/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.html new file mode 100644 index 0000000..d8e4aac --- /dev/null +++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.html
@@ -0,0 +1,5 @@ +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="cups_printer_types.html"> +<link rel="import" href="cups_printers_browser_proxy.html"> +<script src="cups_printers_entry_manager.js"></script> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.js b/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.js new file mode 100644 index 0000000..0beacd37 --- /dev/null +++ b/chrome/browser/resources/settings/printing_page/cups_printers_entry_manager.js
@@ -0,0 +1,191 @@ +// 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. + +/** + * Function which provides the client with metadata about a change + * to a list of saved printers. The first parameter is the updated list of + * printers after the change, the second parameter is the newly-added printer + * (if it exists), and the third parameter is the newly-removed printer + * (if it exists). + * @typedef {!function(!Array<!PrinterListEntry>, !Array<!PrinterListEntry>, + * !Array<!PrinterListEntry>): void} + */ +let PrintersListWithDeltasCallback; + +/** + * Function which provides the client with a list that contains the nearby + * printers list. The parameter is the updated list of printers after any + * changes. + * @typedef {function(!Array<!PrinterListEntry>): void} + */ +let PrintersListCallback; + +cr.define('settings.printing', function() { + /** + * @param {!PrinterListEntry} first + * @param {!PrinterListEntry} second + * @return {boolean} + * @private + */ + function arePrinterIdsEqual_(first, second) { + return first.printerInfo.printerId == second.printerInfo.printerId; + } + + /** + * Finds the printers that are in |firstArr| but not in |secondArr|. + * @param {!Array<!PrinterListEntry>} firstArr + * @param {!Array<!PrinterListEntry>} secondArr + * @return {!Array<!PrinterListEntry>} + * @private + */ + function findDifference_(firstArr, secondArr) { + return firstArr.filter((firstArrEntry) => { + return !secondArr.some(arePrinterIdsEqual_.bind(this, firstArrEntry)); + }); + } + + /** + * Class for managing printer entries. Holds both Saved and Nearby printers + * and notifies observers of any applicable changes to either printer lists. + */ + class CupsPrintersEntryManager { + constructor() { + /** @private {!Array<!PrinterListEntry>} */ + this.savedPrinters_ = []; + + /** @private {!Array<!PrinterListEntry>} */ + this.nearbyPrinters_ = []; + + /** @private {!Array<PrintersListWithDeltasCallback>} */ + this.onSavedPrintersChangedListeners_ = []; + + /** @type {!Array<PrintersListCallback>} */ + this.onNearbyPrintersChangedListeners_ = []; + } + + addWebUIListeners() { + // TODO(1005905): Add on-printers-changed listener here once legacy code + // is removed. + cr.addWebUIListener( + 'on-nearby-printers-changed', this.setNearbyPrintersList.bind(this)); + settings.CupsPrintersBrowserProxyImpl.getInstance() + .startDiscoveringPrinters(); + } + + removeWebUIListeners() { + cr.removeWebUIListener('on-nearby-printers-changed'); + } + + /** @return {!Array<!PrinterListEntry>} */ + get savedPrinters() { + return this.savedPrinters_; + } + + /** @return {!Array<!PrinterListEntry>} */ + get nearbyPrinters() { + return this.nearbyPrinters_; + } + + /** @param {PrintersListWithDeltasCallback} listener */ + addOnSavedPrintersChangedListener(listener) { + this.onSavedPrintersChangedListeners_.push(listener); + } + + /** @param {PrintersListWithDeltasCallback} listener */ + removeOnSavedPrintersChangedListener(listener) { + this.onSavedPrintersChangedListeners_ = + this.onSavedPrintersChangedListeners_.filter(lis => lis != listener); + } + + /** @param {PrintersListCallback} listener */ + addOnNearbyPrintersChangedListener(listener) { + this.onNearbyPrintersChangedListeners_.push(listener); + } + + /** @param {PrintersListCallback} listener */ + removeOnNearbyPrintersChangedListener(listener) { + this.onNearbyPrintersChangedListeners_ = + this.onNearbyPrintersChangedListeners_.filter(lis => lis != listener); + } + + /** + * Sets the saved printers list and notifies observers of any applicable + * changes. + * @param {!Array<!PrinterListEntry>} printerList + */ + setSavedPrintersList(printerList) { + if (printerList.length > this.savedPrinters_.length) { + const diff = findDifference_(printerList, this.savedPrinters_); + this.savedPrinters_ = printerList; + this.notifyOnSavedPrintersChangedListeners_( + this.savedPrinters_, diff, [] /* printersRemoved */); + return; + } + + if (printerList.length < this.savedPrinters_.length) { + const diff = findDifference_(this.savedPrinters_, printerList); + this.savedPrinters_ = printerList; + this.notifyOnSavedPrintersChangedListeners_( + this.savedPrinters_, [] /* printersAdded */, diff); + return; + } + + this.savedPrinters_ = printerList; + this.notifyOnSavedPrintersChangedListeners_( + this.savedPrinters_, [] /* printersAdded */, + [] /* printersRemoved */); + } + + /** + * Sets the nearby printers list and notifies observers of any applicable + * changes. + * @param {!Array<!CupsPrinterInfo>} automaticPrinters + * @param {!Array<!CupsPrinterInfo>} discoveredPrinters + */ + setNearbyPrintersList(automaticPrinters, discoveredPrinters) { + if (!automaticPrinters && !discoveredPrinters) { + return; + } + + this.nearbyPrinters_ = []; + + for (const printer of automaticPrinters) { + this.nearbyPrinters_.push( + {printerInfo: printer, printerType: PrinterType.AUTOMATIC}); + } + + for (const printer of discoveredPrinters) { + this.nearbyPrinters_.push( + {printerInfo: printer, printerType: PrinterType.DISCOVERED}); + } + + this.notifyOnNearbyPrintersChangedListeners_(); + } + + /** + * Non-empty/null fields indicate the applicable change to be notified. + * @param {!Array<!PrinterListEntry>} savedPrinters + * @param {!Array<!PrinterListEntry>} addedPrinter + * @param {!Array<!PrinterListEntry>} removedPrinter + * @private + */ + notifyOnSavedPrintersChangedListeners_( + savedPrinters, addedPrinter, removedPrinter) { + this.onSavedPrintersChangedListeners_.forEach( + listener => listener(savedPrinters, addedPrinter, removedPrinter)); + } + + /** @private */ + notifyOnNearbyPrintersChangedListeners_() { + this.onNearbyPrintersChangedListeners_.forEach( + listener => listener(this.nearbyPrinters_)); + } + } + + cr.addSingletonGetter(CupsPrintersEntryManager); + + return { + CupsPrintersEntryManager: CupsPrintersEntryManager, + }; +}); \ No newline at end of file
diff --git a/chrome/browser/resources/settings/printing_page/cups_saved_printers.html b/chrome/browser/resources/settings/printing_page/cups_saved_printers.html index 1bb09c08..6d89dcd 100644 --- a/chrome/browser/resources/settings/printing_page/cups_saved_printers.html +++ b/chrome/browser/resources/settings/printing_page/cups_saved_printers.html
@@ -1,10 +1,12 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> +<link rel="import" href="chrome://resources/html/list_property_update_behavior.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="cups_printer_types.html"> <link rel="import" href="cups_printers_browser_proxy.html"> <link rel="import" href="cups_printers_entry_list.html"> +<link rel="import" href="cups_printers_entry_list_behavior.html"> <link rel="import" href="../settings_shared_css.html"> <dom-module id="settings-cups-saved-printers">
diff --git a/chrome/browser/resources/settings/printing_page/cups_saved_printers.js b/chrome/browser/resources/settings/printing_page/cups_saved_printers.js index 85ef694..77c68a95 100644 --- a/chrome/browser/resources/settings/printing_page/cups_saved_printers.js +++ b/chrome/browser/resources/settings/printing_page/cups_saved_printers.js
@@ -9,16 +9,14 @@ Polymer({ is: 'settings-cups-saved-printers', + // ListPropertyUpdateBehavior is used in CupsPrintersEntryListBehavior. behaviors: [ - WebUIListenerBehavior, + CupsPrintersEntryListBehavior, + ListPropertyUpdateBehavior, + WebUIListenerBehavior, ], properties: { - /** @type {!Array<!PrinterListEntry>} */ - savedPrinters: { - type: Array, - }, - /** * Search term for filtering |savedPrinters|. * @type {string} @@ -28,6 +26,12 @@ value: '', }, + /** @type {?CupsPrinterInfo} */ + activePrinter: { + type: Object, + notify: true, + }, + /** * @type {number} * @private @@ -36,12 +40,6 @@ type: Number, value: -1, }, - - /** @type {?CupsPrinterInfo} */ - activePrinter: { - type: Object, - notify: true, - }, }, listeners: { @@ -62,9 +60,8 @@ */ onOpenActionMenu_: function(e) { const item = /** @type {!PrinterListEntry} */(e.detail.item); - this.activePrinterListEntryIndex_ = - this.savedPrinters.findIndex( - printer => printer.printerInfo == item.printerInfo); + this.activePrinterListEntryIndex_ = this.savedPrinters.findIndex( + printer => printer.printerInfo.printerId == item.printerInfo.printerId); this.activePrinter = this.get(['savedPrinters', this.activePrinterListEntryIndex_]) .printerInfo; @@ -92,5 +89,6 @@ /** @private */ closeActionMenu_: function() { this.$$('cr-action-menu').close(); - } + }, + });
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index fc7e730..9db64f2 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -987,6 +987,18 @@ <structure name="IDR_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_JS" file="printing_page/cups_printers_entry_list.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_HTML" + file="printing_page/cups_printers_entry_list_behavior.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CUPS_PRINTERS_ENTRY_LIST_BEHAVIOR_JS" + file="printing_page/cups_printers_entry_list_behavior.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_HTML" + file="printing_page/cups_printers_entry_manager.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CUPS_PRINTERS_ENTRY_MANAGER_JS" + file="printing_page/cups_printers_entry_manager.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_CUPS_PRINTERS_LIST_HTML" file="printing_page/cups_printers_list.html" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/site_settings/category_default_setting.js b/chrome/browser/resources/settings/site_settings/category_default_setting.js index 5426cf0..a3e2d32 100644 --- a/chrome/browser/resources/settings/site_settings/category_default_setting.js +++ b/chrome/browser/resources/settings/site_settings/category_default_setting.js
@@ -177,10 +177,22 @@ if (update.source !== undefined && update.source != ContentSettingProvider.PREFERENCE) { basePref.enforcement = chrome.settingsPrivate.Enforcement.ENFORCED; - basePref.controlledBy = - update.source == ContentSettingProvider.EXTENSION ? - chrome.settingsPrivate.ControlledBy.EXTENSION : - chrome.settingsPrivate.ControlledBy.USER_POLICY; + switch (update.source) { + case ContentSettingProvider.POLICY: + basePref.controlledBy = + chrome.settingsPrivate.ControlledBy.DEVICE_POLICY; + break; + case ContentSettingProvider.SUPERVISED_USER: + basePref.controlledBy = chrome.settingsPrivate.ControlledBy.PARENT; + break; + case ContentSettingProvider.EXTENSION: + basePref.controlledBy = chrome.settingsPrivate.ControlledBy.EXTENSION; + break; + default: + basePref.controlledBy = + chrome.settingsPrivate.ControlledBy.USER_POLICY; + break; + } } const prefValue = this.computeIsSettingEnabled(update.setting);
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js index 2da1d57b..2b826c3 100644 --- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js +++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -14,8 +14,16 @@ * @enum {string} */ const ContentSettingProvider = { + POLICY: 'policy', + SUPERVISED_USER: 'supervised_user', EXTENSION: 'extension', + INSTALLED_WEBAPP_PROVIDER: 'installed_webapp_provider', + NOTIFICATION_ANDROID: 'notification_android', + EPHEMERAL: 'ephemeral', PREFERENCE: 'preference', + DEFAULT: 'default', + TESTS: 'tests', + TESTS_OTHER: 'tests_other' }; /**
diff --git a/chrome/browser/resources/webapks/BUILD.gn b/chrome/browser/resources/webapks/BUILD.gn index 6e4c0a5..2a50290 100644 --- a/chrome/browser/resources/webapks/BUILD.gn +++ b/chrome/browser/resources/webapks/BUILD.gn
@@ -12,9 +12,8 @@ js_library("about_webapks") { deps = [ - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:load_time_data", - "//ui/webui/resources/js:util", + "//ui/webui/resources/js:cr.m", + "//ui/webui/resources/js:util.m", ] externs_list = [ "$externs_path/chrome_send.js" ] }
diff --git a/chrome/browser/resources/webapks/about_webapks.html b/chrome/browser/resources/webapks/about_webapks.html index f09ce2c5d..4e91c52 100644 --- a/chrome/browser/resources/webapks/about_webapks.html +++ b/chrome/browser/resources/webapks/about_webapks.html
@@ -11,12 +11,8 @@ <title>About WebAPKs</title> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> <link rel="stylesheet" href="about_webapks.css"> - <link rel="import" href="chrome://resources/html/cr.html"> - <link rel="import" href="chrome://resources/html/load_time_data.html"> - <link rel="import" href="chrome://resources/html/util.html"> - <script src="chrome://webapks/webapks.js"></script> - <script src="chrome://webapks/strings.js"></script> + <script type="module" src="webapks.js"></script> </head> <body>
diff --git a/chrome/browser/resources/webapks/about_webapks.js b/chrome/browser/resources/webapks/about_webapks.js index b21be02..10bc849 100644 --- a/chrome/browser/resources/webapks/about_webapks.js +++ b/chrome/browser/resources/webapks/about_webapks.js
@@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import './strings.m.js'; + +import {addWebUIListener} from 'chrome://resources/js/cr.m.js'; +import {$, createElementWithClassName} from 'chrome://resources/js/util.m.js'; + /** * @typedef {{ * name: string, @@ -54,17 +59,6 @@ } /** - * Callback from the backend with the information of a WebAPK to display. - * This will be called once per WebAPK. - * - * @param {!WebApkInfo} webApkInfo Object with information about an - * installed WebAPK. - */ -function returnWebApkInfo(webApkInfo) { - addWebApk(webApkInfo); -} - -/** * @param {HTMLElement} webApkList List of elements which contain WebAPK * attributes. * @param {string} label Text that identifies the new element. @@ -96,7 +90,7 @@ /** * Adds a new entry to the page with the information of a WebAPK. * - * @param {WebApkInfo} webApkInfo Information about an installed WebAPK. + * @param {!WebApkInfo} webApkInfo Information about an installed WebAPK. */ function addWebApk(webApkInfo) { /** @type {HTMLElement} */ const webApkList = $('webapk-list'); @@ -160,5 +154,8 @@ } document.addEventListener('DOMContentLoaded', function() { + // Add a WebUI listener for the 'web-apk-info' event emmitted from the + // backend. This will be triggered once per WebAPK. + addWebUIListener('web-apk-info', addWebApk); chrome.send('requestWebApksInfo'); });
diff --git a/chrome/browser/safe_browsing/download_protection/download_reporter.cc b/chrome/browser/safe_browsing/download_protection/download_reporter.cc index 356314c..8bfb96d7 100644 --- a/chrome/browser/safe_browsing/download_protection/download_reporter.cc +++ b/chrome/browser/safe_browsing/download_protection/download_reporter.cc
@@ -90,62 +90,34 @@ DownloadReporter::DownloadReporter() { profiles_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); - profiles_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, - content::NotificationService::AllSources()); } -DownloadReporter::~DownloadReporter() { - profiles_registrar_.RemoveAll(); - - for (download::SimpleDownloadManagerCoordinator* coordinator : - observed_coordinators_) { - coordinator->RemoveObserver(this); - } - - for (download::DownloadItem* download_item : observed_downloads_) { - download_item->RemoveObserver(this); - } -} +DownloadReporter::~DownloadReporter() = default; void DownloadReporter::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - switch (type) { - case chrome::NOTIFICATION_PROFILE_CREATED: { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - Profile* profile = content::Source<Profile>(source).ptr(); - download::SimpleDownloadManagerCoordinator* coordinator = - SimpleDownloadManagerCoordinatorFactory::GetForKey( - profile->GetProfileKey()); - coordinator->AddObserver(this); - observed_coordinators_.insert(coordinator); - break; - } - case chrome::NOTIFICATION_PROFILE_DESTROYED: { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - Profile* profile = content::Source<Profile>(source).ptr(); - download::SimpleDownloadManagerCoordinator* coordinator = - SimpleDownloadManagerCoordinatorFactory::GetForKey( - profile->GetProfileKey()); - coordinator->RemoveObserver(this); - observed_coordinators_.erase(coordinator); - break; - } - default: - NOTREACHED(); - } + DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_CREATED); + Profile* profile = content::Source<Profile>(source).ptr(); + download::SimpleDownloadManagerCoordinator* coordinator = + SimpleDownloadManagerCoordinatorFactory::GetForKey( + profile->GetProfileKey()); + observed_coordinators_.Add(coordinator); +} + +void DownloadReporter::OnManagerGoingDown( + download::SimpleDownloadManagerCoordinator* coordinator) { + observed_coordinators_.Remove(coordinator); } void DownloadReporter::OnDownloadCreated(download::DownloadItem* download) { danger_types_[download] = download->GetDangerType(); - download->AddObserver(this); - observed_downloads_.insert(download); + observed_downloads_.Add(download); } void DownloadReporter::OnDownloadDestroyed(download::DownloadItem* download) { - download->RemoveObserver(this); + observed_downloads_.Remove(download); danger_types_.erase(download); - observed_downloads_.erase(download); } void DownloadReporter::OnDownloadUpdated(download::DownloadItem* download) {
diff --git a/chrome/browser/safe_browsing/download_protection/download_reporter.h b/chrome/browser/safe_browsing/download_protection/download_reporter.h index ab2bb7b..0815bc5 100644 --- a/chrome/browser/safe_browsing/download_protection/download_reporter.h +++ b/chrome/browser/safe_browsing/download_protection/download_reporter.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_REPORTER_H_ #define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_REPORTER_H_ +#include "base/macros.h" +#include "base/scoped_observer.h" #include "components/download/public/common/download_item.h" #include "components/download/public/common/simple_download_manager_coordinator.h" #include "content/public/browser/notification_observer.h" @@ -28,6 +30,8 @@ const content::NotificationDetails& details) override; // SimpleDownloadManagerCoordinator::Observer implementation: + void OnManagerGoingDown( + download::SimpleDownloadManagerCoordinator* coordinator) override; void OnDownloadCreated(download::DownloadItem* download) override; // DownloadItem::Observer implementation: @@ -38,8 +42,13 @@ content::NotificationRegistrar profiles_registrar_; base::flat_map<download::DownloadItem*, download::DownloadDangerType> danger_types_; - std::set<download::SimpleDownloadManagerCoordinator*> observed_coordinators_; - std::set<download::DownloadItem*> observed_downloads_; + ScopedObserver<download::SimpleDownloadManagerCoordinator, + download::SimpleDownloadManagerCoordinator::Observer> + observed_coordinators_{this}; + ScopedObserver<download::DownloadItem, download::DownloadItem::Observer> + observed_downloads_{this}; + + DISALLOW_COPY_AND_ASSIGN(DownloadReporter); }; } // namespace safe_browsing
diff --git a/chrome/browser/search/ntp_features.cc b/chrome/browser/search/ntp_features.cc index 0f7d2d5..fe2de2e 100644 --- a/chrome/browser/search/ntp_features.cc +++ b/chrome/browser/search/ntp_features.cc
@@ -23,7 +23,7 @@ // If enabled, the NTP shortcut layout will be replaced with a grid layout that // enables better animations. const base::Feature kGridLayoutForNtpShortcuts{ - "GridLayoutForNtpShortcuts", base::FEATURE_DISABLED_BY_DEFAULT}; + "GridLayoutForNtpShortcuts", base::FEATURE_ENABLED_BY_DEFAULT}; // If enabled, the user will see the second version of the customization picker. const base::Feature kNtpCustomizationMenuV2{"NtpCustomizationMenuV2",
diff --git a/chrome/browser/search/search_suggest/search_suggest_service.cc b/chrome/browser/search/search_suggest/search_suggest_service.cc index 3a0a2365..655a01f 100644 --- a/chrome/browser/search/search_suggest/search_suggest_service.cc +++ b/chrome/browser/search/search_suggest/search_suggest_service.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/search/search.h" #include "chrome/browser/search/search_suggest/search_suggest_loader.h" #include "chrome/common/pref_names.h" +#include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/common/omnibox_features.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" @@ -97,10 +98,16 @@ // static bool SearchSuggestService::IsEnabled() { - // Search suggestions should be disabled when on-focus zero-prefix suggestions - // are displaying in the NTP. return !base::FeatureList::IsEnabled(omnibox::kZeroSuggestionsOnNTP) && - !base::FeatureList::IsEnabled(omnibox::kZeroSuggestionsOnNTPRealbox); + !base::FeatureList::IsEnabled(omnibox::kZeroSuggestionsOnNTPRealbox) && + !(base::FeatureList::IsEnabled(omnibox::kOnFocusSuggestions) && + (!OmniboxFieldTrial::GetZeroSuggestVariants( + metrics::OmniboxEventProto::NTP_REALBOX) + .empty() || + !OmniboxFieldTrial::GetZeroSuggestVariants( + metrics::OmniboxEventProto:: + INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS) + .empty())); } SearchSuggestService::SearchSuggestService(
diff --git a/chrome/browser/search/search_suggest/search_suggest_service.h b/chrome/browser/search/search_suggest/search_suggest_service.h index a4ecd027..386b4c1 100644 --- a/chrome/browser/search/search_suggest/search_suggest_service.h +++ b/chrome/browser/search/search_suggest/search_suggest_service.h
@@ -28,6 +28,11 @@ // user signs in or out, the cached value is cleared. class SearchSuggestService : public KeyedService { public: + // Search suggestions should be disabled when on-focus zero-prefix suggestions + // are displaying in the NTP. Returns false if omnibox::kZeroSuggestionsOnNTP + // or omnibox::kZeroSuggestionsOnNTPRealboxkNtpRealbox are enabled; or + // omnibox::kOnFocusSuggestions is enabled and configured to show suggestions + // of some type in the NTP Omnibox or Realbox. static bool IsEnabled(); SearchSuggestService(Profile* profile,
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 8ce24d1..1328428 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -939,9 +939,13 @@ // to do a command reset when quitting and restoring. class SessionRestoreTabGroupsTest : public SessionRestoreTest, public testing::WithParamInterface<bool> { + public: + SessionRestoreTabGroupsTest() { + feature_override_.InitAndEnableFeature(features::kTabGroups); + } + protected: void SetUpOnMainThread() override { - feature_override_.InitAndEnableFeature(features::kTabGroups); SessionRestoreTest::SetUpOnMainThread(); } @@ -1031,8 +1035,11 @@ // Ensure tab groups aren't restored if |features::kTabGroups| is disabled. // Regression test for crbug.com/983962. +// +// TODO(https://crbug.com/1012605): Find a way to cover this regression without +// relying on dynamic FeatureList overrides mid-test. IN_PROC_BROWSER_TEST_F(SessionRestoreTest, - GroupsNotRestoredWhenFeatureDisabled) { + DISABLED_GroupsNotRestoredWhenFeatureDisabled) { auto feature_override = std::make_unique<base::test::ScopedFeatureList>(); feature_override->InitAndEnableFeature(features::kTabGroups); @@ -1866,7 +1873,12 @@ class SecFetchSiteSessionRestoreTest : public SessionRestoreTest { public: SecFetchSiteSessionRestoreTest() - : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) { + feature_list_.InitWithFeatures( + {network::features::kFetchMetadata, + network::features::kFetchMetadataDestination}, + {}); + } void SetUpOnMainThread() override { SessionRestoreTest::SetUpOnMainThread(); @@ -1877,11 +1889,6 @@ https_test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); ASSERT_TRUE(https_test_server_.Start()); ASSERT_TRUE(embedded_test_server()->Start()); - - feature_list_.InitWithFeatures( - {network::features::kFetchMetadata, - network::features::kFetchMetadataDestination}, - {}); } content::WebContents* GetTab(Browser* browser, int tab_index) {
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc index d0d9661..fcbc65ce 100644 --- a/chrome/browser/sessions/tab_restore_browsertest.cc +++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -891,10 +891,17 @@ EXPECT_EQ(sessions::TabRestoreService::TAB, service->entries().front()->type); } -IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoreGroupedTab) { - base::test::ScopedFeatureList feature_override; - feature_override.InitAndEnableFeature(features::kTabGroups); +class TabRestoreTestWithTabGroupsEnabled : public TabRestoreTest { + public: + TabRestoreTestWithTabGroupsEnabled() { + feature_list_.InitAndEnableFeature(features::kTabGroups); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(TabRestoreTestWithTabGroupsEnabled, RestoreGroupedTab) { const int tab_count = AddSomeTabs(browser(), 1); ASSERT_LE(2, tab_count); @@ -914,10 +921,8 @@ browser()->tab_strip_model()->GetTabGroupForTab(grouped_tab_index)); } -IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoreWindowWithGroupedTabs) { - base::test::ScopedFeatureList feature_override; - feature_override.InitAndEnableFeature(features::kTabGroups); - +IN_PROC_BROWSER_TEST_F(TabRestoreTestWithTabGroupsEnabled, + RestoreWindowWithGroupedTabs) { ui_test_utils::NavigateToURLWithDisposition( browser(), GURL(chrome::kChromeUINewTabURL), WindowOpenDisposition::NEW_WINDOW, @@ -962,7 +967,12 @@ // Ensure tab groups aren't restored if |features::kTabGroups| is disabled. // Regression test for crbug.com/983962. -IN_PROC_BROWSER_TEST_F(TabRestoreTest, GroupsNotRestoredWhenFeatureDisabled) { +// +// NOTE: This test is currently disabled because it fundamentally relies on +// manipulating the FeatureList state mid-test, which is NOT safe and not +// allowed by the FeatureList API. +IN_PROC_BROWSER_TEST_F(TabRestoreTest, + DISABLED_GroupsNotRestoredWhenFeatureDisabled) { auto feature_override = std::make_unique<base::test::ScopedFeatureList>(); feature_override->InitAndEnableFeature(features::kTabGroups);
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc b/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc index 60e68e7..9fb4cfe 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" #include "chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h" @@ -35,11 +36,11 @@ } // namespace // Browser tests for the Click To Call feature. -class ClickToCallBrowserTest : public SharingBrowserTest { +class ClickToCallBrowserTestBase : public SharingBrowserTest { public: - ClickToCallBrowserTest() {} + ClickToCallBrowserTestBase() {} - ~ClickToCallBrowserTest() override {} + ~ClickToCallBrowserTestBase() override {} std::string GetTestPageURL() const override { return std::string(kTestPageURL); @@ -59,16 +60,26 @@ sharing_message.click_to_call_message().phone_number()); } + protected: + base::test::ScopedFeatureList feature_list_; + private: - DISALLOW_COPY_AND_ASSIGN(ClickToCallBrowserTest); + DISALLOW_COPY_AND_ASSIGN(ClickToCallBrowserTestBase); +}; + +class ClickToCallBrowserTest : public ClickToCallBrowserTestBase { + public: + ClickToCallBrowserTest() { + feature_list_.InitWithFeatures({kSharingDeviceRegistration, kClickToCallUI, + kClickToCallContextMenuForSelectedText}, + {}); + } }; // TODO(himanshujaju): Add UI checks. IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_TelLink_SingleDeviceAvailable) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); SetUpDevices(/*count=*/1); auto devices = sharing_service()->GetDeviceCandidates( @@ -93,9 +104,7 @@ } IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_NoDevicesAvailable) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); AwaitQuiescence(); std::unique_ptr<TestRenderViewContextMenu> menu = @@ -109,9 +118,7 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_DevicesAvailable_SyncTurnedOff) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); SetUpDevices(/*count=*/1); // Disable syncing preferences which is necessary for Sharing. GetSyncService(0)->GetUserSettings()->SetSelectedTypes(false, {}); @@ -128,9 +135,7 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_TelLink_MultipleDevicesAvailable) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); SetUpDevices(/*count=*/2); auto devices = sharing_service()->GetDeviceCandidates( @@ -166,9 +171,7 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_HighlightedText_MultipleDevicesAvailable) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); SetUpDevices(/*count=*/2); auto devices = sharing_service()->GetDeviceCandidates( @@ -205,11 +208,19 @@ } } +class ClickToCallBrowserTestWithContextMenuDisabled + : public ClickToCallBrowserTestBase { + public: + ClickToCallBrowserTestWithContextMenuDisabled() { + feature_list_.InitWithFeatures({kSharingDeviceRegistration, kClickToCallUI}, + {kClickToCallContextMenuForSelectedText}); + } +}; + IN_PROC_BROWSER_TEST_F( - ClickToCallBrowserTest, + ClickToCallBrowserTestWithContextMenuDisabled, ContextMenu_HighlightedText_DevicesAvailable_FeatureFlagOff) { - Init({kSharingDeviceRegistration, kClickToCallUI}, - {kClickToCallContextMenuForSelectedText}); + Init(); SetUpDevices(/*count=*/2); auto devices = sharing_service()->GetDeviceCandidates( @@ -228,9 +239,7 @@ } IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_UKM) { - Init({kSharingDeviceRegistration, kClickToCallUI, - kClickToCallContextMenuForSelectedText}, - {}); + Init(); SetUpDevices(/*count=*/1); ukm::TestAutoSetUkmRecorder ukm_recorder; @@ -279,8 +288,17 @@ // TODO(knollr): mock apps and verify |has_apps| here too. } +class ClickToCallBrowserTestWithContextMenuFeatureDefault + : public ClickToCallBrowserTestBase { + public: + ClickToCallBrowserTestWithContextMenuFeatureDefault() { + feature_list_.InitWithFeatures({kSharingDeviceRegistration, kClickToCallUI}, + {}); + } +}; + IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, CloseTabWithBubble) { - Init({kSharingDeviceRegistration, kClickToCallUI}, {}); + Init(); SetUpDevices(/*count=*/1); base::RunLoop run_loop;
diff --git a/chrome/browser/sharing/sharing_browsertest.cc b/chrome/browser/sharing/sharing_browsertest.cc index 483005b5..ab0fa6ce 100644 --- a/chrome/browser/sharing/sharing_browsertest.cc +++ b/chrome/browser/sharing/sharing_browsertest.cc
@@ -32,11 +32,7 @@ host_resolver()->AddRule("mock.http", "127.0.0.1"); } -void SharingBrowserTest::Init( - const std::vector<base::Feature>& enabled_features, - const std::vector<base::Feature>& disabled_features) { - scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); - +void SharingBrowserTest::Init() { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/sharing/sharing_browsertest.h b/chrome/browser/sharing/sharing_browsertest.h index 661425b..0f1d3b7a 100644 --- a/chrome/browser/sharing/sharing_browsertest.h +++ b/chrome/browser/sharing/sharing_browsertest.h
@@ -9,7 +9,6 @@ #include <string> #include "base/macros.h" -#include "base/test/scoped_feature_list.h" #include "chrome/browser/gcm/gcm_profile_service_factory.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" #include "chrome/browser/sharing/sharing_service.h" @@ -28,8 +27,7 @@ void SetUpOnMainThread() override; - void Init(const std::vector<base::Feature>& enabled_features, - const std::vector<base::Feature>& disabled_features); + void Init(); virtual std::string GetTestPageURL() const = 0; @@ -52,7 +50,6 @@ private: gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller scoped_testing_factory_installer_; - base::test::ScopedFeatureList scoped_feature_list_; gcm::FakeGCMProfileService* gcm_service_; content::WebContents* web_contents_; syncer::FakeDeviceInfoTracker fake_device_info_tracker_;
diff --git a/chrome/browser/subresource_filter/ruleset_browsertest.cc b/chrome/browser/subresource_filter/ruleset_browsertest.cc index d84ba9a2..7e045c3 100644 --- a/chrome/browser/subresource_filter/ruleset_browsertest.cc +++ b/chrome/browser/subresource_filter/ruleset_browsertest.cc
@@ -186,23 +186,41 @@ 1); } -IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, LazyRulesetValidation) { +class SubresourceFilterBrowserTestWithoutAdTagging + : public SubresourceFilterBrowserTest { + public: + SubresourceFilterBrowserTestWithoutAdTagging() { + feature_list_.InitAndDisableFeature(subresource_filter::kAdTagging); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTestWithoutAdTagging, + LazyRulesetValidation) { // The ruleset shouldn't be validated until it's used, unless ad tagging is // enabled. - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(subresource_filter::kAdTagging); SetRulesetToDisallowURLsWithPathSuffix("included_script.js"); RulesetVerificationStatus dealer_status = GetRulesetVerification(); EXPECT_EQ(RulesetVerificationStatus::kNotVerified, dealer_status); } -IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, +class SubresourceFilterBrowserTestWithAdTagging + : public SubresourceFilterBrowserTest { + public: + SubresourceFilterBrowserTestWithAdTagging() { + feature_list_.InitAndEnableFeature(subresource_filter::kAdTagging); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTestWithAdTagging, AdsTaggingImmediateRulesetValidation) { // When Ads Tagging is enabled, the ruleset should be validated as soon as // it's published. - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(subresource_filter::kAdTagging); - SetRulesetToDisallowURLsWithPathSuffix("included_script.js"); RulesetVerificationStatus dealer_status = GetRulesetVerification(); EXPECT_EQ(RulesetVerificationStatus::kIntact, dealer_status);
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc index e13250d..5b3bf3f 100644 --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -724,11 +724,20 @@ tester, true /* expect_performance_measurements */); } -IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, +class SubresourceFilterBrowserTestWithoutAdTagging + : public SubresourceFilterBrowserTest { + public: + SubresourceFilterBrowserTestWithoutAdTagging() { + feature_list_.InitAndDisableFeature(kAdTagging); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// This test only makes sense when AdTagging is disabled. +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTestWithoutAdTagging, ExpectHistogramsNotRecordedWhenFilteringNotActivated) { - // This test only makes sense when AdTagging is disabled. - base::test::ScopedFeatureList scoped_tagging; - scoped_tagging.InitAndDisableFeature(kAdTagging); ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix( "suffix-that-does-not-match-anything")); ResetConfigurationToEnableOnPhishingSites(true /* measure_performance */);
diff --git a/chrome/browser/subresource_filter/subresource_filter_devtools_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_devtools_browsertest.cc index c40ccc3..07e33f6 100644 --- a/chrome/browser/subresource_filter/subresource_filter_devtools_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_devtools_browsertest.cc
@@ -153,14 +153,22 @@ console_observer.Wait(); } +class SubresourceFilterDevtoolsBrowserTestWithSitePerProcess + : public SubresourceFilterDevtoolsBrowserTest { + public: + SubresourceFilterDevtoolsBrowserTestWithSitePerProcess() { + feature_list_.InitAndEnableFeature(features::kSitePerProcess); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // See crbug.com/813197, where agent hosts from subframes could send messages to // disable ad blocking when they are detached (e.g. when the subframe goes // away). -IN_PROC_BROWSER_TEST_F(SubresourceFilterDevtoolsBrowserTest, +IN_PROC_BROWSER_TEST_F(SubresourceFilterDevtoolsBrowserTestWithSitePerProcess, IsolatedSubframe_DoesNotSendAdBlockingMessages) { - base::test::ScopedFeatureList scoped_isolation; - scoped_isolation.InitAndEnableFeature(features::kSitePerProcess); - ASSERT_NO_FATAL_FAILURE( SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); ScopedDevtoolsOpener page_opener(web_contents());
diff --git a/chrome/browser/subresource_filter/subresource_filter_intercepting_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_intercepting_browsertest.cc index ae2df5d..72f54b9 100644 --- a/chrome/browser/subresource_filter/subresource_filter_intercepting_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_intercepting_browsertest.cc
@@ -176,14 +176,24 @@ EXPECT_GE(timer.Elapsed(), delay); } +class SubresourceFilterInterceptingBrowserTestConsiderRedirects + : public SubresourceFilterInterceptingBrowserTest { + public: + SubresourceFilterInterceptingBrowserTestConsiderRedirects() { + feature_list_.InitAndEnableFeature( + kSafeBrowsingSubresourceFilterConsiderRedirects); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Verify that the correct safebrowsing result is reported when there is a // redirect chain. With kSafeBrowsingSubresourceFilterConsiderRedirects, the // result with the highest priority should be returned. -IN_PROC_BROWSER_TEST_F(SubresourceFilterInterceptingBrowserTest, - SafeBrowsingNotificationsCheckBest) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - kSafeBrowsingSubresourceFilterConsiderRedirects); +IN_PROC_BROWSER_TEST_F( + SubresourceFilterInterceptingBrowserTestConsiderRedirects, + SafeBrowsingNotificationsCheckBest) { ASSERT_NO_FATAL_FAILURE( SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); GURL redirect_url(embedded_test_server()->GetURL( @@ -194,14 +204,24 @@ EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame())); } +class SubresourceFilterInterceptingBrowserTestDontConsiderRedirects + : public SubresourceFilterInterceptingBrowserTest { + public: + SubresourceFilterInterceptingBrowserTestDontConsiderRedirects() { + feature_list_.InitAndDisableFeature( + kSafeBrowsingSubresourceFilterConsiderRedirects); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Verify that the correct safebrowsing result is reported when there is a // redirect chain. Without kSafeBrowsingSubresourceFilterConsiderRedirects, the // last result should be used. -IN_PROC_BROWSER_TEST_F(SubresourceFilterInterceptingBrowserTest, - SafeBrowsingNotificationsCheckLastResult) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - kSafeBrowsingSubresourceFilterConsiderRedirects); +IN_PROC_BROWSER_TEST_F( + SubresourceFilterInterceptingBrowserTestDontConsiderRedirects, + SafeBrowsingNotificationsCheckLastResult) { ASSERT_NO_FATAL_FAILURE( SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); GURL redirect_url(embedded_test_server()->GetURL(
diff --git a/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc index 16e90556..0f7433d 100644 --- a/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc
@@ -94,9 +94,7 @@ // Tests that subresource_filter interacts well with the abusive enforcement in // chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker. class SubresourceFilterPopupBrowserTest - : public SubresourceFilterListInsertingBrowserTest, - public ::testing::WithParamInterface< - bool /* enable_adblock_on_abusive_sites */> { + : public SubresourceFilterListInsertingBrowserTest { public: void SetUpOnMainThread() override { SubresourceFilterBrowserTest::SetUpOnMainThread(); @@ -169,13 +167,24 @@ embedded_test_server()->GetURL("/title1.html")); } -IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTest, +class SubresourceFilterPopupBrowserTestWithParam + : public SubresourceFilterPopupBrowserTest, + public ::testing::WithParamInterface< + bool /* enable_adblock_on_abusive_sites */> { + public: + SubresourceFilterPopupBrowserTestWithParam() { + const bool enable_adblock_on_abusive_sites = GetParam(); + feature_list_.InitWithFeatureState( + subresource_filter::kFilterAdsOnAbusiveSites, + enable_adblock_on_abusive_sites); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTestWithParam, BlockCreatingNewWindows) { - bool enable_adblock_on_abusive_sites = GetParam(); - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureState( - subresource_filter::kFilterAdsOnAbusiveSites, - enable_adblock_on_abusive_sites); base::HistogramTester tester; const char kWindowOpenPath[] = "/subresource_filter/window_open.html"; GURL a_url(embedded_test_server()->GetURL("a.com", kWindowOpenPath)); @@ -203,6 +212,7 @@ &opened_window)); EXPECT_FALSE(opened_window); + const bool enable_adblock_on_abusive_sites = GetParam(); EXPECT_EQ(enable_adblock_on_abusive_sites, AreDisallowedRequestsBlocked()); // Navigate to |b_url|, which should successfully open the popup. @@ -331,12 +341,8 @@ web_contents(), {kActivationConsoleMessage}, {kAbusiveEnforceMessage}); } -IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTest, BlockOpenURLFromTab) { - bool enable_adblock_on_abusive_sites = GetParam(); - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureState( - subresource_filter::kFilterAdsOnAbusiveSites, - enable_adblock_on_abusive_sites); +IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTestWithParam, + BlockOpenURLFromTab) { base::HistogramTester tester; const char kWindowOpenPath[] = "/subresource_filter/window_open_spoof_click.html"; @@ -356,6 +362,7 @@ EXPECT_TRUE(TabSpecificContentSettings::FromWebContents(web_contents) ->IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS)); + const bool enable_adblock_on_abusive_sites = GetParam(); EXPECT_EQ(enable_adblock_on_abusive_sites, AreDisallowedRequestsBlocked()); // Navigate to |b_url|, which should successfully open the popup. @@ -373,13 +380,8 @@ EXPECT_FALSE(AreDisallowedRequestsBlocked()); } -IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTest, +IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTestWithParam, BlockOpenURLFromTabInIframe) { - bool enable_adblock_on_abusive_sites = GetParam(); - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureState( - subresource_filter::kFilterAdsOnAbusiveSites, - enable_adblock_on_abusive_sites); const char popup_path[] = "/subresource_filter/iframe_spoof_click_popup.html"; GURL a_url(embedded_test_server()->GetURL("a.com", popup_path)); ConfigureAsAbusiveAndBetterAds( @@ -396,16 +398,12 @@ EXPECT_TRUE(sent_open); EXPECT_TRUE(TabSpecificContentSettings::FromWebContents(web_contents) ->IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS)); + const bool enable_adblock_on_abusive_sites = GetParam(); EXPECT_EQ(enable_adblock_on_abusive_sites, AreDisallowedRequestsBlocked()); } -IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTest, +IN_PROC_BROWSER_TEST_P(SubresourceFilterPopupBrowserTestWithParam, TraditionalWindowOpen_NotBlocked) { - bool enable_adblock_on_abusive_sites = GetParam(); - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureState( - subresource_filter::kFilterAdsOnAbusiveSites, - enable_adblock_on_abusive_sites); GURL url(GetTestUrl("/title2.html")); ConfigureAsAbusiveAndBetterAds( url, SubresourceFilterLevel::ENFORCE /* abusive_level */, @@ -422,11 +420,12 @@ browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents) ->IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS)); + const bool enable_adblock_on_abusive_sites = GetParam(); EXPECT_EQ(enable_adblock_on_abusive_sites, AreDisallowedRequestsBlocked()); } INSTANTIATE_TEST_SUITE_P(/* no prefix */, - SubresourceFilterPopupBrowserTest, + SubresourceFilterPopupBrowserTestWithParam, ::testing::Values(false, true)); } // namespace subresource_filter
diff --git a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc index 9dc97528..34b0ca23 100644 --- a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
@@ -46,29 +46,6 @@ EXPECT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage)); } -// This test simply verifies that preferences registered after sync started -// get properly synced. -IN_PROC_BROWSER_TEST_F(SingleClientPreferencesSyncTest, LateRegistration) { - ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; - PrefRegistrySyncable* registry = GetRegistry(GetProfile(0)); - const std::string pref_name = "testing.my-test-preference"; - registry->WhitelistLateRegistrationPrefForSync(pref_name); - ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - registry->RegisterBooleanPref( - pref_name, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - // Verify the default is properly used. - EXPECT_TRUE(GetProfile(0)->GetPrefs()->GetBoolean(pref_name)); - // Now make a change and verify it gets uploaded. - GetProfile(0)->GetPrefs()->SetBoolean(pref_name, false); - ASSERT_FALSE(GetProfile(0)->GetPrefs()->GetBoolean(pref_name)); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - - GetRegistry(verifier()) - ->RegisterBooleanPref(pref_name, true, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - EXPECT_FALSE(BooleanPrefMatches(pref_name.c_str())); -} - // Flaky on Windows. https://crbug.com/930482 #if defined(OS_WIN) #define MAYBE_ShouldRemoveBadDataWhenRegistering \
diff --git a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc index ff307d4..c3f74e6a 100644 --- a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
@@ -222,47 +222,6 @@ DISALLOW_COPY_AND_ASSIGN(TwoClientPreferencesSyncTestWithSelfNotifications); }; -// Tests that late registered prefs are kept in sync with other clients. -IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTestWithSelfNotifications, - E2E_ENABLED(LateRegisteredPrefsShouldSync)) { - ResetSyncForPrimaryAccount(); - // client0 has the pref registered before sync and is modifying a pref before - // that pref got registered with client1 (but after client1 started syncing). - ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; - - constexpr char pref_name[] = "testing.my-test-preference"; - GetRegistry(GetProfile(0)) - ->RegisterBooleanPref(pref_name, false, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - GetRegistry(GetProfile(1)) - ->WhitelistLateRegistrationPrefForSync("testing.my-test-preference"); - - ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - - ASSERT_THAT(GetPrefs(0)->GetBoolean(pref_name), Eq(false)); - ChangeBooleanPref(0, pref_name); - ASSERT_THAT(GetPrefs(0)->GetBoolean(pref_name), Eq(true)); - GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)); - - // Now register the pref and verify it's up-to-date. - GetRegistry(GetProfile(1)) - ->RegisterBooleanPref(pref_name, false, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - EXPECT_THAT(GetPrefs(1)->GetBoolean(pref_name), Eq(true)); - - // Make sure that subsequent changes are synced. - ChangeBooleanPref(0, pref_name); - ASSERT_THAT(GetPrefs(0)->GetBoolean(pref_name), Eq(false)); - EXPECT_TRUE(BooleanPrefMatchChecker(pref_name).Wait()); - EXPECT_THAT(GetPrefs(1)->GetBoolean(pref_name), Eq(false)); - - // Make sure that subsequent changes are synced. - ChangeBooleanPref(1, pref_name); - ASSERT_THAT(GetPrefs(1)->GetBoolean(pref_name), Eq(true)); - EXPECT_TRUE(BooleanPrefMatchChecker(pref_name).Wait()); - EXPECT_THAT(GetPrefs(0)->GetBoolean(pref_name), Eq(true)); -} - IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTestWithSelfNotifications, E2E_ENABLED(ShouldKeepLocalDataOnTypeMismatch)) { ResetSyncForPrimaryAccount(); @@ -276,8 +235,6 @@ GetRegistry(GetProfile(0)) ->RegisterBooleanPref(pref_name, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - GetRegistry(GetProfile(1)) - ->WhitelistLateRegistrationPrefForSync("testing.my-test-preference"); ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ChangeBooleanPref(0, pref_name);
diff --git a/chrome/browser/touch_to_fill/android/BUILD.gn b/chrome/browser/touch_to_fill/android/BUILD.gn index 30e485b..c449988 100644 --- a/chrome/browser/touch_to_fill/android/BUILD.gn +++ b/chrome/browser/touch_to_fill/android/BUILD.gn
@@ -15,6 +15,7 @@ deps = [ ":jni_headers", + "//ui/gfx", ] }
diff --git a/chrome/browser/touch_to_fill/android/internal/BUILD.gn b/chrome/browser/touch_to_fill/android/internal/BUILD.gn index 7792ea5..4b27588d 100644 --- a/chrome/browser/touch_to_fill/android/internal/BUILD.gn +++ b/chrome/browser/touch_to_fill/android/internal/BUILD.gn
@@ -17,14 +17,13 @@ ] java_files = [ + "java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java", "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java", - "java/src/org/chromium/chrome/browser/touch_to_fill/helper/ListViewAdapter.java", - "java/src/org/chromium/chrome/browser/touch_to_fill/helper/SimpleListViewMcp.java", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml index af57e8a5..1180edf6 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
@@ -15,16 +15,15 @@ <ImageView android:id="@+id/favicon" - android:layout_width="24dp" - android:layout_height="24dp" + android:layout_width="@dimen/touch_to_fill_favicon_size" + android:layout_height="@dimen/touch_to_fill_favicon_size" android:layout_marginStart="12dp" android:importantForAccessibility="no" android:layout_gravity="center"/> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_margin="6dp" - android:layout_marginStart="12dp" + android:layout_margin="12dp" android:layout_weight="1" android:orientation="vertical"> <TextView
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml b/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml new file mode 100644 index 0000000..d41f1d4 --- /dev/null +++ b/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml
@@ -0,0 +1,8 @@ +<?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. --> + +<resources> + <dimen name="touch_to_fill_favicon_size">24dp</dimen> +</resources>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java new file mode 100644 index 0000000..3fdcb98 --- /dev/null +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.touch_to_fill; + +import android.graphics.Bitmap; + +import org.chromium.chrome.browser.touch_to_fill.data.Credential; +import org.chromium.ui.modelutil.PropertyModel; + +/** + * Properties for a credential entry in TouchToFill sheet. + */ +class CredentialProperties { + static final int DEFAULT_ITEM_TYPE = 0; // Credential list has only one entry type. + + static final PropertyModel.WritableObjectPropertyKey<Bitmap> FAVICON = + new PropertyModel.WritableObjectPropertyKey<>("favicon"); + static final PropertyModel.WritableObjectPropertyKey<Credential> CREDENTIAL = + new PropertyModel.WritableObjectPropertyKey<>("credential"); +}
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java index 3609eddc..0a9fa5a 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java
@@ -4,6 +4,11 @@ package org.chromium.chrome.browser.touch_to_fill; +import android.graphics.Bitmap; + +import androidx.annotation.Px; + +import org.chromium.base.Callback; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.browser.ChromeActivity; @@ -68,9 +73,17 @@ TouchToFillBridgeJni.get().onCredentialSelected(mNativeView, credential); } + @Override + public void fetchFavicon(String origin, @Px int desiredSize, Callback<Bitmap> callback) { + assert mNativeView != 0 : "Favicon was requested after the bridge was destroyed!"; + TouchToFillBridgeJni.get().fetchFavicon(mNativeView, origin, desiredSize, callback); + } + @NativeMethods interface Natives { void onCredentialSelected(long nativeTouchToFillViewImpl, Credential credential); void onDismiss(long nativeTouchToFillViewImpl); + void fetchFavicon(long nativeTouchToFillViewImpl, String origin, int desiredSizeInPx, + Callback<Bitmap> callback); } }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java index 9236cda..de759c5 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java
@@ -4,14 +4,10 @@ package org.chromium.chrome.browser.touch_to_fill; -import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST; - import android.content.Context; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.touch_to_fill.data.Credential; -import org.chromium.chrome.browser.touch_to_fill.helper.ListViewAdapter; -import org.chromium.chrome.browser.touch_to_fill.helper.SimpleListViewMcp; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; @@ -29,7 +25,8 @@ @Override public void initialize(Context context, BottomSheetController sheetController, TouchToFillComponent.Delegate delegate) { - mMediator.initialize(delegate, mModel); + mMediator.initialize(delegate, mModel, + context.getResources().getDimensionPixelSize(R.dimen.touch_to_fill_favicon_size)); setUpModelChangeProcessors(mModel, new TouchToFillView(context, sheetController)); } @@ -46,10 +43,7 @@ */ @VisibleForTesting static void setUpModelChangeProcessors(PropertyModel model, TouchToFillView view) { - PropertyModelChangeProcessor.create(model, view, TouchToFillViewBinder::bind); - view.setCredentialListAdapter( - new ListViewAdapter<>(new SimpleListViewMcp<>(model.get(CREDENTIAL_LIST), - TouchToFillViewBinder::bindCredentialView), - TouchToFillViewBinder::createCredentialView)); + PropertyModelChangeProcessor.create( + model, view, TouchToFillViewBinder::bindTouchToFillView); } }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java index ccc945ff..af73205 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
@@ -4,12 +4,19 @@ package org.chromium.chrome.browser.touch_to_fill; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.CREDENTIAL; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.FAVICON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE; +import androidx.annotation.Px; + import org.chromium.chrome.browser.touch_to_fill.data.Credential; +import org.chromium.ui.modelutil.MVCListAdapter; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; import java.util.List; @@ -21,11 +28,14 @@ class TouchToFillMediator implements TouchToFillProperties.ViewEventListener { private TouchToFillComponent.Delegate mDelegate; private PropertyModel mModel; + private @Px int mDesiredFaviconSize; - void initialize(TouchToFillComponent.Delegate delegate, PropertyModel model) { + void initialize(TouchToFillComponent.Delegate delegate, PropertyModel model, + @Px int desiredFaviconSize) { assert delegate != null; mDelegate = delegate; mModel = model; + mDesiredFaviconSize = desiredFaviconSize; } void showCredentials( @@ -34,15 +44,26 @@ mModel.set(FORMATTED_URL, formattedUrl); mModel.set(ORIGIN_SECURE, isOriginSecure); mModel.set(VISIBLE, true); - mModel.get(CREDENTIAL_LIST).clear(); - mModel.get(CREDENTIAL_LIST).addAll(credentials); + + ModelList credentialList = mModel.get(CREDENTIAL_LIST); + credentialList.clear(); + for (Credential credential : credentials) { + PropertyModel propertyModel = new PropertyModel.Builder(FAVICON, CREDENTIAL) + .with(FAVICON, null) + .with(CREDENTIAL, credential) + .build(); + credentialList.add(new MVCListAdapter.ListItem(DEFAULT_ITEM_TYPE, propertyModel)); + mDelegate.fetchFavicon(credential.getOriginUrl(), mDesiredFaviconSize, + (bitmap) -> propertyModel.set(FAVICON, bitmap)); + } } @Override public void onSelectItemAt(int position) { - assert position >= 0 && position < mModel.get(CREDENTIAL_LIST).size(); + ModelList credentialList = mModel.get(CREDENTIAL_LIST); + assert position >= 0 && position < credentialList.size(); mModel.set(VISIBLE, false); - mDelegate.onCredentialSelected(mModel.get(CREDENTIAL_LIST).get(position)); + mDelegate.onCredentialSelected(credentialList.get(position).model.get(CREDENTIAL)); } @Override
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java index 4a132dbf..a52ca84 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java
@@ -4,8 +4,7 @@ package org.chromium.chrome.browser.touch_to_fill; -import org.chromium.chrome.browser.touch_to_fill.data.Credential; -import org.chromium.ui.modelutil.ListModel; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; /** @@ -18,7 +17,7 @@ new PropertyModel.WritableObjectPropertyKey<>("formatted_url"); static final PropertyModel.WritableBooleanPropertyKey ORIGIN_SECURE = new PropertyModel.WritableBooleanPropertyKey("origin_secure"); - static final PropertyModel.ReadableObjectPropertyKey<ListModel<Credential>> CREDENTIAL_LIST = + static final PropertyModel.ReadableObjectPropertyKey<ModelList> CREDENTIAL_LIST = new PropertyModel.ReadableObjectPropertyKey<>("credential_list"); static final PropertyModel.ReadableObjectPropertyKey<ViewEventListener> VIEW_EVENT_LISTENER = new PropertyModel.ReadableObjectPropertyKey<>("view_event_listener"); @@ -29,7 +28,7 @@ VISIBLE, FORMATTED_URL, ORIGIN_SECURE, CREDENTIAL_LIST, VIEW_EVENT_LISTENER) .with(VISIBLE, false) .with(ORIGIN_SECURE, false) - .with(CREDENTIAL_LIST, new ListModel<>()) + .with(CREDENTIAL_LIST, new ModelList()) .with(VIEW_EVENT_LISTENER, listener) .build(); }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java index 22c75c4..3258329 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java
@@ -39,13 +39,6 @@ mEventListener.onDismissed(); mBottomSheetController.getBottomSheet().removeObserver(mBottomSheetObserver); } - - @Override - public void onSheetFullyPeeked() { - super.onSheetFullyPeeked(); - // Since isPeekStateEnabled doesn't seem to skip the Peek state, force-expand the sheet. - mBottomSheetController.expandSheet(); - } }; /** @@ -107,6 +100,10 @@ mCredentialListView.setAdapter(adapter); } + Context getContext() { + return mContext; + } + private void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { assert adapterView == mCredentialListView : "Use this click handler only for credentials!"; assert mEventListener != null; @@ -150,8 +147,8 @@ } @Override - public boolean isPeekStateEnabled() { - return true; // For some reason, false isn't working properly. Extend it explicitly! + public int getPeekHeight() { + return BottomSheet.HeightMode.DISABLED; } @Override
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java index 9c4ab49..4e84d94 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
@@ -11,13 +11,16 @@ import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE; import static org.chromium.chrome.browser.util.UrlUtilities.stripScheme; +import android.content.Context; import android.text.method.PasswordTransformationMethod; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import org.chromium.chrome.browser.touch_to_fill.data.Credential; +import org.chromium.ui.modelutil.ModelListAdapter; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -30,31 +33,43 @@ * Factory used to create a new View inside the ListView inside the TouchToFillView. * @param parent The parent {@link ViewGroup} of the new item. */ - static View createCredentialView(ViewGroup parent) { - return LayoutInflater.from(parent.getContext()) - .inflate(R.layout.touch_to_fill_credential_item, parent, false); + static View createCredentialView(Context context) { + return LayoutInflater.from(context).inflate( + R.layout.touch_to_fill_credential_item, null, false); } /** * Called whenever a credential is bound to this view holder. Please note that this method * might be called on the same list entry repeatedly, so make sure to always set a default for * unused fields. - * @param view The view to be bound. - * @param credential The {@link Credential} whose data needs to be displayed. + * @param model The model containing the data for the view + * @param view The view to be bound + * @param propertyKey The key of the property to be bound */ - static void bindCredentialView(View view, Credential credential) { - TextView pslOriginText = view.findViewById(R.id.credential_origin); - String formattedOrigin = stripScheme(credential.getOriginUrl()); - formattedOrigin = formattedOrigin.replaceFirst("/$", ""); // Strip possibly trailing slash. - pslOriginText.setText(formattedOrigin); - pslOriginText.setVisibility(credential.isPublicSuffixMatch() ? View.VISIBLE : View.GONE); + static void bindCredentialView(PropertyModel model, View view, PropertyKey propertyKey) { + if (propertyKey == CredentialProperties.FAVICON) { + ImageView imageView = view.findViewById(R.id.favicon); + imageView.setImageBitmap(model.get(CredentialProperties.FAVICON)); + } else if (propertyKey == CredentialProperties.CREDENTIAL) { + Credential credential = model.get(CredentialProperties.CREDENTIAL); - TextView usernameText = view.findViewById(R.id.username); - usernameText.setText(credential.getFormattedUsername()); + TextView pslOriginText = view.findViewById(R.id.credential_origin); + String formattedOrigin = stripScheme(credential.getOriginUrl()); + formattedOrigin = + formattedOrigin.replaceFirst("/$", ""); // Strip possibly trailing slash. + pslOriginText.setText(formattedOrigin); + pslOriginText.setVisibility( + credential.isPublicSuffixMatch() ? View.VISIBLE : View.GONE); - TextView passwordText = view.findViewById(R.id.password); - passwordText.setText(credential.getPassword()); - passwordText.setTransformationMethod(new PasswordTransformationMethod()); + TextView usernameText = view.findViewById(R.id.username); + usernameText.setText(credential.getFormattedUsername()); + + TextView passwordText = view.findViewById(R.id.password); + passwordText.setText(credential.getPassword()); + passwordText.setTransformationMethod(new PasswordTransformationMethod()); + } else { + assert false : "Every possible property update needs to be handled!"; + } } /** @@ -63,7 +78,8 @@ * @param view The {@link TouchToFillView} to update. * @param propertyKey The {@link PropertyKey} which changed. */ - static void bind(PropertyModel model, TouchToFillView view, PropertyKey propertyKey) { + static void bindTouchToFillView( + PropertyModel model, TouchToFillView view, PropertyKey propertyKey) { if (propertyKey == VIEW_EVENT_LISTENER) { view.setEventListener(model.get(VIEW_EVENT_LISTENER)); } else if (propertyKey == VISIBLE) { @@ -75,7 +91,11 @@ view.setNonSecureSubtitle(model.get(FORMATTED_URL)); } } else if (propertyKey == CREDENTIAL_LIST) { - // No binding required. Single items are bound via bindCredentialView. + ModelListAdapter adapter = new ModelListAdapter(model.get(CREDENTIAL_LIST)); + adapter.registerType(CredentialProperties.DEFAULT_ITEM_TYPE, + () -> TouchToFillViewBinder.createCredentialView(view.getContext()), + TouchToFillViewBinder::bindCredentialView); + view.setCredentialListAdapter(adapter); } else { assert false : "Every possible property update needs to be handled!"; }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/ListViewAdapter.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/ListViewAdapter.java deleted file mode 100644 index ae745a1c..0000000 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/ListViewAdapter.java +++ /dev/null
@@ -1,170 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.touch_to_fill.helper; - -import android.database.DataSetObserver; -import android.support.annotation.Nullable; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListAdapter; - -import org.chromium.ui.modelutil.ListObservable; - -import java.util.HashSet; -import java.util.Set; - -/** - * This Adapter creates Views of type {@link V} for a {@link android.widget.ListView} and binds - * items of type {@link T} to each of the created views. It defers most tasks to a {@link Delegate}. - * - * Construct with a {@link SimpleListViewMcp} to update a ListView according to a list model. - * - * @param <T> The item type inside the observed list. It's passed to the {@link Delegate}. - * @param <V> The view type of a single list entry as created by the {@link ViewFactory}. - */ -public class ListViewAdapter<T, V extends View> - implements ListObservable.ListObserver<Void>, ListAdapter { - private final Delegate<T, V> mDelegate; - private final ViewFactory<V> mViewFactory; - private final Set<DataSetObserver> mObservers = new HashSet<>(); - - /** - * This delegates decouples the ListViewAdapter from the underlying model and handles all tasks - * for which the model might be necessary. - * @param <T> The item type inside the observed list. - * @param <V> The view type of a single list entry as created by the {@link ViewFactory}. - */ - public interface Delegate<T, V extends View> { - /** - * Returns the list item at the given position. - * @param pos The position inside the list to retrieve the item for. - * @return An item of type {@link T}. - */ - T getItemAt(int pos); - - /** - * @return The total number of items in the observed list. - */ - int getItemCount(); - - /** - * Binds the data of the given item to the given View. - * @param view A View inside the ListView of type {@link V}. - * @param item An Item inside the observed list of type {@link T}. - */ - void onBindView(V view, T item); - } - - /** - * Subclasses of this interface create the View that represents an item in a ListView. - * @param <V> The type of {@link View} this factory creates. - */ - public interface ViewFactory<V extends View> { - /** - * Creates a View used in a ListView and attaches it to the given parent. - * @param parent The parent of the newly created View. - * @return A {@link View} that represents an item in a ListView. - */ - V create(ViewGroup parent); - } - - /** - * Creates a new ListViewAdapter. - * @param delegate The {@link Delegate} to bind views and query for list information. - * @param viewFactory The {@link ViewFactory} used to create new views for the ListView. - */ - public ListViewAdapter(Delegate<T, V> delegate, ViewFactory<V> viewFactory) { - mDelegate = delegate; - mViewFactory = viewFactory; - } - - @Override - public void onItemMoved(ListObservable source, int curIndex, int newIndex) { - notifyObserversChanged(); - } - - @Override - public void onItemRangeChanged( - ListObservable source, int index, int count, @Nullable Void payload) { - notifyObserversChanged(); - } - - @Override - public void onItemRangeInserted(ListObservable source, int index, int count) { - notifyObserversChanged(); - } - - @Override - public void onItemRangeRemoved(ListObservable source, int index, int count) { - notifyObserversChanged(); - } - - private void notifyObserversChanged() { - for (DataSetObserver observer : mObservers) observer.onChanged(); - } - - @Override - public void registerDataSetObserver(DataSetObserver dataSetObserver) { - mObservers.add(dataSetObserver); - } - - @Override - public void unregisterDataSetObserver(DataSetObserver dataSetObserver) { - mObservers.remove(dataSetObserver); - } - - @Override - public int getCount() { - return mDelegate.getItemCount(); - } - - @Override - public Object getItem(int i) { - return mDelegate.getItemAt(i); - } - - @Override - public long getItemId(int i) { - return i; - } - - @Override - public boolean hasStableIds() { - return false; - } - - @Override - @SuppressWarnings("unchecked") - public View getView(int pos, View view, ViewGroup parent) { - if (view == null) view = mViewFactory.create(parent); - mDelegate.onBindView((V) view, mDelegate.getItemAt(pos)); - return view; - } - - @Override - public int getItemViewType(int i) { - return 0; // Always the same view type. - } - - @Override - public int getViewTypeCount() { - return 1; // Always the same view type. - } - - @Override - public boolean isEmpty() { - return mDelegate.getItemCount() == 0; - } - - @Override - public boolean areAllItemsEnabled() { - return true; // There are no disabled items yet. - } - - @Override - public boolean isEnabled(int i) { - return true; // There are no disabled items yet. - } -}
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/SimpleListViewMcp.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/SimpleListViewMcp.java deleted file mode 100644 index 0bbfccc..0000000 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/helper/SimpleListViewMcp.java +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.touch_to_fill.helper; - -import android.view.View; - -import org.chromium.ui.modelutil.ForwardingListObservable; -import org.chromium.ui.modelutil.ListModel; - -// TODO(fhorschig): Ask org.chromium.ui.modelutil OWNERS whether this should be shared. -/** - * Observes a {@link ListModel} and forwards any changes. It implements the - * {@link ListViewAdapter.Delegate} so it can be used to bind views as needed by a - * {@link android.widget.ListView} that ends up displaying the observed Entries. - * - * @param <T> The item type inside the passed ListModel. It's passed to the {@link ViewBinder}. - * @param <V> The view type of a single list entry. - */ -public class SimpleListViewMcp<T, V extends View> - extends ForwardingListObservable<Void> implements ListViewAdapter.Delegate<T, V> { - private final ListModel<T> mModel; - private final ViewBinder<T, V> mViewBinder; - - /** - * Subclasses of this interface bind a given item to a given view. - * @param <T> The item type of a list entry. - * @param <V> The view type of a single list entry. - */ - public interface ViewBinder<T, V extends View> { - /** - * Binds a given item to a given view. That means, the item properties are mapped to view - * properties. No logic should happen in here. - * @param view The view that holds the data of a list entry. - * @param item The item describing a single list entry. - */ - void bind(V view, T item); - } - - /** - * This creates a new Model Change Processor that observes the given model. - * @param model The {@Link ListModel} to be observed. - * @param viewBinder The {@link ViewBinder} used to bind items to views inside the ListView. - */ - public SimpleListViewMcp(ListModel<T> model, ViewBinder<T, V> viewBinder) { - mModel = model; - mViewBinder = viewBinder; - model.addObserver(this); - } - - @Override - public void onBindView(V view, T item) { - mViewBinder.bind(view, item); - } - - @Override - public T getItemAt(int pos) { - return mModel.get(pos); - } - - @Override - public int getItemCount() { - return mModel.size(); - } -} \ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java index 3445d58..bc8d0ce 100644 --- a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java +++ b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java
@@ -5,7 +5,11 @@ package org.chromium.chrome.browser.touch_to_fill; import android.content.Context; +import android.graphics.Bitmap; +import androidx.annotation.Px; + +import org.chromium.base.Callback; import org.chromium.chrome.browser.touch_to_fill.data.Credential; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; @@ -31,6 +35,11 @@ * selected. */ void onDismissed(); + + /** + * Called to fetch a favicon for one origin to display it in the UI. + */ + void fetchFavicon(String origin, @Px int desiredSize, Callback<Bitmap> callback); } /**
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java index b64ab2be..9bdd577 100644 --- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java +++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -11,6 +11,9 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.CREDENTIAL; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.FAVICON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE; @@ -41,10 +44,9 @@ import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TouchCommon; +import org.chromium.ui.modelutil.MVCListAdapter; import org.chromium.ui.modelutil.PropertyModel; -import java.util.Arrays; - /** * View tests for the Touch To Fill component ensure that model changes are reflected in the sheet. */ @@ -116,11 +118,12 @@ public void testCredentialsChangedByModel() { TestThreadUtils.runOnUiThreadBlocking(() -> { mTouchToFillView.setVisible(true); - mModel.get(CREDENTIAL_LIST) - .addAll(Arrays.asList(new Credential("Ana", "S3cr3t", "Ana", "", false), - new Credential("", "***", "No Username", "http://m.example.xyz/", true), - new Credential( - "Bob", "***", "Bob", "http://mobile.example.xyz", true))); + MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST); + credentialList.add(buildCredentialItem("Ana", "S3cr3t", "Ana", "", false)); + credentialList.add( + buildCredentialItem("", "***", "No Username", "http://m.example.xyz/", true)); + credentialList.add( + buildCredentialItem("Bob", "***", "Bob", "http://mobile.example.xyz", true)); }); pollUiThread(() -> getBottomSheetState() == SheetState.FULL); @@ -149,8 +152,9 @@ public void testCredentialsAreClickable() { TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(CREDENTIAL_LIST) - .addAll(Arrays.asList(new Credential("Carl", "G3h3!m", "Carl", "", false), - new Credential("Bob", "***", "Bob", "m.example.xyz", true))); + .add(buildCredentialItem("Carl", "G3h3!m", "Carl", "", false)); + mModel.get(CREDENTIAL_LIST) + .add(buildCredentialItem("Bob", "***", "Bob", "m.example.xyz", true)); mModel.set(VISIBLE, true); }); pollUiThread(() -> getBottomSheetState() == SheetState.FULL); @@ -205,4 +209,16 @@ return verify(mMockListener, timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))); } + + private static MVCListAdapter.ListItem buildCredentialItem(String username, String password, + String formattedUsername, String originUrl, boolean isPublicSuffixMatch) { + PropertyModel propertyModel = + new PropertyModel.Builder(FAVICON, CREDENTIAL) + .with(FAVICON, null) + .with(CREDENTIAL, + new Credential(username, password, formattedUsername, originUrl, + isPublicSuffixMatch)) + .build(); + return new MVCListAdapter.ListItem(DEFAULT_ITEM_TYPE, propertyModel); + } }
diff --git a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java index 06f91dc..7b7c382e 100644 --- a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java +++ b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
@@ -8,22 +8,34 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VIEW_EVENT_LISTENER; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE; +import android.graphics.Bitmap; + +import androidx.annotation.Px; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.chromium.base.Callback; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.touch_to_fill.data.Credential; +import org.chromium.ui.modelutil.MVCListAdapter; import org.chromium.ui.modelutil.PropertyModel; import java.util.Arrays; @@ -36,15 +48,21 @@ @RunWith(BaseRobolectricTestRunner.class) public class TouchToFillControllerTest { private static final String TEST_URL = "www.example.xyz"; - private static final String TEST_MOBILE_URL = "www.example.xyz"; - private static final Credential ANA = new Credential("Ana", "S3cr3t", "Ana", "", false); + private static final String TEST_SUBDOMAIN_URL = "subdomain.example.xyz"; + private static final Credential ANA = new Credential("Ana", "S3cr3t", "Ana", TEST_URL, false); private static final Credential BOB = - new Credential("Bob", "*****", "Bob", TEST_MOBILE_URL, true); - private static final Credential CARL = new Credential("Carl", "G3h3!m", "Carl", "", false); + new Credential("Bob", "*****", "Bob", TEST_SUBDOMAIN_URL, true); + private static final Credential CARL = + new Credential("Carl", "G3h3!m", "Carl", TEST_URL, false); + private static final @Px int DESIRED_FAVICON_SIZE = 64; @Mock private TouchToFillComponent.Delegate mMockDelegate; + // Can't be local, as it has to be initialized by initMocks. + @Captor + private ArgumentCaptor<Callback<Bitmap>> mCallbackArgumentCaptor; + private final TouchToFillMediator mMediator = new TouchToFillMediator(); private final PropertyModel mModel = TouchToFillProperties.createDefaultModel(mMediator); @@ -54,7 +72,7 @@ @Before public void setUp() { - mMediator.initialize(mMockDelegate, mModel); + mMediator.initialize(mMockDelegate, mModel, DESIRED_FAVICON_SIZE); } @Test @@ -74,24 +92,65 @@ } @Test - public void testShowCredentialsSetsCredentialList() { + public void testShowCredentialsSetsCredentialListAndRequestsFavicons() { mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB)); - assertThat(mModel.get(CREDENTIAL_LIST).size(), is(3)); - assertThat(mModel.get(CREDENTIAL_LIST).get(0), is(ANA)); - assertThat(mModel.get(CREDENTIAL_LIST).get(1), is(CARL)); - assertThat(mModel.get(CREDENTIAL_LIST).get(2), is(BOB)); + MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST); + assertThat(credentialList.size(), is(3)); + // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList. + assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(ANA)); + assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue())); + assertThat(credentialList.get(1).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(1).model.get(CredentialProperties.CREDENTIAL), is(CARL)); + assertThat(credentialList.get(1).model.get(CredentialProperties.FAVICON), is(nullValue())); + assertThat(credentialList.get(2).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(2).model.get(CredentialProperties.CREDENTIAL), is(BOB)); + assertThat(credentialList.get(2).model.get(CredentialProperties.FAVICON), is(nullValue())); + + // ANA and CARL both have TEST_URL as their origin URL + verify(mMockDelegate, times(2)).fetchFavicon(eq(TEST_URL), eq(DESIRED_FAVICON_SIZE), any()); + verify(mMockDelegate).fetchFavicon(eq(BOB.getOriginUrl()), eq(DESIRED_FAVICON_SIZE), any()); + } + + @Test + public void testFetchFaviconUpdatesModel() { + mMediator.showCredentials(TEST_URL, true, Collections.singletonList(CARL)); + MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST); + assertThat(credentialList.size(), is(1)); + // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList. + assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(CARL)); + assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue())); + + // ANA and CARL both have TEST_URL as their origin URL + verify(mMockDelegate) + .fetchFavicon( + eq(TEST_URL), eq(DESIRED_FAVICON_SIZE), mCallbackArgumentCaptor.capture()); + Callback<Bitmap> callback = mCallbackArgumentCaptor.getValue(); + Bitmap bitmap = Bitmap.createBitmap( + DESIRED_FAVICON_SIZE, DESIRED_FAVICON_SIZE, Bitmap.Config.ARGB_8888); + callback.onResult(bitmap); + assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(bitmap)); } @Test public void testClearsCredentialListWhenShowingAgain() { mMediator.showCredentials(TEST_URL, true, Collections.singletonList(ANA)); - assertThat(mModel.get(CREDENTIAL_LIST).size(), is(1)); - assertThat(mModel.get(CREDENTIAL_LIST).get(0), is(ANA)); + MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST); + // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList. + assertThat(credentialList.size(), is(1)); + assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(ANA)); + assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue())); // Showing the sheet a second time should replace all changed credentials. mMediator.showCredentials(TEST_URL, true, Collections.singletonList(BOB)); - assertThat(mModel.get(CREDENTIAL_LIST).size(), is(1)); - assertThat(mModel.get(CREDENTIAL_LIST).get(0), is(BOB)); + credentialList = mModel.get(CREDENTIAL_LIST); + // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList. + assertThat(credentialList.size(), is(1)); + assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE)); + assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(BOB)); + assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue())); } @Test
diff --git a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc index 3448382..ebe7fe2 100644 --- a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc +++ b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/android/callback_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/macros.h" @@ -17,6 +18,8 @@ #include "components/password_manager/core/browser/origin_credential_store.h" #include "ui/android/view_android.h" #include "ui/android/window_android.h" +#include "ui/gfx/android/java_bitmap.h" +#include "ui/gfx/image/image.h" #include "url/gurl.h" using base::android::AttachCurrentThread; @@ -42,6 +45,15 @@ Java_Credential_isPublicSuffixMatch(env, credential))); } +void OnFaviconFetched( + const base::android::ScopedJavaGlobalRef<jobject>& j_callback, + const gfx::Image& image) { + base::android::ScopedJavaLocalRef<jobject> bitmap; + if (!image.IsEmpty()) + bitmap = gfx::ConvertToJavaBitmap(image.ToSkBitmap()); + base::android::RunObjectCallbackAndroid(j_callback, bitmap); +} + } // namespace TouchToFillViewImpl::TouchToFillViewImpl(TouchToFillController* controller) @@ -89,6 +101,17 @@ controller_->OnDismiss(); } +void TouchToFillViewImpl::FetchFavicon( + JNIEnv* env, + const JavaParamRef<jstring>& j_origin, + jint desized_size_in_pixel, + const JavaParamRef<jobject>& j_callback) { + controller_->FetchFavicon( + ConvertJavaStringToUTF8(env, j_origin), desized_size_in_pixel, + base::BindOnce(&OnFaviconFetched, + base::android::ScopedJavaGlobalRef<jobject>(j_callback))); +} + void TouchToFillViewImpl::OnCredentialSelected( JNIEnv* env, const JavaParamRef<jobject>& credential) {
diff --git a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h index 356770f..506b3d2 100644 --- a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h +++ b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h
@@ -9,6 +9,10 @@ #include "base/callback.h" #include "chrome/browser/touch_to_fill/touch_to_fill_view.h" +namespace gfx { +class Image; +} + class TouchToFillController; // This class provides an implementation of the TouchToFillView interface and @@ -28,6 +32,10 @@ void OnDismiss() override; // Called from Java via JNI: + void FetchFavicon(JNIEnv* env, + const base::android::JavaParamRef<jstring>& j_origin, + jint desized_size_in_pixel, + const base::android::JavaParamRef<jobject>& j_callback); void OnCredentialSelected( JNIEnv* env, const base::android::JavaParamRef<jobject>& credential);
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc index c627836..7ea0d59 100644 --- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc +++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -344,17 +344,24 @@ } // Browser Test for AppListClient that observes search result changes. -using AppListClientSearchResultsBrowserTest = extensions::ExtensionBrowserTest; +class AppListClientSearchResultsBrowserTest + : public extensions::ExtensionBrowserTest { + public: + AppListClientSearchResultsBrowserTest() { + // Zero state changes UI behavior. This test case tests the expected UI + // behavior with zero state being disabled. + // TODO(jennyz): write new test case for zero state, crbug.com/925195. + feature_list_.InitAndDisableFeature( + app_list_features::kEnableZeroStateSuggestions); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; // Test showing search results, and uninstalling one of them while displayed. IN_PROC_BROWSER_TEST_F(AppListClientSearchResultsBrowserTest, UninstallSearchResult) { - // Zero state changes UI behavior. This test case tests the expected UI - // behavior with zero state being disabled. - // TODO(jennyz): write new test case for zero state, crbug.com/925195. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - app_list_features::kEnableZeroStateSuggestions); ASSERT_FALSE(app_list_features::IsZeroStateSuggestionsEnabled()); base::FilePath test_extension_path;
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc index 2db8b2c8..d251fda 100644 --- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc +++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -203,11 +203,19 @@ settings->RemoveObserver(&observer); } -IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, - OpenOSSettingsAppFromArc) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); +class ChromeNewWindowClientBrowserTestWithSplitSettings + : public ChromeNewWindowClientBrowserTest { + public: + ChromeNewWindowClientBrowserTestWithSplitSettings() { + feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettings); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTestWithSplitSettings, + OpenOSSettingsAppFromArc) { // When flag is on, opening a browser setting should not open the OS setting // window. TestOpenSettingFromArc( @@ -222,12 +230,20 @@ /*expected_setting_window_count=*/1); } -// TODO(crbug/950007): This should be removed when the split is complete. -IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, - OpenSettingsAppFromArc) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(chromeos::features::kSplitSettings); +class ChromeNewWindowClientBrowserTestWithoutSplitSettings + : public ChromeNewWindowClientBrowserTest { + public: + ChromeNewWindowClientBrowserTestWithoutSplitSettings() { + feature_list_.InitAndDisableFeature(chromeos::features::kSplitSettings); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +// TODO(crbug/950007): This should be removed when the split is complete. +IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTestWithoutSplitSettings, + OpenSettingsAppFromArc) { // When flag is off, opening a browser setting should open the setting window. TestOpenSettingFromArc( browser(), ChromePage::AUTOFILL, @@ -336,11 +352,8 @@ TestOpenChromePage(ChromePage::ABOUTBLANK, GURL(url::kAboutBlankURL)); } -IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, +IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTestWithSplitSettings, TestOpenChromePageWithSplitFlagOn) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); - // Install the Settings App. web_app::WebAppProvider::Get(browser()->profile()) ->system_web_app_manager() @@ -352,11 +365,8 @@ } // TODO(crbug/950007): This should be removed when the split is complete. -IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, +IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTestWithoutSplitSettings, TestOpenChromePageWithSplitFlagOff) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(chromeos::features::kSplitSettings); - // Install the Settings App. web_app::WebAppProvider::Get(browser()->profile()) ->system_web_app_manager()
diff --git a/chrome/browser/ui/ash/overview_scroll_interactive_uitest.cc b/chrome/browser/ui/ash/overview_scroll_interactive_uitest.cc index 7bde497..0b59e2c1 100644 --- a/chrome/browser/ui/ash/overview_scroll_interactive_uitest.cc +++ b/chrome/browser/ui/ash/overview_scroll_interactive_uitest.cc
@@ -19,14 +19,15 @@ // Test overview scroll performance when the new overview layout is active. class OverviewScrollTest : public UIPerformanceTest { public: - OverviewScrollTest() = default; + OverviewScrollTest() { + scoped_feature_list_.InitAndEnableFeature( + ash::features::kNewOverviewLayout); + } + ~OverviewScrollTest() override = default; // UIPerformanceTest: void SetUpOnMainThread() override { - scoped_feature_list_.InitAndEnableFeature( - ash::features::kNewOverviewLayout); - UIPerformanceTest::SetUpOnMainThread(); // Create twelve windows total, scrolling is only needed when six or more
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc index 2a112093..d2b90d9 100644 --- a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc +++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
@@ -223,7 +223,7 @@ gfx::kChromeIconGrey); } if (icon_str == "httpsInvalid") { - return gfx::CreateVectorIcon(omnibox::kHttpsInvalidIcon, kIconSize, + return gfx::CreateVectorIcon(omnibox::kNotSecureWarningIcon, kIconSize, gfx::kGoogleRed700); } if (icon_str == "keyIcon") {
diff --git a/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc index 6ff5ccd3..1950b59 100644 --- a/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc
@@ -44,6 +44,9 @@ class TabUnderBlockerBrowserTest : public extensions::ExtensionBrowserTest { public: TabUnderBlockerBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + TabUnderNavigationThrottle::kBlockTabUnders); + EXPECT_CALL(provider_, IsInitializationComplete(testing::_)) .WillRepeatedly(testing::Return(true)); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); @@ -53,8 +56,6 @@ void SetUpOnMainThread() override { extensions::ExtensionBrowserTest::SetUpOnMainThread(); - scoped_feature_list_.InitAndEnableFeature( - TabUnderNavigationThrottle::kBlockTabUnders); host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(embedded_test_server()->Start()); }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 831f97a..44c534d2 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -2320,6 +2320,10 @@ if (tab_strip_model_->GetIndexOfWebContents(source) == TabStripModel::kNoTab) return; + // We ignore |INVALIDATE_TYPE_AUDIO| since we subscribe to + // RecentlyAudibleHelper via |OnTabAudibilityChanged()|. + changed_flags &= ~content::INVALIDATE_TYPE_AUDIO; + // Do some synchronous updates. if (changed_flags & content::INVALIDATE_TYPE_URL) { if (source == tab_strip_model_->GetActiveWebContents()) { @@ -2409,8 +2413,8 @@ } // Updates that don't depend upon the selected state go here. - if (flags & (content::INVALIDATE_TYPE_TAB | content::INVALIDATE_TYPE_TITLE | - content::INVALIDATE_TYPE_AUDIO)) { + if (flags & + (content::INVALIDATE_TYPE_TAB | content::INVALIDATE_TYPE_TITLE)) { tab_strip_model_->UpdateWebContentsStateAt( tab_strip_model_->GetIndexOfWebContents(contents), TabChangeType::kAll); @@ -2588,10 +2592,16 @@ zoom::ZoomController::FromWebContents(web_contents)->AddObserver(this); content_translate_driver->AddObserver(this); BookmarkTabHelper::FromWebContents(web_contents)->AddObserver(this); + audibility_subscriptions_[web_contents] = + RecentlyAudibleHelper::FromWebContents(web_contents) + ->RegisterCallback( + base::BindRepeating(&Browser::OnTabAudibilityChanged, + base::Unretained(this), web_contents)); } else { zoom::ZoomController::FromWebContents(web_contents)->RemoveObserver(this); content_translate_driver->RemoveObserver(this); BookmarkTabHelper::FromWebContents(web_contents)->RemoveObserver(this); + audibility_subscriptions_.erase(web_contents); } } @@ -2903,3 +2913,9 @@ return contents; } + +void Browser::OnTabAudibilityChanged(content::WebContents* contents, + bool recently_audible) { + tab_strip_model_->UpdateWebContentsStateAt( + tab_strip_model_->GetIndexOfWebContents(contents), TabChangeType::kAll); +}
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index cf4b6e0..d0ac5fc 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -29,6 +29,7 @@ #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/profile_chooser_constants.h" +#include "chrome/browser/ui/recently_audible_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/unload_controller.h" #include "components/content_settings/core/common/content_settings.h" @@ -1007,6 +1008,10 @@ const std::string& partition_id, content::SessionStorageNamespace* session_storage_namespace); + // Callback for RecentlyAudibleHelper. + void OnTabAudibilityChanged(content::WebContents* contents, + bool recently_audible); + // Data members ///////////////////////////////////////////////////////////// std::vector<InterstitialObserver*> interstitial_observers_; @@ -1148,6 +1153,13 @@ extension_browser_window_helper_; #endif + // These subscriptions are returned by RecentlyAudibleHelper when registering + // a callback. They de-register the callback when destroyed and safely handle + // destruction of the associated RecentlyAudibleHelper. + std::map<content::WebContents*, + std::unique_ptr<RecentlyAudibleHelper::Subscription>> + audibility_subscriptions_; + // The following factory is used for chrome update coalescing. base::WeakPtrFactory<Browser> chrome_updater_factory_{this};
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index d300c87..8707e58c 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -887,11 +887,19 @@ alert->native_dialog()->AcceptAppModalDialog(); } -IN_PROC_BROWSER_TEST_F(BrowserTest, NewTabFromLinkOpensInGroup) { - ASSERT_TRUE(embedded_test_server()->Start()); +class BrowserTestWithTabGroupsEnabled : public BrowserTest { + public: + BrowserTestWithTabGroupsEnabled() { + feature_list_.InitAndEnableFeature(features::kTabGroups); + } - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kTabGroups); + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(BrowserTestWithTabGroupsEnabled, + NewTabFromLinkOpensInGroup) { + ASSERT_TRUE(embedded_test_server()->Start()); // Add a grouped tab. TabStripModel* const model = browser()->tab_strip_model();
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc index 1d8d041..43a8a14 100644 --- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc +++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -47,13 +47,21 @@ ui::PageTransition::PAGE_TRANSITION_TYPED); } +class BrowserNavigatorTestChromeOSWithSplitSettings + : public BrowserNavigatorTestChromeOS { + public: + BrowserNavigatorTestChromeOSWithSplitSettings() { + feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettings); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Verifies that the OS settings page opens in a standalone surface when // accessed via link or url. -IN_PROC_BROWSER_TEST_F(BrowserNavigatorTestChromeOS, NavigateToOSSettings) { - // Enable SplitSettings feature. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); - +IN_PROC_BROWSER_TEST_F(BrowserNavigatorTestChromeOSWithSplitSettings, + NavigateToOSSettings) { // Install the Settings App. web_app::WebAppProvider::Get(browser()->profile()) ->system_web_app_manager()
diff --git a/chrome/browser/ui/extensions/application_launch_browsertest.cc b/chrome/browser/ui/extensions/application_launch_browsertest.cc index 53f03db..6cfd46a 100644 --- a/chrome/browser/ui/extensions/application_launch_browsertest.cc +++ b/chrome/browser/ui/extensions/application_launch_browsertest.cc
@@ -15,19 +15,20 @@ class ApplicationLaunchBrowserTest : public InProcessBrowserTest { public: - ApplicationLaunchBrowserTest() = default; + ApplicationLaunchBrowserTest() { + feature_list_.InitAndEnableFeature(features::kFocusMode); + } content::WebContents* GetWebContentsForTab(Browser* browser, int index) { return browser->tab_strip_model()->GetWebContentsAt(index); } - protected: - base::test::ScopedFeatureList feature_list; + private: + base::test::ScopedFeatureList feature_list_; }; IN_PROC_BROWSER_TEST_F(ApplicationLaunchBrowserTest, ReparentWebContentsForFocusModeSingleTab) { - feature_list.InitAndEnableFeature(features::kFocusMode); const GURL url("http://aaa.com/empty.html"); ui_test_utils::NavigateToURL(browser(), url); @@ -51,7 +52,6 @@ IN_PROC_BROWSER_TEST_F(ApplicationLaunchBrowserTest, ReparentWebContentsForFocusModeMultipleTabs) { const GURL url("http://aaa.com/empty.html"); - feature_list.InitAndEnableFeature(features::kFocusMode); chrome::AddTabAt(browser(), url, -1, true); chrome::AddTabAt(browser(), GURL(), -1, true); EXPECT_FALSE(browser()->is_focus_mode());
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc index 6626716e..694e2aa 100644 --- a/chrome/browser/ui/hats/hats_service_browsertest.cc +++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -81,22 +81,15 @@ class HatsServiceProbabilityZero : public HatsServiceBrowserTestBase { protected: - HatsServiceProbabilityZero() = default; - ~HatsServiceProbabilityZero() override = default; - - private: - void SetUpOnMainThread() override { - HatsServiceBrowserTestBase::SetUpOnMainThread(); - - // The HatsService must not be created so that feature parameters can be - // injected below. - ASSERT_FALSE( - HatsServiceFactory::GetForProfile(browser()->profile(), false)); + HatsServiceProbabilityZero() { scoped_feature_list_.InitAndEnableFeatureWithParameters( features::kHappinessTrackingSurveysForDesktop, {{"probability", "0.000"}}); } + ~HatsServiceProbabilityZero() override = default; + + private: base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(HatsServiceProbabilityZero); @@ -113,17 +106,7 @@ class HatsServiceProbabilityOne : public HatsServiceBrowserTestBase { protected: - HatsServiceProbabilityOne() = default; - ~HatsServiceProbabilityOne() override = default; - - private: - void SetUpOnMainThread() override { - HatsServiceBrowserTestBase::SetUpOnMainThread(); - - // The HatsService must not be created so that feature parameters can be - // injected below. - ASSERT_FALSE( - HatsServiceFactory::GetForProfile(browser()->profile(), false)); + HatsServiceProbabilityOne() { // TODO(weili): refactor to use constants from hats_service.cc for these // parameters. scoped_feature_list_.InitAndEnableFeatureWithParameters( @@ -131,6 +114,14 @@ {{"probability", "1.000"}, {"survey", "satisfaction"}, {"en_site_id", "test_site_id"}}); + } + + ~HatsServiceProbabilityOne() override = default; + + private: + void SetUpOnMainThread() override { + HatsServiceBrowserTestBase::SetUpOnMainThread(); + // Set the profile creation time to be old enough to ensure triggering. browser()->profile()->SetCreationTimeForTesting( base::Time::Now() - base::TimeDelta::FromDays(45));
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc index ac929c60..3a48d76 100644 --- a/chrome/browser/ui/login/login_handler_browsertest.cc +++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -177,12 +177,13 @@ auth_map_["foo"] = AuthInfo("testuser", "foopassword"); auth_map_["bar"] = AuthInfo("testuser", "barpassword"); auth_map_["testrealm"] = AuthInfo(username_basic_, password_); + + scoped_feature_list_.InitAndEnableFeature( + features::kHTTPAuthCommittedInterstitials); } void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); - scoped_feature_list.InitAndEnableFeature( - features::kHTTPAuthCommittedInterstitials); } protected: @@ -207,7 +208,9 @@ std::string password_; std::string username_basic_; std::string username_digest_; - base::test::ScopedFeatureList scoped_feature_list; + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) { @@ -1811,6 +1814,18 @@ EXPECT_EQ(0u, observer.handlers().size()); } +class ProxyBrowserTestWithHttpAuthCommittedInterstitials + : public ProxyBrowserTest { + public: + ProxyBrowserTestWithHttpAuthCommittedInterstitials() { + feature_list_.InitAndEnableFeature( + features::kHTTPAuthCommittedInterstitials); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests that basic proxy auth works as expected, for HTTPS pages. #if defined(OS_MACOSX) // TODO(https://crbug.com/1000446): Re-enable this test. @@ -1818,10 +1833,8 @@ #else #define MAYBE_ProxyAuthHTTPS ProxyAuthHTTPS #endif -IN_PROC_BROWSER_TEST_F(ProxyBrowserTest, MAYBE_ProxyAuthHTTPS) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kHTTPAuthCommittedInterstitials); +IN_PROC_BROWSER_TEST_F(ProxyBrowserTestWithHttpAuthCommittedInterstitials, + MAYBE_ProxyAuthHTTPS) { net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); https_server.AddDefaultHandlers(GetChromeTestDataDir()); ASSERT_TRUE(https_server.Start()); @@ -1830,10 +1843,8 @@ } // Tests that basic proxy auth works as expected, for HTTP pages. -IN_PROC_BROWSER_TEST_F(ProxyBrowserTest, ProxyAuthHTTP) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kHTTPAuthCommittedInterstitials); +IN_PROC_BROWSER_TEST_F(ProxyBrowserTestWithHttpAuthCommittedInterstitials, + ProxyAuthHTTP) { ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_NO_FATAL_FAILURE( TestProxyAuth(browser(), embedded_test_server()->GetURL("/simple.html")));
diff --git a/chrome/browser/ui/manifest_web_app_browsertest.cc b/chrome/browser/ui/manifest_web_app_browsertest.cc index fed1acdb..81a9897 100644 --- a/chrome/browser/ui/manifest_web_app_browsertest.cc +++ b/chrome/browser/ui/manifest_web_app_browsertest.cc
@@ -34,10 +34,19 @@ std::unique_ptr<base::HistogramTester> histogram_tester_; }; +class ManifestWebAppTestWithFocusModeEnabled : public ManifestWebAppTest { + public: + ManifestWebAppTestWithFocusModeEnabled() { + feature_list_.InitAndEnableFeature(features::kFocusMode); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Opens a basic example site in focus mode window. -IN_PROC_BROWSER_TEST_F(ManifestWebAppTest, OpenExampleSite) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kFocusMode); +IN_PROC_BROWSER_TEST_F(ManifestWebAppTestWithFocusModeEnabled, + OpenExampleSite) { const GURL url("http://example.org/"); ui_test_utils::NavigateToURL(browser(), url); Browser* app_browser = web_app::ReparentWebContentsForFocusMode( @@ -55,9 +64,7 @@ EXPECT_EQ(controller->GetThemeColor(), SK_ColorWHITE); } -IN_PROC_BROWSER_TEST_F(ManifestWebAppTest, MetricsTest) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kFocusMode); +IN_PROC_BROWSER_TEST_F(ManifestWebAppTestWithFocusModeEnabled, MetricsTest) { Browser* app_browser = web_app::ReparentWebContentsForFocusMode( browser()->tab_strip_model()->GetWebContentsAt(0));
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc index 8c31a7b..746e5de 100644 --- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc +++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -1609,12 +1609,19 @@ // TODO(msw): Test that AltGr+V does not paste. } -IN_PROC_BROWSER_TEST_F(OmniboxViewTest, EditSearchEngines) { +class OmniboxViewTestWithoutSplitSettings : public OmniboxViewTest { + public: + OmniboxViewTestWithoutSplitSettings() { #if defined(OS_CHROMEOS) - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(chromeos::features::kSplitSettings); + feature_list_.InitAndDisableFeature(chromeos::features::kSplitSettings); #endif + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(OmniboxViewTestWithoutSplitSettings, EditSearchEngines) { OmniboxView* omnibox_view = nullptr; ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view)); #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc index 7480da4..77324b5 100644 --- a/chrome/browser/ui/page_info/page_info.cc +++ b/chrome/browser/ui/page_info/page_info.cc
@@ -778,7 +778,7 @@ security_state::SafetyTipStatus::kNone && visible_security_state.safety_tip_status != security_state::SafetyTipStatus::kUnknown && - base::FeatureList::IsEnabled(features::kSafetyTipUI)) { + base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) { site_details_message_ = l10n_util::GetStringUTF16( IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION); } @@ -998,7 +998,7 @@ info.connection_status_description = UTF16ToUTF8(site_connection_details_); info.identity_status = site_identity_status_; info.safe_browsing_status = safe_browsing_status_; - if (base::FeatureList::IsEnabled(features::kSafetyTipUI)) { + if (base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) { info.safety_tip_status = safety_tip_status_; } info.identity_status_description = UTF16ToUTF8(site_details_message_);
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc index ec8391d..c8a7fb7 100644 --- a/chrome/browser/ui/page_info/page_info_unittest.cc +++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -1162,7 +1162,8 @@ // various Safety Tip statuses. TEST_F(PageInfoTest, SafetyTipMetrics) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kSafetyTipUI); + scoped_feature_list.InitAndEnableFeature( + security_state::features::kSafetyTipUI); struct TestCase { const security_state::SafetyTipStatus safety_tip_status; const std::string histogram_name;
diff --git a/chrome/browser/ui/passwords/google_password_manager_navigation_throttle_browsertest.cc b/chrome/browser/ui/passwords/google_password_manager_navigation_throttle_browsertest.cc index 5eada638..7b132200 100644 --- a/chrome/browser/ui/passwords/google_password_manager_navigation_throttle_browsertest.cc +++ b/chrome/browser/ui/passwords/google_password_manager_navigation_throttle_browsertest.cc
@@ -76,11 +76,28 @@ return true; }))) {} - std::unique_ptr<ProfileSyncServiceHarness> EnableGooglePasswordManagerAndSync( - Profile* profile) { + protected: + void TearDownOnMainThread() override { + interceptor_.reset(); + SyncTest::TearDownOnMainThread(); + } + + private: + // Instantiate a content::URLLoaderInterceptor that will fail all requests + // with net::ERR_FAILED. This is done, because we are interested in being + // redirected when a navigation fails. + std::unique_ptr<content::URLLoaderInterceptor> interceptor_; +}; + +class GooglePasswordManagerNavigationThrottleTestWithPasswordManager + : public GooglePasswordManagerNavigationThrottleTest { + public: + GooglePasswordManagerNavigationThrottleTestWithPasswordManager() { feature_list_.InitAndEnableFeature( password_manager::features::kGooglePasswordManager); + } + std::unique_ptr<ProfileSyncServiceHarness> EnableSync(Profile* profile) { ProfileSyncServiceFactory::GetAsProfileSyncServiceForProfile(profile) ->OverrideNetworkResourcesForTest( std::make_unique<fake_server::FakeServerNetworkResources>( @@ -105,18 +122,6 @@ EXPECT_TRUE(harness->SetupSync()); return harness; } - - protected: - void TearDownOnMainThread() override { - interceptor_.reset(); - SyncTest::TearDownOnMainThread(); - } - - private: - // Instantiate a content::URLLoaderInterceptor that will fail all requests - // with net::ERR_FAILED. This is done, because we are interested in being - // redirected when a navigation fails. - std::unique_ptr<content::URLLoaderInterceptor> interceptor_; }; // No navigation should be redirected in case the Google Password Manager and @@ -140,29 +145,32 @@ // Settings Subpage when trying to access the Google Password Manager when the // user's profile should be considered and the user clicked a link to get to the // Google Password Manager page. -IN_PROC_BROWSER_TEST_F(GooglePasswordManagerNavigationThrottleTest, - ExampleWithGPMAndSync) { +IN_PROC_BROWSER_TEST_F( + GooglePasswordManagerNavigationThrottleTestWithPasswordManager, + ExampleWithGPMAndSync) { std::unique_ptr<ProfileSyncServiceHarness> harness = - EnableGooglePasswordManagerAndSync(browser()->profile()); + EnableSync(browser()->profile()); EXPECT_EQ(GetExampleURL(), NavigateToURL(browser(), GetExampleURL(), ui::PageTransition::PAGE_TRANSITION_LINK)); } -IN_PROC_BROWSER_TEST_F(GooglePasswordManagerNavigationThrottleTest, - PasswordsWithGPMAndSyncUserTyped) { +IN_PROC_BROWSER_TEST_F( + GooglePasswordManagerNavigationThrottleTestWithPasswordManager, + PasswordsWithGPMAndSyncUserTyped) { std::unique_ptr<ProfileSyncServiceHarness> harness = - EnableGooglePasswordManagerAndSync(browser()->profile()); + EnableSync(browser()->profile()); EXPECT_EQ(GetGooglePasswordManagerURL(), NavigateToURL(browser(), GetGooglePasswordManagerURL(), ui::PageTransition::PAGE_TRANSITION_TYPED)); } -IN_PROC_BROWSER_TEST_F(GooglePasswordManagerNavigationThrottleTest, - PasswordsWithGPMAndSyncUserClickedLink) { +IN_PROC_BROWSER_TEST_F( + GooglePasswordManagerNavigationThrottleTestWithPasswordManager, + PasswordsWithGPMAndSyncUserClickedLink) { base::HistogramTester tester; std::unique_ptr<ProfileSyncServiceHarness> harness = - EnableGooglePasswordManagerAndSync(browser()->profile()); + EnableSync(browser()->profile()); #if defined(OS_CHROMEOS) // Install the Settings App.
diff --git a/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc b/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc index 5eb525f..2f47eee4 100644 --- a/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc +++ b/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc
@@ -157,29 +157,47 @@ EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); } -// TODO(crbug/950007): Remove ScopedFeatureList when kSplitSettings flag is on -// by default. -IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTest, OpenAboutPageSplitSettings) { +// TODO(crbug/950007): Remove when kSplitSettings flag is on by default. +class SettingsWindowManagerTestWithSplitSettings + : public SettingsWindowManagerTest { + public: + SettingsWindowManagerTestWithSplitSettings() { + feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettings); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// TODO(crbug/950007): Remove when kSplitSettings flag is on by default. +class SettingsWindowManagerTestWithoutSplitSettings + : public SettingsWindowManagerTest { + public: + SettingsWindowManagerTestWithoutSplitSettings() { + feature_list_.InitAndDisableFeature(chromeos::features::kSplitSettings); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTestWithSplitSettings, + OpenAboutPageSplitSettings) { // About should open settings window when split settings feature flag is on. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); chrome::ShowAboutChrome(browser()); EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); } -// TODO(crbug/950007): Remove when kSplitSettings flag is on by default. -IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTest, OpenAboutPage) { +IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTestWithoutSplitSettings, + OpenAboutPage) { // About should open a new browser window when split settings feature flag is // off. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(chromeos::features::kSplitSettings); chrome::ShowAboutChrome(browser()); EXPECT_EQ(2u, chrome::GetTotalBrowserCount()); } -IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTest, SplitSettings) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); +IN_PROC_BROWSER_TEST_P(SettingsWindowManagerTestWithSplitSettings, + SplitSettings) { EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); // Browser settings opens in the existing browser window.
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc index 5f55535..f08715f 100644 --- a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc +++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
@@ -570,20 +570,18 @@ : public LocalCardMigrationBrowserTest { protected: LocalCardMigrationBrowserTestForStatusChip() - : LocalCardMigrationBrowserTest() {} - - ~LocalCardMigrationBrowserTestForStatusChip() override {} - - void SetUp() override { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( + : LocalCardMigrationBrowserTest() { + feature_list_.InitWithFeatures( /*enabled_features=*/{features::kAutofillCreditCardUploadFeedback, features::kAutofillEnableToolbarStatusChip, features::kAutofillUpstream}, /*disabled_features=*/{}); - - LocalCardMigrationBrowserTest::SetUp(); } + + ~LocalCardMigrationBrowserTestForStatusChip() override = default; + + private: + base::test::ScopedFeatureList feature_list_; }; // Ensures that migration is not offered when user saves a new card. @@ -904,12 +902,21 @@ EXPECT_EQ(nullptr, personal_data_->GetCreditCardByNumber(kSecondCardNumber)); } +class LocalCardMigrationBrowserTestWithStrikeSystemV2 + : public LocalCardMigrationBrowserTest { + public: + LocalCardMigrationBrowserTestWithStrikeSystemV2() { + feature_list_.InitAndEnableFeature( + features::kAutofillLocalCardMigrationUsesStrikeSystemV2); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Ensures that rejecting the main migration dialog adds 3 strikes. -IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTestWithStrikeSystemV2, ClosingDialogAddsLocalCardMigrationStrikes) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillLocalCardMigrationUsesStrikeSystemV2); base::HistogramTester histogram_tester; SaveLocalCard(kFirstCardNumber); @@ -926,11 +933,8 @@ } // Ensures that rejecting the migration bubble adds 2 strikes. -IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTestWithStrikeSystemV2, ClosingBubbleAddsLocalCardMigrationStrikes) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillLocalCardMigrationUsesStrikeSystemV2); base::HistogramTester histogram_tester; SaveLocalCard(kFirstCardNumber); @@ -949,11 +953,8 @@ // Ensures that rejecting the migration bubble repeatedly adds 2 strikes every // time, even for the same tab. -IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTestWithStrikeSystemV2, ClosingBubbleAgainAddsLocalCardMigrationStrikes) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillLocalCardMigrationUsesStrikeSystemV2); base::HistogramTester histogram_tester; SaveLocalCard(kFirstCardNumber); @@ -976,12 +977,8 @@ // Ensures that reshowing and closing bubble after previously closing it does // not add strikes. -IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTestWithStrikeSystemV2, ReshowingBubbleDoesNotAddStrikes) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kAutofillLocalCardMigrationUsesStrikeSystemV2); - SaveLocalCard(kFirstCardNumber); SaveLocalCard(kSecondCardNumber); UseCardAndWaitForMigrationOffer(kFirstCardNumber);
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc index 81c8ebd..d0e126ca 100644 --- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc +++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -337,14 +337,6 @@ } void SetUpForEditableExpirationDate() { - // Enable the EditableExpirationDate experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstreamEditableExpirationDate, - features::kAutofillUpstream}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); } @@ -830,8 +822,6 @@ base::CallbackList<void(content::BrowserContext*)>::Subscription> will_create_browser_context_services_subscription_; - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<ProfileSyncServiceHarness> harness_; CreditCardSaveManager* credit_card_save_manager_ = nullptr; @@ -845,6 +835,23 @@ DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleViewsFullFormBrowserTest); }; +class SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate() { + // Enable the EditableExpirationDate experiment. + feature_list_.InitWithFeatures( + // Enabled + {features::kAutofillUpstreamEditableExpirationDate, + features::kAutofillUpstream}, + // Disabled + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // TODO(crbug.com/932818): Remove this class after experiment flag is cleaned // up. Otherwise we need it because the toolbar is init-ed before each test is // set up. Thus need to enable the feature in the general browsertest SetUp(). @@ -856,8 +863,7 @@ ~SaveCardBubbleViewsFullFormBrowserTestForStatusChip() override {} void SetUp() override { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( + feature_list_.InitWithFeatures( /*enabled_features=*/{features::kAutofillCreditCardUploadFeedback, features::kAutofillEnableToolbarStatusChip, features::kAutofillUpstream}, @@ -865,6 +871,9 @@ SaveCardBubbleViewsFullFormBrowserTest::SetUp(); } + + private: + base::test::ScopedFeatureList feature_list_; }; // Tests the local save bubble. Ensures that clicking the [Save] button @@ -937,13 +946,23 @@ } #endif +class SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream() { + feature_list_.InitAndEnableFeature(features::kAutofillUpstream); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the sign in promo bubble. Ensures that the sign-in promo // is not shown when the user is signed-in and syncing, even if the local save // bubble is shown. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Local_NoSigninPromoShowsWhenUserIsSyncing) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Local_NoSigninPromoShowsWhenUserIsSyncing) { // Start sync. harness_->SetupSync(); @@ -1076,16 +1095,25 @@ AutofillMetrics::MANAGE_CARDS_SHOWN, 1); } +class SaveCardBubbleViewsFullFormBrowserTestWithoutSplitSettings + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithoutSplitSettings() { +#if defined(OS_CHROMEOS) + feature_list_.InitAndDisableFeature(chromeos::features::kSplitSettings); +#endif + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // TODO(crbug/950007): Remove this test when kSplitSettings is on by default // Tests the manage cards bubble. Ensures that clicking the [Manage cards] // button redirects properly. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Local_ManageCardsButtonRedirects) { -#if defined(OS_CHROMEOS) - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(chromeos::features::kSplitSettings); -#endif - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithoutSplitSettings, + Local_ManageCardsButtonRedirects) { base::HistogramTester histogram_tester; OpenSettingsFromManageCardsPrompt(); @@ -1106,15 +1134,22 @@ Bucket(AutofillMetrics::MANAGE_CARDS_MANAGE_CARDS, 1))); } +class SaveCardBubbleViewsFullFormBrowserTestWithSplitSettings + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithSplitSettings() { +#if defined(OS_CHROMEOS) + feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettings); +#endif + } + + private: + base::test::ScopedFeatureList feature_list_; +}; // Tests the manage cards bubble. Ensures that clicking the [Manage cards] // button redirects properly. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, +IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestWithSplitSettings, Local_ManageCardsButtonRedirects_WithSplitSettings) { -#if defined(OS_CHROMEOS) - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); -#endif - base::HistogramTester histogram_tester; OpenSettingsFromManageCardsPrompt(); @@ -1249,13 +1284,23 @@ } #endif +class SaveCardBubbleViewsFullFormBrowserTestWithoutNoThanks + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithoutNoThanks() { + feature_list_.InitAndDisableFeature( + features::kAutofillSaveCardShowNoThanks); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + #if defined(OS_CHROMEOS) // Tests the local save bubble. Ensures that the bubble does not have a // [No thanks] button (it has an [X] Close button instead.) -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, +IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestWithoutNoThanks, Local_ShouldNotHaveNoThanksButton) { - scoped_feature_list_.InitAndDisableFeature( - features::kAutofillSaveCardShowNoThanks); FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); @@ -1263,12 +1308,21 @@ EXPECT_FALSE(FindViewInBubbleById(DialogViewId::CANCEL_BUTTON)); } +class SaveCardBubbleViewsFullFormBrowserTestWithNoThanks + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithNoThanks() { + feature_list_.InitAndEnableFeature(features::kAutofillSaveCardShowNoThanks); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the local save bubble. Ensures that the bubble has a // [No thanks] button if |kAutofillSaveCardShowNoThanks| experiment is enabled. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, +IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestWithNoThanks, Local_ShouldHaveNoThanksButtonIfExperimentEnabled) { - scoped_feature_list_.InitAndEnableFeature( - features::kAutofillSaveCardShowNoThanks); FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); @@ -1309,10 +1363,9 @@ // Tests the upload save bubble. Ensures that clicking the [Save] button // successfully causes the bubble to go away and sends an UploadCardRequest RPC // to Google Payments. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ClickingSaveClosesBubble) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Upload_ClickingSaveClosesBubble) { // Start sync. harness_->SetupSync(); @@ -1339,15 +1392,16 @@ class SaveCardBubbleViewsSyncTransportFullFormBrowserTest : public SaveCardBubbleViewsFullFormBrowserTest { protected: - SaveCardBubbleViewsSyncTransportFullFormBrowserTest() = default; - - void SetUpInProcessBrowserTestFixture() override { + SaveCardBubbleViewsSyncTransportFullFormBrowserTest() { // Set up Sync the transport mode, so that sync starts on content-area // signins. Also add wallet data type to the list of enabled types. - scoped_feature_list_.InitWithFeatures( + feature_list_.InitWithFeatures( /*enabled_features=*/{features::kAutofillUpstream, features::kAutofillEnableAccountWalletStorage}, /*disabled_features=*/{}); + } + + void SetUpInProcessBrowserTestFixture() override { test_signin_client_factory_ = secondary_account_helper::SetUpSigninClient(test_url_loader_factory()); @@ -1370,6 +1424,7 @@ } private: + base::test::ScopedFeatureList feature_list_; secondary_account_helper::ScopedSigninClientFactory test_signin_client_factory_; @@ -1438,20 +1493,20 @@ SaveCardBubbleViewsSyncTransportWithEditableCardholderNameFullFormBrowserTest : public SaveCardBubbleViewsFullFormBrowserTest { protected: - SaveCardBubbleViewsSyncTransportWithEditableCardholderNameFullFormBrowserTest() = - default; - - void SetUpInProcessBrowserTestFixture() override { + SaveCardBubbleViewsSyncTransportWithEditableCardholderNameFullFormBrowserTest() { // Set up Sync the transport mode, so that sync starts on content-area // signins. Also add wallet data type to the list of enabled types and // enable EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( + feature_list_.InitWithFeatures( // Enabled {features::kAutofillUpstream, features::kAutofillUpstreamEditableCardholderName, features::kAutofillEnableAccountWalletStorage}, // Disabled {}); + } + + void SetUpInProcessBrowserTestFixture() override { test_signin_client_factory_ = secondary_account_helper::SetUpSigninClient(test_url_loader_factory()); @@ -1459,6 +1514,7 @@ } private: + base::test::ScopedFeatureList feature_list_; secondary_account_helper::ScopedSigninClientFactory test_signin_client_factory_; @@ -1503,10 +1559,9 @@ // Tests the fully-syncing state. Ensures that the Butter (i) info icon does not // appear for fully-syncing users. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_NotTransportMode_InfoTextIconDoesNotExist) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Upload_NotTransportMode_InfoTextIconDoesNotExist) { // Start sync. harness_->SetupSync(); @@ -1522,10 +1577,9 @@ (defined(OS_LINUX) && !defined(OS_CHROMEOS)) // Tests the upload save bubble. Ensures that clicking the [No thanks] button // successfully causes the bubble to go away. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ClickingNoThanksClosesBubble) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Upload_ClickingNoThanksClosesBubble) { // Start sync. harness_->SetupSync(); @@ -1544,16 +1598,26 @@ #endif #if defined(OS_CHROMEOS) +class SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndWithoutNoThanks + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndWithoutNoThanks() { + feature_list_.InitWithFeatures( + // Enabled + {features::kAutofillUpstream}, + // Disabled + {features::kAutofillSaveCardShowNoThanks}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the upload save bubble. Ensures that the bubble does not have a // [No thanks] button (it has an [X] Close button instead.) -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ShouldNotHaveNoThanksButton) { - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream}, - // Disabled - {features::kAutofillSaveCardShowNoThanks}); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndWithoutNoThanks, + Upload_ShouldNotHaveNoThanksButton) { // Start sync. harness_->SetupSync(); @@ -1564,16 +1628,26 @@ EXPECT_FALSE(FindViewInBubbleById(DialogViewId::CANCEL_BUTTON)); } +class SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndNoThanks + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndNoThanks() { + feature_list_.InitWithFeatures( + // Enabled + {features::kAutofillUpstream, features::kAutofillSaveCardShowNoThanks}, + // Disabled + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the upload save bubble. Ensures that the bubble has a // [No thanks] button if |kAutofillSaveCardShowNoThanks| experiment is enabled. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ShouldHaveNoThanksButtonIfExperimentEnabled) { - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillSaveCardShowNoThanks, features::kAutofillUpstream}, - // Disabled - {}); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillAndNoThanks, + Upload_ShouldHaveNoThanksButtonIfExperimentEnabled) { // Start sync. harness_->SetupSync(); @@ -1587,10 +1661,9 @@ // Tests the upload save bubble. Ensures that clicking the top-right [X] close // button successfully causes the bubble to go away. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ClickingCloseClosesBubble) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Upload_ClickingCloseClosesBubble) { // Start sync. harness_->SetupSync(); @@ -1601,18 +1674,28 @@ ClickOnCloseButton(); } +class SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName() { + // Enable the EditableCardholderName experiment. + feature_list_.InitWithFeatures( + // Enabled + {features::kAutofillUpstream, + features::kAutofillUpstreamEditableCardholderName}, + // Disabled + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the upload save bubble. Ensures that the bubble does not surface the // cardholder name textfield if it is not needed. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ShouldNotRequestCardholderNameInHappyPath) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, + Upload_ShouldNotRequestCardholderNameInHappyPath) { // Start sync. harness_->SetupSync(); @@ -1626,16 +1709,8 @@ // Tests the upload save bubble. Ensures that the bubble surfaces a textfield // requesting cardholder name if cardholder name is missing. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); @@ -1648,16 +1723,8 @@ // Tests the upload save bubble. Ensures that the bubble surfaces a textfield // requesting cardholder name if cardholder name is conflicting. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_SubmittingFormWithConflictingNamesRequestsCardholderNameIfExpOn) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); @@ -1675,16 +1742,8 @@ // Tests the upload save bubble. Ensures that if the cardholder name textfield // is empty, the user is not allowed to click [Save] and close the dialog. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_SaveButtonIsDisabledIfNoCardholderNameAndCardholderNameRequested) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); @@ -1714,16 +1773,8 @@ // Tests the upload save bubble. Ensures that if cardholder name is explicitly // requested, filling it and clicking [Save] closes the dialog. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_EnteringCardholderNameAndClickingSaveClosesBubbleIfCardholderNameRequested) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); @@ -1755,16 +1806,9 @@ // Tests the upload save bubble. Ensures that if cardholder name is explicitly // requested, it is prefilled with the name from the user's Google Account. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_RequestedCardholderNameTextfieldIsPrefilledWithFocusName) { base::HistogramTester histogram_tester; - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); // Start sync. harness_->SetupSync(); @@ -1794,16 +1838,10 @@ // requested but the name on the user's Google Account is unable to be fetched // for any reason, the textfield is left blank. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_RequestedCardholderNameTextfieldIsNotPrefilledWithFocusNameIfMissing) { // Enable the EditableCardholderName experiment. base::HistogramTester histogram_tester; - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); // Start sync. harness_->SetupSync(); @@ -1829,16 +1867,8 @@ // requested and the user accepts the dialog without changing it, the correct // metric is logged. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_CardholderNameRequested_SubmittingPrefilledValueLogsUneditedMetric) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); // Set the user's full name. @@ -1863,16 +1893,8 @@ // requested and the user accepts the dialog after changing it, the correct // metric is logged. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableCardholderName, Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric) { - // Enable the EditableCardholderName experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName}, - // Disabled - {}); - // Start sync. harness_->SetupSync(); // Set the user's full name. @@ -1897,21 +1919,32 @@ "Autofill.SaveCardCardholderNameWasEdited", true, 1); } +class SaveCardBubbleViewsFullFormBrowserTestWithBlankEditableCardholderName + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithBlankEditableCardholderName() { + // Enable the EditableCardholderName and BlankCardholderNameField + // experiments. + feature_list_.InitWithFeatures( + {features::kAutofillUpstream, + features::kAutofillUpstreamEditableCardholderName, + features::kAutofillUpstreamBlankCardholderNameField}, + // Disabled + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the upload save bubble. Ensures that if cardholder name is explicitly // requested but the AutofillUpstreamBlankCardholderNameField experiment is // active, the textfield is NOT prefilled even though the user's Google Account // name is available. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithBlankEditableCardholderName, Upload_CardholderNameNotPrefilledIfBlankNameExperimentEnabled) { base::HistogramTester histogram_tester; - // Enable the EditableCardholderName and BlankCardholderNameField experiments. - scoped_feature_list_.InitWithFeatures( - {features::kAutofillUpstream, - features::kAutofillUpstreamEditableCardholderName, - features::kAutofillUpstreamBlankCardholderNameField}, - // Disabled - {}); // Start sync. harness_->SetupSync(); @@ -1943,10 +1976,9 @@ // Tests the upload save logic. Ensures that Chrome offers a local save when the // data is complete, even if Payments rejects the data. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldOfferLocalSaveIfPaymentsDeclines) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldOfferLocalSaveIfPaymentsDeclines) { // Start sync. harness_->SetupSync(); @@ -1970,10 +2002,9 @@ // Tests the upload save logic. Ensures that Chrome offers a local save when the // data is complete, even if the Payments upload fails unexpectedly. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldOfferLocalSaveIfPaymentsFails) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldOfferLocalSaveIfPaymentsFails) { // Start sync. harness_->SetupSync(); @@ -1998,10 +2029,8 @@ // Tests the upload save logic. Ensures that Chrome delegates the offer-to-save // call to Payments, and offers to upload save the card if Payments allows it. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, Logic_CanOfferToSaveEvenIfNothingFoundIfPaymentsAccepts) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - // Start sync. harness_->SetupSync(); @@ -2015,10 +2044,9 @@ // Tests the upload save logic. Ensures that Chrome offers a upload save for // dynamic change form. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_CanOfferToSaveDynamicForm) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_CanOfferToSaveDynamicForm) { // Start sync. harness_->SetupSync(); @@ -2042,10 +2070,8 @@ // call to Payments, and still does not surface the offer to upload save dialog // if Payments declines it. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, Logic_ShouldNotOfferToSaveIfNothingFoundAndPaymentsDeclines) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - // Start sync. harness_->SetupSync(); @@ -2067,10 +2093,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if CVC is not detected. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfCvcNotFound) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfCvcNotFound) { // Start sync. harness_->SetupSync(); @@ -2084,10 +2109,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if the detected CVC is invalid. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfInvalidCvcFound) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfInvalidCvcFound) { // Start sync. harness_->SetupSync(); @@ -2103,10 +2127,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if address/cardholder name is not // detected. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfNameNotFound) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfNameNotFound) { // Start sync. harness_->SetupSync(); @@ -2122,10 +2145,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if multiple conflicting names are // detected. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfNamesConflict) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfNamesConflict) { // Start sync. harness_->SetupSync(); @@ -2144,10 +2166,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if billing address is not detected. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfAddressNotFound) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfAddressNotFound) { // Start sync. harness_->SetupSync(); @@ -2163,10 +2184,9 @@ // Tests the upload save logic. Ensures that Chrome lets Payments decide whether // upload save should be offered, even if multiple conflicting billing address // postal codes are detected. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Logic_ShouldAttemptToOfferToSaveIfPostalCodesConflict) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + Logic_ShouldAttemptToOfferToSaveIfPostalCodesConflict) { // Start sync. harness_->SetupSync(); @@ -2186,10 +2206,9 @@ // Tests UMA logging for the upload save bubble. Ensures that if the user // declines upload, Autofill.UploadAcceptedCardOrigin is not logged. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, Upload_DecliningUploadDoesNotLogUserAcceptedCardOriginUMA) { base::HistogramTester histogram_tester; - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); // Start sync. harness_->SetupSync(); @@ -2210,7 +2229,7 @@ // Tests the upload save bubble. Ensures that the bubble surfaces a pair of // dropdowns requesting expiration date if expiration date is missing. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithMissingExpirationDateRequestsExpirationDate) { SetUpForEditableExpirationDate(); FillFormWithoutExpirationDate(); @@ -2221,7 +2240,7 @@ // Tests the upload save bubble. Ensures that the bubble surfaces a pair of // dropdowns requesting expiration date if expiration date is expired. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithExpiredExpirationDateRequestsExpirationDate) { SetUpForEditableExpirationDate(); FillFormWithSpecificExpirationDate("08", "2000"); @@ -2229,18 +2248,28 @@ VerifyExpirationDateDropdownsAreVisible(); } +class + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstreamAndNoEditableExpirationDate + : public SaveCardBubbleViewsFullFormBrowserTest { + public: + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstreamAndNoEditableExpirationDate() { + // Disable the EditableExpirationDate experiment. + feature_list_.InitWithFeatures( + // Enabled + {features::kAutofillUpstream}, + // Disabled + {features::kAutofillUpstreamEditableExpirationDate}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Tests the upload save bubble. Ensures that the bubble is not shown when // expiration date is passed, but the flag is disabled. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstreamAndNoEditableExpirationDate, Logic_ShouldNotOfferToSaveIfSubmittingExpiredExpirationDateAndExpOff) { - // Disable the EditableExpirationDate experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream}, - // Disabled - {features::kAutofillUpstreamEditableExpirationDate}); - // The credit card will not be imported if the expiration date is expired and // experiment is off. FillFormWithSpecificExpirationDate("08", "2000"); @@ -2251,15 +2280,8 @@ // Tests the upload save bubble. Ensures that the bubble is not shown when // expiration date is missing, but the flag is disabled. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstreamAndNoEditableExpirationDate, Logic_ShouldNotOfferToSaveIfMissingExpirationDateAndExpOff) { - // Disable the EditableExpirationDate experiment. - scoped_feature_list_.InitWithFeatures( - // Enabled - {features::kAutofillUpstream}, - // Disabled - {features::kAutofillUpstreamEditableExpirationDate}); - // The credit card will not be imported if there is no expiration date and // experiment is off. FillFormWithoutExpirationDate(); @@ -2269,8 +2291,9 @@ // Tests the upload save bubble. Ensures that the bubble does not surface the // expiration date dropdowns if it is not needed. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - Upload_ShouldNotRequestExpirationDateInHappyPath) { +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, + Upload_ShouldNotRequestExpirationDateInHappyPath) { SetUpForEditableExpirationDate(); FillForm(); SubmitFormAndWaitForCardUploadSaveBubble(); @@ -2288,7 +2311,7 @@ // Tests the upload save bubble. Ensures that if the expiration date drop down // box is changing, [Save] button will change status correctly. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SaveButtonStatusResetBetweenExpirationDateSelectionChanges) { SetUpForEditableExpirationDate(); FillFormWithoutExpirationDate(); @@ -2320,7 +2343,7 @@ // Tests the upload save bubble. Ensures that if the user is selecting an // expired expiration date, it is not allowed to click [Save]. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SaveButtonIsDisabledIfExpiredExpirationDateAndExpirationDateRequested) { SetUpForEditableExpirationDate(); FillFormWithoutExpirationDate(); @@ -2346,7 +2369,7 @@ // dropdowns requesting expiration date with year pre-populated if year is valid // but month is missing. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithMissingExpirationDateMonthAndWithValidYear) { SetUpForEditableExpirationDate(); // Submit the form with a year value, but not a month value. @@ -2364,7 +2387,7 @@ // dropdowns requesting expiration date with month pre-populated if month is // detected but year is missing. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithMissingExpirationDateYearAndWithMonth) { SetUpForEditableExpirationDate(); // Submit the form with a month value, but not a year value. @@ -2382,7 +2405,7 @@ // dropdowns requesting expiration date if month is missing and year is detected // but out of the range of dropdown. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithExpirationDateMonthAndWithYearIsOutOfRange) { SetUpForEditableExpirationDate(); // Fill form but with an expiration year ten years in the future which is out @@ -2400,7 +2423,7 @@ // dropdowns requesting expiration date if expiration date month is missing and // year is detected but passed. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithExpirationDateMonthAndYearExpired) { SetUpForEditableExpirationDate(); // Fill form with a valid month but a passed year. @@ -2418,7 +2441,7 @@ // dropdowns requesting expiration date if expiration date is expired but is // current year. IN_PROC_BROWSER_TEST_F( - SaveCardBubbleViewsFullFormBrowserTest, + SaveCardBubbleViewsFullFormBrowserTestWithEditableExpirationDate, Upload_SubmittingFormWithExpirationDateMonthAndCurrentYear) { SetUpForEditableExpirationDate(); const base::Time kJune2017 = base::Time::FromDoubleT(1497552271); @@ -2475,10 +2498,9 @@ // Tests StrikeDatabase interaction with the upload save bubble. Ensures that a // strike is added if the bubble is ignored. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - StrikeDatabase_Upload_AddStrikeIfBubbleIgnored) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + StrikeDatabase_Upload_AddStrikeIfBubbleIgnored) { TestAutofillClock test_clock; test_clock.SetNow(base::Time::Now()); @@ -2533,10 +2555,9 @@ (defined(OS_LINUX) && !defined(OS_CHROMEOS)) // Tests the upload save bubble. Ensures that clicking the [No thanks] button // successfully causes a strike to be added. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - StrikeDatabase_Upload_AddStrikeIfBubbleDeclined) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + StrikeDatabase_Upload_AddStrikeIfBubbleDeclined) { // Start sync. harness_->SetupSync(); @@ -2633,10 +2654,9 @@ // example of declining the prompt three times and ensuring that the // offer-to-save bubble does not appear on the fourth try. Then, ensures that no // strikes are added if the card already has max strikes. -IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, - StrikeDatabase_Upload_FullFlowTest) { - scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - +IN_PROC_BROWSER_TEST_F( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + StrikeDatabase_Upload_FullFlowTest) { bool controller_observer_set = false; // Start sync.
diff --git a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller_dialog_browsertest.cc b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller_dialog_browsertest.cc index 7faaad1..3740fe1 100644 --- a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller_dialog_browsertest.cc +++ b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller_dialog_browsertest.cc
@@ -18,14 +18,15 @@ class ReopenTabPromoControllerDialogBrowserTest : public DialogBrowserTest { public: - ReopenTabPromoControllerDialogBrowserTest() = default; + ReopenTabPromoControllerDialogBrowserTest() { + feature_list_.InitAndEnableFeature( + feature_engagement::kIPHReopenTabFeature); + } void SetUpOnMainThread() override { promo_controller_ = std::make_unique<ReopenTabPromoController>( BrowserView::GetBrowserViewForBrowser(browser())); promo_controller_->disable_bubble_timeout_for_test(); - feature_list_.InitAndEnableFeature( - feature_engagement::kIPHReopenTabFeature); } void ShowUi(const std::string& name) override {
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc index 7398f91..300c442 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -131,6 +131,11 @@ observer.OnMediaSessionMetadataUpdated(); } +const std::map<const std::string, MediaNotificationContainerImpl*>& +MediaDialogView::GetNotificationsForTesting() const { + return active_sessions_view_->notifications_for_testing(); +} + MediaDialogView::MediaDialogView(views::View* anchor_view, MediaToolbarButtonController* controller, service_manager::Connector* connector)
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h index ab5c816..689abe0 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -15,6 +15,7 @@ } // namespace service_manager class MediaDialogViewObserver; +class MediaNotificationContainerImpl; class MediaNotificationListView; class MediaToolbarButtonController; @@ -49,6 +50,9 @@ void OnMediaSessionMetadataChanged(); + const std::map<const std::string, MediaNotificationContainerImpl*>& + GetNotificationsForTesting() const; + private: explicit MediaDialogView(views::View* anchor_view, MediaToolbarButtonController* controller,
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc index b2ee861..878b9b0 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -10,11 +10,13 @@ #include "chrome/browser/ui/global_media_controls/media_toolbar_button_observer.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/global_media_controls/media_dialog_view_observer.h" +#include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h" #include "chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/media_message_center/media_notification_view.h" #include "content/public/browser/web_contents.h" #include "content/public/test/media_start_stop_observer.h" #include "media/base/media_switches.h" @@ -116,24 +118,21 @@ run_loop_->Run(); } + // Checks the title and artist of each notification in the dialog to see if + // |text| is contained anywhere in the dialog. bool DialogContainsText(const base::string16& text) { - return ViewContainsText(MediaDialogView::GetDialogViewForTesting(), text); - } - - // Recursively tries to find a views::Label containing |text| within |view| - // and its children. - bool ViewContainsText(const views::View* view, const base::string16& text) { - if (view->GetClassName() == views::Label::kViewClassName) { - const views::Label* label = static_cast<const views::Label*>(view); - if (label->GetText().find(text) != std::string::npos) + for (const auto notification_pair : + MediaDialogView::GetDialogViewForTesting() + ->GetNotificationsForTesting()) { + const media_message_center::MediaNotificationView* view = + notification_pair.second->view_for_testing(); + if (view->title_label_for_testing()->GetText().find(text) != + std::string::npos || + view->artist_label_for_testing()->GetText().find(text) != + std::string::npos) { return true; + } } - - for (const views::View* child : view->children()) { - if (ViewContainsText(child, text)) - return true; - } - return false; }
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h index bd54b19..7565301 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h +++ b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h
@@ -49,6 +49,10 @@ // views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; + media_message_center::MediaNotificationView* view_for_testing() { + return view_.get(); + } + private: class DismissButton;
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_list_view.h b/chrome/browser/ui/views/global_media_controls/media_notification_list_view.h index e094acbe..dc7c6fd6 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_list_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_notification_list_view.h
@@ -25,6 +25,11 @@ void HideNotification(const std::string& id); bool empty() { return notifications_.empty(); } + const std::map<const std::string, MediaNotificationContainerImpl*>& + notifications_for_testing() const { + return notifications_; + } + private: std::map<const std::string, MediaNotificationContainerImpl*> notifications_;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index 24dd1d6..ac4e1f3 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -436,7 +436,7 @@ if (!label()->GetVisible()) { // Start animation from the current width, otherwise the icon will also be // included if visible. - grow_animation_starting_width_ = width(); + grow_animation_starting_width_ = GetVisible() ? width() : 0; if (string_id) { base::string16 label = l10n_util::GetStringUTF16(string_id.value()); SetLabel(label);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc index 4478480..b51bfdf 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
@@ -188,11 +188,26 @@ // and use specified certificate validation results. This allows tests to mock // Extended Validation (EV) certificate connections. const char kMockSecureHostname[] = "example-secure.test"; -const GURL kMockSecureURL = GURL("https://example-secure.test"); -class SecurityIndicatorTest : public InProcessBrowserTest { +struct SecurityIndicatorTestParams { + bool is_enabled; + bool use_secure_url; + net::CertStatus cert_status; + security_state::SecurityLevel security_level; + bool should_show_text; + base::string16 indicator_text; +}; + +class SecurityIndicatorTest + : public InProcessBrowserTest, + public ::testing::WithParamInterface<SecurityIndicatorTestParams> { public: - SecurityIndicatorTest() : InProcessBrowserTest(), cert_(nullptr) {} + SecurityIndicatorTest() : InProcessBrowserTest(), cert_(nullptr) { + if (GetParam().is_enabled) + feature_list_.InitAndEnableFeature(omnibox::kSimplifyHttpsIndicator); + else + feature_list_.InitAndDisableFeature(omnibox::kSimplifyHttpsIndicator); + } void SetUpInProcessBrowserTestFixture() override { cert_ = @@ -238,6 +253,8 @@ } private: + base::test::ScopedFeatureList feature_list_; + scoped_refptr<net::X509Certificate> cert_; std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_; @@ -247,30 +264,10 @@ // Check that the security indicator text is correctly set for the various // variations of the Security UI Study (https://crbug.com/803501). -IN_PROC_BROWSER_TEST_F(SecurityIndicatorTest, CheckIndicatorText) { +IN_PROC_BROWSER_TEST_P(SecurityIndicatorTest, CheckIndicatorText) { + const GURL kMockSecureURL = GURL("https://example-secure.test"); const GURL kMockNonsecureURL = embedded_test_server()->GetURL("example.test", "/"); - const base::string16 kEvString = base::ASCIIToUTF16("Test CA [US]"); - const base::string16 kEmptyString = base::string16(); - - const struct { - bool is_enabled; - GURL url; - net::CertStatus cert_status; - security_state::SecurityLevel security_level; - bool should_show_text; - base::string16 indicator_text; - } cases[]{ - // Disabled (show EV UI in omnibox) - {false, kMockSecureURL, net::CERT_STATUS_IS_EV, security_state::EV_SECURE, - true, kEvString}, - {false, kMockSecureURL, 0, security_state::SECURE, false, kEmptyString}, - {false, kMockNonsecureURL, 0, security_state::NONE, false, kEmptyString}, - // Default (lock-only in omnibox) - {true, kMockSecureURL, net::CERT_STATUS_IS_EV, security_state::EV_SECURE, - false, kEmptyString}, - {true, kMockSecureURL, 0, security_state::SECURE, false, kEmptyString}, - {true, kMockNonsecureURL, 0, security_state::NONE, false, kEmptyString}}; content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); @@ -279,22 +276,36 @@ ASSERT_TRUE(helper); LocationBarView* location_bar_view = GetLocationBarView(); - for (const auto& c : cases) { - base::test::ScopedFeatureList scoped_feature_list; - if (c.is_enabled) { - scoped_feature_list.InitAndEnableFeature( - omnibox::kSimplifyHttpsIndicator); - } else { - scoped_feature_list.InitAndDisableFeature( - omnibox::kSimplifyHttpsIndicator); - } - SetUpInterceptor(c.cert_status); - ui_test_utils::NavigateToURL(browser(), c.url); - EXPECT_EQ(c.security_level, helper->GetSecurityLevel()); - EXPECT_EQ(c.should_show_text, - location_bar_view->location_icon_view()->ShouldShowLabel()); - EXPECT_EQ(c.indicator_text, - location_bar_view->location_icon_view()->GetText()); - ResetInterceptor(); - } + auto c = GetParam(); + SetUpInterceptor(c.cert_status); + ui_test_utils::NavigateToURL( + browser(), c.use_secure_url ? kMockSecureURL : kMockNonsecureURL); + EXPECT_EQ(c.security_level, helper->GetSecurityLevel()); + EXPECT_EQ(c.should_show_text, + location_bar_view->location_icon_view()->ShouldShowLabel()); + EXPECT_EQ(c.indicator_text, + location_bar_view->location_icon_view()->GetText()); + ResetInterceptor(); } + +const base::string16 kEvString = base::ASCIIToUTF16("Test CA [US]"); +const base::string16 kEmptyString = base::string16(); +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + SecurityIndicatorTest, + ::testing::Values( + // Disabled (show EV UI in omnibox) + SecurityIndicatorTestParams{false, true, net::CERT_STATUS_IS_EV, + security_state::EV_SECURE, true, kEvString}, + SecurityIndicatorTestParams{false, true, 0, security_state::SECURE, + false, kEmptyString}, + SecurityIndicatorTestParams{false, false, 0, security_state::NONE, + false, kEmptyString}, + // Default (lock-only in omnibox) + SecurityIndicatorTestParams{true, true, net::CERT_STATUS_IS_EV, + security_state::EV_SECURE, false, + kEmptyString}, + SecurityIndicatorTestParams{true, true, 0, security_state::SECURE, + false, kEmptyString}, + SecurityIndicatorTestParams{true, false, 0, security_state::NONE, false, + kEmptyString}));
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc index a5532da2..21d8730 100644 --- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -32,6 +32,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/safe_browsing/db/v4_protocol_manager_util.h" +#include "components/security_state/core/features.h" #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_contents.h" @@ -159,18 +160,19 @@ void SetUp() override { switch (ui_status()) { case UIStatus::kDisabled: - feature_list_.InitAndDisableFeature(features::kSafetyTipUI); + feature_list_.InitAndDisableFeature( + security_state::features::kSafetyTipUI); break; case UIStatus::kEnabled: feature_list_.InitWithFeaturesAndParameters( - {{features::kSafetyTipUI, {}}, + {{security_state::features::kSafetyTipUI, {}}, {features::kLookalikeUrlNavigationSuggestionsUI, {{"topsites", "true"}}}}, {}); break; case UIStatus::kEnabledWithEditDistance: feature_list_.InitWithFeaturesAndParameters( - {{features::kSafetyTipUI, + {{security_state::features::kSafetyTipUI, {{"editdistance", "true"}, {"editdistance_siteengagement", "true"}}}, {features::kLookalikeUrlNavigationSuggestionsUI, @@ -178,6 +180,7 @@ {}); } + InitializeSafetyTipConfig(); InProcessBrowserTest::SetUp(); } @@ -292,6 +295,25 @@ ASSERT_NO_FATAL_FAILURE(CheckPageInfoShowsSafetyTipInfo(browser())); } +// Ensure explicitly-allowed sites don't get blocked when the site is otherwise +// blocked server-side. +IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, + NoShowOnAllowlist) { + auto kNavigatedUrl = GetURL("site1.com"); + + // Ensure a Safety Tip is triggered initially... + SetSafetyTipBadRepPatterns({"site1.com/"}); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_TRUE(IsUIShowingIfEnabled()); + ASSERT_NO_FATAL_FAILURE(CheckPageInfoShowsSafetyTipInfo(browser())); + + // ...but suppressed by the allowlist. + SetSafetyTipAllowlistPatterns({"site1.com/"}); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_FALSE(IsUIShowing()); + ASSERT_NO_FATAL_FAILURE(CheckPageInfoDoesNotShowSafetyTipInfo(browser())); +} + // After the user clicks 'leave site', the user should end up on a safe domain. IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, LeaveSiteLeavesSite) { @@ -435,6 +457,25 @@ ASSERT_NO_FATAL_FAILURE(CheckPageInfoDoesNotShowSafetyTipInfo(browser())); } +// Tests that Safety Tips don't trigger on lookalike domains that are explicitly +// allowed by the allowlist. +IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, + NoTriggersOnLookalikeAllowlist) { + // This domain is a lookalike of a top domain not in the top 500. + const GURL kNavigatedUrl = GetURL("googlé.sk"); + + // Ensure a Safety Tip is triggered initially... + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_TRUE(IsUIShowingIfEnabled()); + + // ...but suppressed by the allowlist. + SetSafetyTipAllowlistPatterns({"xn--googl-fsa.sk/"}); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_FALSE(IsUIShowing()); +} + // Tests that Safety Tips trigger (or not) on lookalike domains with edit // distance when enabled, and not otherwise. IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc index 68d5006c..0864a37 100644 --- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -225,11 +225,20 @@ EXPECT_TRUE(save_button->GetEnabled()); } -IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest, EditingMaskedCard) { - // Masked cards are from Google Pay. - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kReturnGooglePayInBasicCard); +class PaymentRequestCreditCardEditorTestWithGooglePayEnabled + : public PaymentRequestCreditCardEditorTest { + public: + PaymentRequestCreditCardEditorTestWithGooglePayEnabled() { + // Masked cards are from Google Pay. + feature_list_.InitAndEnableFeature(features::kReturnGooglePayInBasicCard); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTestWithGooglePayEnabled, + EditingMaskedCard) { NavigateTo("/payment_request_no_shipping_test.html"); autofill::TestAutofillClock test_clock; test_clock.SetNow(kJune2017); @@ -309,12 +318,8 @@ EXPECT_EQ(additional_profile.guid(), selected->billing_address_id()); } -IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest, +IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTestWithGooglePayEnabled, EditingMaskedCard_ClickOnPaymentsLink) { - // Masked cards are from Google Pay. - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kReturnGooglePayInBasicCard); - NavigateTo("/payment_request_no_shipping_test.html"); autofill::TestAutofillClock test_clock; test_clock.SetNow(kJune2017);
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc index ca498db..d928e02 100644 --- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -194,14 +194,24 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COULD_NOT_SHOW); } -IN_PROC_BROWSER_TEST_F(PaymentRequestJourneyLoggerMultipleShowTest, - StartNewRequest) { +class PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersEnabled + : public PaymentRequestJourneyLoggerMultipleShowTest { + public: + PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersEnabled() { + // Enable payment handlers, also known as service worker payment apps. The + // rest of the test is identical to + // "StartNewRequestWithoutPaymentAppsFeature" testcase above. + feature_list_.InitAndEnableFeature(features::kServiceWorkerPaymentApps); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersEnabled, + StartNewRequest) { NavigateTo("/payment_request_multiple_show_test.html"); - // Enable payment handlers, also known as service worker payment apps. The - // rest of the test is identical to "StartNewRequestWithoutPaymentAppsFeature" - // testcase above. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kServiceWorkerPaymentApps); base::HistogramTester histogram_tester; @@ -300,14 +310,23 @@ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_COULD_NOT_SHOW); } -IN_PROC_BROWSER_TEST_F(PaymentRequestJourneyLoggerMultipleShowTest, - StartNewRequestWithoutPaymentAppsFeature) { +class PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersDisabled + : public PaymentRequestJourneyLoggerMultipleShowTest { + public: + PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersDisabled() { + // Disable payment handlers, also known as service worker payment apps. The + // rest of the test is identical to "StartNewRequest" testcase above. + feature_list_.InitAndDisableFeature(features::kServiceWorkerPaymentApps); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + PaymentRequestJourneyLoggerMultipleShowTestWithPaymentHandlersDisabled, + StartNewRequestWithoutPaymentAppsFeature) { NavigateTo("/payment_request_multiple_show_test.html"); - // Disable payment handlers, also known as service worker payment apps. The - // rest of the test is identical to "StartNewRequest" testcase above. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - features::kServiceWorkerPaymentApps); base::HistogramTester histogram_tester;
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc index 960bd94b6..1758dc1c 100644 --- a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
@@ -469,15 +469,25 @@ } } -IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest, SkipUIEnabledWithBobPay) { +class PaymentRequestPaymentAppTestWithPaymentHandlersAndUiSkip + : public PaymentRequestPaymentAppTest { + public: + PaymentRequestPaymentAppTestWithPaymentHandlersAndUiSkip() { + feature_list_.InitWithFeatures( + { + payments::features::kWebPaymentsSingleAppUiSkip, + ::features::kServiceWorkerPaymentApps, + }, + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTestWithPaymentHandlersAndUiSkip, + SkipUIEnabledWithBobPay) { base::HistogramTester histogram_tester; - base::test::ScopedFeatureList features; - features.InitWithFeatures( - { - payments::features::kWebPaymentsSingleAppUiSkip, - ::features::kServiceWorkerPaymentApps, - }, - {}); InstallBobPayForMethod("https://bobpay.com"); { @@ -508,15 +518,8 @@ } } -IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest, +IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTestWithPaymentHandlersAndUiSkip, SkipUIDisabledWithMultipleAcceptedMethods) { - base::test::ScopedFeatureList features; - features.InitWithFeatures( - { - payments::features::kWebPaymentsSingleAppUiSkip, - ::features::kServiceWorkerPaymentApps, - }, - {}); InstallBobPayForMethod("https://bobpay.com"); { @@ -536,15 +539,8 @@ } } -IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest, +IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTestWithPaymentHandlersAndUiSkip, SkipUIDisabledWithRequestedPayerEmail) { - base::test::ScopedFeatureList features; - features.InitWithFeatures( - { - payments::features::kWebPaymentsSingleAppUiSkip, - ::features::kServiceWorkerPaymentApps, - }, - {}); InstallBobPayForMethod("https://bobpay.com"); autofill::AutofillProfile profile(autofill::test::GetFullProfile()); AddAutofillProfile(profile);
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc index 29264e8..2c571f6 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc
@@ -127,7 +127,6 @@ } void AllowPluginVm() { - EnablePluginVmFeature(); EnterpriseEnrollDevice(); SetUserWithAffiliation(); SetPluginVmDevicePolicies(); @@ -175,7 +174,6 @@ chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_; chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_; - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; PluginVmLauncherViewForTesting* view_; @@ -184,10 +182,6 @@ chromeos::FakeConciergeClient* fake_concierge_client_; private: - void EnablePluginVmFeature() { - scoped_feature_list_.InitAndEnableFeature(features::kPluginVm); - } - void EnterpriseEnrollDevice() { scoped_stub_install_attributes_.Get()->SetCloudManaged("example.com", "device_id"); @@ -215,12 +209,23 @@ DISALLOW_COPY_AND_ASSIGN(PluginVmLauncherViewBrowserTest); }; +class PluginVmLauncherViewBrowserTestWithFeatureEnabled + : public PluginVmLauncherViewBrowserTest { + public: + PluginVmLauncherViewBrowserTestWithFeatureEnabled() { + feature_list_.InitAndEnableFeature(features::kPluginVm); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + // Test the dialog is actually can be launched. IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, InvokeUi_default) { ShowAndVerifyUi(); } -IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, +IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTestWithFeatureEnabled, SetupShouldFinishSuccessfully) { AllowPluginVm(); plugin_vm::SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); @@ -237,7 +242,7 @@ plugin_vm::PluginVmSetupResult::kSuccess, 1); } -IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, +IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTestWithFeatureEnabled, SetupShouldFailAsHashesDoNotMatch) { AllowPluginVm(); // Reset PluginVmImage hash to non-matching. @@ -256,7 +261,7 @@ plugin_vm::PluginVmSetupResult::kErrorDownloadingPluginVmImage, 1); } -IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, +IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTestWithFeatureEnabled, SetupShouldFailAsImportingFails) { AllowPluginVm(); SetPluginVmImagePref(embedded_test_server()->GetURL(kJpgFile).spec(), @@ -274,7 +279,7 @@ plugin_vm::PluginVmSetupResult::kErrorImportingPluginVmImage, 1); } -IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, +IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTestWithFeatureEnabled, CouldRetryAfterFailedSetup) { AllowPluginVm(); // Reset PluginVmImage hash to non-matching.
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc index 3533fc5..23073be 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -496,11 +496,20 @@ ShowAndVerifyUi(); } +class ProfileMenuViewExtensionsParamTestWithScopedAccountConsistency + : public ProfileMenuViewExtensionsParamTest { + public: + ProfileMenuViewExtensionsParamTestWithScopedAccountConsistency() = default; + + private: + ScopedAccountConsistencyDice scoped_dice_; +}; + // Shows the |ProfileMenuView| during a Guest browsing session when the DICE // flag is enabled. -IN_PROC_BROWSER_TEST_P(ProfileMenuViewExtensionsParamTest, - InvokeUi_DiceGuest) { - ScopedAccountConsistencyDice scoped_dice; +IN_PROC_BROWSER_TEST_P( + ProfileMenuViewExtensionsParamTestWithScopedAccountConsistency, + InvokeUi_DiceGuest) { ShowAndVerifyUi(); } @@ -525,6 +534,15 @@ ShowAndVerifyUi(); } +class ProfileMenuViewExtensionsTestWithScopedAccountConsistency + : public ProfileMenuViewExtensionsTest { + public: + ProfileMenuViewExtensionsTestWithScopedAccountConsistency() = default; + + private: + ScopedAccountConsistencyDice scoped_dice_; +}; + // Open the profile chooser to increment the Dice sign-in promo show counter // below the threshold. // TODO(https://crbug.com/862573): Re-enable when no longer failing when @@ -536,9 +554,9 @@ #define MAYBE_IncrementDiceSigninPromoShowCounter \ IncrementDiceSigninPromoShowCounter #endif -IN_PROC_BROWSER_TEST_F(ProfileMenuViewExtensionsTest, - MAYBE_IncrementDiceSigninPromoShowCounter) { - ScopedAccountConsistencyDice scoped_dice; +IN_PROC_BROWSER_TEST_F( + ProfileMenuViewExtensionsTestWithScopedAccountConsistency, + MAYBE_IncrementDiceSigninPromoShowCounter) { browser()->profile()->GetPrefs()->SetInteger( prefs::kDiceSigninUserMenuPromoCount, 7); ASSERT_NO_FATAL_FAILURE(OpenProfileMenuView(browser())); @@ -556,9 +574,9 @@ #define MAYBE_DiceSigninPromoWithoutIllustration \ DiceSigninPromoWithoutIllustration #endif -IN_PROC_BROWSER_TEST_F(ProfileMenuViewExtensionsTest, - MAYBE_DiceSigninPromoWithoutIllustration) { - ScopedAccountConsistencyDice scoped_dice; +IN_PROC_BROWSER_TEST_F( + ProfileMenuViewExtensionsTestWithScopedAccountConsistency, + MAYBE_DiceSigninPromoWithoutIllustration) { browser()->profile()->GetPrefs()->SetInteger( prefs::kDiceSigninUserMenuPromoCount, 10); ASSERT_NO_FATAL_FAILURE(OpenProfileMenuView(browser())); @@ -894,12 +912,12 @@ ProfileMenuClickTest_WithUnconsentedPrimaryAccount::kOrderedActionableItems []; +// TODO(crbug.com/1012167): Flaky. IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_WithUnconsentedPrimaryAccount, - SetupAndRunTest) { + DISABLED_SetupAndRunTest) { signin::MakeAccountAvailableWithCookies(identity_manager(), &test_url_loader_factory_, "user@example.com", "gaia_id"); - ASSERT_TRUE(sync_harness()->AwaitSyncTransportActive()); // Check that the setup was successful. ASSERT_FALSE(identity_manager()->HasPrimaryAccount()); ASSERT_TRUE(identity_manager()->HasUnconsentedPrimaryAccount());
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index c61e6e5..c9b21ad 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -648,8 +648,6 @@ Browser* browser() const { return InProcessBrowserTest::browser(); } - base::test::ScopedFeatureList scoped_feature_list_; - private: #if defined(OS_CHROMEOS) // The root window for the event generator. @@ -659,6 +657,17 @@ DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest); }; +class DetachToBrowserTabDragControllerTestWithTabGroupsEnabled + : public DetachToBrowserTabDragControllerTest { + public: + DetachToBrowserTabDragControllerTestWithTabGroupsEnabled() { + scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + // Creates a browser with two tabs, drags the second to the first. IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) { AddTabsAndResetBrowser(browser(), 1); @@ -687,10 +696,8 @@ // removal of the dragged tab from its group. Then dragging the second tab to // after the third tab will also result in a removal of that dragged tab from // its group. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragRightToUngroupTab) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -730,10 +737,8 @@ // removal of the dragged tab from its group. Then dragging the third tab to // before the second tab will also result in a removal of that dragged tab from // its group. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragLeftToUngroupTab) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -772,9 +777,8 @@ // Creates a browser with four tabs. The first three belong in the same Tab // Group. Dragging tabs in a tab group within the defined threshold does not // modify the group of the dragged tab. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragTabWithinGroupDoesNotModifyGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -808,10 +812,8 @@ // Creates a browser with four tabs. The first tab is in a Tab Group. Dragging // the only tab in that group will remove the group. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragOnlyTabInGroupRemovesGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -839,10 +841,8 @@ // tab over one to the left will result in the tab joining Tab Group 1. Then // dragging the fourth tab over one to the left will result in the tab joining // Tab Group 1 as well. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragSingleTabLeftIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -895,10 +895,8 @@ // over one to the right will result in the tab joining Tab Group 1. Then // dragging the first tab over one to the right will result in the tab joining // Tab Group 1 as well. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragSingleTabRightIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -943,10 +941,8 @@ // tabs joining the same group as the tab in the second position. Then dragging // the tabs over two to the right will result in the tabs joining the same group // as the last tab. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragMultipleTabsRightIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -994,10 +990,8 @@ // Creates a browser with four tabs each in its own group. Selecting and // dragging the second and fourth tabs left at the fourth tab will result in the // tabs joining the same group as the tab in the third position. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragMultipleTabsLeftIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -1032,10 +1026,8 @@ // Dragging the third tab over one to the left will result in the tab joining // Tab Group 1. While this drag is still in session, pressing escape will revert // group of the tab to before the drag session started. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, RevertDragSingleTabIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -1065,10 +1057,8 @@ // will result in the tab joining Tab Group 1. While this drag is still in // session, pressing escape will revert group of the tab to before the drag // session started. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, RevertDragSingleTabGroupIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -1848,10 +1838,8 @@ // two tabs in another group {group1}. Dragging the two tabs in the first // browser into the middle of the second browser will insert the two dragged // tabs into the {group1}} after the first tab. -IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, DragWindowIntoGroup) { - scoped_feature_list_.InitAndEnableFeature(features::kTabGroups); - TabStrip* tab_strip = GetTabStripForBrowser(browser()); TabStripModel* model = browser()->tab_strip_model(); @@ -3686,6 +3674,10 @@ INSTANTIATE_TEST_SUITE_P(TabDragging, DetachToBrowserTabDragControllerTest, ::testing::Values("mouse", "touch")); +INSTANTIATE_TEST_SUITE_P( + TabDragging, + DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, + ::testing::Values("mouse", "touch")); INSTANTIATE_TEST_SUITE_P(TabDragging, DetachToBrowserInSeparateDisplayTabDragControllerTest, ::testing::Values("mouse")); @@ -3703,4 +3695,8 @@ INSTANTIATE_TEST_SUITE_P(TabDragging, DetachToBrowserTabDragControllerTest, ::testing::Values("mouse")); +INSTANTIATE_TEST_SUITE_P( + TabDragging, + DetachToBrowserTabDragControllerTestWithTabGroupsEnabled, + ::testing::Values("mouse")); #endif
diff --git a/chrome/browser/ui/views/translate/translate_language_browsertest.cc b/chrome/browser/ui/views/translate/translate_language_browsertest.cc index 0590946..6de8009d 100644 --- a/chrome/browser/ui/views/translate/translate_language_browsertest.cc +++ b/chrome/browser/ui/views/translate/translate_language_browsertest.cc
@@ -279,10 +279,19 @@ EXPECT_EQ("fr", GetLanguageState().current_language()); } -IN_PROC_BROWSER_TEST_F(TranslateLanguageBrowserTest, RecentTargetLanguage) { - base::test::ScopedFeatureList enable_feature; - enable_feature.InitAndEnableFeature(kTranslateRecentTarget); +class TranslateLanguageBrowserTestWithTranslateRecentTarget + : public TranslateLanguageBrowserTest { + public: + TranslateLanguageBrowserTestWithTranslateRecentTarget() { + feature_list_.InitAndEnableFeature(kTranslateRecentTarget); + } + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(TranslateLanguageBrowserTestWithTranslateRecentTarget, + RecentTargetLanguage) { InitInIncognitoMode(false); // Before browsing: set auto translate from French to Chinese.
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc index 41f5e3c..6807af9 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc
@@ -201,8 +201,11 @@ // Tests that the Settings app migrates the launcher and app list details from // the Settings internal app. +// +// TODO(https://crbug.com/1012967): Find a way to implement this that does not +// depend on unsupported behavior of the FeatureList API. IN_PROC_BROWSER_TEST_F(WebAppUiManagerMigrationBrowserTest, - SettingsSystemWebAppMigration) { + DISABLED_SettingsSystemWebAppMigration) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature(features::kSystemWebApps);
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc index 55649387..c23cac4 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
@@ -99,14 +99,21 @@ // https://crbug.com/855344. } -IN_PROC_BROWSER_TEST_F(SystemWebDialogTest, FontSize) { +class SystemWebDialogTestWithSplitSettings : public SystemWebDialogTest { + public: + SystemWebDialogTestWithSplitSettings() { + feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettings); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SystemWebDialogTestWithSplitSettings, FontSize) { const content::WebPreferences kDefaultPrefs; const int kDefaultFontSize = kDefaultPrefs.default_font_size; const int kDefaultFixedFontSize = kDefaultPrefs.default_fixed_font_size; - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kSplitSettings); - // Set the browser font sizes to non-default values. PrefService* profile_prefs = browser()->profile()->GetPrefs(); profile_prefs->SetInteger(prefs::kWebKitDefaultFontSize, @@ -127,10 +134,7 @@ EXPECT_EQ(kDefaultFixedFontSize, dialog_prefs.default_fixed_font_size); } -IN_PROC_BROWSER_TEST_F(SystemWebDialogTest, PageZoom) { - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(features::kSplitSettings); - +IN_PROC_BROWSER_TEST_F(SystemWebDialogTestWithSplitSettings, PageZoom) { // Set the default browser page zoom to 150%. double level = blink::PageZoomFactorToZoomLevel(1.5); browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(level);
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 b9660fb..86da30a 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -966,6 +966,7 @@ void CupsPrintersHandler::HandleStartDiscovery(const base::ListValue* args) { PRINTER_LOG(DEBUG) << "Start printer discovery"; + AllowJavascript(); discovery_active_ = true; OnPrintersChanged(PrinterClass::kAutomatic, printers_manager_->GetPrinters(PrinterClass::kAutomatic));
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc index b4dbace..51865b80 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
@@ -11,6 +11,7 @@ #include "base/base64.h" #include "base/bind.h" +#include "base/strings/string_piece.h" #include "base/values.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" @@ -45,8 +46,6 @@ // Writes bytes to a std::vector that can be fetched. This is used to record the // output of skia image encoding. -// -// TODO(crbug.com/991393): remove this when we no longer transcode images here. class BufferWStream : public SkWStream { public: BufferWStream() = default; @@ -68,26 +67,23 @@ std::vector<unsigned char> result_; }; -std::string EncodeImage(gfx::ImageSkia image, - SkEncodedImageFormat format, - float scale_factor) { +std::string MakeDataURIForImage(base::span<const uint8_t> image_data, + base::StringPiece mime_subtype) { + std::string result = "data:image/"; + result.append(mime_subtype.begin(), mime_subtype.end()); + result += ";base64,"; + result += base::Base64Encode(image_data); + return result; +} + +std::string EncodePNGAndMakeDataURI(gfx::ImageSkia image, float scale_factor) { const SkBitmap& bitmap = image.GetRepresentation(scale_factor).GetBitmap(); BufferWStream stream; - const bool encoding_succeeded = SkEncodeImage(&stream, bitmap, format, 100); + const bool encoding_succeeded = + SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100); DCHECK(encoding_succeeded); - const std::vector<unsigned char> image_data = stream.GetBuffer(); - - std::string mime_subtype; - if (format == SkEncodedImageFormat::kJPEG) { - mime_subtype = "jpeg"; - } else if (format == SkEncodedImageFormat::kPNG) { - mime_subtype = "png"; - } else { - NOTREACHED(); - } - - return "data:image/" + mime_subtype + ";base64," + - base::Base64Encode(base::as_bytes(base::make_span(image_data))); + return MakeDataURIForImage( + base::as_bytes(base::make_span(stream.GetBuffer())), "png"); } class WebUITabContextMenu : public ui::SimpleMenuModel::Delegate, @@ -224,10 +220,9 @@ tab_data.SetString("url", tab_renderer_data.visible_url.GetContent()); if (!tab_renderer_data.favicon.isNull()) { - tab_data.SetString( - "favIconUrl", - EncodeImage(tab_renderer_data.favicon, SkEncodedImageFormat::kPNG, - web_ui()->GetDeviceScaleFactor())); + tab_data.SetString("favIconUrl", EncodePNGAndMakeDataURI( + tab_renderer_data.favicon, + web_ui()->GetDeviceScaleFactor())); } tab_data.SetInteger("networkState", @@ -349,24 +344,15 @@ // Callback passed to |thumbnail_tracker_|. Called when a tab's thumbnail // changes, or when we start watching the tab. - void HandleThumbnailUpdate(content::WebContents* tab, gfx::ImageSkia image) { + void HandleThumbnailUpdate(content::WebContents* tab, + ThumbnailTracker::CompressedThumbnailData image) { // Send base-64 encoded image to JS side. - // - // TODO(crbug.com/991393): streamline the process from tab capture to - // sending the image. Currently, a frame is captured, sent to - // ThumbnailImage, encoded to JPEG (w/ a copy), decoded to a raw bitmap - // (another copy), and sent to observers. Here, we then re-encode the image - // to a JPEG (another copy), encode to base64 (another copy), append the - // base64 header (another copy), and send it (another copy). This is 6 - // copies of essentially the same image, and it is de-encoded and re-encoded - // to the same format. We can reduce the number of copies and avoid the - // redundant encoding. - std::string encoded_image = EncodeImage(image, SkEncodedImageFormat::kJPEG, - web_ui()->GetDeviceScaleFactor()); + std::string data_uri = + MakeDataURIForImage(base::make_span(image->data), "jpeg"); const int tab_id = extensions::ExtensionTabUtil::GetTabId(tab); FireWebUIListener("tab-thumbnail-updated", base::Value(tab_id), - base::Value(encoded_image)); + base::Value(data_uri)); } Browser* const browser_;
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h index 02c375f..e7b7818 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h
@@ -45,7 +45,8 @@ void Initialize(Browser* browser, Embedder* embedder); private: - void HandleThumbnailUpdate(int extension_tab_id, gfx::ImageSkia image); + void HandleThumbnailUpdate(int extension_tab_id, + ThumbnailTracker::CompressedThumbnailData image); DISALLOW_COPY_AND_ASSIGN(TabStripUI); };
diff --git a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc index 262144c..4ec05c2 100644 --- a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc +++ b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/scoped_observer.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/thumbnails/thumbnail_image.h" #include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h" #include "content/public/browser/web_contents_observer.h" @@ -28,7 +27,7 @@ void RequestThumbnail() { if (thumbnail_) - thumbnail_->RequestThumbnailImage(); + thumbnail_->RequestCompressedThumbnailData(); } // content::WebContents: @@ -45,7 +44,8 @@ } // ThumbnailImage::Observer: - void OnThumbnailImageAvailable(gfx::ImageSkia thumbnail_image) override { + void OnCompressedThumbnailDataAvailable( + CompressedThumbnailData thumbnail_image) override { parent_->ThumbnailUpdated(web_contents(), thumbnail_image); } @@ -79,7 +79,7 @@ } void ThumbnailTracker::ThumbnailUpdated(content::WebContents* contents, - gfx::ImageSkia image) { + CompressedThumbnailData image) { callback_.Run(contents, image); }
diff --git a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h index 2d64d3d..feb174d 100644 --- a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h +++ b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h
@@ -9,19 +9,20 @@ #include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" +#include "chrome/browser/ui/thumbnails/thumbnail_image.h" #include "ui/gfx/image/image_skia.h" namespace content { class WebContents; } -class ThumbnailImage; - // Tracks the thumbnails of a set of WebContentses. This set is dynamically // managed, and WebContents closure is handled gracefully. The user is notified // of any thumbnail change via a callback specified on construction. class ThumbnailTracker { public: + using CompressedThumbnailData = ThumbnailImage::CompressedThumbnailData; + // Should return the ThumbnailImage instance for a WebContents. using GetThumbnailCallback = base::RepeatingCallback<scoped_refptr<ThumbnailImage>( @@ -29,7 +30,8 @@ // Handles a thumbnail update for a tab. using ThumbnailUpdatedCallback = - base::RepeatingCallback<void(content::WebContents*, gfx::ImageSkia)>; + base::RepeatingCallback<void(content::WebContents*, + CompressedThumbnailData)>; explicit ThumbnailTracker(ThumbnailUpdatedCallback callback); // Specifies how to get a ThumbnailImage for a WebContents. This is intended @@ -44,7 +46,8 @@ void WatchTab(content::WebContents* contents); private: - void ThumbnailUpdated(content::WebContents* contents, gfx::ImageSkia image); + void ThumbnailUpdated(content::WebContents* contents, + CompressedThumbnailData image); void ContentsClosed(content::WebContents* contents); // The default |GetThumbnailCallback| implementation.
diff --git a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker_unittest.cc b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker_unittest.cc index eac65cc..71429601 100644 --- a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker_unittest.cc +++ b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker_unittest.cc
@@ -99,11 +99,9 @@ // Verify that WatchTab() gets the current image, waiting for the decoding to // happen. EXPECT_CALL(thumbnail_updated_callback_, Run(contents.get(), _)).Times(1); - base::RunLoop notify_loop; thumbnail->set_async_operation_finished_callback_for_testing( - notify_loop.QuitClosure()); + base::RepeatingClosure()); thumbnail_tracker_.WatchTab(contents.get()); - notify_loop.Run(); } TEST_F(ThumbnailTrackerTest, PropagatesThumbnailUpdate) {
diff --git a/chrome/browser/ui/webui/webapks_handler.cc b/chrome/browser/ui/webui/webapks_handler.cc index 2fa4467..e7417b0 100644 --- a/chrome/browser/ui/webui/webapks_handler.cc +++ b/chrome/browser/ui/webui/webapks_handler.cc
@@ -78,5 +78,5 @@ webapk_info.is_backing_browser ? webapk_info.update_status : "Current browser doesn't own this WebAPK."); - CallJavascriptFunction("returnWebApkInfo", result); + FireWebUIListener("web-apk-info", result); }
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.cc b/chrome/browser/vr/test/webxr_vr_browser_test.cc index 80e276c..e29416f 100644 --- a/chrome/browser/vr/test/webxr_vr_browser_test.cc +++ b/chrome/browser/vr/test/webxr_vr_browser_test.cc
@@ -16,6 +16,7 @@ WebXrVrBrowserTestBase::WebXrVrBrowserTestBase() { enable_features_.push_back(features::kWebXr); + enable_features_.push_back(features::kWebXrGamepadModule); } WebXrVrBrowserTestBase::~WebXrVrBrowserTestBase() = default;
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc index 6d5bc1d..921779c 100644 --- a/chrome/browser/vr/testapp/vr_test_context.cc +++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -720,8 +720,8 @@ security_state::SecurityLevel::SECURE, &omnibox::kHttpsValidIcon, true, false}, {GURL("https://www.domain.com/path/segment/directory/file.html"), - security_state::SecurityLevel::DANGEROUS, &omnibox::kHttpsInvalidIcon, - true, false}, + security_state::SecurityLevel::DANGEROUS, + &omnibox::kNotSecureWarningIcon, true, false}, // Do not show URL {GURL(), security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, false, false},
diff --git a/chrome/browser/wake_lock/wake_lock_browsertest.cc b/chrome/browser/wake_lock/wake_lock_browsertest.cc index d75567a..051c1f33 100644 --- a/chrome/browser/wake_lock/wake_lock_browsertest.cc +++ b/chrome/browser/wake_lock/wake_lock_browsertest.cc
@@ -154,13 +154,9 @@ PermissionRequestObserver observer( browser()->tab_strip_model()->GetActiveWebContents()); - std::string response; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - browser()->tab_strip_model()->GetActiveWebContents(), - "WakeLock.requestPermission('screen').then(status => " - " domAutomationController.send(status));", - &response)); - EXPECT_EQ(response, "granted"); + EXPECT_EQ("granted", content::EvalJs( + browser()->tab_strip_model()->GetActiveWebContents(), + "WakeLock.requestPermission('screen')")); EXPECT_EQ(observer.request_shown(), false); } @@ -172,13 +168,11 @@ PermissionRequestObserver observer( browser()->tab_strip_model()->GetActiveWebContents()); - std::string response; - EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractString( - browser()->tab_strip_model()->GetActiveWebContents(), - "WakeLock.requestPermission('screen').then(status => " - " domAutomationController.send(status));", - &response)); - EXPECT_EQ(response, "granted"); + EXPECT_EQ( + "granted", + content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), + "WakeLock.requestPermission('screen')", + content::EvalJsOptions::EXECUTE_SCRIPT_NO_USER_GESTURE)); EXPECT_EQ(observer.request_shown(), false); } @@ -189,13 +183,9 @@ PermissionRequestObserver observer( browser()->tab_strip_model()->GetActiveWebContents()); - std::string response; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - browser()->tab_strip_model()->GetActiveWebContents(), - "WakeLock.requestPermission('system').then(status => " - " domAutomationController.send(status));", - &response)); - EXPECT_EQ(response, "denied"); + EXPECT_EQ("denied", content::EvalJs( + browser()->tab_strip_model()->GetActiveWebContents(), + "WakeLock.requestPermission('system')")); EXPECT_EQ(observer.request_shown(), false); } @@ -207,12 +197,10 @@ PermissionRequestObserver observer( browser()->tab_strip_model()->GetActiveWebContents()); - std::string response; - EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractString( - browser()->tab_strip_model()->GetActiveWebContents(), - "WakeLock.requestPermission('system').then(status => " - " domAutomationController.send(status));", - &response)); - EXPECT_EQ(response, "denied"); + EXPECT_EQ( + "denied", + content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), + "WakeLock.requestPermission('system')", + content::EvalJsOptions::EXECUTE_SCRIPT_NO_USER_GESTURE)); EXPECT_EQ(observer.request_shown(), false); }
diff --git a/chrome/chrome_cleaner/OWNERS b/chrome/chrome_cleaner/OWNERS index 6459769..276db6fa 100644 --- a/chrome/chrome_cleaner/OWNERS +++ b/chrome/chrome_cleaner/OWNERS
@@ -1,4 +1,4 @@ -joenotcharles@google.com +joenotcharles@chromium.org proberge@chromium.org # TEAM: security-dev@chromium.org
diff --git a/chrome/chrome_cleaner/README.md b/chrome/chrome_cleaner/README.md index c09c808..8fb4958 100644 --- a/chrome/chrome_cleaner/README.md +++ b/chrome/chrome_cleaner/README.md
@@ -69,4 +69,4 @@ ## Contact -joenotcharles@google.com +joenotcharles@chromium.org
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index d9a59c46..f196895 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -614,10 +614,6 @@ "RemoveSupervisedUsersOnStartup", base::FEATURE_DISABLED_BY_DEFAULT}; #endif -// Controls whether to show Safety Tip warnings on low-reputation sites. -const base::Feature kSafetyTipUI{"SafetyTip", - base::FEATURE_DISABLED_BY_DEFAULT}; - // Controls whether the user is prompted when sites request attestation. const base::Feature kSecurityKeyAttestationPrompt{ "SecurityKeyAttestationPrompt", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index e1c88f1..3e7105a 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -391,9 +391,6 @@ #endif COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::Feature kSafetyTipUI; - -COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSecurityKeyAttestationPrompt; #if defined(OS_ANDROID)
diff --git a/chrome/installer/mac/notarize_thing.py b/chrome/installer/mac/notarize_thing.py index e4f41c4..de893aa 100755 --- a/chrome/installer/mac/notarize_thing.py +++ b/chrome/installer/mac/notarize_thing.py
@@ -63,7 +63,7 @@ config_class = OverrideBundleIDConfig - config = config_class('notused', None, args.user, args.password, + config = config_class('notused', 'notused', None, args.user, args.password, args.asc_provider) uuids = []
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc index 43b0f39..7e1d62f 100644 --- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -1709,6 +1709,7 @@ EXPECT_FALSE( password_autofill_agent_->TryToShowTouchToFill(password_element_)); EXPECT_FALSE(password_autofill_agent_->TryToShowTouchToFill(random_element)); + EXPECT_FALSE(password_autofill_agent_->ShouldSuppressKeyboard()); // This changes once fill data is simulated. |random_element| continue to // have no fill data, though. @@ -1717,6 +1718,7 @@ EXPECT_CALL(fake_driver_, ShowTouchToFill); EXPECT_TRUE( password_autofill_agent_->TryToShowTouchToFill(username_element_)); + EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard()); base::RunLoop().RunUntilIdle(); } @@ -1726,6 +1728,7 @@ EXPECT_CALL(fake_driver_, ShowTouchToFill); EXPECT_TRUE( password_autofill_agent_->TryToShowTouchToFill(password_element_)); + EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard()); base::RunLoop().RunUntilIdle(); } @@ -1734,18 +1737,16 @@ // Touch to fill will be shown multiple times until TouchToFillDismissed() // gets called. - EXPECT_CALL(fake_driver_, ShowTouchToFill).Times(2); - EXPECT_TRUE( - password_autofill_agent_->TryToShowTouchToFill(username_element_)); + EXPECT_CALL(fake_driver_, ShowTouchToFill); EXPECT_TRUE( password_autofill_agent_->TryToShowTouchToFill(password_element_)); + EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard()); base::RunLoop().RunUntilIdle(); password_autofill_agent_->TouchToFillDismissed(); EXPECT_FALSE( - password_autofill_agent_->TryToShowTouchToFill(username_element_)); - EXPECT_FALSE( password_autofill_agent_->TryToShowTouchToFill(password_element_)); + EXPECT_FALSE(password_autofill_agent_->ShouldSuppressKeyboard()); base::RunLoop().RunUntilIdle(); // Reload the page and simulate fill. @@ -1758,6 +1759,7 @@ EXPECT_CALL(fake_driver_, ShowTouchToFill); EXPECT_TRUE( password_autofill_agent_->TryToShowTouchToFill(password_element_)); + EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard()); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc index 97cdcb2..a83edcf 100644 --- a/chrome/test/chromedriver/element_commands.cc +++ b/chrome/test/chromedriver/element_commands.cc
@@ -34,6 +34,10 @@ const int kFlickTouchEventsPerSecond = 30; const std::set<std::string> textControlTypes = {"text", "search", "tel", "url", "password"}; +const std::set<std::string> inputControlTypes = { + "text", "search", "url", "tel", "email", + "password", "date", "month", "week", "time", + "datetime-local", "number", "range", "color", "file"}; namespace { @@ -321,6 +325,56 @@ Status status = CheckElement(element_id); if (status.IsError()) return status; + + std::string tag_name; + status = GetElementTagName(session, web_view, element_id, &tag_name); + if (status.IsError()) + return status; + std::string element_type; + bool is_input_control = false; + + if (tag_name == "input") { + std::unique_ptr<base::Value> get_element_type; + status = GetElementAttribute(session, web_view, element_id, "type", + &get_element_type); + if (status.IsError()) + return status; + if (get_element_type->GetAsString(&element_type)) + element_type = base::ToLowerASCII(element_type); + + is_input_control = + inputControlTypes.find(element_type) != inputControlTypes.end(); + } + + bool is_text = tag_name == "textarea"; + bool is_content_editable = false; + if (!is_text && !is_input_control) { + std::unique_ptr<base::Value> get_content_editable; + base::ListValue args; + args.Append(CreateElement(element_id)); + status = web_view->CallFunction(session->GetCurrentFrameId(), + "element => element.isContentEditable", + args, &get_content_editable); + if (status.IsError()) + return status; + get_content_editable->GetAsBoolean(&is_content_editable); + } + + std::unique_ptr<base::Value> get_readonly; + bool is_readonly = false; + base::DictionaryValue params_readOnly; + if (!is_content_editable) { + params_readOnly.SetString("name", "readOnly"); + status = ExecuteGetElementProperty(session, web_view, element_id, + params_readOnly, &get_readonly); + get_readonly->GetAsBoolean(&is_readonly); + if (status.IsError()) + return status; + } + bool is_editable = + (is_input_control || is_text || is_content_editable) && !is_readonly; + if (!is_editable) + return Status(kInvalidElementState); // Scrolling to element is done by webdriver::atoms::CLEAR bool is_displayed = false; base::TimeTicks start_time = base::TimeTicks::Now();
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js index 806134f..1689b4e 100644 --- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
@@ -35,6 +35,28 @@ indicator.indicatorType, indicator.indicatorSourceName)); }); + test('parent-controlled indicator', function() { + indicator.indicatorType = CrPolicyIndicatorType.PARENT; + + assertTrue(indicator.indicatorVisible); + assertEquals('cr20:kite', indicator.indicatorIcon); + assertEquals( + 'parent', + indicator.getIndicatorTooltip( + indicator.indicatorType, indicator.indicatorSourceName)); + }); + + test('child-restriction indicator', function() { + indicator.indicatorType = CrPolicyIndicatorType.CHILD_RESTRICTION; + + assertTrue(indicator.indicatorVisible); + assertEquals('cr20:kite', indicator.indicatorIcon); + assertEquals( + 'Restricted for child', + indicator.getIndicatorTooltip( + indicator.indicatorType, indicator.indicatorSourceName)); + }); + test('recommended indicator', function() { indicator.indicatorType = CrPolicyIndicatorType.RECOMMENDED;
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js index 5f1b092..a3f2323 100644 --- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
@@ -40,5 +40,17 @@ assertEquals('cr:person', icon.iconClass); assertEquals('owner: foo@example.com', icon.tooltipText); } + + indicator.indicatorType = CrPolicyIndicatorType.PARENT; + + assertFalse(icon.hidden); + assertEquals('cr20:kite', icon.iconClass); + assertEquals('parent', icon.tooltipText); + + indicator.indicatorType = CrPolicyIndicatorType.CHILD_RESTRICTION; + + assertFalse(icon.hidden); + assertEquals('cr20:kite', icon.iconClass); + assertEquals('Restricted for child', icon.tooltipText); }); });
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js index f65305e..3c40a55 100644 --- a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
@@ -544,10 +544,6 @@ nearbyPrintersElement = page.$$('settings-cups-nearby-printers'); assertTrue(!!nearbyPrintersElement); - // Assert that no printers have been detected. - let nearbyPrinterEntries = getPrinterEntries(nearbyPrintersElement); - assertEquals(0, nearbyPrinterEntries.length); - // Simuluate finding nearby printers. cr.webUIListenerCallback( 'on-nearby-printers-changed', automaticPrinterList, @@ -570,10 +566,6 @@ nearbyPrintersElement = page.$$('settings-cups-nearby-printers'); assertTrue(!!nearbyPrintersElement); - // Assert that no printers are detected. - let nearbyPrinterEntries = getPrinterEntries(nearbyPrintersElement); - assertEquals(0, nearbyPrinterEntries.length); - // Simuluate finding nearby printers. cr.webUIListenerCallback( 'on-nearby-printers-changed', automaticPrinterList, @@ -613,10 +605,6 @@ nearbyPrintersElement = page.$$('settings-cups-nearby-printers'); assertTrue(!!nearbyPrintersElement); - // Assert that there are initially no detected printers. - let nearbyPrinterEntries = getPrinterEntries(nearbyPrintersElement); - assertEquals(0, nearbyPrinterEntries.length); - // Simuluate finding nearby printers. cr.webUIListenerCallback( 'on-nearby-printers-changed', automaticPrinterList,
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto index 666bffa..efba971 100644 --- a/chromecast/browser/webview/proto/webview.proto +++ b/chromecast/browser/webview/proto/webview.proto
@@ -184,13 +184,26 @@ string message = 2; } +// Associate a cast application with a platform view +message AssociateCastAppWindowRequest { + // This identifies the surface that the cast app will display into. + // It should be unique from all other platform views. + // This is the same platform id that is set in webview_id in + // WebviewCreateRequest + int32 platform_view_id = 1; + // This is the id of a cast application. + int32 app_window_id = 2; +} + +message AssociateCastAppWindowResponse {} + message WebviewRequest { // Unique identifier for the request. For requests that will have a response, // the response id will match the request id. // Valid ID values must be greater than 0. int64 id = 18; oneof type { - // This must be the first message. + // This must be the first message for CreateWebview. WebviewCreateRequest create = 1; // No response. InputEvent input = 2; @@ -226,6 +239,8 @@ SetAutoMediaPlaybackPolicyRequest set_auto_media_playback_policy = 17; // Response to a navigation request. NavigationDecision navigation_decision = 19; + // This must be the first request for CreateCastAppWindowLink + AssociateCastAppWindowRequest associate = 20; } } @@ -247,10 +262,20 @@ // Events sents from JS inside of Webviews to the embedder who added JS // channels via AddJavascriptChannelsRequest. JavascriptChannelMessage javascript_channel_message = 10; + AssociateCastAppWindowResponse associate = 20; } } +// TODO(sagallea): Deprecate this after moving to new service. service WebviewService { // Creates a webview. See the comment at the top of the file. rpc CreateWebview(stream WebviewRequest) returns (stream WebviewResponse); } + +service PlatformViewsService { + // Creates a webview. See the comment at the top of the file. + rpc CreateWebview(stream WebviewRequest) returns (stream WebviewResponse); + // Only AssociateRequest and InputEvent requests are valid. + rpc CreateCastAppWindowLink(stream WebviewRequest) + returns (stream WebviewResponse); +}
diff --git a/chromecast/media/cma/backend/cast_audio_json.cc b/chromecast/media/cma/backend/cast_audio_json.cc index fcdc424..a3521a1 100644 --- a/chromecast/media/cma/backend/cast_audio_json.cc +++ b/chromecast/media/cma/backend/cast_audio_json.cc
@@ -8,18 +8,37 @@ #include <utility> #include "base/bind.h" -#include "base/files/file_path_watcher.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" #include "base/location.h" #include "base/logging.h" -#include "base/message_loop/message_pump_type.h" -#include "base/sequenced_task_runner.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" #include "build/build_config.h" namespace chromecast { namespace media { +namespace { + +void ReadFileRunCallback(CastAudioJsonProvider::TuningChangedCallback callback, + const base::FilePath& path, + bool error) { + DCHECK(callback); + + std::string contents; + base::ReadFileToString(path, &contents); + std::unique_ptr<base::Value> value = + base::JSONReader::ReadDeprecated(contents); + if (value) { + callback.Run(std::move(value)); + return; + } + LOG(ERROR) << "Unable to parse JSON in " << path; +} + +} // namespace + #if defined(OS_FUCHSIA) const char kCastAudioJsonFilePath[] = "/system/data/cast_audio.json"; #else @@ -27,14 +46,6 @@ #endif const char kCastAudioJsonFileName[] = "cast_audio.json"; -#define ENSURE_OWN_THREAD(method, ...) \ - if (!task_runner_->RunsTasksInCurrentSequence()) { \ - task_runner_->PostTask( \ - FROM_HERE, base::BindOnce(&CastAudioJsonProviderImpl::method, \ - base::Unretained(this), ##__VA_ARGS__)); \ - return; \ - } - // static base::FilePath CastAudioJson::GetFilePath() { base::FilePath tuning_path = CastAudioJson::GetFilePathForTuning(); @@ -56,17 +67,11 @@ } CastAudioJsonProviderImpl::CastAudioJsonProviderImpl() - : thread_("cast_audio_json_provider"), - cast_audio_watcher_(std::make_unique<base::FilePathWatcher>()) { - base::Thread::Options options; - options.message_pump_type = base::MessagePumpType::IO; - thread_.StartWithOptions(options); - task_runner_ = thread_.task_runner(); -} + : cast_audio_watcher_(base::SequenceBound<FileWatcher>( + base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock(), + base::TaskPriority::LOWEST}))) {} -CastAudioJsonProviderImpl::~CastAudioJsonProviderImpl() { - StopWatchingFileOnThread(); -} +CastAudioJsonProviderImpl::~CastAudioJsonProviderImpl() = default; std::unique_ptr<base::Value> CastAudioJsonProviderImpl::GetCastAudioConfig() { std::string contents; @@ -76,35 +81,18 @@ void CastAudioJsonProviderImpl::SetTuningChangedCallback( TuningChangedCallback callback) { - ENSURE_OWN_THREAD(SetTuningChangedCallback, std::move(callback)); + cast_audio_watcher_.Post(FROM_HERE, &FileWatcher::SetTuningChangedCallback, + std::move(callback)); +} - CHECK(!callback_); - callback_ = callback; - cast_audio_watcher_->Watch( +CastAudioJsonProviderImpl::FileWatcher::FileWatcher() = default; +CastAudioJsonProviderImpl::FileWatcher::~FileWatcher() = default; + +void CastAudioJsonProviderImpl::FileWatcher::SetTuningChangedCallback( + TuningChangedCallback callback) { + watcher_.Watch( CastAudioJson::GetFilePathForTuning(), false /* recursive */, - base::BindRepeating(&CastAudioJsonProviderImpl::OnTuningFileChanged, - base::Unretained(this))); -} - -void CastAudioJsonProviderImpl::StopWatchingFileOnThread() { - ENSURE_OWN_THREAD(StopWatchingFileOnThread); - cast_audio_watcher_.reset(); -} - -void CastAudioJsonProviderImpl::OnTuningFileChanged(const base::FilePath& path, - bool error) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - DCHECK(callback_); - - std::string contents; - base::ReadFileToString(path, &contents); - std::unique_ptr<base::Value> value = - base::JSONReader::ReadDeprecated(contents); - if (value) { - callback_.Run(std::move(value)); - return; - } - LOG(ERROR) << "Unable to parse JSON in " << path; + base::BindRepeating(&ReadFileRunCallback, std::move(callback))); } } // namespace media
diff --git a/chromecast/media/cma/backend/cast_audio_json.h b/chromecast/media/cma/backend/cast_audio_json.h index 38fc7668..99dadec 100644 --- a/chromecast/media/cma/backend/cast_audio_json.h +++ b/chromecast/media/cma/backend/cast_audio_json.h
@@ -9,15 +9,11 @@ #include "base/callback.h" #include "base/files/file_path.h" +#include "base/files/file_path_watcher.h" #include "base/memory/scoped_refptr.h" -#include "base/threading/thread.h" +#include "base/threading/sequence_bound.h" #include "base/values.h" -namespace base { -class FilePathWatcher; -class SequencedTaskRunner; -} // namespace base - namespace chromecast { namespace media { @@ -48,9 +44,8 @@ virtual std::unique_ptr<base::Value> GetCastAudioConfig() = 0; // |callback| will be called when a new cast_audio config is available. - // |callback| will always be called from the same thread, but not the same - // thread on which |SetTuningChangedCallback| is called. - // |callback| will never be called after ~CastAudioJsonProvider() is called. + // |callback| will always be called from the same thread, but not necessarily + // the same thread on which |SetTuningChangedCallback| is called. virtual void SetTuningChangedCallback(TuningChangedCallback callback) = 0; }; @@ -60,17 +55,22 @@ ~CastAudioJsonProviderImpl() override; private: + class FileWatcher { + public: + FileWatcher(); + ~FileWatcher(); + + void SetTuningChangedCallback(TuningChangedCallback callback); + + private: + base::FilePathWatcher watcher_; + }; + // CastAudioJsonProvider implementation: std::unique_ptr<base::Value> GetCastAudioConfig() override; void SetTuningChangedCallback(TuningChangedCallback callback) override; - void StopWatchingFileOnThread(); - void OnTuningFileChanged(const base::FilePath& path, bool error); - - TuningChangedCallback callback_; - base::Thread thread_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; - std::unique_ptr<base::FilePathWatcher> cast_audio_watcher_; + base::SequenceBound<FileWatcher> cast_audio_watcher_; DISALLOW_COPY_AND_ASSIGN(CastAudioJsonProviderImpl); };
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 8e44cf9..1dd3a2e 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -12585.0.0 \ No newline at end of file +12586.0.0 \ No newline at end of file
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 89be0f6..3b31ce64 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -850,8 +850,10 @@ DCHECK(!node.IsNull()); focused_node_was_last_clicked_ = node.Focused(); - if (IsKeyboardAccessoryEnabled() || !focus_requires_scroll_) + if (IsTouchToFillEnabled() || IsKeyboardAccessoryEnabled() || + !focus_requires_scroll_) { HandleFocusChangeComplete(); + } } void AutofillAgent::SelectControlDidChange( @@ -881,12 +883,9 @@ bool AutofillAgent::ShouldSuppressKeyboard( const WebFormControlElement& element) { - // The keyboard should be suppressed if we can show the Touch To Fill UI. - // // Note: This is currently only implemented for passwords. Consider supporting // other autofill types in the future as well. - return IsTouchToFillEnabled() && - password_autofill_agent_->TryToShowTouchToFill(element); + return password_autofill_agent_->ShouldSuppressKeyboard(); } void AutofillAgent::SelectWasUpdated( @@ -913,6 +912,9 @@ if (!input_element && !form_util::IsTextAreaElement(element)) return; + if (IsTouchToFillEnabled()) + password_autofill_agent_->TryToShowTouchToFill(element); + ShowSuggestionsOptions options; options.autofill_on_empty_values = true; // Show full suggestions when clicking on an already-focused form field.
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index 6e94315..1915f4c 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -774,8 +774,16 @@ #endif } +bool PasswordAutofillAgent::ShouldSuppressKeyboard() { + // The keyboard should be suppressed if we are showing the Touch To Fill UI. + return touch_to_fill_state_ == TouchToFillState::kIsShowing; +} + bool PasswordAutofillAgent::TryToShowTouchToFill( const WebFormControlElement& control_element) { + if (touch_to_fill_state_ != TouchToFillState::kShouldShow) + return false; + const WebInputElement* element = ToWebInputElement(&control_element); WebInputElement username_element; WebInputElement password_element; @@ -786,10 +794,8 @@ return false; } - if (!should_show_touch_to_fill_) - return false; - GetPasswordManagerDriver()->ShowTouchToFill(); + touch_to_fill_state_ = TouchToFillState::kIsShowing; return true; } @@ -1197,7 +1203,7 @@ } void PasswordAutofillAgent::TouchToFillDismissed() { - should_show_touch_to_fill_ = false; + touch_to_fill_state_ = TouchToFillState::kWasShown; } void PasswordAutofillAgent::AnnotateFieldsWithParsingResult( @@ -1358,7 +1364,7 @@ autofilled_elements_cache_.clear(); last_updated_field_renderer_id_ = FormData::kNotSetFormRendererId; last_updated_form_renderer_id_ = FormData::kNotSetFormRendererId; - should_show_touch_to_fill_ = true; + touch_to_fill_state_ = TouchToFillState::kShouldShow; #if !defined(OS_ANDROID) && !defined(OS_IOS) page_passwords_analyser_.Reset(); #endif
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h index e5b5512..9e0e43c 100644 --- a/components/autofill/content/renderer/password_autofill_agent.h +++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -179,6 +179,9 @@ // no check request were sent from this frame load. void MaybeCheckSafeBrowsingReputation(const blink::WebInputElement& element); + // Returns whether the soft keyboard should be suppressed. + bool ShouldSuppressKeyboard(); + // Asks the agent to show the touch to fill UI for |control_element|. Returns // whether the agent was able to do so. bool TryToShowTouchToFill( @@ -247,6 +250,16 @@ RESTRICTION_NON_EMPTY_PASSWORD }; + // Enumeration representing possible Touch To Fill states. This is used to + // make sure that Touch To Fill will only be shown in response to the first + // password form focus during a frame's life time and to suppress the soft + // keyboard when Touch To Fill is shown. + enum class TouchToFillState { + kShouldShow, + kIsShowing, + kWasShown, + }; + struct PasswordInfo { blink::WebInputElement password_field; PasswordFormFillData fill_data; @@ -537,10 +550,9 @@ // Contains renderer id of the form of the last updated input element. uint32_t last_updated_form_renderer_id_ = FormData::kNotSetFormRendererId; - // Flag that determines whether we instruct the browser to show the Touch To - // Fill sheet if applicable. This is set to false when TouchToFillDismissed() - // is invoked and gets reset during CleanupOnDocumentShutdown. - bool should_show_touch_to_fill_ = true; + // Current state of Touch To Fill. This is reset during + // CleanupOnDocumentShutdown. + TouchToFillState touch_to_fill_state_ = TouchToFillState::kShouldShow; DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent); };
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.h b/components/autofill/core/browser/payments/credit_card_save_manager.h index 2cdd297..941d7c0 100644 --- a/components/autofill/core/browser/payments/credit_card_save_manager.h +++ b/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -144,10 +144,11 @@ friend class SaveCardBubbleViewsFullFormBrowserTest; friend class SaveCardInfobarEGTestHelper; friend class ::SaveCardOfferObserver; + FRIEND_TEST_ALL_PREFIXES( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + StrikeDatabase_Upload_FullFlowTest); FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest, StrikeDatabase_Local_FullFlowTest); - FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest, - StrikeDatabase_Upload_FullFlowTest); FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTestForStatusChip, Feedback_CardSavingAnimation);
diff --git a/components/dom_distiller/core/BUILD.gn b/components/dom_distiller/core/BUILD.gn index 7d6ac95..e29b253 100644 --- a/components/dom_distiller/core/BUILD.gn +++ b/components/dom_distiller/core/BUILD.gn
@@ -26,14 +26,10 @@ "dom_distiller_constants.h", "dom_distiller_features.cc", "dom_distiller_features.h", - "dom_distiller_model.cc", - "dom_distiller_model.h", "dom_distiller_request_view_base.cc", "dom_distiller_request_view_base.h", "dom_distiller_service.cc", "dom_distiller_service.h", - "dom_distiller_store.cc", - "dom_distiller_store.h", "dom_distiller_switches.cc", "dom_distiller_switches.h", "experiments.cc", @@ -128,7 +124,6 @@ "distilled_page_prefs_unittests.cc", "distiller_unittest.cc", "distiller_url_fetcher_unittest.cc", - "dom_distiller_model_unittest.cc", "dom_distiller_request_view_base_unittest.cc", "dom_distiller_service_unittest.cc", "page_features_unittest.cc",
diff --git a/components/dom_distiller/core/dom_distiller_model.cc b/components/dom_distiller/core/dom_distiller_model.cc deleted file mode 100644 index f49d625..0000000 --- a/components/dom_distiller/core/dom_distiller_model.cc +++ /dev/null
@@ -1,103 +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 "components/dom_distiller/core/dom_distiller_model.h" - -#include <unordered_set> -#include <utility> - -using syncer::SyncChange; -using syncer::SyncChangeList; -using syncer::SyncData; -using syncer::SyncDataList; - -namespace dom_distiller { - -DomDistillerModel::DomDistillerModel() : next_key_(1) {} - -DomDistillerModel::DomDistillerModel( - const std::vector<ArticleEntry>& initial_data) - : next_key_(1) { - for (size_t i = 0; i < initial_data.size(); ++i) { - AddEntry(initial_data[i]); - } -} - -DomDistillerModel::~DomDistillerModel() {} - -bool DomDistillerModel::GetEntryById(const std::string& entry_id, - ArticleEntry* entry) const { - KeyType key = 0; - if (!GetKeyById(entry_id, &key)) { - return false; - } - GetEntryByKey(key, entry); - return true; -} - -bool DomDistillerModel::GetEntryByUrl(const GURL& url, - ArticleEntry* entry) const { - KeyType key = 0; - if (!GetKeyByUrl(url, &key)) { - return false; - } - GetEntryByKey(key, entry); - return true; -} - -bool DomDistillerModel::GetKeyById(const std::string& entry_id, - KeyType* key) const { - auto it = entry_id_to_key_map_.find(entry_id); - if (it == entry_id_to_key_map_.end()) { - return false; - } - if (key != nullptr) { - *key = it->second; - } - return true; -} - -bool DomDistillerModel::GetKeyByUrl(const GURL& url, KeyType* key) const { - auto it = url_to_key_map_.find(url.spec()); - if (it == url_to_key_map_.end()) { - return false; - } - if (key != nullptr) { - *key = it->second; - } - return true; -} - -void DomDistillerModel::GetEntryByKey(KeyType key, ArticleEntry* entry) const { - if (entry != nullptr) { - auto it = entries_.find(key); - DCHECK(it != entries_.end()); - *entry = it->second; - } -} - -size_t DomDistillerModel::GetNumEntries() const { - return entries_.size(); -} - -std::vector<ArticleEntry> DomDistillerModel::GetEntries() const { - std::vector<ArticleEntry> entries_list; - for (auto it = entries_.begin(); it != entries_.end(); ++it) { - entries_list.push_back(it->second); - } - return entries_list; -} - -void DomDistillerModel::AddEntry(const ArticleEntry& entry) { - const std::string& entry_id = entry.entry_id(); - KeyType key = next_key_++; - DCHECK(!GetKeyById(entry_id, nullptr)); - entries_.insert(std::make_pair(key, entry)); - entry_id_to_key_map_.insert(std::make_pair(entry_id, key)); - for (int i = 0; i < entry.pages_size(); ++i) { - url_to_key_map_.insert(std::make_pair(entry.pages(i).url(), key)); - } -} - -} // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_model.h b/components/dom_distiller/core/dom_distiller_model.h deleted file mode 100644 index 4914f88..0000000 --- a/components/dom_distiller/core/dom_distiller_model.h +++ /dev/null
@@ -1,69 +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 COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_ -#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <string> -#include <unordered_map> -#include <vector> - -#include "base/containers/id_map.h" -#include "base/macros.h" -#include "components/dom_distiller/core/article_entry.h" -#include "components/sync/model/sync_change.h" -#include "components/sync/model/sync_data.h" -#include "url/gurl.h" - -namespace dom_distiller { - -// This stores the in-memory model of the DOM distiller list. Entries can be -// looked up by URL or by entry_id. -// The model assumes that an URL corresponds to at most a single entry. If this -// assumption is broken, lookup by URL may return unexpected results. -class DomDistillerModel { - public: - DomDistillerModel(); - explicit DomDistillerModel(const std::vector<ArticleEntry>& initial_data); - - ~DomDistillerModel(); - - // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry - // was found. On success, if |entry| is not null, it will contain the entry. - bool GetEntryById(const std::string& entry_id, ArticleEntry* entry) const; - bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) const; - - std::vector<ArticleEntry> GetEntries() const; - size_t GetNumEntries() const; - - private: - typedef int32_t KeyType; - typedef std::unordered_map<KeyType, ArticleEntry> EntryMap; - typedef std::unordered_map<std::string, KeyType> StringToKeyMap; - - void AddEntry(const ArticleEntry& entry); - - // Lookup an entry's key by ID or URL. Returns whether a corresponding key was - // found. On success, if |key| is not null, it will contain the entry. - bool GetKeyById(const std::string& entry_id, KeyType* key) const; - bool GetKeyByUrl(const GURL& url, KeyType* key) const; - - // If |entry| is not null, assigns the entry for |key| to it. |key| must map - // to an entry in |entries_|. - void GetEntryByKey(KeyType key, ArticleEntry* entry) const; - - KeyType next_key_; - EntryMap entries_; - StringToKeyMap url_to_key_map_; - StringToKeyMap entry_id_to_key_map_; - - DISALLOW_COPY_AND_ASSIGN(DomDistillerModel); -}; - -} // namespace dom_distiller - -#endif // COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_
diff --git a/components/dom_distiller/core/dom_distiller_model_unittest.cc b/components/dom_distiller/core/dom_distiller_model_unittest.cc deleted file mode 100644 index ad8328b..0000000 --- a/components/dom_distiller/core/dom_distiller_model_unittest.cc +++ /dev/null
@@ -1,74 +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 "components/dom_distiller/core/dom_distiller_model.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace dom_distiller { - -TEST(DomDistillerModelTest, TestGetByEntryId) { - ArticleEntry entry1; - entry1.set_entry_id("id1"); - entry1.set_title("title1"); - ArticleEntry entry2; - entry2.set_entry_id("id2"); - entry2.set_title("title1"); - - std::vector<ArticleEntry> initial_model; - initial_model.push_back(entry1); - initial_model.push_back(entry2); - - DomDistillerModel model(initial_model); - - ArticleEntry found_entry; - EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); - - EXPECT_FALSE(model.GetEntryById("some_other_id", nullptr)); -} - -TEST(DomDistillerModelTest, TestGetByUrl) { - ArticleEntry entry1; - entry1.set_entry_id("id1"); - entry1.set_title("title1"); - ArticleEntryPage* page1 = entry1.add_pages(); - page1->set_url("http://example.com/1"); - ArticleEntryPage* page2 = entry1.add_pages(); - page2->set_url("http://example.com/2"); - - ArticleEntry entry2; - entry2.set_entry_id("id2"); - entry2.set_title("title1"); - ArticleEntryPage* page3 = entry2.add_pages(); - page3->set_url("http://example.com/a1"); - - std::vector<ArticleEntry> initial_model; - initial_model.push_back(entry1); - initial_model.push_back(entry2); - - DomDistillerModel model(initial_model); - - ArticleEntry found_entry; - EXPECT_TRUE(model.GetEntryByUrl(GURL(page1->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryByUrl(GURL(page2->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryByUrl(GURL(page3->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); - - EXPECT_FALSE(model.GetEntryByUrl(GURL("http://example.com/foo"), nullptr)); -} - -} // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_service.cc b/components/dom_distiller/core/dom_distiller_service.cc index 10d6afff..82fa073 100644 --- a/components/dom_distiller/core/dom_distiller_service.cc +++ b/components/dom_distiller/core/dom_distiller_service.cc
@@ -13,7 +13,6 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "components/dom_distiller/core/distilled_content_store.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/dom_distiller/core/proto/distilled_article.pb.h" #include "components/dom_distiller/core/task_tracker.h" #include "url/gurl.h" @@ -35,12 +34,10 @@ } // namespace DomDistillerService::DomDistillerService( - std::unique_ptr<DomDistillerStoreInterface> store, std::unique_ptr<DistillerFactory> distiller_factory, std::unique_ptr<DistillerPageFactory> distiller_page_factory, std::unique_ptr<DistilledPagePrefs> distilled_page_prefs) - : store_(std::move(store)), - content_store_(new InMemoryContentStore(kDefaultMaxNumCachedEntries)), + : content_store_(new InMemoryContentStore(kDefaultMaxNumCachedEntries)), distiller_factory_(std::move(distiller_factory)), distiller_page_factory_(std::move(distiller_page_factory)), distilled_page_prefs_(std::move(distilled_page_prefs)) {} @@ -60,14 +57,10 @@ } bool DomDistillerService::HasEntry(const std::string& entry_id) { - return store_ && store_->GetEntryById(entry_id, nullptr); + return false; } std::string DomDistillerService::GetUrlForEntry(const std::string& entry_id) { - ArticleEntry entry; - if (store_ && store_->GetEntryById(entry_id, &entry)) { - return entry.pages().Get(0).url(); - } return ""; } @@ -75,22 +68,7 @@ ViewRequestDelegate* delegate, std::unique_ptr<DistillerPage> distiller_page, const std::string& entry_id) { - ArticleEntry entry; - if (!store_ || !store_->GetEntryById(entry_id, &entry)) { - return std::unique_ptr<ViewerHandle>(); - } - - TaskTracker* task_tracker = nullptr; - bool was_created = GetOrCreateTaskTrackerForEntry(entry, &task_tracker); - std::unique_ptr<ViewerHandle> viewer_handle = - task_tracker->AddViewer(delegate); - if (was_created) { - task_tracker->StartDistiller(distiller_factory_.get(), - std::move(distiller_page)); - task_tracker->StartBlobFetcher(); - } - - return viewer_handle; + return nullptr; } std::unique_ptr<ViewerHandle> DomDistillerService::ViewUrl( @@ -118,11 +96,6 @@ bool DomDistillerService::GetOrCreateTaskTrackerForUrl( const GURL& url, TaskTracker** task_tracker) { - ArticleEntry entry; - if (store_ && store_->GetEntryByUrl(url, &entry)) { - return GetOrCreateTaskTrackerForEntry(entry, task_tracker); - } - *task_tracker = GetTaskTrackerForUrl(url); if (*task_tracker) { return false; @@ -142,28 +115,6 @@ return nullptr; } -TaskTracker* DomDistillerService::GetTaskTrackerForEntry( - const ArticleEntry& entry) const { - const std::string& entry_id = entry.entry_id(); - for (auto it = tasks_.begin(); it != tasks_.end(); ++it) { - if ((*it)->HasEntryId(entry_id)) { - return (*it).get(); - } - } - return nullptr; -} - -bool DomDistillerService::GetOrCreateTaskTrackerForEntry( - const ArticleEntry& entry, - TaskTracker** task_tracker) { - *task_tracker = GetTaskTrackerForEntry(entry); - if (!*task_tracker) { - *task_tracker = CreateTaskTracker(entry); - return true; - } - return false; -} - TaskTracker* DomDistillerService::CreateTaskTracker(const ArticleEntry& entry) { TaskTracker::CancelCallback cancel_callback = base::Bind(&DomDistillerService::CancelTask, base::Unretained(this));
diff --git a/components/dom_distiller/core/dom_distiller_service.h b/components/dom_distiller/core/dom_distiller_service.h index 8532d8a..21ad150 100644 --- a/components/dom_distiller/core/dom_distiller_service.h +++ b/components/dom_distiller/core/dom_distiller_service.h
@@ -22,7 +22,6 @@ class DistilledContentStore; class DistillerFactory; class DistillerPageFactory; -class DomDistillerStoreInterface; class TaskTracker; class ViewerHandle; class ViewRequestDelegate; @@ -35,22 +34,9 @@ typedef base::Callback<void(bool)> ArticleAvailableCallback; virtual ~DomDistillerServiceInterface() {} - // Returns whether an article stored has the given entry id. + // TODO(crbug.com/1007942): Remove these methods; no entries ever exist. virtual bool HasEntry(const std::string& entry_id) = 0; - - // Returns the source URL given an entry ID. If the entry ID article has - // multiple pages, this will return the URL of the first page. Returns an - // empty string if there is no entry associated with the given entry ID. virtual std::string GetUrlForEntry(const std::string& entry_id) = 0; - - // Request to view an article by entry id. Returns a null pointer if no entry - // with |entry_id| exists. The ViewerHandle should be destroyed before the - // ViewRequestDelegate. The request will be cancelled when the handle is - // destroyed (or when this service is destroyed), which also ensures that - // the |delegate| is not called after that. - // Use CreateDefaultDistillerPage() to create a default |distiller_page|. - // The provided |distiller_page| is only used if there is not already a - // distillation task in progress for the given |entry_id|. virtual std::unique_ptr<ViewerHandle> ViewEntry( ViewRequestDelegate* delegate, std::unique_ptr<DistillerPage> distiller_page, @@ -86,7 +72,6 @@ class DomDistillerService : public DomDistillerServiceInterface { public: DomDistillerService( - std::unique_ptr<DomDistillerStoreInterface> store, std::unique_ptr<DistillerFactory> distiller_factory, std::unique_ptr<DistillerPageFactory> distiller_page_factory, std::unique_ptr<DistilledPagePrefs> distilled_page_prefs); @@ -114,20 +99,15 @@ TaskTracker* CreateTaskTracker(const ArticleEntry& entry); - TaskTracker* GetTaskTrackerForEntry(const ArticleEntry& entry) const; TaskTracker* GetTaskTrackerForUrl(const GURL& url) const; - // Gets the task tracker for the given |url| or |entry|. If no appropriate + // Gets the task tracker for the given |url|. If no appropriate // tracker exists, this will create one and put it in the |TaskTracker| // parameter passed into this function, initialize it, and add it to - // |tasks_|. If a |TaskTracker| needed to be created, these functions will - // return true. + // |tasks_|. Return whether a |TaskTracker| needed to be created. bool GetOrCreateTaskTrackerForUrl(const GURL& url, TaskTracker** task_tracker); - bool GetOrCreateTaskTrackerForEntry(const ArticleEntry& entry, - TaskTracker** task_tracker); - std::unique_ptr<DomDistillerStoreInterface> store_; std::unique_ptr<DistilledContentStore> content_store_; std::unique_ptr<DistillerFactory> distiller_factory_; std::unique_ptr<DistillerPageFactory> distiller_page_factory_;
diff --git a/components/dom_distiller/core/dom_distiller_service_unittest.cc b/components/dom_distiller/core/dom_distiller_service_unittest.cc index bb9c859..24f8b0d 100644 --- a/components/dom_distiller/core/dom_distiller_service_unittest.cc +++ b/components/dom_distiller/core/dom_distiller_service_unittest.cc
@@ -13,8 +13,6 @@ #include "base/test/task_environment.h" #include "components/dom_distiller/core/article_entry.h" #include "components/dom_distiller/core/distilled_page_prefs.h" -#include "components/dom_distiller/core/dom_distiller_model.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/dom_distiller/core/fake_distiller.h" #include "components/dom_distiller/core/fake_distiller_page.h" #include "components/dom_distiller/core/task_tracker.h" @@ -22,7 +20,6 @@ #include "testing/gtest/include/gtest/gtest.h" using testing::_; -using testing::Invoke; using testing::Return; namespace dom_distiller { @@ -30,8 +27,6 @@ namespace { -const char kTestEntryId[] = "id0"; - class FakeViewRequestDelegate : public ViewRequestDelegate { public: ~FakeViewRequestDelegate() override {} @@ -68,15 +63,9 @@ class DomDistillerServiceTest : public testing::Test { public: void SetUp() override { - // Create a test entry in the DB. - ArticleEntry entry; - entry.set_entry_id(kTestEntryId); - entry.add_pages()->set_url("http://www.example.com/p1"); - store_ = new DomDistillerStore({entry}); distiller_factory_ = new MockDistillerFactory(); distiller_page_factory_ = new MockDistillerPageFactory(); service_.reset(new DomDistillerService( - std::unique_ptr<DomDistillerStoreInterface>(store_), std::unique_ptr<DistillerFactory>(distiller_factory_), std::unique_ptr<DistillerPageFactory>(distiller_page_factory_), std::unique_ptr<DistilledPagePrefs>())); @@ -84,38 +73,17 @@ void TearDown() override { base::RunLoop().RunUntilIdle(); - store_ = nullptr; distiller_factory_ = nullptr; service_.reset(); } protected: base::test::SingleThreadTaskEnvironment task_environment_; - // store is owned by service_. - DomDistillerStoreInterface* store_; MockDistillerFactory* distiller_factory_; MockDistillerPageFactory* distiller_page_factory_; std::unique_ptr<DomDistillerService> service_; }; -TEST_F(DomDistillerServiceTest, TestViewEntry) { - FakeDistiller* distiller = new FakeDistiller(false); - EXPECT_CALL(*distiller_factory_, CreateDistillerImpl()) - .WillOnce(Return(distiller)); - - FakeViewRequestDelegate viewer_delegate; - std::unique_ptr<ViewerHandle> handle = service_->ViewEntry( - &viewer_delegate, service_->CreateDefaultDistillerPage(gfx::Size()), - kTestEntryId); - - ASSERT_FALSE(distiller->GetArticleCallback().is_null()); - - std::unique_ptr<DistilledArticleProto> proto = CreateDefaultArticle(); - EXPECT_CALL(viewer_delegate, OnArticleReady(proto.get())); - - RunDistillerCallback(distiller, std::move(proto)); -} - TEST_F(DomDistillerServiceTest, TestViewUrl) { FakeDistiller* distiller = new FakeDistiller(false); EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc deleted file mode 100644 index 4f37d22..0000000 --- a/components/dom_distiller/core/dom_distiller_store.cc +++ /dev/null
@@ -1,34 +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 "components/dom_distiller/core/dom_distiller_store.h" - -#include <stddef.h> - -#include <utility> - -namespace dom_distiller { - -DomDistillerStore::DomDistillerStore() {} - -DomDistillerStore::DomDistillerStore( - const std::vector<ArticleEntry>& initial_data) - : model_(initial_data) {} - -DomDistillerStore::~DomDistillerStore() {} - -bool DomDistillerStore::GetEntryById(const std::string& entry_id, - ArticleEntry* entry) { - return model_.GetEntryById(entry_id, entry); -} - -bool DomDistillerStore::GetEntryByUrl(const GURL& url, ArticleEntry* entry) { - return model_.GetEntryByUrl(url, entry); -} - -std::vector<ArticleEntry> DomDistillerStore::GetEntries() const { - return model_.GetEntries(); -} - -} // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h deleted file mode 100644 index a548c426..0000000 --- a/components/dom_distiller/core/dom_distiller_store.h +++ /dev/null
@@ -1,69 +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 COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_STORE_H_ -#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_STORE_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "components/dom_distiller/core/article_entry.h" -#include "components/dom_distiller/core/dom_distiller_model.h" -#include "url/gurl.h" - -namespace dom_distiller { - -// Interface for accessing the stored DomDistiller entries. -class DomDistillerStoreInterface { - public: - virtual ~DomDistillerStoreInterface() {} - - // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry - // was found. On success, if |entry| is not null, it will contain the entry. - virtual bool GetEntryById(const std::string& entry_id, - ArticleEntry* entry) = 0; - virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) = 0; - - // Gets a copy of all the current entries. - virtual std::vector<ArticleEntry> GetEntries() const = 0; -}; - -// Implements syncing/storing of DomDistiller entries. This keeps three -// models of the DOM distiller data in sync: the local database, sync, and the -// user (i.e. of DomDistillerStore). No changes are accepted while the local -// database is loading. Once the local database has loaded, changes from any of -// the three sources (technically just two, since changes don't come from the -// database) are handled similarly: -// 1. convert the change to a SyncChangeList. -// 2. apply that change to the in-memory model, calculating what changed -// (changes_applied) and what is missing--i.e. entries missing for a full merge, -// conflict resolution for normal changes-- (changes_missing). -// 3. send a message (possibly handled asynchronously) containing -// changes_missing to the source of the change. -// 4. send messages (possibly handled asynchronously) containing changes_applied -// to the other (i.e. non-source) two models. -// TODO(cjhopman): Support deleting entries. -class DomDistillerStore : public DomDistillerStoreInterface { - public: - DomDistillerStore(); - - // Initializes the internal model to |initial_model|. - DomDistillerStore(const std::vector<ArticleEntry>& initial_data); - - ~DomDistillerStore() override; - - bool GetEntryById(const std::string& entry_id, ArticleEntry* entry) override; - bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) override; - std::vector<ArticleEntry> GetEntries() const override; - - private: - DomDistillerModel model_; - - DISALLOW_COPY_AND_ASSIGN(DomDistillerStore); -}; - -} // namespace dom_distiller - -#endif // COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_STORE_H_
diff --git a/components/dom_distiller/standalone/content_extractor_browsertest.cc b/components/dom_distiller/standalone/content_extractor_browsertest.cc index d85a15ab..b0c9284 100644 --- a/components/dom_distiller/standalone/content_extractor_browsertest.cc +++ b/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -28,7 +28,6 @@ #include "components/dom_distiller/core/distilled_page_prefs.h" #include "components/dom_distiller/core/distiller.h" #include "components/dom_distiller/core/dom_distiller_service.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/dom_distiller/core/proto/distilled_article.pb.h" #include "components/dom_distiller/core/proto/distilled_page.pb.h" #include "components/dom_distiller/core/task_tracker.h" @@ -131,8 +130,6 @@ // Setting up PrefService for DistilledPagePrefs. DistilledPagePrefs::RegisterProfilePrefs(pref_service->registry()); - auto dom_distiller_store = std::make_unique<DomDistillerStore>(); - auto distiller_page_factory = std::make_unique<DistillerPageWebContentsFactory>(context); auto distiller_url_fetcher_factory = @@ -166,8 +163,7 @@ std::move(distiller_url_fetcher_factory), options, file_to_url_map); return std::make_unique<DomDistillerService>( - std::move(dom_distiller_store), std::move(distiller_factory), - std::move(distiller_page_factory), + std::move(distiller_factory), std::move(distiller_page_factory), std::make_unique<DistilledPagePrefs>(pref_service)); }
diff --git a/components/download/internal/common/all_download_event_notifier.cc b/components/download/internal/common/all_download_event_notifier.cc index e28d8b0..e4bed56 100644 --- a/components/download/internal/common/all_download_event_notifier.cc +++ b/components/download/internal/common/all_download_event_notifier.cc
@@ -49,7 +49,9 @@ active_downloads_only); } -void AllDownloadEventNotifier::OnManagerGoingDown() { +void AllDownloadEventNotifier::OnManagerGoingDown( + SimpleDownloadManagerCoordinator* manager) { + DCHECK_EQ(manager, simple_download_manager_coordinator_); for (auto& observer : observers_) observer.OnManagerGoingDown(simple_download_manager_coordinator_); simple_download_manager_coordinator_->RemoveObserver(this);
diff --git a/components/download/internal/common/simple_download_manager_coordinator.cc b/components/download/internal/common/simple_download_manager_coordinator.cc index 493e99f..dfbf5ae 100644 --- a/components/download/internal/common/simple_download_manager_coordinator.cc +++ b/components/download/internal/common/simple_download_manager_coordinator.cc
@@ -31,7 +31,7 @@ if (simple_download_manager_) simple_download_manager_->RemoveObserver(this); for (auto& observer : observers_) - observer.OnManagerGoingDown(); + observer.OnManagerGoingDown(this); } void SimpleDownloadManagerCoordinator::SetSimpleDownloadManager(
diff --git a/components/download/public/common/all_download_event_notifier.h b/components/download/public/common/all_download_event_notifier.h index d9a8989..c786702 100644 --- a/components/download/public/common/all_download_event_notifier.h +++ b/components/download/public/common/all_download_event_notifier.h
@@ -56,7 +56,7 @@ private: // SimpleDownloadManagerCoordinator::Observer void OnDownloadsInitialized(bool active_downloads_only) override; - void OnManagerGoingDown() override; + void OnManagerGoingDown(SimpleDownloadManagerCoordinator* manager) override; void OnDownloadCreated(DownloadItem* item) override; // DownloadItem::Observer
diff --git a/components/download/public/common/simple_download_manager_coordinator.h b/components/download/public/common/simple_download_manager_coordinator.h index b56adef1..c5d7a5f 100644 --- a/components/download/public/common/simple_download_manager_coordinator.h +++ b/components/download/public/common/simple_download_manager_coordinator.h
@@ -36,7 +36,8 @@ Observer() = default; virtual ~Observer() = default; - virtual void OnManagerGoingDown() {} + virtual void OnManagerGoingDown( + SimpleDownloadManagerCoordinator* coordinator) {} virtual void OnDownloadsInitialized(bool active_downloads_only) {} virtual void OnDownloadCreated(DownloadItem* item) {}
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index 2d3fe18d..41d54b1 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -1024,7 +1024,7 @@ if (wasPip && !window_state->IsMinimized()) { // Expanding PIP should end split-view. See crbug.com/941788. - ash::Shell::Get()->split_view_controller()->EndSplitView( + ash::SplitViewController::Get()->EndSplitView( ash::SplitViewController::EndReason::kPipExpanded); // As Android doesn't activate PIP tasks after they are expanded, we need // to do it here explicitly.
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 9dbfb039..5d72514 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1003,8 +1003,7 @@ // Test the snap functionalities in splitscreen in tablet mode. TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) { UpdateDisplay("807x607"); - ash::Shell* shell = ash::Shell::Get(); - shell->tablet_mode_controller()->SetEnabledForTest(true); + ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); const gfx::Size buffer_size(800, 600); std::unique_ptr<Buffer> buffer1( @@ -1026,7 +1025,7 @@ // Snap window to left. ash::SplitViewController* split_view_controller = - shell->split_view_controller(); + ash::SplitViewController::Get(); split_view_controller->SnapWindow(window1, ash::SplitViewController::LEFT); state1->set_bounds_locally(true); window1->SetBounds(split_view_controller->GetSnappedWindowBoundsInScreen( @@ -2017,7 +2016,7 @@ ExpandingPipInTabletModeEndsSplitView) { EnableTabletMode(true); - auto* split_view_controller = ash::Shell::Get()->split_view_controller(); + auto* split_view_controller = ash::SplitViewController::Get(); EXPECT_FALSE(split_view_controller->InSplitViewMode()); // Create a PIP window: @@ -2053,7 +2052,7 @@ DismissingPipInTabletModeDoesNotEndSplitView) { EnableTabletMode(true); - auto* split_view_controller = ash::Shell::Get()->split_view_controller(); + auto* split_view_controller = ash::SplitViewController::Get(); EXPECT_FALSE(split_view_controller->InSplitViewMode()); // Create a PIP window:
diff --git a/components/heap_profiling/supervisor.cc b/components/heap_profiling/supervisor.cc index f5aeda8..c0f7e51 100644 --- a/components/heap_profiling/supervisor.cc +++ b/components/heap_profiling/supervisor.cc
@@ -125,7 +125,8 @@ } auto finished_dump_callback = base::BindOnce( - [](TraceFinishedCallback callback, bool success, uint64_t dump_guid) { + [](TraceFinishedCallback callback, bool anonymize, bool success, + uint64_t dump_guid) { // Once the trace has stopped, run |callback| on the UI thread. auto finish_sink_callback = base::BindOnce( [](TraceFinishedCallback callback, @@ -137,13 +138,15 @@ base::BindOnce(std::move(callback), true, std::move(result))); }, - base::Passed(std::move(callback))); + std::move(callback)); scoped_refptr<content::TracingController::TraceDataEndpoint> sink = content::TracingController::CreateStringEndpoint( std::move(finish_sink_callback)); - content::TracingController::GetInstance()->StopTracing(sink); + content::TracingController::GetInstance()->StopTracing( + sink, + /*agent_label=*/"", anonymize); }, - std::move(callback)); + std::move(callback), anonymize); auto trigger_memory_dump_callback = base::BindOnce( [](base::OnceCallback<void(bool success, uint64_t dump_guid)>
diff --git a/components/media_message_center/media_notification_view.h b/components/media_message_center/media_notification_view.h index 02263b99..ab07f0d 100644 --- a/components/media_message_center/media_notification_view.h +++ b/components/media_message_center/media_notification_view.h
@@ -90,6 +90,10 @@ const std::set<media_session::mojom::MediaSessionAction>& actions); void UpdateWithMediaArtwork(const gfx::ImageSkia& image); + const views::Label* title_label_for_testing() const { return title_label_; } + + const views::Label* artist_label_for_testing() const { return artist_label_; } + private: friend class MediaNotificationViewTest;
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index 6bbed3b..aa0cfc1 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -46,10 +46,10 @@ "extension_app.icon", "find_in_page.icon", "http.icon", - "https_invalid.icon", "https_valid.icon", "https_valid_in_chip.icon", "keyword_search.icon", + "not_secure_warning.icon", "offline_pin.icon", "page.icon", "pedal.icon",
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc index 3ea39cb8..6d18ad3 100644 --- a/components/omnibox/browser/location_bar_model_impl.cc +++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -195,7 +195,7 @@ case security_state::SECURE_WITH_POLICY_INSTALLED_CERT: return vector_icons::kBusinessIcon; case security_state::DANGEROUS: - return omnibox::kHttpsInvalidIcon; + return omnibox::kNotSecureWarningIcon; case security_state::SECURITY_LEVEL_COUNT: NOTREACHED(); return omnibox::kHttpIcon;
diff --git a/components/omnibox/browser/vector_icons/https_invalid.icon b/components/omnibox/browser/vector_icons/not_secure_warning.icon similarity index 100% rename from components/omnibox/browser/vector_icons/https_invalid.icon rename to components/omnibox/browser/vector_icons/not_secure_warning.icon
diff --git a/components/pref_registry/pref_registry_syncable.cc b/components/pref_registry/pref_registry_syncable.cc index a7b4fe9d..674e26a 100644 --- a/components/pref_registry/pref_registry_syncable.cc +++ b/components/pref_registry/pref_registry_syncable.cc
@@ -47,14 +47,4 @@ return registry; } -void PrefRegistrySyncable::WhitelistLateRegistrationPrefForSync( - const std::string& pref_name) { - sync_unknown_prefs_whitelist_.insert(pref_name); -} - -bool PrefRegistrySyncable::IsWhitelistedLateRegistrationPref( - const std::string& path) const { - return sync_unknown_prefs_whitelist_.count(path) != 0; -} - } // namespace user_prefs
diff --git a/components/pref_registry/pref_registry_syncable.h b/components/pref_registry/pref_registry_syncable.h index 9533e15..b2f630a4 100644 --- a/components/pref_registry/pref_registry_syncable.h +++ b/components/pref_registry/pref_registry_syncable.h
@@ -7,7 +7,6 @@ #include <stdint.h> -#include <set> #include <string> #include "base/callback.h" @@ -70,16 +69,6 @@ // store. scoped_refptr<PrefRegistrySyncable> ForkForIncognito(); - // Adds a the preference with name |pref_name| to the whitelist of prefs which - // will be synced even before they got registered. Note that it's still - // illegal to read or write a whitelisted preference via the PrefService - // before its registration. - void WhitelistLateRegistrationPrefForSync(const std::string& pref_name); - - // Checks weather the preference with name |path| is on the whitelist of - // sync-supported prefs before registration. - bool IsWhitelistedLateRegistrationPref(const std::string& path) const; - private: ~PrefRegistrySyncable() override; @@ -88,7 +77,6 @@ uint32_t flags) override; SyncableRegistrationCallback callback_; - std::set<std::string> sync_unknown_prefs_whitelist_; DISALLOW_COPY_AND_ASSIGN(PrefRegistrySyncable); };
diff --git a/components/security_state/core/features.cc b/components/security_state/core/features.cc index 961cee5..9dcd8b9 100644 --- a/components/security_state/core/features.cc +++ b/components/security_state/core/features.cc
@@ -18,5 +18,8 @@ const base::Feature kLegacyTLSWarnings{"LegacyTLSWarnings", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSafetyTipUI{"SafetyTip", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace security_state
diff --git a/components/security_state/core/features.h b/components/security_state/core/features.h index 1e7f4721..8e8bd50 100644 --- a/components/security_state/core/features.h +++ b/components/security_state/core/features.h
@@ -33,6 +33,9 @@ // TLS version (TLS 1.0 or 1.1). extern const base::Feature kLegacyTLSWarnings; +// This feature enables Safety Tip warnings on possibly-risky sites. +extern const base::Feature kSafetyTipUI; + } // namespace features } // namespace security_state
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc index 88f048f5..b282c32b 100644 --- a/components/security_state/core/security_state.cc +++ b/components/security_state/core/security_state.cc
@@ -90,6 +90,31 @@ return std::string(); } +// Returns whether to set the security level based on the safety tip status. +// Sets |level| to the right value if status should be set. +bool ShouldSetSecurityLevelFromSafetyTip(security_state::SafetyTipStatus status, + SecurityLevel* level) { + if (!base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) { + return false; + } + + switch (status) { + case security_state::SafetyTipStatus::kBadReputation: + *level = security_state::NONE; + return true; + case security_state::SafetyTipStatus::kLookalike: + // PageInfo doesn't differ for lookalikes, so don't degrade the indicator. + case security_state::SafetyTipStatus::kBadKeyword: + // TODO(crbug/1012982): Decide whether to degrade the indicator once the + // UI lands. + case security_state::SafetyTipStatus::kUnknown: + case security_state::SafetyTipStatus::kNone: + return false; + } + NOTREACHED(); + return false; +} + } // namespace SecurityLevel GetSecurityLevel( @@ -163,6 +188,13 @@ return WARNING; } + // Downgrade the security level for pages that trigger a Safety Tip. + SecurityLevel safety_tip_level; + if (ShouldSetSecurityLevelFromSafetyTip( + visible_security_state.safety_tip_status, &safety_tip_level)) { + return safety_tip_level; + } + // In most cases, SHA1 use is treated as a certificate error, in which case // DANGEROUS will have been returned above. If SHA1 was permitted by policy, // downgrade the security level to Neutral.
diff --git a/components/security_state/core/security_state_unittest.cc b/components/security_state/core/security_state_unittest.cc index af0a2b3..8927fcda 100644 --- a/components/security_state/core/security_state_unittest.cc +++ b/components/security_state/core/security_state_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/scoped_feature_list.h" #include "components/security_state/core/features.h" #include "components/security_state/core/insecure_input_event_data.h" +#include "components/security_state/core/security_state.h" #include "net/cert/x509_certificate.h" #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_connection_status_flags.h" @@ -59,7 +60,8 @@ malicious_content_status_(MALICIOUS_CONTENT_STATUS_NONE), is_error_page_(false), is_view_source_(false), - has_policy_certificate_(false) {} + has_policy_certificate_(false), + safety_tip_status_(security_state::SafetyTipStatus::kUnknown) {} virtual ~TestSecurityStateHelper() {} void SetCertificate(scoped_refptr<net::X509Certificate> cert) { @@ -105,6 +107,11 @@ } void SetUrl(const GURL& url) { url_ = url; } + void set_safety_tip_status( + security_state::SafetyTipStatus safety_tip_status) { + safety_tip_status_ = safety_tip_status; + } + std::unique_ptr<VisibleSecurityState> GetVisibleSecurityState() const { auto state = std::make_unique<VisibleSecurityState>(); state->connection_info_initialized = true; @@ -119,6 +126,7 @@ state->is_error_page = is_error_page_; state->is_view_source = is_view_source_; state->insecure_input_events = insecure_input_events_; + state->safety_tip_status = safety_tip_status_; return state; } @@ -145,6 +153,7 @@ bool is_view_source_; bool has_policy_certificate_; InsecureInputEventData insecure_input_events_; + security_state::SafetyTipStatus safety_tip_status_; }; } // namespace @@ -355,6 +364,36 @@ EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel()); } +// Tests that |safety_tip_status| effects security level appropriately. +TEST(SecurityStateTest, SafetyTipSometimesRemovesSecure) { + using security_state::SafetyTipStatus; + + struct SafetyTipCase { + SafetyTipStatus safety_tip_status; + security_state::SecurityLevel expected_level; + }; + + const SafetyTipCase kTestCases[] = { + {SafetyTipStatus::kUnknown, SECURE}, + {SafetyTipStatus::kNone, SECURE}, + {SafetyTipStatus::kBadReputation, NONE}, + {SafetyTipStatus::kLookalike, SECURE}, + {SafetyTipStatus::kBadKeyword, SECURE}, + }; + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + security_state::features::kSafetyTipUI); + + for (auto testcase : kTestCases) { + TestSecurityStateHelper helper; + helper.set_cert_status(0); + EXPECT_EQ(SECURE, helper.GetSecurityLevel()); + helper.set_safety_tip_status(testcase.safety_tip_status); + EXPECT_EQ(testcase.expected_level, helper.GetSecurityLevel()); + } +} + // Tests IsSchemeCryptographic function. TEST(SecurityStateTest, CryptographicSchemeUrl) { // HTTPS is a cryptographic scheme.
diff --git a/components/sync_preferences/BUILD.gn b/components/sync_preferences/BUILD.gn index e55d6b6..ed1dbe4 100644 --- a/components/sync_preferences/BUILD.gn +++ b/components/sync_preferences/BUILD.gn
@@ -17,8 +17,6 @@ "synced_pref_change_registrar.cc", "synced_pref_change_registrar.h", "synced_pref_observer.h", - "unknown_user_pref_accessor.cc", - "unknown_user_pref_accessor.h", ] deps = [
diff --git a/components/sync_preferences/pref_model_associator.cc b/components/sync_preferences/pref_model_associator.cc index 266b7b4..6cf1f4d 100644 --- a/components/sync_preferences/pref_model_associator.cc +++ b/components/sync_preferences/pref_model_associator.cc
@@ -22,6 +22,7 @@ #include "base/values.h" #include "components/prefs/persistent_pref_store.h" #include "components/prefs/pref_service.h" +#include "components/sync/base/model_type.h" #include "components/sync/model/sync_change.h" #include "components/sync/model/sync_change_processor.h" #include "components/sync/model/sync_error_factory.h" @@ -29,7 +30,6 @@ #include "components/sync/protocol/sync.pb.h" #include "components/sync_preferences/pref_model_associator_client.h" #include "components/sync_preferences/pref_service_syncable.h" -#include "components/sync_preferences/synced_pref_observer.h" using syncer::PREFERENCES; using syncer::PRIORITY_PREFERENCES; @@ -65,10 +65,11 @@ PrefModelAssociator::PrefModelAssociator( const PrefModelAssociatorClient* client, syncer::ModelType type, - UnknownUserPrefAccessor* accessor) - : pref_accessor_(accessor), type_(type), client_(client) { + PersistentPrefStore* user_pref_store) + : type_(type), client_(client), user_pref_store_(user_pref_store) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES); + DCHECK(user_pref_store_); } PrefModelAssociator::~PrefModelAssociator() { @@ -82,15 +83,8 @@ const syncer::SyncData& sync_pref, const std::string& pref_name, syncer::SyncChangeList* sync_changes) { - UnknownUserPrefAccessor::PreferenceState local_pref_state = - pref_accessor_->GetPreferenceState(type_, pref_name); - if (local_pref_state.registration_state == - UnknownUserPrefAccessor::RegistrationState::kUnknown || - local_pref_state.registration_state == - UnknownUserPrefAccessor::RegistrationState::kNotSyncable) { - // Only process syncable prefs and unknown prefs if whitelisted. - return; - } + const base::Value* user_pref_value = + pref_service_->GetUserPrefValue(pref_name); VLOG(1) << "Associating preference " << pref_name; if (sync_pref.IsValid()) { @@ -105,20 +99,20 @@ return; } - if (local_pref_state.persisted_value) { + if (user_pref_value) { DVLOG(1) << "Found user pref value for " << pref_name; // We have both server and local values. Merge them. - std::unique_ptr<base::Value> new_value(MergePreference( - pref_name, *local_pref_state.persisted_value, *sync_value)); + std::unique_ptr<base::Value> new_value( + MergePreference(pref_name, *user_pref_value, *sync_value)); // Update the local preference based on what we got from the // sync server. Note: this only updates the user value store, which is // ignored if the preference is policy controlled. if (new_value->is_none()) { LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); - pref_accessor_->ClearPref(pref_name, local_pref_state); - } else if (!local_pref_state.persisted_value->Equals(new_value.get())) { - pref_accessor_->SetPref(pref_name, local_pref_state, *new_value); + pref_service_->ClearPref(pref_name); + } else if (!user_pref_value->Equals(new_value.get())) { + SetPrefWithTypeCheck(pref_name, *new_value); } // If the merge resulted in an updated value, inform the syncer. @@ -134,19 +128,16 @@ } } else if (!sync_value->is_none()) { // Only a server value exists. Just set the local user value. - pref_accessor_->SetPref(pref_name, local_pref_state, *sync_value); + SetPrefWithTypeCheck(pref_name, *sync_value); } else { LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); } synced_preferences_.insert(preference.name()); - } else if (local_pref_state.persisted_value) { - DCHECK_EQ(local_pref_state.registration_state, - UnknownUserPrefAccessor::RegistrationState::kSyncable); + } else if (user_pref_value) { // The server does not know about this preference and should be added // to the syncer's database. syncer::SyncData sync_data; - if (!CreatePrefSyncData(pref_name, *local_pref_state.persisted_value, - &sync_data)) { + if (!CreatePrefSyncData(pref_name, *user_pref_value, &sync_data)) { LOG(ERROR) << "Failed to update preference."; return; } @@ -194,6 +185,16 @@ const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter); std::string sync_pref_name = preference.name(); + + if (remaining_preferences.count(sync_pref_name) == 0) { + // We're not syncing this preference locally, ignore the sync data. + // TODO(zea): Eventually we want to be able to have the syncable service + // reconstruct all sync data for its datatype (therefore having + // GetAllSyncData be a complete representation). We should store this + // data somewhere, even if we don't use it. + continue; + } + remaining_preferences.erase(sync_pref_name); InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes); } @@ -204,9 +205,6 @@ InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes); } - UMA_HISTOGRAM_COUNTS_1000("Sync.Preferences.SyncingUnknownPrefs", - pref_accessor_->GetNumberOfSyncingUnknownPrefs()); - // Push updates to sync. merge_result.set_error( sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); @@ -327,6 +325,10 @@ return result; } +// Note: This will build a model of all preferences registered as syncable +// with user controlled data. We do not track any information for preferences +// not registered locally as syncable and do not inform the syncer of +// non-user controlled preferences. syncer::SyncDataList PrefModelAssociator::GetAllSyncData( syncer::ModelType type) const { DCHECK_EQ(type_, type); @@ -334,10 +336,6 @@ for (auto iter = synced_preferences_.begin(); iter != synced_preferences_.end(); ++iter) { std::string name = *iter; - if (pref_accessor_->GetPreferenceState(type_, name).registration_state != - UnknownUserPrefAccessor::RegistrationState::kSyncable) { - continue; - } const PrefService::Preference* pref = pref_service_->FindPreference(name); DCHECK(pref); if (!pref->IsUserControlled() || pref->IsDefaultValue()) @@ -367,24 +365,16 @@ const sync_pb::PreferenceSpecifics& pref_specifics = GetSpecifics(iter->sync_data()); - UnknownUserPrefAccessor::PreferenceState local_pref_state = - pref_accessor_->GetPreferenceState(type_, pref_specifics.name()); - if (local_pref_state.registration_state == - UnknownUserPrefAccessor::RegistrationState::kUnknown) { - // It is possible that we may receive a change to a preference we do not - // want to sync. For example if the user is syncing a Mac client and a - // Windows client, the Windows client does not support - // kConfirmToQuitEnabled. Ignore updates from these preferences. - // We only sync such prefs if they are whitelisted. + // It is possible that we may receive a change to a preference we do not + // want to sync. For example if the user is syncing a Mac client and a + // Windows client, the Windows client does not support + // kConfirmToQuitEnabled. Ignore updates from these preferences. + std::string pref_name = pref_specifics.name(); + if (!IsPrefRegistered(pref_name)) continue; - } - if (local_pref_state.registration_state == - UnknownUserPrefAccessor::RegistrationState::kNotSyncable) { - // Don't process remote changes for prefs this client doesn't want synced. - continue; - } + if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { - pref_accessor_->ClearPref(pref_specifics.name(), local_pref_state); + pref_service_->ClearPref(pref_name); continue; } @@ -397,17 +387,24 @@ continue; } + if (!TypeMatchesUserPrefStore(pref_name, *new_value)) { + // Ignore updates where the server type doesn't match the local type. + // Don't use SetPrefWithTypeCheck() because we want to skip notifying + // observers and inserting into |synced_preferences_|. + continue; + } + // This will only modify the user controlled value store, which takes // priority over the default value but is ignored if the preference is // policy controlled. - pref_accessor_->SetPref(pref_specifics.name(), local_pref_state, - *new_value); + pref_service_->Set(pref_name, *new_value); NotifySyncedPrefObservers(pref_specifics.name(), true /*from_sync*/); - // Keep track of any newly synced preferences. This can happen if a - // preference was late registered or remotely added (ACTION_ADD). - synced_preferences_.insert(pref_specifics.name()); + // Keep track of any newly synced preferences. + if (iter->change_type() == syncer::SyncChange::ACTION_ADD) { + synced_preferences_.insert(pref_specifics.name()); + } } return syncer::SyncError(); } @@ -450,15 +447,14 @@ } void PrefModelAssociator::RegisterPref(const std::string& name) { - DCHECK(!registered_preferences_.count(name)); + DCHECK(registered_preferences_.count(name) == 0); registered_preferences_.insert(name); - // This pref might be registered after sync started. Make sure data in the - // local store matches the registered type. + // Make sure data in the local store matches the registered type. // If this results in a modification of the local pref store, we don't want // to tell ChromeSync about these -- it's a local anomaly, base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); - pref_accessor_->EnforceRegisteredTypeInStore(name); + EnforceRegisteredTypeInStore(name); } bool PrefModelAssociator::IsPrefRegistered(const std::string& name) const { @@ -474,9 +470,6 @@ if (!models_associated_) return; - // From now on, this method does not have to deal with lazily registered - // prefs, as local changes can only happen after they were registered. - const PrefService::Preference* preference = pref_service_->FindPreference(name); // TODO(tschumann): When can this ever happen? Should this be a DCHECK? @@ -505,10 +498,9 @@ NotifySyncedPrefObservers(name, false /*from_sync*/); if (synced_preferences_.count(name) == 0) { - // Not in synced_preferences_ means no synced data. - // InitPrefAndAssociate(..) will determine if we care about its data (e.g. - // if it has a default value and hasn't been changed yet we don't) and - // take care syncing any new data. + // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..) + // will determine if we care about its data (e.g. if it has a default value + // and hasn't been changed yet we don't) and take care syncing any new data. InitPrefAndAssociate(syncer::SyncData(), name, &changes); } else { // We are already syncing this preference, just update or delete its sync @@ -518,7 +510,7 @@ LOG(ERROR) << "Failed to update preference."; return; } - if (pref_accessor_->GetPreferenceState(type_, name).persisted_value) { + if (pref_service_->GetUserPrefValue(name)) { // If the pref was updated, update it. changes.push_back(syncer::SyncChange( FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data)); @@ -547,4 +539,49 @@ observer.OnSyncedPrefChanged(path, from_sync); } +void PrefModelAssociator::SetPrefWithTypeCheck(const std::string& pref_name, + const base::Value& new_value) { + if (TypeMatchesUserPrefStore(pref_name, new_value)) + pref_service_->Set(pref_name, new_value); +} + +bool PrefModelAssociator::TypeMatchesUserPrefStore( + const std::string& pref_name, + const base::Value& new_value) const { + const base::Value* local_value = nullptr; + user_pref_store_->GetValue(pref_name, &local_value); + if (!local_value || local_value->type() == new_value.type()) + return true; + + UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.RemotePrefTypeMismatch", true); + DLOG(WARNING) << "Unexpected type mis-match for pref. " + << "Synced value for " << pref_name << " is of type " + << new_value.type() << " which doesn't match the locally " + << "present pref type: " << local_value->type(); + return false; +} + +void PrefModelAssociator::EnforceRegisteredTypeInStore( + const std::string& pref_name) { + const base::Value* persisted_value = nullptr; + if (user_pref_store_->GetValue(pref_name, &persisted_value)) { + // Get the registered type (typically from the default value). + const PrefService::Preference* pref = + pref_service_->FindPreference(pref_name); + DCHECK(pref); + if (pref->GetType() != persisted_value->type()) { + // We see conflicting type information and there's a chance the local + // type-conflicting data came in via sync. Remove it. + // TODO(tschumann): The value should get removed silently. Add a method + // RemoveValueSilently() to WriteablePrefStore. Note, that as of today + // that removal will only notify other pref stores but not sync -- that's + // done on a higher level. + user_pref_store_->RemoveValue( + pref_name, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.ClearedLocalPrefOnTypeMismatch", + true); + } + } +} + } // namespace sync_preferences
diff --git a/components/sync_preferences/pref_model_associator.h b/components/sync_preferences/pref_model_associator.h index 4271095d..6b39aa1 100644 --- a/components/sync_preferences/pref_model_associator.h +++ b/components/sync_preferences/pref_model_associator.h
@@ -17,7 +17,9 @@ #include "base/sequence_checker.h" #include "components/sync/model/sync_data.h" #include "components/sync/model/syncable_service.h" -#include "components/sync_preferences/unknown_user_pref_accessor.h" +#include "components/sync_preferences/synced_pref_observer.h" + +class PersistentPrefStore; namespace base { class Value; @@ -31,7 +33,6 @@ class PrefModelAssociatorClient; class PrefServiceSyncable; -class SyncedPrefObserver; // Contains all preference sync related logic. // TODO(sync): Merge this into PrefService once we separate the profile @@ -39,11 +40,11 @@ class PrefModelAssociator : public syncer::SyncableService { public: // Constructs a PrefModelAssociator initializing the |client_| and |type_| - // instance variable. |client| and |accessor| are not owned by this object - // and the caller must ensure they outlive the PrefModelAssociator. + // instance variable. The |client| and |user_pref_store| are not owned by this + // object and they must outlive the PrefModelAssociator. PrefModelAssociator(const PrefModelAssociatorClient* client, syncer::ModelType type, - UnknownUserPrefAccessor* accessor); + PersistentPrefStore* user_pref_store); ~PrefModelAssociator() override; // See description above field for details. @@ -66,9 +67,6 @@ // inform the syncer of non-user controlled preferences. syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; - // TODO(tschumann): Replace the RegisterPref() call with a - // VerifyPersistedPrefType() method. All pref registration checks are now - // done via the registry; no need to duplicate that concept. // Register a preference with the specified name for syncing. We do not care // about the type at registration time, but when changes arrive from the // syncer, we check if they can be applied and if not drop them. @@ -80,9 +78,6 @@ // sent to the syncer. void ProcessPrefChange(const std::string& name); - // TODO(tschumann): Remove the associator's dependency on PrefServiceSyncable. - // It's only needed for calling OnIsSyncingChanged. This logic can be moved - // onto the associator: PrefServiceSyncable forwards the registration calls. void SetPrefService(PrefServiceSyncable* pref_service); // Merges the local_value into the supplied server_value and returns @@ -145,6 +140,22 @@ void NotifySyncedPrefObservers(const std::string& path, bool from_sync) const; + // Sets |pref_name| to |new_value| if |new_value| has an appropriate type for + // this preference. Otherwise records metrics and logs a warning. + void SetPrefWithTypeCheck(const std::string& pref_name, + const base::Value& new_value); + + // Returns true if the |new_value| for |pref_name| has the same type as the + // existing value in the user's local pref store. If the types don't match, + // records metrics and logs a warning. + bool TypeMatchesUserPrefStore(const std::string& pref_name, + const base::Value& new_value) const; + + // Verifies that the type which preference |pref_name| was registered with + // matches the type of any persisted value. On mismatch, the persisted value + // gets removed. + void EnforceRegisteredTypeInStore(const std::string& pref_name); + // Do we have an active association between the preferences and sync models? // Set when start syncing, reset in StopSyncing. While this is not set, we // ignore any local preference changes (when we start syncing we will look @@ -173,9 +184,6 @@ // The PrefService we are syncing to. PrefServiceSyncable* pref_service_ = nullptr; - // A pref accessor to access prefs which might not be registered. - UnknownUserPrefAccessor* pref_accessor_; - // Sync's syncer::SyncChange handler. We push all our changes through this. std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_; @@ -193,9 +201,10 @@ base::ObserverList<SyncedPrefObserver>::Unchecked; std::unordered_map<std::string, std::unique_ptr<SyncedPrefObserverList>> synced_pref_observers_; - const PrefModelAssociatorClient* client_; // Weak. + PersistentPrefStore* const user_pref_store_; + SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(PrefModelAssociator);
diff --git a/components/sync_preferences/pref_service_syncable.cc b/components/sync_preferences/pref_service_syncable.cc index 7cdc8ed..e9a9698d 100644 --- a/components/sync_preferences/pref_service_syncable.cc +++ b/components/sync_preferences/pref_service_syncable.cc
@@ -42,18 +42,17 @@ bool async) : PrefService(std::move(pref_notifier), std::move(pref_value_store), - std::move(user_prefs), + user_prefs, pref_registry, std::move(read_error_callback), async), pref_service_forked_(false), - unknown_pref_accessor_(this, pref_registry.get(), user_pref_store_.get()), pref_sync_associator_(pref_model_associator_client, syncer::PREFERENCES, - &unknown_pref_accessor_), + user_prefs.get()), priority_pref_sync_associator_(pref_model_associator_client, syncer::PRIORITY_PREFERENCES, - &unknown_pref_accessor_), + user_prefs.get()), pref_registry_(std::move(pref_registry)) { pref_sync_associator_.SetPrefService(this); priority_pref_sync_associator_.SetPrefService(this); @@ -180,12 +179,8 @@ uint32_t flags) { DCHECK(FindPreference(path)); if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PREF) { - DCHECK(!pref_sync_associator_.models_associated() || - pref_registry_->IsWhitelistedLateRegistrationPref(path)); pref_sync_associator_.RegisterPref(path); } else if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF) { - DCHECK(!priority_pref_sync_associator_.models_associated() || - pref_registry_->IsWhitelistedLateRegistrationPref(path)); priority_pref_sync_associator_.RegisterPref(path); } }
diff --git a/components/sync_preferences/pref_service_syncable.h b/components/sync_preferences/pref_service_syncable.h index 85e3384..8013edb 100644 --- a/components/sync_preferences/pref_service_syncable.h +++ b/components/sync_preferences/pref_service_syncable.h
@@ -18,7 +18,6 @@ #include "components/prefs/pref_value_store.h" #include "components/sync_preferences/pref_model_associator.h" #include "components/sync_preferences/synced_pref_observer.h" -#include "components/sync_preferences/unknown_user_pref_accessor.h" namespace syncer { class SyncableService; @@ -106,7 +105,6 @@ // "forked" PrefService. bool pref_service_forked_; - UnknownUserPrefAccessor unknown_pref_accessor_; PrefModelAssociator pref_sync_associator_; PrefModelAssociator priority_pref_sync_associator_; const scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
diff --git a/components/sync_preferences/pref_service_syncable_unittest.cc b/components/sync_preferences/pref_service_syncable_unittest.cc index 85fda24..5e2d214 100644 --- a/components/sync_preferences/pref_service_syncable_unittest.cc +++ b/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -538,47 +538,6 @@ EXPECT_TRUE(GetPreferenceValue(kDictPrefName).Equals(&expected_dict)); } -TEST_F(PrefServiceSyncableMergeTest, InitWithUnknownPrefsValue) { - base::HistogramTester histogram_tester; - const std::string pref_name1 = "testing.whitelisted_pref1"; - const std::string pref_name2 = "testing.whitelisted_pref2"; - pref_registry_->WhitelistLateRegistrationPrefForSync(pref_name1); - pref_registry_->WhitelistLateRegistrationPrefForSync(pref_name2); - - syncer::SyncDataList in; - AddToRemoteDataList(pref_name1, base::Value("remote_value1"), &in); - AddToRemoteDataList(pref_name2, base::Value("remote_value2"), &in); - syncer::SyncChangeList out; - InitWithSyncDataTakeOutput(in, &out); - pref_registry_->RegisterStringPref( - pref_name1, "default_value", - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - EXPECT_THAT(GetPreferenceValue(pref_name1).GetString(), Eq("remote_value1")); - - histogram_tester.ExpectBucketCount("Sync.Preferences.SyncingUnknownPrefs", 2, - 1); -} - -TEST_F(PrefServiceSyncableMergeTest, ReceiveUnknownPrefsValue) { - base::HistogramTester histogram_tester; - const std::string pref_name = "testing.whitelisted_pref"; - pref_registry_->WhitelistLateRegistrationPrefForSync(pref_name); - - syncer::SyncChangeList out; - InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); - - syncer::SyncChangeList remote_changes; - remote_changes.push_back(MakeRemoteChange( - 1, pref_name, base::Value("remote_value"), SyncChange::ACTION_UPDATE)); - pref_sync_service_->ProcessSyncChanges(FROM_HERE, remote_changes); - EXPECT_THAT(prefs_.IsPrefSynced(pref_name), Eq(true)); - - pref_registry_->RegisterStringPref( - pref_name, "default_value", - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - EXPECT_THAT(GetPreferenceValue(pref_name).GetString(), Eq("remote_value")); -} - TEST_F(PrefServiceSyncableMergeTest, KeepPriorityPreferencesSeparately) { base::HistogramTester histogram_tester; const std::string pref_name = "testing.priority_pref"; @@ -608,28 +567,20 @@ TEST_F(PrefServiceSyncableMergeTest, RegisterShouldClearTypeMismatchingData) { base::HistogramTester histogram_tester; - const std::string pref_name = "testing.whitelisted_pref"; - pref_registry_->WhitelistLateRegistrationPrefForSync(pref_name); + const std::string pref_name = "testing.pref"; + user_prefs_->SetString(pref_name, "string_value"); + ASSERT_TRUE(user_prefs_->GetValue(pref_name, nullptr)); + // Make sure no changes will be communicated to any synced pref listeners // (those listeners are typically only used for metrics but we still don't // want to inform them). ShouldNotBeNotifedObserver observer; prefs_.AddSyncedPrefObserver(pref_name, &observer); - syncer::SyncDataList in; - AddToRemoteDataList(pref_name, base::Value("remote_value"), &in); - syncer::SyncChangeList out; - InitWithSyncDataTakeOutput(in, &out); - ASSERT_THAT(out, IsEmpty()); - - EXPECT_TRUE(user_prefs_->GetValue(pref_name, nullptr)); pref_registry_->RegisterListPref( pref_name, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); EXPECT_TRUE(GetPreferenceValue(pref_name).GetList().empty()); EXPECT_FALSE(user_prefs_->GetValue(pref_name, nullptr)); - // Make sure the removal of the value was not communicated to sync via the - // SyncProcessor. - EXPECT_THAT(out, IsEmpty()); histogram_tester.ExpectBucketCount( "Sync.Preferences.ClearedLocalPrefOnTypeMismatch", true, 1); @@ -655,33 +606,6 @@ EXPECT_THAT(GetPreferenceValue(pref_name).GetString(), Eq("default_value")); } -TEST_F(PrefServiceSyncableMergeTest, GetAllSyncDataForLateRegisteredPrefs) { - const std::string pref_name = "testing.whitelisted_pref"; - pref_registry_->WhitelistLateRegistrationPrefForSync(pref_name); - - syncer::SyncDataList in; - AddToRemoteDataList(pref_name, base::Value("remote_value"), &in); - syncer::SyncChangeList out; - InitWithSyncDataTakeOutput(in, &out); - - syncer::SyncDataList all_data = - prefs_.GetSyncableService(syncer::PREFERENCES) - ->GetAllSyncData(syncer::PREFERENCES); - EXPECT_THAT(all_data, IsEmpty()); - - // Make sure the preference appears in the result once it's registered. - pref_registry_->RegisterStringPref( - pref_name, "default_value", - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); - - all_data = prefs_.GetSyncableService(syncer::PREFERENCES) - ->GetAllSyncData(syncer::PREFERENCES); - ASSERT_THAT(all_data, SizeIs(1)); - EXPECT_THAT(all_data[0].GetSpecifics().preference().name(), Eq(pref_name)); - EXPECT_THAT(all_data[0].GetSpecifics().preference().value(), - Eq("\"remote_value\"")); -} - TEST_F(PrefServiceSyncableTest, FailModelAssociation) { syncer::SyncChangeList output; TestSyncProcessorStub* stub = new TestSyncProcessorStub(&output);
diff --git a/components/sync_preferences/unknown_user_pref_accessor.cc b/components/sync_preferences/unknown_user_pref_accessor.cc deleted file mode 100644 index 063b5ae..0000000 --- a/components/sync_preferences/unknown_user_pref_accessor.cc +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/sync_preferences/unknown_user_pref_accessor.h" - -#include <iterator> -#include <memory> - -#include "base/json/json_string_value_serializer.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/values.h" -#include "components/prefs/persistent_pref_store.h" -#include "components/prefs/pref_service.h" -#include "components/sync_preferences/pref_service_syncable.h" - -namespace sync_preferences { - -UnknownUserPrefAccessor::UnknownUserPrefAccessor( - PrefService* pref_service, - user_prefs::PrefRegistrySyncable* pref_registry, - PersistentPrefStore* user_prefs) - : pref_service_(pref_service), - pref_registry_(pref_registry), - user_prefs_(user_prefs) {} - -UnknownUserPrefAccessor::~UnknownUserPrefAccessor() {} - -UnknownUserPrefAccessor::PreferenceState -UnknownUserPrefAccessor::GetPreferenceState( - syncer::ModelType type, - const std::string& pref_name) const { - PreferenceState result; - result.registration_state = GetRegistrationState(type, pref_name); - switch (result.registration_state) { - case RegistrationState::kUnknown: - case RegistrationState::kUnknownWhitelisted: - if (!user_prefs_->GetValue(pref_name, &result.persisted_value)) { - result.persisted_value = nullptr; - } - break; - case RegistrationState::kSyncable: - case RegistrationState::kNotSyncable: - result.persisted_value = pref_service_->GetUserPrefValue(pref_name); - break; - } - return result; -} - -void UnknownUserPrefAccessor::ClearPref( - const std::string& pref_name, - const PreferenceState& local_pref_state) { - switch (local_pref_state.registration_state) { - case RegistrationState::kUnknown: - NOTREACHED() << "Sync attempted to update an unknown pref which is not " - "whitelisted: " - << pref_name; - break; - case RegistrationState::kUnknownWhitelisted: - user_prefs_->RemoveValue(pref_name, - WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); - break; - case RegistrationState::kSyncable: - pref_service_->ClearPref(pref_name); - break; - case RegistrationState::kNotSyncable: - // As this can happen if different clients disagree about which - // preferences should be synced, we only log a warning. - DLOG(WARNING) - << "Sync attempted to update a pref which is not registered as " - "syncable. Ignoring the remote change for pref: " - << pref_name; - break; - } -} - -int UnknownUserPrefAccessor::GetNumberOfSyncingUnknownPrefs() const { - return synced_unknown_prefs_.size(); -} - -namespace { - -bool VerifyTypesBeforeSet(const std::string& pref_name, - const base::Value* local_value, - const base::Value& new_value) { - if (local_value == nullptr || local_value->type() == new_value.type()) { - return true; - } - UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.RemotePrefTypeMismatch", true); - DLOG(WARNING) << "Unexpected type mis-match for pref. " - << "Synced value for " << pref_name << " is of type " - << new_value.type() << " which doesn't match the locally " - << "present pref type: " << local_value->type(); - return false; -} - -} // namespace - -void UnknownUserPrefAccessor::SetPref(const std::string& pref_name, - const PreferenceState& local_pref_state, - const base::Value& value) { - // On type mis-match, we trust the local preference DB and ignore the remote - // change. - switch (local_pref_state.registration_state) { - case RegistrationState::kUnknown: - NOTREACHED() << "Sync attempted to update a unknown pref which is not " - "whitelisted: " - << pref_name; - break; - case RegistrationState::kUnknownWhitelisted: - if (VerifyTypesBeforeSet(pref_name, local_pref_state.persisted_value, - value)) { - user_prefs_->SetValue(pref_name, value.CreateDeepCopy(), - WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); - } - synced_unknown_prefs_.insert(pref_name); - break; - case RegistrationState::kSyncable: - if (VerifyTypesBeforeSet(pref_name, local_pref_state.persisted_value, - value)) { - pref_service_->Set(pref_name, value); - } - break; - case RegistrationState::kNotSyncable: - // As this can happen if different clients disagree about which - // preferences should be synced, we only log a warning. - DLOG(WARNING) - << "Sync attempted to update a pref which is not registered as " - "syncable. Ignoring the remote change for pref: " - << pref_name; - break; - } -} - -void UnknownUserPrefAccessor::EnforceRegisteredTypeInStore( - const std::string& pref_name) { - const base::Value* persisted_value = nullptr; - if (user_prefs_->GetValue(pref_name, &persisted_value)) { - // Get the registered type (typically from the default value). - const PrefService::Preference* pref = - pref_service_->FindPreference(pref_name); - DCHECK(pref); - if (pref->GetType() != persisted_value->type()) { - // We see conflicting type information and there's a chance the local - // type-conflicting data came in via sync. Remove it. - // TODO(tschumann): The value should get removed silently. Add a method - // RemoveValueSilently() to WriteablePrefStore. Note, that as of today - // that removal will only notify other pref stores but not sync -- that's - // done on a higher level. - user_prefs_->RemoveValue(pref_name, - WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); - UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.ClearedLocalPrefOnTypeMismatch", - true); - } - } - synced_unknown_prefs_.erase(pref_name); -} - -UnknownUserPrefAccessor::RegistrationState -UnknownUserPrefAccessor::GetRegistrationState( - syncer::ModelType type, - const std::string& pref_name) const { - uint32_t type_flag = 0; - switch (type) { - case syncer::PRIORITY_PREFERENCES: - type_flag = user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF; - break; - case syncer::PREFERENCES: - type_flag = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF; - break; - default: - NOTREACHED() << "unexpected model type for preferences: " << type; - } - if (pref_registry_->defaults()->GetValue(pref_name, nullptr)) { - uint32_t flags = pref_registry_->GetRegistrationFlags(pref_name); - if (flags & type_flag) { - return RegistrationState::kSyncable; - } - // Imagine the case where a preference has been synced as SYNCABLE_PREF - // first and then got changed to SYNCABLE_PRIORITY_PREF: - // In that situation, it could be argued for both, the preferences to be - // considered unknown or not synced. However, as we plan to eventually also - // sync unknown preferences, we cannot label them as unknown and treat them - // as not synced instead. (The underlying problem is that priority - // preferences are a concept only known to sync. The persistent stores don't - // distinguish between those two). - return RegistrationState::kNotSyncable; - } - if (pref_registry_->IsWhitelistedLateRegistrationPref(pref_name)) { - return RegistrationState::kUnknownWhitelisted; - } - return RegistrationState::kUnknown; -} - -} // namespace sync_preferences
diff --git a/components/sync_preferences/unknown_user_pref_accessor.h b/components/sync_preferences/unknown_user_pref_accessor.h deleted file mode 100644 index 34336a0..0000000 --- a/components/sync_preferences/unknown_user_pref_accessor.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SYNC_PREFERENCES_UNKNOWN_USER_PREF_ACCESSOR_H_ -#define COMPONENTS_SYNC_PREFERENCES_UNKNOWN_USER_PREF_ACCESSOR_H_ - -#include <memory> -#include <set> -#include <string> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "components/sync/base/model_type.h" - -class PersistentPrefStore; -class PrefService; - -namespace base { -class Value; -} - -namespace user_prefs { -class PrefRegistrySyncable; -} - -namespace sync_preferences { - -// A class to access user prefs even before they were registered. -// Currently, accessing not registered (unknown) prefs is limited to a -// whitelist. -class UnknownUserPrefAccessor { - public: - enum class RegistrationState { - kUnknown, // Preference is not registered (on this Chrome instance). - kUnknownWhitelisted, // Preference is not registered but whitelisted to be - // synced without being registered. - kSyncable, // Preference is registered as being synced. - kNotSyncable // Preference is registered as not being synced. - }; - - struct PreferenceState { - // The registration state of a preference. - RegistrationState registration_state = RegistrationState::kUnknown; - - // The actually stored value. nullptr if no value is persisted and the pref - // service serves a default value for this pref. - // Ownership lies with the underlying pref-store. - const base::Value* persisted_value = nullptr; - }; - - // |pref_service|, |pref_registry|, and |user_prefs| must not be null and must - // outlive the lifetime of the created instance. The caller keeps ownership - // over these objects. - UnknownUserPrefAccessor(PrefService* pref_service, - user_prefs::PrefRegistrySyncable* pref_registry, - PersistentPrefStore* user_prefs); - ~UnknownUserPrefAccessor(); - - // Computes the state of a preference with name |pref_name| which gives - // information about whether it's registered and the locally persisted value. - PreferenceState GetPreferenceState(syncer::ModelType type, - const std::string& pref_name) const; - - // Removes the value of the preference |pref_name| from the user prefstore. - // Must not be called for preferences having RegistrationState::kUnknown. - // When called for preferences registiered as not syncable - // (RegistrationState::kNotSyncable), no changes to the storage are made. - void ClearPref(const std::string& pref_name, - const PreferenceState& local_pref_state); - - // Changes the value of the preference |pref_name| on the user prefstore. - // Must not be called for preferences having RegistrationState::kUnknown. - // When called for preferences registiered as not syncable - // (RegistrationState::kNotSyncable), no changes to the storage are made. - void SetPref(const std::string& pref_name, - const PreferenceState& local_pref_state, - const base::Value& value); - - // Verifies that the type which preference |pref_name| was registered with - // matches the type of any persisted value. On mismatch, the persisted value - // gets removed. - void EnforceRegisteredTypeInStore(const std::string& pref_name); - - // Returns the number of synced preferences which have not been registered (so - // far). - int GetNumberOfSyncingUnknownPrefs() const; - - private: - RegistrationState GetRegistrationState(syncer::ModelType type, - const std::string& pref_name) const; - - std::set<std::string> synced_unknown_prefs_; - PrefService* const pref_service_; - user_prefs::PrefRegistrySyncable* const pref_registry_; - PersistentPrefStore* const user_prefs_; - - DISALLOW_COPY_AND_ASSIGN(UnknownUserPrefAccessor); -}; - -} // namespace sync_preferences - -#endif // COMPONENTS_SYNC_PREFERENCES_UNKNOWN_USER_PREF_ACCESSOR_H_
diff --git a/components/tracing/common/trace_startup_config.cc b/components/tracing/common/trace_startup_config.cc index 8720fe0c..152c51a 100644 --- a/components/tracing/common/trace_startup_config.cc +++ b/components/tracing/common/trace_startup_config.cc
@@ -72,8 +72,6 @@ // First 10k events at start are sufficient to debug startup traces. trace_config.SetTraceBufferSizeInEvents(10000); trace_config.SetProcessFilterConfig(process_config); - // Enable argument filter since we could be background tracing. - trace_config.EnableArgumentFilter(); return trace_config; } @@ -248,6 +246,8 @@ SetBackgroundStartupTracingEnabled(false); trace_config_ = GetDefaultBrowserStartupConfig(); + trace_config_.EnableArgumentFilter(); + is_enabled_ = true; session_owner_ = SessionOwner::kBackgroundTracing; should_trace_to_result_file_ = false;
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index 1e9fca6..5b1edca 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -24,8 +24,13 @@ base::FEATURE_ENABLED_BY_DEFAULT}; #endif +#if defined(OS_CHROMEOS) const base::Feature kEnableVizHitTestSurfaceLayer{ "VizHitTestSurfaceLayer", base::FEATURE_DISABLED_BY_DEFAULT}; +#else +const base::Feature kEnableVizHitTestSurfaceLayer{ + "VizHitTestSurfaceLayer", base::FEATURE_ENABLED_BY_DEFAULT}; +#endif // Use Skia's readback API instead of GLRendererCopier. const base::Feature kUseSkiaForGLReadback{"UseSkiaForGLReadback",
diff --git a/components/viz/host/hit_test/hit_test_query_unittest.cc b/components/viz/host/hit_test/hit_test_query_unittest.cc index 1b116b8..5e4a768 100644 --- a/components/viz/host/hit_test/hit_test_query_unittest.cc +++ b/components/viz/host/hit_test/hit_test_query_unittest.cc
@@ -27,14 +27,17 @@ protected: HitTestQuery& hit_test_query() { return hit_test_query_; } void SetUp() override { - if (!GetParam()) { + if (GetParam()) { + feature_list_.InitAndEnableFeature( + features::kEnableVizHitTestSurfaceLayer); + } + + if (!features::IsVizHitTestingSurfaceLayerEnabled()) { // kHitTestIgnore has different meanings in v1 and v2. Some tests set // kHitTestIgnore for certain regions which works for v1 but fails v2. test_flags_ |= HitTestRegionFlags::kHitTestIgnore; return; } - - feature_list_.InitAndEnableFeature(features::kEnableVizHitTestSurfaceLayer); } base::test::ScopedFeatureList feature_list_;
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index a4adc6c..63ac0dd 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1164,6 +1164,13 @@ bool BrowserAccessibilityAndroid::CanScrollForward() const { if (IsSlider()) { + // If it's not a native INPUT element, then increment and decrement + // won't work. + std::string html_tag = + GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); + if (html_tag != "input") + return false; + float value = GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange); float max = GetFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange); return value < max; @@ -1174,6 +1181,13 @@ bool BrowserAccessibilityAndroid::CanScrollBackward() const { if (IsSlider()) { + // If it's not a native INPUT element, then increment and decrement + // won't work. + std::string html_tag = + GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); + if (html_tag != "input") + return false; + float value = GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange); float min = GetFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange); return value > min;
diff --git a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc index 2def64e..6c332f6 100644 --- a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc +++ b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc
@@ -294,9 +294,9 @@ blob = std::move(response->blob->blob); blob_size = response->blob->size; } - if (response->side_data_blob) { - side_data_blob = std::move(response->side_data_blob->blob); - side_data_blob_size = response->side_data_blob->size; + if (response->side_data_blob_for_cache_put) { + side_data_blob = std::move(response->side_data_blob_for_cache_put->blob); + side_data_blob_size = response->side_data_blob_for_cache_put->size; } return std::make_unique<PutContext>( @@ -307,9 +307,20 @@ void PopulateResponseBody(scoped_refptr<DiskCacheBlobEntry> blob_entry, blink::mojom::FetchAPIResponse* response) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // First create the blob and store it in the field for the main body + // loading. response->blob = CreateBlobWithSideData( std::move(blob_entry), CacheStorageCache::INDEX_RESPONSE_BODY, CacheStorageCache::INDEX_SIDE_DATA); + + // Then clone the blob to the |side_data_blob| field for loading code_cache. + mojo::Remote<blink::mojom::Blob> blob_remote( + std::move(response->blob->blob)); + blob_remote->Clone(response->blob->blob.InitWithNewPipeAndPassReceiver()); + response->side_data_blob = blink::mojom::SerializedBlob::New( + response->blob->uuid, response->blob->content_type, + response->blob->size, blob_remote.Unbind()); } void PopulateRequestBody(scoped_refptr<DiskCacheBlobEntry> blob_entry,
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc index f05c5d7..2d8a059 100644 --- a/content/browser/cache_storage/cache_storage_cache_unittest.cc +++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -527,7 +527,9 @@ nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown, response_time_, std::string() /* cache_storage_cache_name */, std::vector<std::string>() /* cors_exposed_header_names */, - nullptr /* side_data_blob */, nullptr /* content_security_policy */); + nullptr /* side_data_blob */, + nullptr /* side_data_blob_for_cache_put */, + nullptr /* content_security_policy */); } std::unique_ptr<storage::BlobDataHandle> BuildBlobHandle( @@ -541,12 +543,16 @@ void CopySideDataToResponse(storage::BlobDataHandle* side_data_blob_handle, blink::mojom::FetchAPIResponse* response) { - response->side_data_blob = blink::mojom::SerializedBlob::New(); - response->side_data_blob->uuid = side_data_blob_handle->uuid(); - response->side_data_blob->size = side_data_blob_handle->size(); + response->side_data_blob_for_cache_put = + blink::mojom::SerializedBlob::New(); + response->side_data_blob_for_cache_put->uuid = + side_data_blob_handle->uuid(); + response->side_data_blob_for_cache_put->size = + side_data_blob_handle->size(); storage::BlobImpl::Create( std::make_unique<storage::BlobDataHandle>(*side_data_blob_handle), - response->side_data_blob->blob.InitWithNewPipeAndPassReceiver()); + response->side_data_blob_for_cache_put->blob + .InitWithNewPipeAndPassReceiver()); } blink::mojom::FetchAPIRequestPtr CopyFetchRequest( @@ -1741,7 +1747,7 @@ operation->operation_type = blink::mojom::OperationType::kPut; operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_); operation->response = std::move(response); - operation->response->side_data_blob->size = + operation->response->side_data_blob_for_cache_put->size = std::numeric_limits<uint64_t>::max(); std::vector<blink::mojom::BatchOperationPtr> operations;
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc index 0eb5de1..7c9f18c 100644 --- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc +++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -5,6 +5,7 @@ #include "content/browser/cache_storage/cache_storage_dispatcher_host.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" @@ -18,10 +19,12 @@ #include "content/browser/cache_storage/cache_storage_manager.h" #include "content/browser/cache_storage/cache_storage_trace_utils.h" #include "content/common/background_fetch/background_fetch_types.h" +#include "content/public/common/content_features.h" #include "content/public/common/origin_util.h" #include "content/public/common/referrer_type_converters.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" +#include "third_party/blink/public/common/blob/blob_utils.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h" #include "url/gurl.h" #include "url/origin.h" @@ -64,6 +67,43 @@ return true; } +blink::mojom::MatchResultPtr EagerlyReadResponseBody( + blink::mojom::FetchAPIResponsePtr response) { + if (!response->blob || + !base::FeatureList::IsEnabled(features::kCacheStorageEagerReading)) { + return blink::mojom::MatchResult::NewResponse(std::move(response)); + } + + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = + blink::BlobUtils::GetDataPipeCapacity(response->blob->size); + + mojo::ScopedDataPipeProducerHandle producer_handle; + mojo::ScopedDataPipeConsumerHandle consumer_handle; + MojoResult rv = CreateDataPipe(&options, &producer_handle, &consumer_handle); + if (rv != MOJO_RESULT_OK) + return blink::mojom::MatchResult::NewResponse(std::move(response)); + + mojo::PendingRemote<blink::mojom::BlobReaderClient> reader_client; + auto pending_receiver = reader_client.InitWithNewPipeAndPassReceiver(); + + mojo::Remote<blink::mojom::Blob> blob(std::move(response->blob->blob)); + blob->ReadAll(std::move(producer_handle), std::move(reader_client)); + + // Clear the main body blob entry. There should still be a |side_data_blob| + // value for reading code cache, however. + response->blob = nullptr; + DCHECK(response->side_data_blob); + + return blink::mojom::MatchResult::NewEagerResponse( + blink::mojom::EagerResponse::New(std::move(response), + std::move(consumer_handle), + std::move(pending_receiver))); +} + } // namespace // Implements the mojom interface CacheStorageCache. It's owned by @@ -80,6 +120,7 @@ // blink::mojom::CacheStorageCache implementation: void Match(blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr match_options, + bool in_related_fetch_event, int64_t trace_id, MatchCallback callback) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -98,7 +139,8 @@ auto cb = base::BindOnce( [](base::TimeTicks start_time, bool ignore_search, - bool cache_initialized, int64_t trace_id, + bool in_related_fetch_event, bool cache_initialized, + int64_t trace_id, blink::mojom::CacheStorageCache::MatchCallback callback, blink::mojom::CacheStorageError error, blink::mojom::FetchAPIResponsePtr response) { @@ -136,11 +178,19 @@ TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "response", CacheStorageTracedValue(response)); - std::move(callback).Run( - blink::mojom::MatchResult::NewResponse(std::move(response))); + + blink::mojom::MatchResultPtr result; + if (in_related_fetch_event) { + result = EagerlyReadResponseBody(std::move(response)); + } else { + result = + blink::mojom::MatchResult::NewResponse(std::move(response)); + } + std::move(callback).Run(std::move(result)); }, - base::TimeTicks::Now(), match_options->ignore_search, cache_initialized, - trace_id, std::move(callback)); + base::TimeTicks::Now(), match_options->ignore_search, + in_related_fetch_event, cache_initialized, trace_id, + std::move(callback)); if (!cache) { std::move(cb).Run(CacheStorageError::kErrorNotFound, nullptr); @@ -471,6 +521,7 @@ void Match(blink::mojom::FetchAPIRequestPtr request, blink::mojom::MultiCacheQueryOptionsPtr match_options, + bool in_related_fetch_event, int64_t trace_id, blink::mojom::CacheStorage::MatchCallback callback) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -482,7 +533,8 @@ "options", CacheStorageTracedValue(match_options)); auto cb = BindOnce( - [](base::TimeTicks start_time, bool match_all_caches, int64_t trace_id, + [](base::TimeTicks start_time, bool match_all_caches, + bool in_related_fetch_event, int64_t trace_id, blink::mojom::CacheStorage::MatchCallback callback, CacheStorageError error, blink::mojom::FetchAPIResponsePtr response) { @@ -513,11 +565,18 @@ TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "response", CacheStorageTracedValue(response)); - std::move(callback).Run( - blink::mojom::MatchResult::NewResponse(std::move(response))); + + blink::mojom::MatchResultPtr result; + if (in_related_fetch_event) { + result = EagerlyReadResponseBody(std::move(response)); + } else { + result = + blink::mojom::MatchResult::NewResponse(std::move(response)); + } + std::move(callback).Run(std::move(result)); }, - base::TimeTicks::Now(), !match_options->cache_name, trace_id, - std::move(callback)); + base::TimeTicks::Now(), !match_options->cache_name, + in_related_fetch_event, trace_id, std::move(callback)); content::CacheStorage* cache_storage = GetOrCreateCacheStorage(); if (!cache_storage) {
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index d89bcd3..7ce4e94 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -667,7 +667,9 @@ std::move(blob), blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(), std::string() /* cache_storage_cache_name */, std::vector<std::string>() /* cors_exposed_header_names */, - nullptr /* side_data_blob */, nullptr /* content_security_policy */); + nullptr /* side_data_blob */, + nullptr /* side_data_blob_for_cache_put */, + nullptr /* content_security_policy */); blink::mojom::BatchOperationPtr operation = blink::mojom::BatchOperation::New();
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc index ce9e979..cf52c78 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -356,7 +356,8 @@ std::vector<std::string>( metadata.response().cors_exposed_header_names().begin(), metadata.response().cors_exposed_header_names().end()), - nullptr /* side_data_blob */, nullptr /* content_security_policy */); + nullptr /* side_data_blob */, nullptr /* side_data_blob_for_cache_put */, + nullptr /* content_security_policy */); } // The size of opaque (non-cors) resource responses are padded in order @@ -642,9 +643,10 @@ for (const auto& operation : operations) { if (operation->operation_type == blink::mojom::OperationType::kPut) { safe_space_required += CalculateRequiredSafeSpaceForPut(operation); - safe_side_data_size += (operation->response->side_data_blob - ? operation->response->side_data_blob->size - : 0); + safe_side_data_size += + (operation->response->side_data_blob_for_cache_put + ? operation->response->side_data_blob_for_cache_put->size + : 0); } } if (!safe_space_required.IsValid() || !safe_side_data_size.IsValid()) { @@ -755,7 +757,7 @@ switch (operation->operation_type) { case blink::mojom::OperationType::kPut: if (skip_side_data) { - operation->response->side_data_blob = nullptr; + operation->response->side_data_blob_for_cache_put = nullptr; Put(std::move(operation), trace_id, completion_callback); } else { Put(std::move(operation), trace_id, completion_callback);
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc index bb4fae2..d5376cb 100644 --- a/content/browser/media/session/media_session_browsertest.cc +++ b/content/browser/media/session/media_session_browsertest.cc
@@ -75,11 +75,11 @@ // Integration tests for content::MediaSession that do not take into // consideration the implementation details contrary to // MediaSessionImplBrowserTest. -class MediaSessionBrowserTest : public ContentBrowserTest { +class MediaSessionBrowserTestBase : public ContentBrowserTest { public: - MediaSessionBrowserTest() { + MediaSessionBrowserTestBase() { embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( - &MediaSessionBrowserTest::OnServerRequest, base::Unretained(this))); + &MediaSessionBrowserTestBase::OnServerRequest, base::Unretained(this))); } void SetUp() override { @@ -91,14 +91,6 @@ command_line->AppendSwitchASCII( switches::kAutoplayPolicy, switches::autoplay::kNoUserGestureRequiredPolicy); - - scoped_feature_list_.InitAndEnableFeature(media::kInternalMediaSession); - } - - void DisableInternalMediaSession() { - disabled_feature_list_.InitWithFeatures( - {}, {media::kInternalMediaSession, - media_session::features::kMediaSessionService}); } void StartPlaybackAndWait(Shell* shell, const std::string& id) { @@ -173,10 +165,6 @@ return embedded_test_server()->GetURL(kMediaSessionTestImagePath); } - protected: - base::test::ScopedFeatureList scoped_feature_list_; - base::test::ScopedFeatureList disabled_feature_list_; - private: void OnServerRequest(const net::test_server::HttpRequest& request) { // Note this method is called on the EmbeddedTestServer's background thread. @@ -190,31 +178,57 @@ base::Lock visited_urls_lock_; std::set<GURL> visited_urls_; - DISALLOW_COPY_AND_ASSIGN(MediaSessionBrowserTest); + DISALLOW_COPY_AND_ASSIGN(MediaSessionBrowserTestBase); +}; + +class MediaSessionBrowserTest : public MediaSessionBrowserTestBase { + public: + MediaSessionBrowserTest() { + feature_list_.InitAndEnableFeature(media::kInternalMediaSession); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +class MediaSessionBrowserTestWithoutInternalMediaSession + : public MediaSessionBrowserTestBase { + public: + MediaSessionBrowserTestWithoutInternalMediaSession() { + disabled_feature_list_.InitWithFeatures( + {}, {media::kInternalMediaSession, + media_session::features::kMediaSessionService}); + } + + private: + base::test::ScopedFeatureList disabled_feature_list_; }; // A MediaSessionBrowserTest with BackForwardCache enabled. class MediaSessionBrowserTestWithBackForwardCache - : public MediaSessionBrowserTest { - void SetUpOnMainThread() override { - host_resolver()->AddRule("*", "127.0.0.1"); - MediaSessionBrowserTest::SetUpOnMainThread(); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - scoped_feature_list_.InitWithFeaturesAndParameters( + : public MediaSessionBrowserTestBase { + public: + MediaSessionBrowserTestWithBackForwardCache() { + feature_list_.InitWithFeaturesAndParameters( {{features::kBackForwardCache, {{"TimeToLiveInBackForwardCacheInSeconds", "3600"}}}, {media::kInternalMediaSession, {}}}, /*disabled_features=*/{}); } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + MediaSessionBrowserTestBase::SetUpOnMainThread(); + } + + private: + base::test::ScopedFeatureList feature_list_; }; } // anonymous namespace -IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, MediaSessionNoOpWhenDisabled) { - DisableInternalMediaSession(); - +IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTestWithoutInternalMediaSession, + MediaSessionNoOpWhenDisabled) { EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("media/session", "media-session.html")));
diff --git a/content/browser/notifications/devtools_event_logging.cc b/content/browser/notifications/devtools_event_logging.cc index 0dacfeb5..1e04df75e 100644 --- a/content/browser/notifications/devtools_event_logging.cc +++ b/content/browser/notifications/devtools_event_logging.cc
@@ -7,6 +7,7 @@ #include "base/callback.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/time/time_to_iso8601.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/devtools_background_services_context.h" #include "content/public/browser/notification_database_data.h" @@ -115,8 +116,7 @@ std::move(callback).Run( /* event_name= */ "Notification scheduled", - {{"Show Trigger Timestamp", - base::NumberToString(show_trigger_timestamp.ToJsTime())}, + {{"Show Trigger Timestamp", base::TimeToISO8601(show_trigger_timestamp)}, {"Title", base::UTF16ToUTF8(data.notification_data.title)}, {"Body", base::UTF16ToUTF8(data.notification_data.body)}}); }
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc index d0fba3d..56550d4 100644 --- a/content/browser/portal/portal_browsertest.cc +++ b/content/browser/portal/portal_browsertest.cc
@@ -12,12 +12,13 @@ #include "content/browser/frame_host/render_frame_host_manager.h" #include "content/browser/frame_host/render_frame_proxy_host.h" #include "content/browser/portal/portal.h" +#include "content/browser/portal/portal_created_observer.h" +#include "content/browser/portal/portal_interceptor_for_testing.h" #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h" #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" #include "content/browser/web_contents/web_contents_impl.h" -#include "content/common/frame.mojom-test-utils.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" @@ -33,7 +34,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" -#include "third_party/blink/public/mojom/portal/portal.mojom-test-utils.h" #include "third_party/blink/public/mojom/portal/portal.mojom.h" #include "url/url_constants.h" @@ -41,203 +41,6 @@ namespace content { -// The PortalInterceptorForTesting can be used in tests to inspect Portal IPCs. -class PortalInterceptorForTesting final - : public blink::mojom::PortalInterceptorForTesting { - public: - static PortalInterceptorForTesting* Create( - RenderFrameHostImpl* render_frame_host_impl, - mojo::PendingAssociatedReceiver<blink::mojom::Portal> receiver, - mojo::AssociatedRemote<blink::mojom::PortalClient> client); - static PortalInterceptorForTesting* Create( - RenderFrameHostImpl* render_frame_host_impl, - content::Portal* portal); - static PortalInterceptorForTesting* From(content::Portal* portal); - - void Activate(blink::TransferableMessage data, - ActivateCallback callback) override { - portal_activated_ = true; - - if (run_loop_) { - run_loop_->Quit(); - run_loop_ = nullptr; - } - - // |this| can be destroyed after Activate() is called. - portal_->Activate(std::move(data), std::move(callback)); - } - - void Navigate(const GURL& url, - blink::mojom::ReferrerPtr referrer, - NavigateCallback callback) override { - if (navigate_callback_) { - navigate_callback_.Run(url, std::move(referrer), std::move(callback)); - return; - } - - portal_->Navigate(url, std::move(referrer), std::move(callback)); - } - - void WaitForActivate() { - if (portal_activated_) - return; - - base::RunLoop run_loop; - run_loop_ = &run_loop; - run_loop.Run(); - } - - // Test getters. - content::Portal* GetPortal() { return portal_.get(); } - WebContents* GetPortalContents() { return portal_->GetPortalContents(); } - - // IPC callbacks - base::RepeatingCallback< - void(const GURL&, blink::mojom::ReferrerPtr, NavigateCallback)> - navigate_callback_; - - private: - explicit PortalInterceptorForTesting( - RenderFrameHostImpl* render_frame_host_impl) - : portal_(content::Portal::CreateForTesting(render_frame_host_impl)) {} - PortalInterceptorForTesting(RenderFrameHostImpl* render_frame_host_impl, - std::unique_ptr<content::Portal> portal) - : portal_(std::move(portal)) {} - - blink::mojom::Portal* GetForwardingInterface() override { - return portal_.get(); - } - - std::unique_ptr<content::Portal> portal_; - bool portal_activated_ = false; - base::RunLoop* run_loop_ = nullptr; -}; - -// static -PortalInterceptorForTesting* PortalInterceptorForTesting::Create( - RenderFrameHostImpl* render_frame_host_impl, - mojo::PendingAssociatedReceiver<blink::mojom::Portal> receiver, - mojo::AssociatedRemote<blink::mojom::PortalClient> client) { - auto test_portal_ptr = - base::WrapUnique(new PortalInterceptorForTesting(render_frame_host_impl)); - PortalInterceptorForTesting* test_portal = test_portal_ptr.get(); - test_portal->GetPortal()->SetBindingForTesting( - mojo::MakeStrongAssociatedBinding<blink::mojom::Portal>( - std::move(test_portal_ptr), std::move(receiver))); - test_portal->GetPortal()->SetClientForTesting(std::move(client)); - return test_portal; -} - -PortalInterceptorForTesting* PortalInterceptorForTesting::Create( - RenderFrameHostImpl* render_frame_host_impl, - content::Portal* portal) { - // Take ownership of the portal. - std::unique_ptr<blink::mojom::Portal> mojom_portal_ptr = - portal->GetBindingForTesting()->SwapImplForTesting(nullptr); - std::unique_ptr<content::Portal> portal_ptr = base::WrapUnique( - static_cast<content::Portal*>(mojom_portal_ptr.release())); - - // Create PortalInterceptorForTesting. - auto test_portal_ptr = base::WrapUnique(new PortalInterceptorForTesting( - render_frame_host_impl, std::move(portal_ptr))); - PortalInterceptorForTesting* test_portal = test_portal_ptr.get(); - - // Set the binding for the PortalInterceptorForTesting. - portal->GetBindingForTesting()->SwapImplForTesting( - std::move(test_portal_ptr)); - - return test_portal; -} - -// static -PortalInterceptorForTesting* PortalInterceptorForTesting::From( - content::Portal* portal) { - blink::mojom::Portal* impl = portal->GetBindingForTesting()->impl(); - auto* interceptor = static_cast<PortalInterceptorForTesting*>(impl); - CHECK_NE(static_cast<blink::mojom::Portal*>(portal), impl); - CHECK_EQ(interceptor->GetPortal(), portal); - return interceptor; -} - -// The PortalCreatedObserver observes portal creations on -// |render_frame_host_impl|. This observer can be used to monitor for multiple -// Portal creations on the same RenderFrameHost, by repeatedly calling -// WaitUntilPortalCreated(). -class PortalCreatedObserver : public mojom::FrameHostInterceptorForTesting { - public: - explicit PortalCreatedObserver(RenderFrameHostImpl* render_frame_host_impl) - : render_frame_host_impl_(render_frame_host_impl) { - old_impl_ = render_frame_host_impl_->frame_host_receiver_for_testing() - .SwapImplForTesting(this); - } - - ~PortalCreatedObserver() override { - render_frame_host_impl_->frame_host_receiver_for_testing() - .SwapImplForTesting(old_impl_); - } - - FrameHost* GetForwardingInterface() override { - return render_frame_host_impl_; - } - - void CreatePortal( - mojo::PendingAssociatedReceiver<blink::mojom::Portal> portal, - mojo::PendingAssociatedRemote<blink::mojom::PortalClient> client, - CreatePortalCallback callback) override { - PortalInterceptorForTesting* portal_interceptor = - PortalInterceptorForTesting::Create( - render_frame_host_impl_, std::move(portal), - mojo::AssociatedRemote<blink::mojom::PortalClient>( - std::move(client))); - portal_ = portal_interceptor->GetPortal(); - RenderFrameProxyHost* proxy_host = portal_->CreateProxyAndAttachPortal(); - std::move(callback).Run(proxy_host->GetRoutingID(), portal_->portal_token(), - portal_->GetDevToolsFrameToken()); - - if (run_loop_) - run_loop_->Quit(); - } - - void AdoptPortal(const base::UnguessableToken& portal_token, - AdoptPortalCallback callback) override { - Portal* portal = Portal::FromToken(portal_token); - PortalInterceptorForTesting* portal_interceptor = - PortalInterceptorForTesting::Create(render_frame_host_impl_, portal); - portal_ = portal_interceptor->GetPortal(); - RenderFrameProxyHost* proxy_host = portal_->CreateProxyAndAttachPortal(); - std::move(callback).Run( - proxy_host->GetRoutingID(), - proxy_host->frame_tree_node()->current_replication_state(), - portal->GetDevToolsFrameToken()); - - if (run_loop_) - run_loop_->Quit(); - } - - Portal* WaitUntilPortalCreated() { - Portal* portal = portal_; - if (portal) { - portal_ = nullptr; - return portal; - } - - base::RunLoop run_loop; - run_loop_ = &run_loop; - run_loop.Run(); - run_loop_ = nullptr; - - portal = portal_; - portal_ = nullptr; - return portal; - } - - private: - RenderFrameHostImpl* render_frame_host_impl_; - mojom::FrameHost* old_impl_; - base::RunLoop* run_loop_ = nullptr; - Portal* portal_ = nullptr; -}; - class PortalBrowserTest : public ContentBrowserTest { protected: PortalBrowserTest() {} @@ -760,13 +563,13 @@ PortalInterceptorForTesting::From(portal); // Try to navigate to chrome://settings and wait for the process to die. - portal_interceptor->navigate_callback_ = base::BindRepeating( + portal_interceptor->SetNavigateCallback(base::BindRepeating( [](Portal* portal, const GURL& url, blink::mojom::ReferrerPtr referrer, blink::mojom::Portal::NavigateCallback callback) { GURL chrome_url("chrome://settings"); portal->Navigate(chrome_url, std::move(referrer), std::move(callback)); }, - portal); + portal)); RenderProcessHostKillWaiter kill_waiter(main_frame->GetProcess()); GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); ignore_result(ExecJs(main_frame, JsReplace("portal.src = $1;", a_url))); @@ -1190,11 +993,10 @@ } #endif -// TODO(crbug.com/1010675): Test fails flakily. // Touch input transfer is only implemented in the content layer for Aura. #if defined(USE_AURA) IN_PROC_BROWSER_TEST_F(PortalBrowserTest, - DISABLED_TouchInputTransferAcrossReactivation) { + TouchInputTransferAcrossReactivation) { EXPECT_TRUE(NavigateToURL( shell(), embedded_test_server()->GetURL( "portal.test",
diff --git a/content/browser/portal/portal_created_observer.cc b/content/browser/portal/portal_created_observer.cc new file mode 100644 index 0000000..1a563ff --- /dev/null +++ b/content/browser/portal/portal_created_observer.cc
@@ -0,0 +1,86 @@ +// 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/portal/portal_created_observer.h" + +#include <utility> +#include "base/run_loop.h" +#include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/frame_host/render_frame_proxy_host.h" +#include "content/browser/portal/portal.h" +#include "content/browser/portal/portal_interceptor_for_testing.h" +#include "mojo/public/cpp/bindings/associated_remote.h" + +namespace content { + +PortalCreatedObserver::PortalCreatedObserver( + RenderFrameHostImpl* render_frame_host_impl) + : render_frame_host_impl_(render_frame_host_impl) { + old_impl_ = render_frame_host_impl_->frame_host_receiver_for_testing() + .SwapImplForTesting(this); +} + +PortalCreatedObserver::~PortalCreatedObserver() { + render_frame_host_impl_->frame_host_receiver_for_testing().SwapImplForTesting( + old_impl_); +} + +mojom::FrameHost* PortalCreatedObserver::GetForwardingInterface() { + return render_frame_host_impl_; +} + +void PortalCreatedObserver::CreatePortal( + mojo::PendingAssociatedReceiver<blink::mojom::Portal> portal, + mojo::PendingAssociatedRemote<blink::mojom::PortalClient> client, + CreatePortalCallback callback) { + PortalInterceptorForTesting* portal_interceptor = + PortalInterceptorForTesting::Create( + render_frame_host_impl_, std::move(portal), + mojo::AssociatedRemote<blink::mojom::PortalClient>( + std::move(client))); + portal_ = portal_interceptor->GetPortal(); + RenderFrameProxyHost* proxy_host = portal_->CreateProxyAndAttachPortal(); + std::move(callback).Run(proxy_host->GetRoutingID(), portal_->portal_token(), + portal_->GetDevToolsFrameToken()); + + if (run_loop_) + run_loop_->Quit(); +} + +void PortalCreatedObserver::AdoptPortal( + const base::UnguessableToken& portal_token, + AdoptPortalCallback callback) { + Portal* portal = Portal::FromToken(portal_token); + PortalInterceptorForTesting* portal_interceptor = + PortalInterceptorForTesting::Create(render_frame_host_impl_, portal); + portal_ = portal_interceptor->GetPortal(); + RenderFrameProxyHost* proxy_host = portal_->CreateProxyAndAttachPortal(); + std::move(callback).Run( + proxy_host->GetRoutingID(), + proxy_host->frame_tree_node()->current_replication_state(), + portal->GetDevToolsFrameToken()); + + if (run_loop_) + run_loop_->Quit(); +} + +Portal* PortalCreatedObserver::WaitUntilPortalCreated() { + Portal* portal = portal_; + if (portal) { + portal_ = nullptr; + return portal; + } + + base::RunLoop run_loop; + run_loop_ = &run_loop; + run_loop.Run(); + run_loop_ = nullptr; + + portal = portal_; + portal_ = nullptr; + return portal; +} + +} // namespace content
diff --git a/content/browser/portal/portal_created_observer.h b/content/browser/portal/portal_created_observer.h new file mode 100644 index 0000000..a638cbc --- /dev/null +++ b/content/browser/portal/portal_created_observer.h
@@ -0,0 +1,51 @@ +// 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_PORTAL_PORTAL_CREATED_OBSERVER_H_ +#define CONTENT_BROWSER_PORTAL_PORTAL_CREATED_OBSERVER_H_ + +#include "content/common/frame.mojom-test-utils.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_associated_remote.h" +#include "third_party/blink/public/mojom/portal/portal.mojom.h" + +namespace base { +class RunLoop; +} // namespace base + +namespace content { + +class Portal; +class RenderFrameHostImpl; + +// The PortalCreatedObserver observes portal creations on +// |render_frame_host_impl|. This observer can be used to monitor for multiple +// Portal creations on the same RenderFrameHost, by repeatedly calling +// WaitUntilPortalCreated(). +class PortalCreatedObserver : public mojom::FrameHostInterceptorForTesting { + public: + explicit PortalCreatedObserver(RenderFrameHostImpl* render_frame_host_impl); + ~PortalCreatedObserver() override; + + // mojom::FrameHostInterceptorForTesting + mojom::FrameHost* GetForwardingInterface() override; + void CreatePortal( + mojo::PendingAssociatedReceiver<blink::mojom::Portal> portal, + mojo::PendingAssociatedRemote<blink::mojom::PortalClient> client, + CreatePortalCallback callback) override; + void AdoptPortal(const base::UnguessableToken& portal_token, + AdoptPortalCallback callback) override; + + Portal* WaitUntilPortalCreated(); + + private: + RenderFrameHostImpl* render_frame_host_impl_; + mojom::FrameHost* old_impl_; + base::RunLoop* run_loop_ = nullptr; + Portal* portal_ = nullptr; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_PORTAL_PORTAL_CREATED_OBSERVER_H_
diff --git a/content/browser/portal/portal_interceptor_for_testing.cc b/content/browser/portal/portal_interceptor_for_testing.cc new file mode 100644 index 0000000..00339b0 --- /dev/null +++ b/content/browser/portal/portal_interceptor_for_testing.cc
@@ -0,0 +1,111 @@ +// 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/portal/portal_interceptor_for_testing.h" + +#include <utility> +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "mojo/public/cpp/bindings/strong_associated_binding.h" + +namespace content { + +// static +PortalInterceptorForTesting* PortalInterceptorForTesting::Create( + RenderFrameHostImpl* render_frame_host_impl, + mojo::PendingAssociatedReceiver<blink::mojom::Portal> receiver, + mojo::AssociatedRemote<blink::mojom::PortalClient> client) { + auto test_portal_ptr = + base::WrapUnique(new PortalInterceptorForTesting(render_frame_host_impl)); + PortalInterceptorForTesting* test_portal = test_portal_ptr.get(); + test_portal->GetPortal()->SetBindingForTesting( + mojo::MakeStrongAssociatedBinding<blink::mojom::Portal>( + std::move(test_portal_ptr), std::move(receiver))); + test_portal->GetPortal()->SetClientForTesting(std::move(client)); + return test_portal; +} + +PortalInterceptorForTesting* PortalInterceptorForTesting::Create( + RenderFrameHostImpl* render_frame_host_impl, + content::Portal* portal) { + // Take ownership of the portal. + std::unique_ptr<blink::mojom::Portal> mojom_portal_ptr = + portal->GetBindingForTesting()->SwapImplForTesting(nullptr); + std::unique_ptr<content::Portal> portal_ptr = base::WrapUnique( + static_cast<content::Portal*>(mojom_portal_ptr.release())); + + // Create PortalInterceptorForTesting. + auto test_portal_ptr = base::WrapUnique(new PortalInterceptorForTesting( + render_frame_host_impl, std::move(portal_ptr))); + PortalInterceptorForTesting* test_portal = test_portal_ptr.get(); + + // Set the binding for the PortalInterceptorForTesting. + portal->GetBindingForTesting()->SwapImplForTesting( + std::move(test_portal_ptr)); + + return test_portal; +} + +// static +PortalInterceptorForTesting* PortalInterceptorForTesting::From( + content::Portal* portal) { + blink::mojom::Portal* impl = portal->GetBindingForTesting()->impl(); + auto* interceptor = static_cast<PortalInterceptorForTesting*>(impl); + CHECK_NE(static_cast<blink::mojom::Portal*>(portal), impl); + CHECK_EQ(interceptor->GetPortal(), portal); + return interceptor; +} + +PortalInterceptorForTesting::PortalInterceptorForTesting( + RenderFrameHostImpl* render_frame_host_impl) + : portal_(content::Portal::CreateForTesting(render_frame_host_impl)) {} + +PortalInterceptorForTesting::PortalInterceptorForTesting( + RenderFrameHostImpl* render_frame_host_impl, + std::unique_ptr<content::Portal> portal) + : portal_(std::move(portal)) {} + +PortalInterceptorForTesting::~PortalInterceptorForTesting() = default; + +blink::mojom::Portal* PortalInterceptorForTesting::GetForwardingInterface() { + return portal_.get(); +} + +void PortalInterceptorForTesting::Activate(blink::TransferableMessage data, + ActivateCallback callback) { + portal_activated_ = true; + + if (run_loop_) { + run_loop_->Quit(); + run_loop_ = nullptr; + } + + // |this| can be destroyed after Activate() is called. + portal_->Activate(std::move(data), std::move(callback)); +} + +void PortalInterceptorForTesting::Navigate( + const GURL& url, + blink::mojom::ReferrerPtr referrer, + blink::mojom::Portal::NavigateCallback callback) { + if (navigate_callback_) { + navigate_callback_.Run(url, std::move(referrer), std::move(callback)); + return; + } + + portal_->Navigate(url, std::move(referrer), std::move(callback)); +} + +void PortalInterceptorForTesting::WaitForActivate() { + if (portal_activated_) + return; + + base::RunLoop run_loop; + run_loop_ = &run_loop; + run_loop.Run(); +} + +} // namespace content
diff --git a/content/browser/portal/portal_interceptor_for_testing.h b/content/browser/portal/portal_interceptor_for_testing.h new file mode 100644 index 0000000..ff8bab4c --- /dev/null +++ b/content/browser/portal/portal_interceptor_for_testing.h
@@ -0,0 +1,77 @@ +// 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_PORTAL_PORTAL_INTERCEPTOR_FOR_TESTING_H_ +#define CONTENT_BROWSER_PORTAL_PORTAL_INTERCEPTOR_FOR_TESTING_H_ + +#include <memory> + +#include "base/callback.h" +#include "content/browser/portal/portal.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "third_party/blink/public/mojom/portal/portal.mojom-test-utils.h" +#include "third_party/blink/public/mojom/portal/portal.mojom.h" + +namespace base { +class RunLoop; +} // namespace base + +namespace content { + +class RenderFrameHostImpl; + +// The PortalInterceptorForTesting can be used in tests to inspect Portal IPCs. +class PortalInterceptorForTesting final + : public blink::mojom::PortalInterceptorForTesting { + public: + static PortalInterceptorForTesting* Create( + RenderFrameHostImpl* render_frame_host_impl, + mojo::PendingAssociatedReceiver<blink::mojom::Portal> receiver, + mojo::AssociatedRemote<blink::mojom::PortalClient> client); + static PortalInterceptorForTesting* Create( + RenderFrameHostImpl* render_frame_host_impl, + content::Portal* portal); + static PortalInterceptorForTesting* From(content::Portal* portal); + + ~PortalInterceptorForTesting() override; + + // blink::mojom::PortalInterceptorForTesting + blink::mojom::Portal* GetForwardingInterface() override; + void Activate(blink::TransferableMessage data, + ActivateCallback callback) override; + void Navigate(const GURL& url, + blink::mojom::ReferrerPtr referrer, + blink::mojom::Portal::NavigateCallback callback) override; + + // If set, will be used to replace the implementation of Navigate. + using NavigateCallback = + base::RepeatingCallback<void(const GURL&, + blink::mojom::ReferrerPtr, + blink::mojom::Portal::NavigateCallback)>; + void SetNavigateCallback(NavigateCallback callback) { + navigate_callback_ = std::move(callback); + } + + void WaitForActivate(); + + // Test getters. + content::Portal* GetPortal() { return portal_.get(); } + WebContentsImpl* GetPortalContents() { return portal_->GetPortalContents(); } + + private: + explicit PortalInterceptorForTesting( + RenderFrameHostImpl* render_frame_host_impl); + PortalInterceptorForTesting(RenderFrameHostImpl* render_frame_host_impl, + std::unique_ptr<content::Portal> portal); + + std::unique_ptr<content::Portal> portal_; + NavigateCallback navigate_callback_; + bool portal_activated_ = false; + base::RunLoop* run_loop_ = nullptr; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_PORTAL_PORTAL_INTERCEPTOR_FOR_TESTING_H_
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc index dd26e35..fe3e63e23 100644 --- a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc +++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
@@ -207,6 +207,9 @@ } void PassthroughTouchEventQueue::FlushQueue() { + // Don't allow acks to be processed in AckCompletedEvents as that can + // interfere with gesture event dispatch ordering. + base::AutoReset<bool> process_acks(&processing_acks_, true); drop_remaining_touches_in_sequence_ = true; client_->FlushDeferredGestureQueue(); while (!outstanding_touches_.empty()) {
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index 307a263..87414629 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -143,6 +143,20 @@ return output; } +size_t BlobSideDataLength(blink::mojom::Blob* actual_blob) { + size_t result = 0; + base::RunLoop run_loop; + actual_blob->ReadSideData(base::BindOnce( + [](size_t* result, base::OnceClosure continuation, + const base::Optional<mojo_base::BigBuffer> data) { + *result = data ? data->size() : 0; + std::move(continuation).Run(); + }, + &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; +} + struct FetchResult { blink::ServiceWorkerStatusCode status; ServiceWorkerFetchDispatcher::FetchEventResult result; @@ -3327,9 +3341,9 @@ } ASSERT_EQ(CacheStorageError::kSuccess, error); - ASSERT_TRUE(response->blob); + ASSERT_TRUE(response->side_data_blob); auto blob_handle = base::MakeRefCounted<storage::BlobHandle>( - std::move(response->blob->blob)); + std::move(response->side_data_blob->blob)); blob_handle->get()->ReadSideData(base::BindOnce( [](scoped_refptr<storage::BlobHandle> blob_handle, int* result, base::OnceClosure continuation, @@ -3765,4 +3779,118 @@ SetBrowserClientForTesting(old_content_browser_client); } +class CacheStorageEagerReadingTestBase + : public ServiceWorkerVersionBrowserTest { + public: + explicit CacheStorageEagerReadingTestBase(bool enabled) { + if (enabled) + feature_list.InitAndEnableFeature(features::kCacheStorageEagerReading); + else + feature_list.InitAndDisableFeature(features::kCacheStorageEagerReading); + } + + void SetupServiceWorkerAndDoFetch( + std::string fetch_url, + blink::mojom::FetchAPIResponsePtr* response_out) { + StartServerAndNavigateToSetup(); + InstallTestHelper("/service_worker/cached_fetch_event.js", + blink::ServiceWorkerStatusCode::kOk); + ActivateTestHelper(blink::ServiceWorkerStatusCode::kOk); + + ServiceWorkerFetchDispatcher::FetchEventResult result; + FetchOnRegisteredWorker(fetch_url, &result, response_out); + } + + void ExpectNormalCacheResponse(blink::mojom::FetchAPIResponsePtr response) { + EXPECT_EQ(network::mojom::FetchResponseSource::kCacheStorage, + response->response_source); + + // A normal cache_storage response should have a blob for the body. + mojo::Remote<blink::mojom::Blob> blob(std::move(response->blob->blob)); + + // The blob should contain the expected body content. + EXPECT_EQ(BlobToString(blob.get()).length(), 1075u); + + // Since this js response was stored in the install event it should have + // code cache stored in the blob side data. + EXPECT_GT(BlobSideDataLength(blob.get()), + static_cast<size_t>(kV8CacheTimeStampDataSize)); + } + + void ExpectEagerlyReadCacheResponse( + blink::mojom::FetchAPIResponsePtr response) { + EXPECT_EQ(network::mojom::FetchResponseSource::kCacheStorage, + response->response_source); + + // An eagerly read cache_storage response should not have a blob. Instead + // the body is provided out-of-band in a mojo DataPipe. The pipe is not + // surfaced here in this test. + EXPECT_FALSE(response->blob); + + // An eagerly read response should still have a side_data_blob, though. + // This is provided so that js resources can still load code cache. + mojo::Remote<blink::mojom::Blob> side_data_blob( + std::move(response->side_data_blob->blob)); + + // Since this js response was stored in the install event it should have + // code cache stored in the blob side data. + EXPECT_GT(BlobSideDataLength(side_data_blob.get()), + static_cast<size_t>(kV8CacheTimeStampDataSize)); + } + + // The service worker script always matches against this URL. + static constexpr const char* kCacheMatchURL = + "/service_worker/v8_cache_test.js"; + + // A URL that will be different from the cache.match() executed in + // the service worker fetch handler. + static constexpr const char* kOtherURL = + "/service_worker/non-matching-url.js"; + + private: + base::test::ScopedFeatureList feature_list; +}; + +class CacheStorageEagerReadingEnabledTest + : public CacheStorageEagerReadingTestBase { + public: + CacheStorageEagerReadingEnabledTest() + : CacheStorageEagerReadingTestBase(true) {} +}; + +class CacheStorageEagerReadingDisabledTest + : public CacheStorageEagerReadingTestBase { + public: + CacheStorageEagerReadingDisabledTest() + : CacheStorageEagerReadingTestBase(false) {} +}; + +IN_PROC_BROWSER_TEST_F(CacheStorageEagerReadingDisabledTest, + CacheMatchInRelatedFetchEvent) { + blink::mojom::FetchAPIResponsePtr response; + SetupServiceWorkerAndDoFetch(kCacheMatchURL, &response); + ExpectNormalCacheResponse(std::move(response)); +} + +IN_PROC_BROWSER_TEST_F(CacheStorageEagerReadingDisabledTest, + CacheMatchInUnrelatedFetchEvent) { + blink::mojom::FetchAPIResponsePtr response; + SetupServiceWorkerAndDoFetch(kOtherURL, &response); + ExpectNormalCacheResponse(std::move(response)); +} + +IN_PROC_BROWSER_TEST_F(CacheStorageEagerReadingEnabledTest, + CacheMatchInRelatedFetchEvent) { + blink::mojom::FetchAPIResponsePtr response; + SetupServiceWorkerAndDoFetch(kCacheMatchURL, &response); + ExpectEagerlyReadCacheResponse(std::move(response)); +} + +IN_PROC_BROWSER_TEST_F(CacheStorageEagerReadingEnabledTest, + CacheMatchInUnrelatedFetchEvent) { + blink::mojom::FetchAPIResponsePtr response; + SetupServiceWorkerAndDoFetch(kOtherURL, &response); + ExpectNormalCacheResponse(std::move(response)); +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index 5e0a898..8113173 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -831,54 +831,55 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); - auto* initial_client = - helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( - helper_.get()); - scoped_refptr<ServiceWorkerRegistration> registration = - RunRegisterJob(script1, options); - // Wait until the worker becomes active. - base::RunLoop().RunUntilIdle(); auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); - registration->SetTaskRunnerForTest(runner); + TestServiceWorkerObserver observer(helper_->context_wrapper()); + + scoped_refptr<ServiceWorkerRegistration> old_registration = + RunRegisterJob(script1, options); + old_registration->SetTaskRunnerForTest(runner); + + // Wait until the worker becomes active. + scoped_refptr<ServiceWorkerVersion> old_version = + old_registration->GetNewestVersion(); + observer.RunUntilActivated(old_version.get(), runner); // Add a controllee and queue an unregister to force the uninstalling state. ServiceWorkerProviderHost* host = CreateControllee(); - scoped_refptr<ServiceWorkerVersion> old_version = - registration->active_version(); old_version->AddControllee(host); + EXPECT_TRUE(old_version->HasControllee()); RunUnregisterJob(options.scope); + EXPECT_TRUE(old_registration->is_uninstalling()); // Register another script. - EXPECT_EQ(registration, RunRegisterJob(script2, options)); - // Wait until the worker becomes installed. - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_EQ(old_version, registration->active_version()); + scoped_refptr<ServiceWorkerRegistration> new_registration = + RunRegisterJob(script2, options); + EXPECT_NE(old_registration, new_registration); + new_registration->SetTaskRunnerForTest(runner); + // Wait until the worker becomes active. scoped_refptr<ServiceWorkerVersion> new_version = - registration->waiting_version(); - - // Verify the new version is installed but not activated yet. - EXPECT_EQ(nullptr, registration->installing_version()); - EXPECT_TRUE(new_version); - EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status()); - EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status()); - - // Make the old version eligible for eviction. - old_version->RemoveControllee(host->client_uuid()); - RequestTermination(&initial_client->host()); - - // Wait for activated. - TestServiceWorkerObserver observer(helper_->context_wrapper()); + new_registration->GetNewestVersion(); + EXPECT_NE(old_version, new_version); observer.RunUntilActivated(new_version.get(), runner); - // Verify state after the new version is activated. - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_FALSE(registration->is_uninstalled()); - EXPECT_EQ(nullptr, registration->installing_version()); - EXPECT_EQ(nullptr, registration->waiting_version()); - EXPECT_EQ(new_version, registration->active_version()); + EXPECT_TRUE(old_registration->is_uninstalling()); + EXPECT_EQ(old_version, old_registration->active_version()); + EXPECT_FALSE(old_registration->waiting_version()); + + // Verify the new version is installed and activated, but has no controllee. + EXPECT_FALSE(new_registration->installing_version()); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status()); EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status()); + EXPECT_FALSE(new_version->HasControllee()); + + // Remove the controllee from the old version and verify the new version + // doesn't get a controllee. + EXPECT_TRUE(old_version->HasControllee()); + old_version->RemoveControllee(host->client_uuid()); + EXPECT_FALSE(old_version->HasControllee()); + EXPECT_FALSE(new_version->HasControllee()); + + // Cleanup. + RunUnregisterJob(options.scope); } TEST_F(ServiceWorkerJobTest, RegisterAndUnregisterWhileUninstalling) { @@ -887,28 +888,36 @@ blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = GURL("https://www.example.com/one/"); - scoped_refptr<ServiceWorkerRegistration> registration = + auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); + TestServiceWorkerObserver observer(helper_->context_wrapper()); + + scoped_refptr<ServiceWorkerRegistration> old_registration = RunRegisterJob(script1, options); + old_registration->SetTaskRunnerForTest(runner); + // Wait until the worker becomes active. - base::RunLoop().RunUntilIdle(); + scoped_refptr<ServiceWorkerVersion> old_version = + old_registration->GetNewestVersion(); + observer.RunUntilActivated(old_version.get(), runner); // Add a controllee and queue an unregister to force the uninstalling state. ServiceWorkerProviderHost* host = CreateControllee(); - scoped_refptr<ServiceWorkerVersion> old_version = - registration->active_version(); old_version->AddControllee(host); RunUnregisterJob(options.scope); - EXPECT_EQ(registration, RunRegisterJob(script2, options)); - // Wait until the worker becomes installed. - base::RunLoop().RunUntilIdle(); + scoped_refptr<ServiceWorkerRegistration> new_registration = + RunRegisterJob(script2, options); + EXPECT_NE(old_registration, new_registration); - EXPECT_EQ(registration, FindRegistrationForScope(options.scope)); + // Wait until the worker becomes active. scoped_refptr<ServiceWorkerVersion> new_version = - registration->waiting_version(); - ASSERT_TRUE(new_version); + new_registration->GetNewestVersion(); + ASSERT_NE(old_version, new_version); + observer.RunUntilActivated(new_version.get(), runner); - // Unregister the registration (but it's still live). + EXPECT_EQ(new_registration, FindRegistrationForScope(options.scope)); + + // Unregister the new registration (but the old one is still live). RunUnregisterJob(options.scope); // Now it's not found in the storage. RunUnregisterJob(options.scope, @@ -916,82 +925,23 @@ FindRegistrationForScope(options.scope, blink::ServiceWorkerStatusCode::kErrorNotFound); - EXPECT_TRUE(registration->is_uninstalling()); - EXPECT_EQ(old_version, registration->active_version()); + EXPECT_TRUE(old_registration->is_uninstalling()); + EXPECT_EQ(old_version, old_registration->active_version()); EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, old_version->running_status()); EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, old_version->status()); - EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status()); - EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status()); old_version->RemoveControllee(host->client_uuid()); + // Wait until the worker becomes redundant. + observer.RunUntilStatusChange(old_version.get(), + ServiceWorkerVersion::REDUNDANT); WaitForVersionRunningStatus(old_version, EmbeddedWorkerStatus::STOPPED); WaitForVersionRunningStatus(new_version, EmbeddedWorkerStatus::STOPPED); - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_TRUE(registration->is_uninstalled()); - - EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, old_version->running_status()); + EXPECT_FALSE(old_registration->is_uninstalling()); + EXPECT_TRUE(old_registration->is_uninstalled()); EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status()); - EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, new_version->running_status()); - EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, new_version->status()); -} - -TEST_F(ServiceWorkerJobTest, RegisterSameScriptMultipleTimesWhileUninstalling) { - GURL script1("https://www.example.com/service_worker.js"); - GURL script2("https://www.example.com/service_worker.js?new"); - blink::mojom::ServiceWorkerRegistrationOptions options; - options.scope = GURL("https://www.example.com/one/"); - - auto* initial_client = - helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( - helper_.get()); - scoped_refptr<ServiceWorkerRegistration> registration = - RunRegisterJob(script1, options); - // Wait until the worker becomes active. - base::RunLoop().RunUntilIdle(); - auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); - registration->SetTaskRunnerForTest(runner); - - // Add a controllee and queue an unregister to force the uninstalling state. - ServiceWorkerProviderHost* host = CreateControllee(); - scoped_refptr<ServiceWorkerVersion> old_version = - registration->active_version(); - old_version->AddControllee(host); - RunUnregisterJob(options.scope); - - EXPECT_EQ(registration, RunRegisterJob(script2, options)); - // Wait until the worker becomes installed. - base::RunLoop().RunUntilIdle(); - - scoped_refptr<ServiceWorkerVersion> new_version = - registration->waiting_version(); - ASSERT_TRUE(new_version); - - RunUnregisterJob(options.scope); - - EXPECT_TRUE(registration->is_uninstalling()); - - EXPECT_EQ(registration, RunRegisterJob(script2, options)); - - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_EQ(new_version, registration->waiting_version()); - - old_version->RemoveControllee(host->client_uuid()); - RequestTermination(&initial_client->host()); - - // Wait for activated. - TestServiceWorkerObserver observer(helper_->context_wrapper()); - observer.RunUntilActivated(new_version.get(), runner); - - // Verify state after the new version is activated. - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_FALSE(registration->is_uninstalled()); - EXPECT_EQ(nullptr, registration->installing_version()); - EXPECT_EQ(nullptr, registration->waiting_version()); - EXPECT_EQ(new_version, registration->active_version()); - EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status()); } // A fake service worker for toggling whether a fetch event handler exists. @@ -1880,68 +1830,6 @@ EXPECT_EQ(nullptr, registration->installing_version()); } -TEST_P(ServiceWorkerUpdateJobTest, RegisterMultipleTimesWhileUninstalling) { - GURL script1("https://www.example.com/service_worker.js?first"); - GURL script2("https://www.example.com/service_worker.js?second"); - GURL script3("https://www.example.com/service_worker.js?third"); - blink::mojom::ServiceWorkerRegistrationOptions options; - options.scope = GURL("https://www.example.com/one/"); - - auto* initial_client = - helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>( - helper_.get()); - scoped_refptr<ServiceWorkerRegistration> registration = - RunRegisterJob(script1, options); - // Wait until the worker becomes actvie. - base::RunLoop().RunUntilIdle(); - auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); - registration->SetTaskRunnerForTest(runner); - - // Add a controllee and queue an unregister to force the uninstalling state. - ServiceWorkerProviderHost* host = CreateControllee(); - scoped_refptr<ServiceWorkerVersion> first_version = - registration->active_version(); - first_version->AddControllee(host); - RunUnregisterJob(options.scope); - - EXPECT_EQ(registration, RunRegisterJob(script2, options)); - // Wait until the worker becomes installed. - base::RunLoop().RunUntilIdle(); - - scoped_refptr<ServiceWorkerVersion> second_version = - registration->waiting_version(); - ASSERT_TRUE(second_version); - - RunUnregisterJob(options.scope); - - EXPECT_TRUE(registration->is_uninstalling()); - - EXPECT_EQ(registration, RunRegisterJob(script3, options)); - TestServiceWorkerObserver observer(helper_->context_wrapper()); - observer.RunUntilStatusChange(second_version.get(), - ServiceWorkerVersion::REDUNDANT); - scoped_refptr<ServiceWorkerVersion> third_version = - registration->waiting_version(); - ASSERT_TRUE(third_version); - - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, second_version->status()); - - first_version->RemoveControllee(host->client_uuid()); - RequestTermination(&initial_client->host()); - - // Wait for activated. - observer.RunUntilActivated(third_version.get(), runner); - - // Verify the new version is activated. - EXPECT_FALSE(registration->is_uninstalling()); - EXPECT_FALSE(registration->is_uninstalled()); - EXPECT_EQ(nullptr, registration->installing_version()); - EXPECT_EQ(nullptr, registration->waiting_version()); - EXPECT_EQ(third_version, registration->active_version()); - EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, third_version->status()); -} - class CheckPauseAfterDownloadEmbeddedWorkerInstanceClient : public FakeEmbeddedWorkerInstanceClient { public:
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 60afc9c2..719c7ff7 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -597,8 +597,15 @@ if (!IsContextSecureForServiceWorker()) return; size_t key = registration->scope().spec().size(); - if (base::Contains(matching_registrations_, key)) - return; + if (base::Contains(matching_registrations_, key)) { + if (registration == matching_registrations_[key]) { + // TODO(https://crbug.com/971571): Verify this can never happen and + // replace with a DCHECK. + return; + } + uninstalled_matching_registrations_[key].emplace( + std::move(matching_registrations_[key])); + } registration->AddListener(this); matching_registrations_[key] = registration; ReturnRegistrationForReadyIfNeeded(); @@ -608,12 +615,18 @@ ServiceWorkerRegistration* registration) { DCHECK_NE(controller_registration_, registration); #if DCHECK_IS_ON() - DCHECK(IsMatchingRegistration(registration)); + DCHECK(IsMatchingRegistration(registration) || + IsMatchingUninstalledRegistration(registration)); #endif // DCHECK_IS_ON() registration->RemoveListener(this); size_t key = registration->scope().spec().size(); - matching_registrations_.erase(key); + if (registration == matching_registrations_[key]) { + matching_registrations_.erase(key); + return; + } + DCHECK(base::Contains(uninstalled_matching_registrations_, key)); + uninstalled_matching_registrations_.erase(key); } ServiceWorkerRegistration* ServiceWorkerProviderHost::MatchRegistration() @@ -803,6 +816,15 @@ return false; return true; } + +bool ServiceWorkerProviderHost::IsMatchingUninstalledRegistration( + ServiceWorkerRegistration* registration) { + size_t key = registration->scope().spec().size(); + if (!base::Contains(uninstalled_matching_registrations_, key)) { + return false; + } + return base::Contains(uninstalled_matching_registrations_[key], registration); +} #endif // DCHECK_IS_ON() void ServiceWorkerProviderHost::RemoveAllMatchingRegistrations() { @@ -812,6 +834,13 @@ registration->RemoveListener(this); } matching_registrations_.clear(); + + for (const auto& it : uninstalled_matching_registrations_) { + for (const auto& registration : it.second) { + registration->RemoveListener(this); + } + } + uninstalled_matching_registrations_.clear(); } void ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded() {
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 1a74b95..be572f1 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -373,9 +373,17 @@ // This is subtle: it doesn't keep all registrations (e.g., from storage) in // memory, but just the ones that are possibly the longest-matching one. The // best match from storage is added at load time. That match can't uninstall - // while this host is a controllee, so all the other stored registrations can - // be ignored. Only a newly installed registration can claim it, and new - // installing registrations are added as matches. + // while this host is a controllee, but it can be unregistered and newly + // installed registations can override the entry if they have the same scope + // as an existing match. Since it is possible that multiple service workers + // for the same scope exist at any given time, e.g. when a worker is + // registered while an unregistered worker for the same scope is controlling + // clients, it's the callers responsibility to remove the matching + // registration when they no longer need it. + // + // Note: Chrome's implementation of .ready differs from the spec s.t. the + // ready promise is only resolved once it has been accessed by the user. + // https://github.com/w3c/ServiceWorker/issues/1477 void AddMatchingRegistration(ServiceWorkerRegistration* registration); void RemoveMatchingRegistration(ServiceWorkerRegistration* registration); @@ -515,6 +523,8 @@ #if DCHECK_IS_ON() bool IsMatchingRegistration(ServiceWorkerRegistration* registration) const; + bool IsMatchingUninstalledRegistration( + ServiceWorkerRegistration* registration); #endif // DCHECK_IS_ON() // Discards all references to matching registrations. @@ -674,6 +684,14 @@ // AddMatchingRegistration(). ServiceWorkerRegistrationMap matching_registrations_; + // Similar to ServiceWorkerRegistrationMap, but with multiple registrations. + using ServiceWorkerRegistrationMultiSet = + std::map<size_t, std::set<scoped_refptr<ServiceWorkerRegistration>>>; + // Contains registrations that have been uninstalled, e.g., by + // |registration.unregister()|, but are still alive, e.g., because they are + // controlling clients. + ServiceWorkerRegistrationMultiSet uninstalled_matching_registrations_; + // Contains all ServiceWorkerRegistrationObjectHost instances corresponding to // the service worker registration JavaScript objects for the hosted execution // context (service worker global scope or service worker client) in the
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc index 989d323..68bd487 100644 --- a/content/browser/service_worker/service_worker_register_job.cc +++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -124,15 +124,7 @@ weak_factory_.GetWeakPtr()); } - scoped_refptr<ServiceWorkerRegistration> registration = - context_->storage()->GetUninstallingRegistration(scope_); - if (registration.get()) - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(next_step), - blink::ServiceWorkerStatusCode::kOk, registration)); - else - context_->storage()->FindRegistrationForScope(scope_, std::move(next_step)); + context_->storage()->FindRegistrationForScope(scope_, std::move(next_step)); } void ServiceWorkerRegisterJob::Abort() {
diff --git a/content/browser/tracing/background_tracing_active_scenario.cc b/content/browser/tracing/background_tracing_active_scenario.cc index 4bba2980..b79c56f5 100644 --- a/content/browser/tracing/background_tracing_active_scenario.cc +++ b/content/browser/tracing/background_tracing_active_scenario.cc
@@ -244,7 +244,9 @@ parent_scenario_->GetWeakPtr(), std::move(on_success))), true /* compress_with_background_priority */); - TracingControllerImpl::GetInstance()->StopTracing(trace_data_endpoint); + TracingControllerImpl::GetInstance()->StopTracing( + trace_data_endpoint, "", + parent_scenario_->GetConfig()->requires_anonymized_data()); } void AbortScenario(const base::RepeatingClosure& on_abort_callback) override {
diff --git a/content/browser/tracing/background_tracing_config_impl.cc b/content/browser/tracing/background_tracing_config_impl.cc index 93eca01..ee41a4f 100644 --- a/content/browser/tracing/background_tracing_config_impl.cc +++ b/content/browser/tracing/background_tracing_config_impl.cc
@@ -276,10 +276,6 @@ chrome_config.SetProcessFilterConfig(process_config); } - if (requires_anonymized_data_) { - chrome_config.EnableArgumentFilter(); - } - chrome_config.SetTraceBufferSizeInKb(GetMaximumTraceBufferSizeKb()); #if defined(OS_ANDROID)
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc index 9c682f1..b76c766 100644 --- a/content/browser/tracing/background_tracing_manager_browsertest.cc +++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -1589,7 +1589,7 @@ EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario( std::move(config), trace_receiver_helper.get_receive_callback(), - BackgroundTracingManager::NO_DATA_FILTERING)); + BackgroundTracingManager::ANONYMIZE_DATA)); tracelog_helper.WaitForStartTracing(); background_tracing_helper.WaitForTracingEnabled(); @@ -1598,9 +1598,6 @@ ->GetActiveScenarioForTesting() ->GetConfig() ->requires_anonymized_data()); - EXPECT_TRUE(base::trace_event::TraceLog::GetInstance() - ->GetCurrentTraceConfig() - .IsArgumentFilterEnabled()); // Since we specified a delay in the scenario, we should still be tracing // at this point.
diff --git a/content/browser/tracing/tracing_controller_browsertest.cc b/content/browser/tracing/tracing_controller_browsertest.cc index 6064b19..fb5caa20 100644 --- a/content/browser/tracing/tracing_controller_browsertest.cc +++ b/content/browser/tracing/tracing_controller_browsertest.cc
@@ -224,10 +224,8 @@ base::BindOnce(&TracingControllerTest::StartTracingDoneCallbackTest, base::Unretained(this), run_loop.QuitClosure()); - TraceConfig config = TraceConfig(); - config.EnableArgumentFilter(); - - bool result = controller->StartTracing(config, std::move(callback)); + bool result = + controller->StartTracing(TraceConfig(), std::move(callback)); ASSERT_TRUE(result); run_loop.Run(); EXPECT_EQ(enable_recording_done_callback_count(), 1); @@ -248,7 +246,9 @@ base::Bind(&TracingControllerTest::GenerateMetadataDict, base::Unretained(this))); - bool result = controller->StopTracing(trace_data_endpoint); + bool result = + controller->StopTracing(trace_data_endpoint, /*agent_label=*/"", + /*privacy_filtering_enabled=*/true); ASSERT_TRUE(result); run_loop.Run(); EXPECT_EQ(disable_recording_done_callback_count(), 1);
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 2db4e71..75139f0 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -40,7 +40,7 @@ #include "net/base/network_change_notifier.h" #include "services/service_manager/public/cpp/connector.h" #include "services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h" -#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h" +#include "services/tracing/public/cpp/perfetto/perfetto_config.h" #include "services/tracing/public/cpp/trace_event_agent.h" #include "services/tracing/public/cpp/traced_process_impl.h" #include "services/tracing/public/cpp/tracing_features.h" @@ -217,21 +217,17 @@ } void TracingControllerImpl::ConnectToServiceIfNeeded() { - if (!coordinator_) { + if (!consumer_host_) { GetSystemConnector()->BindInterface(tracing::mojom::kServiceName, - &coordinator_); - coordinator_.set_connection_error_handler(base::BindOnce( + &consumer_host_); + consumer_host_.set_connection_error_handler(base::BindOnce( [](TracingControllerImpl* controller) { - controller->coordinator_.reset(); + controller->consumer_host_.reset(); }, base::Unretained(this))); } } -void TracingControllerImpl::DisconnectFromService() { - coordinator_ = nullptr; -} - // Can be called on any thread. std::unique_ptr<base::DictionaryValue> TracingControllerImpl::GenerateMetadataDict() { @@ -394,15 +390,27 @@ trace_config_ = std::make_unique<base::trace_event::TraceConfig>(trace_config); + DCHECK(!tracing_session_host_); ConnectToServiceIfNeeded(); - coordinator_->StartTracing( - trace_config.ToString(), - base::BindOnce( - [](StartTracingDoneCallback callback, bool success) { - if (!callback.is_null()) - std::move(callback).Run(); - }, - std::move(callback))); + + perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig( + trace_config, /*requires_anonymized_data=*/false); + + mojo::PendingRemote<tracing::mojom::TracingSessionClient> + tracing_session_client; + binding_.Bind(tracing_session_client.InitWithNewPipeAndPassReceiver()); + binding_.set_connection_error_handler(base::BindOnce( + &TracingControllerImpl::OnTracingFailed, base::Unretained(this))); + + consumer_host_->EnableTracing( + mojo::MakeRequest(&tracing_session_host_), + std::move(tracing_session_client), std::move(perfetto_config), + tracing::mojom::TracingClientPriority::kUserInitiated); + tracing_session_host_.set_connection_error_handler(base::BindOnce( + &TracingControllerImpl::OnTracingFailed, base::Unretained(this))); + + start_tracing_callback_ = std::move(callback); + // TODO(chiniforooshan): The actual success value should be sent by the // callback asynchronously. return true; @@ -512,8 +520,9 @@ bool TracingControllerImpl::StopTracing( const scoped_refptr<TraceDataEndpoint>& trace_data_endpoint, - const std::string& agent_label) { - if (!IsTracing() || drainer_ || !coordinator_) + const std::string& agent_label, + bool privacy_filtering_enabled) { + if (!IsTracing() || drainer_ || !tracing_session_host_) return false; DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -521,26 +530,36 @@ base::trace_event::TraceLog::GetInstance()->AddClockSyncMetadataEvent(); #endif + // Setting the argument filter is no longer supported just in the TraceConfig; + // clients of the TracingController that need filtering need to pass that + // option to StopTracing directly as an argument. This is due to Perfetto- + // based tracing requiring this filtering to be done during serialization + // time and not during tracing time. + // TODO(oysteine): Remove the config option once the legacy IPC layer is + // removed. + CHECK(privacy_filtering_enabled || !trace_config_->IsArgumentFilterEnabled()); + tracing::TraceStartupConfig::GetInstance()->SetDisabled(); trace_data_endpoint_ = std::move(trace_data_endpoint); is_data_complete_ = false; - is_metadata_available_ = false; - mojo::DataPipe data_pipe; - drainer_.reset( - new mojo::DataPipeDrainer(this, std::move(data_pipe.consumer_handle))); - if (agent_label.empty()) { - // Stop and flush all agents. - coordinator_->StopAndFlush( - std::move(data_pipe.producer_handle), - base::BindRepeating(&TracingControllerImpl::OnMetadataAvailable, - base::Unretained(this))); - } else { - // Stop all and flush a particular agent. - coordinator_->StopAndFlushAgent( - std::move(data_pipe.producer_handle), agent_label, - base::BindRepeating(&TracingControllerImpl::OnMetadataAvailable, - base::Unretained(this))); + read_buffers_complete_ = false; + + mojo::ScopedDataPipeProducerHandle producer_handle; + mojo::ScopedDataPipeConsumerHandle consumer_handle; + MojoResult result = + mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle); + if (result != MOJO_RESULT_OK) { + CompleteFlush(); + return true; } + + drainer_.reset(new mojo::DataPipeDrainer(this, std::move(consumer_handle))); + + tracing_session_host_->DisableTracingAndEmitJson( + agent_label, std::move(producer_handle), privacy_filtering_enabled, + base::BindOnce(&TracingControllerImpl::OnReadBuffersComplete, + base::Unretained(this))); + // TODO(chiniforooshan): Is the return value used anywhere? return true; } @@ -549,12 +568,14 @@ GetTraceBufferUsageCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - ConnectToServiceIfNeeded(); - coordinator_->RequestBufferUsage(base::BindOnce( + if (!tracing_session_host_) { + std::move(callback).Run(0.0, 0); + return true; + } + + tracing_session_host_->RequestBufferUsage(base::BindOnce( [](GetTraceBufferUsageCallback callback, bool success, float percent_full, - uint32_t approximate_count) { - std::move(callback).Run(percent_full, approximate_count); - }, + bool data_loss) { std::move(callback).Run(percent_full, 0); }, std::move(callback))); // TODO(chiniforooshan): The actual success value should be sent by the // callback asynchronously. @@ -565,15 +586,15 @@ return trace_config_ != nullptr; } -void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) { - DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); - tracing_uis_.insert(tracing_ui); +void TracingControllerImpl::OnTracingEnabled() { + if (start_tracing_callback_) + std::move(start_tracing_callback_).Run(); } -void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) { - auto it = tracing_uis_.find(tracing_ui); - DCHECK(it != tracing_uis_.end()); - tracing_uis_.erase(it); +void TracingControllerImpl::OnTracingDisabled() {} + +void TracingControllerImpl::OnTracingFailed() { + CompleteFlush(); } void TracingControllerImpl::OnDataAvailable(const void* data, @@ -586,42 +607,24 @@ } void TracingControllerImpl::CompleteFlush() { - if (trace_data_endpoint_) { + if (trace_data_endpoint_) trace_data_endpoint_->ReceivedTraceFinalContents(); - } - filtered_metadata_.reset(nullptr); + trace_data_endpoint_ = nullptr; trace_config_ = nullptr; drainer_ = nullptr; + tracing_session_host_.reset(); + binding_.Close(); } void TracingControllerImpl::OnDataComplete() { is_data_complete_ = true; - if (is_metadata_available_) + if (read_buffers_complete_) CompleteFlush(); } -void TracingControllerImpl::OnMetadataAvailable(base::Value metadata) { - DCHECK(!filtered_metadata_); - is_metadata_available_ = true; - base::trace_event::MetadataFilterPredicate metadata_filter; - if (trace_config_->IsArgumentFilterEnabled()) { - metadata_filter = base::trace_event::TraceLog::GetInstance() - ->GetMetadataFilterPredicate(); - } - if (metadata_filter.is_null()) { - filtered_metadata_ = base::DictionaryValue::From( - base::Value::ToUniquePtrValue(std::move(metadata))); - } else { - filtered_metadata_ = std::make_unique<base::DictionaryValue>(); - for (auto it : metadata.DictItems()) { - if (metadata_filter.Run(it.first)) { - filtered_metadata_->SetKey(it.first, std::move(it.second)); - } else { - filtered_metadata_->SetKey(it.first, base::Value("__stripped__")); - } - } - } +void TracingControllerImpl::OnReadBuffersComplete() { + read_buffers_complete_ = true; if (is_data_complete_) CompleteFlush(); }
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h index 34d8841..9c00a9b4 100644 --- a/content/browser/tracing/tracing_controller_impl.h +++ b/content/browser/tracing/tracing_controller_impl.h
@@ -15,8 +15,9 @@ #include "base/timer/timer.h" #include "content/common/content_export.h" #include "content/public/browser/tracing_controller.h" +#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/data_pipe_drainer.h" -#include "services/tracing/public/mojom/tracing.mojom.h" +#include "services/tracing/public/mojom/perfetto_service.mojom.h" namespace base { @@ -35,14 +36,14 @@ class PerfettoFileTracer; class TracingDelegate; -class TracingUI; class TracingControllerImpl : public TracingController, - public mojo::DataPipeDrainer::Client { + public mojo::DataPipeDrainer::Client, + public tracing::mojom::TracingSessionClient { public: // Create an endpoint for dumping the trace data to a callback. CONTENT_EXPORT static scoped_refptr<TraceDataEndpoint> CreateCallbackEndpoint( - base::OnceCallback<void(std::unique_ptr<std::string>)> callback); + CompletionCallback callback); CONTENT_EXPORT static scoped_refptr<TraceDataEndpoint> CreateCompressedStringEndpoint(scoped_refptr<TraceDataEndpoint> endpoint, @@ -59,12 +60,16 @@ StartTracingDoneCallback callback) override; bool StopTracing(const scoped_refptr<TraceDataEndpoint>& endpoint) override; bool StopTracing(const scoped_refptr<TraceDataEndpoint>& endpoint, - const std::string& agent_label) override; + const std::string& agent_label, + bool privacy_filtering_enabled = false) override; bool GetTraceBufferUsage(GetTraceBufferUsageCallback callback) override; bool IsTracing() override; - void RegisterTracingUI(TracingUI* tracing_ui); - void UnregisterTracingUI(TracingUI* tracing_ui); + // tracing::mojom::TracingSessionClient implementation: + void OnTracingEnabled() override; + void OnTracingDisabled() override; + + void OnTracingFailed(); // For unittests. CONTENT_EXPORT void SetTracingDelegateForTesting( @@ -92,14 +97,13 @@ ~TracingControllerImpl() override; void AddAgents(); void ConnectToServiceIfNeeded(); - void DisconnectFromService(); std::unique_ptr<base::DictionaryValue> GenerateMetadataDict(); // mojo::DataPipeDrainer::Client void OnDataAvailable(const void* data, size_t num_bytes) override; void OnDataComplete() override; - void OnMetadataAvailable(base::Value metadata); + void OnReadBuffersComplete(); void CompleteFlush(); @@ -111,16 +115,18 @@ base::FilePath GetStartupTraceFileName() const; std::unique_ptr<PerfettoFileTracer> perfetto_file_tracer_; - tracing::mojom::CoordinatorPtr coordinator_; + tracing::mojom::ConsumerHostPtr consumer_host_; + tracing::mojom::TracingSessionHostPtr tracing_session_host_; + mojo::Binding<tracing::mojom::TracingSessionClient> binding_{this}; + StartTracingDoneCallback start_tracing_callback_; + std::vector<std::unique_ptr<tracing::BaseAgent>> agents_; std::unique_ptr<TracingDelegate> delegate_; std::unique_ptr<base::trace_event::TraceConfig> trace_config_; std::unique_ptr<mojo::DataPipeDrainer> drainer_; scoped_refptr<TraceDataEndpoint> trace_data_endpoint_; - std::unique_ptr<base::DictionaryValue> filtered_metadata_; - std::set<TracingUI*> tracing_uis_; bool is_data_complete_ = false; - bool is_metadata_available_ = false; + bool read_buffers_complete_ = false; base::FilePath startup_trace_file_; // This timer initiates trace file saving.
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 35c3889e..82d6006 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -153,8 +153,8 @@ if (base::FeatureList::IsEnabled(features::kPeriodicBackgroundSync)) WebRuntimeFeatures::EnablePeriodicBackgroundSync(true); - if (base::FeatureList::IsEnabled(features::kWebXr)) - WebRuntimeFeatures::EnableWebXR(true); + WebRuntimeFeatures::EnableWebXR( + base::FeatureList::IsEnabled(features::kWebXr)); if (base::FeatureList::IsEnabled(features::kWebXrArDOMOverlay)) WebRuntimeFeatures::EnableWebXRARDOMOverlay(true); @@ -171,6 +171,9 @@ if (base::FeatureList::IsEnabled(features::kWebXrPlaneDetection)) WebRuntimeFeatures::EnableWebXRPlaneDetection(true); + if (base::FeatureList::IsEnabled(features::kWebXrGamepadModule)) + WebRuntimeFeatures::EnableWebXrGamepadModule(true); + WebRuntimeFeatures::EnableFetchMetadata( base::FeatureList::IsEnabled(network::features::kFetchMetadata)); WebRuntimeFeatures::EnableFetchMetadataDestination(
diff --git a/content/child/webthemeengine_impl_default_browsertest.cc b/content/child/webthemeengine_impl_default_browsertest.cc index 30ae37df..b50a8b78 100644 --- a/content/child/webthemeengine_impl_default_browsertest.cc +++ b/content/child/webthemeengine_impl_default_browsertest.cc
@@ -19,6 +19,11 @@ #if defined(OS_WIN) IN_PROC_BROWSER_TEST_F(WebThemeEngineImplDefaultBrowserTest, GetSystemColor) { + // The test non-deterministically fails on Windows Server 2008 builders due to + // a difference in the default theme. As a result, only run the test on + // Windows version 7 and above. + if (base::win::GetVersion() < base::win::Version::WIN7) + return; GURL url( "data:text/html," "<!doctype html><html>"
diff --git a/content/common/background_fetch/background_fetch_types.cc b/content/common/background_fetch/background_fetch_types.cc index f87695f5..35219482 100644 --- a/content/common/background_fetch/background_fetch_types.cc +++ b/content/common/background_fetch/background_fetch_types.cc
@@ -36,6 +36,7 @@ response->response_time, response->cache_storage_cache_name, response->cors_exposed_header_names, CloneSerializedBlob(response->side_data_blob), + CloneSerializedBlob(response->side_data_blob_for_cache_put), response->content_security_policy.Clone()); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java index 4edc3b9e..55ed58db 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -466,8 +466,9 @@ } case ACTION_SET_TEXT: { if (!WebContentsAccessibilityImplJni.get().isEditableText( - mNativeObj, WebContentsAccessibilityImpl.this, virtualViewId)) + mNativeObj, WebContentsAccessibilityImpl.this, virtualViewId)) { return false; + } if (arguments == null) return false; String newText = arguments.getString(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE); if (newText == null) return false; @@ -481,8 +482,9 @@ } case AccessibilityNodeInfo.ACTION_SET_SELECTION: { if (!WebContentsAccessibilityImplJni.get().isEditableText( - mNativeObj, WebContentsAccessibilityImpl.this, virtualViewId)) + mNativeObj, WebContentsAccessibilityImpl.this, virtualViewId)) { return false; + } int selectionStart = 0; int selectionEnd = 0; if (arguments != null) { @@ -808,8 +810,9 @@ mNativeObj, WebContentsAccessibilityImpl.this, newAccessibilityFocusId); if (WebContentsAccessibilityImplJni.get().isAutofillPopupNode( - mNativeObj, WebContentsAccessibilityImpl.this, mAccessibilityFocusId)) + mNativeObj, WebContentsAccessibilityImpl.this, mAccessibilityFocusId)) { mAutofillPopupView.requestFocus(); + } sendAccessibilityEvent( mAccessibilityFocusId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); @@ -1004,7 +1007,14 @@ @CalledByNative private void handleSliderChanged(int id) { - sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED); + // If the node has accessibility focus, fire TYPE_VIEW_SELECTED, which triggers + // TalkBack to announce the change. If not, fire TYPE_VIEW_SCROLLED, which + // does not trigger an immediate announcement but still ensures some event is fired. + if (mAccessibilityFocusId == id) { + sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SELECTED); + } else { + sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED); + } } @CalledByNative
diff --git a/content/public/browser/tracing_controller.h b/content/public/browser/tracing_controller.h index 7f2ba91..3927389d 100644 --- a/content/public/browser/tracing_controller.h +++ b/content/public/browser/tracing_controller.h
@@ -114,7 +114,8 @@ const scoped_refptr<TraceDataEndpoint>& trace_data_endpoint) = 0; virtual bool StopTracing( const scoped_refptr<TraceDataEndpoint>& trace_data_endpoint, - const std::string& agent_label) = 0; + const std::string& agent_label, + bool privacy_filtering_enabled = false) = 0; // Get the maximum across processes of trace buffer percent full state. // When the TraceBufferUsage value is determined, the callback is
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 49770ae..ec56ae7 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -102,6 +102,12 @@ const base::Feature kCacheStorageParallelOps{"CacheStorageParallelOps", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables eagerly reading the response body in cache.match() when the +// operation was started from a FetchEvent handler with a matching request +// URL. +const base::Feature kCacheStorageEagerReading{ + "CacheStorageEagerReading", base::FEATURE_DISABLED_BY_DEFAULT}; + // If Canvas2D Image Chromium is allowed, this feature controls whether it is // enabled. const base::Feature kCanvas2DImageChromium { @@ -693,7 +699,7 @@ const base::Feature kWebUsb{"WebUSB", base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether the WebXR Device API is enabled. -const base::Feature kWebXr{"WebXR", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kWebXr{"WebXR", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables access to AR features via the WebXR API. const base::Feature kWebXrArModule{"WebXRARModule", @@ -703,6 +709,10 @@ const base::Feature kWebXrAnchors{"WebXRAnchors", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables access to the WebXR Device API gamepad module. +const base::Feature kWebXrGamepadModule{"WebXrGamepadModule", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables access to raycasting against estimated XR scene geometry. const base::Feature kWebXrHitTest{"WebXRHitTest", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 2dda53e..da8a21e 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -32,6 +32,7 @@ CONTENT_EXPORT extern const base::Feature kBundledHTTPExchanges; CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode; CONTENT_EXPORT extern const base::Feature kCacheStorageParallelOps; +CONTENT_EXPORT extern const base::Feature kCacheStorageEagerReading; CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium; CONTENT_EXPORT extern const base::Feature kConsolidatedMovementXY; CONTENT_EXPORT extern const base::Feature kCookieDeprecationMessages; @@ -148,6 +149,7 @@ CONTENT_EXPORT extern const base::Feature kWebXrArModule; CONTENT_EXPORT extern const base::Feature kWebXrAnchors; CONTENT_EXPORT extern const base::Feature kWebXrArDOMOverlay; +CONTENT_EXPORT extern const base::Feature kWebXrGamepadModule; CONTENT_EXPORT extern const base::Feature kWebXrHitTest; CONTENT_EXPORT extern const base::Feature kWebXrPlaneDetection; CONTENT_EXPORT extern const base::Feature kScriptStreamingOnPreload;
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index c9866111..c557b36 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -589,7 +589,7 @@ granularity); if (injected_type == WebInputEvent::Type::kGestureScrollBegin) { gesture_event->data.scroll_begin.scrollable_area_element_id = - scrollable_area_element_id.GetInternalValue(); + scrollable_area_element_id.GetStableId(); } ui::LatencyInfo latency_info; @@ -668,7 +668,7 @@ params.scroll_delta, params.granularity); if (params.type == WebInputEvent::Type::kGestureScrollBegin) { gesture_event->data.scroll_begin.scrollable_area_element_id = - params.scrollable_area_element_id.GetInternalValue(); + params.scrollable_area_element_id.GetStableId(); last_injected_gesture_was_begin_ = true; } else { last_injected_gesture_was_begin_ = false;
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc index c576e2b..09762f76 100644 --- a/content/renderer/loader/navigation_body_loader.cc +++ b/content/renderer/loader/navigation_body_loader.cc
@@ -10,7 +10,9 @@ #include "content/renderer/loader/code_cache_loader_impl.h" #include "content/renderer/loader/resource_load_stats.h" #include "content/renderer/loader/web_url_loader_impl.h" +#include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "third_party/blink/public/web/web_navigation_params.h" namespace content { @@ -23,7 +25,7 @@ mojom::CommonNavigationParamsPtr common_params, mojom::CommitNavigationParamsPtr commit_params, int request_id, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, mojo::ScopedDataPipeConsumerHandle response_body, network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -50,11 +52,11 @@ navigation_params->redirects[i]; auto& redirect_info = commit_params->redirect_infos[i]; auto& redirect_response = commit_params->redirect_response[i]; - NotifyResourceRedirectReceived(render_frame_id, resource_load_info.get(), - redirect_info, redirect_response); WebURLLoaderImpl::PopulateURLResponse( url, *redirect_response, &redirect.redirect_response, - response_head.ssl_info.has_value(), request_id); + response_head->ssl_info.has_value(), request_id); + NotifyResourceRedirectReceived(render_frame_id, resource_load_info.get(), + redirect_info, std::move(redirect_response)); if (url.SchemeIs(url::kDataScheme)) redirect.redirect_response.SetHttpStatusCode(200); redirect.new_url = redirect_info.new_url; @@ -69,29 +71,28 @@ } WebURLLoaderImpl::PopulateURLResponse( - url, *network::mojom::URLResponseHeadPtr(response_head), - &navigation_params->response, response_head.ssl_info.has_value(), - request_id); + url, *response_head, &navigation_params->response, + response_head->ssl_info.has_value(), request_id); if (url.SchemeIs(url::kDataScheme)) navigation_params->response.SetHttpStatusCode(200); if (url_loader_client_endpoints) { navigation_params->body_loader.reset(new NavigationBodyLoader( - response_head, std::move(response_body), + std::move(response_head), std::move(response_body), std::move(url_loader_client_endpoints), task_runner, render_frame_id, std::move(resource_load_info))); } } NavigationBodyLoader::NavigationBodyLoader( - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, mojo::ScopedDataPipeConsumerHandle response_body, network::mojom::URLLoaderClientEndpointsPtr endpoints, scoped_refptr<base::SingleThreadTaskRunner> task_runner, int render_frame_id, mojom::ResourceLoadInfoPtr resource_load_info) : render_frame_id_(render_frame_id), - response_head_(response_head), + response_head_(std::move(response_head)), response_body_(std::move(response_body)), endpoints_(std::move(endpoints)), task_runner_(std::move(task_runner)), @@ -182,24 +183,29 @@ resource_load_info_->url.possibly_invalid_spec()); client_ = client; + base::Time response_head_response_time = response_head_->response_time; NotifyResourceResponseReceived(render_frame_id_, resource_load_info_.get(), - response_head_, content::PREVIEWS_OFF); + std::move(response_head_), + content::PREVIEWS_OFF); if (use_isolated_code_cache) { code_cache_loader_ = std::make_unique<CodeCacheLoaderImpl>(); code_cache_loader_->FetchFromCodeCache( blink::mojom::CodeCacheType::kJavascript, resource_load_info_->url, base::BindOnce(&NavigationBodyLoader::CodeCacheReceived, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), + response_head_response_time)); return; } BindURLLoaderAndStartLoadingResponseBodyIfPossible(); } -void NavigationBodyLoader::CodeCacheReceived(base::Time response_time, - mojo_base::BigBuffer data) { - if (response_head_.response_time == response_time && client_) { +void NavigationBodyLoader::CodeCacheReceived( + base::Time response_head_response_time, + base::Time response_time, + mojo_base::BigBuffer data) { + if (response_head_response_time == response_time && client_) { base::WeakPtr<NavigationBodyLoader> weak_self = weak_factory_.GetWeakPtr(); client_->BodyCodeCacheReceived(std::move(data)); if (!weak_self)
diff --git a/content/renderer/loader/navigation_body_loader.h b/content/renderer/loader/navigation_body_loader.h index 50a6c83..8780320 100644 --- a/content/renderer/loader/navigation_body_loader.h +++ b/content/renderer/loader/navigation_body_loader.h
@@ -22,6 +22,7 @@ #include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/simple_watcher.h" #include "services/network/public/mojom/url_loader.mojom.h" +#include "services/network/public/mojom/url_response_head.mojom-forward.h" #include "third_party/blink/public/platform/web_navigation_body_loader.h" namespace blink { @@ -53,7 +54,7 @@ mojom::CommonNavigationParamsPtr common_params, mojom::CommitNavigationParamsPtr commit_params, int request_id, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, mojo::ScopedDataPipeConsumerHandle response_body, network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -93,7 +94,7 @@ static constexpr uint32_t kMaxNumConsumedBytesInTask = 64 * 1024; NavigationBodyLoader( - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, mojo::ScopedDataPipeConsumerHandle response_body, network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -120,7 +121,9 @@ mojo::ScopedDataPipeConsumerHandle handle) override; void OnComplete(const network::URLLoaderCompletionStatus& status) override; - void CodeCacheReceived(base::Time response_time, mojo_base::BigBuffer data); + void CodeCacheReceived(base::Time response_head_response_time, + base::Time response_time, + mojo_base::BigBuffer data); void BindURLLoaderAndContinue(); void OnConnectionClosed(); void OnReadable(MojoResult unused); @@ -132,7 +135,7 @@ // Navigation parameters. const int render_frame_id_; - const network::ResourceResponseHead response_head_; + network::mojom::URLResponseHeadPtr response_head_; mojo::ScopedDataPipeConsumerHandle response_body_; network::mojom::URLLoaderClientEndpointsPtr endpoints_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/content/renderer/loader/navigation_body_loader_unittest.cc b/content/renderer/loader/navigation_body_loader_unittest.cc index 9a1d90c..c2a05811 100644 --- a/content/renderer/loader/navigation_body_loader_unittest.cc +++ b/content/renderer/loader/navigation_body_loader_unittest.cc
@@ -49,7 +49,7 @@ auto commit_params = CreateCommitNavigationParams(); NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader( std::move(common_params), std::move(commit_params), 1 /* request_id */, - network::ResourceResponseHead(), + network::mojom::URLResponseHead::New(), mojo::ScopedDataPipeConsumerHandle() /* response_body */, std::move(endpoints), blink::scheduler::GetSingleThreadTaskRunnerForTesting(), @@ -294,8 +294,8 @@ // Tests that FillNavigationParamsResponseAndBodyLoader populates security // details on the response when they are present. TEST_F(NavigationBodyLoaderTest, FillResponseWithSecurityDetails) { - network::ResourceResponseHead response; - response.ssl_info = net::SSLInfo(); + auto response = network::mojom::URLResponseHead::New(); + response->ssl_info = net::SSLInfo(); net::CertificateList certs; ASSERT_TRUE(net::LoadCertificateFiles( {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs)); @@ -306,10 +306,10 @@ base::StringPiece cert1_der = net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()); - response.ssl_info->cert = + response->ssl_info->cert = net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der}); net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2, - &response.ssl_info->connection_status); + &response->ssl_info->connection_status); auto common_params = CreateCommonNavigationParams(); common_params->url = GURL("https://example.test"); @@ -319,7 +319,8 @@ auto endpoints = network::mojom::URLLoaderClientEndpoints::New(); NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader( std::move(common_params), std::move(commit_params), 1 /* request_id */, - response, mojo::ScopedDataPipeConsumerHandle() /* response_body */, + std::move(response), + mojo::ScopedDataPipeConsumerHandle() /* response_body */, std::move(endpoints), blink::scheduler::GetSingleThreadTaskRunnerForTesting(), 2 /* render_frame_id */, true /* is_main_frame */, &navigation_params);
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc index 199b2a40..7def575 100644 --- a/content/renderer/loader/resource_dispatcher.cc +++ b/content/renderer/loader/resource_dispatcher.cc
@@ -44,6 +44,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "third_party/blink/public/common/loader/mime_sniffing_throttle.h" namespace content { @@ -141,38 +142,34 @@ void ResourceDispatcher::OnReceivedResponse( int request_id, - const network::ResourceResponseHead& response_head) { + network::mojom::URLResponseHeadPtr response_head) { TRACE_EVENT0("loading", "ResourceDispatcher::OnReceivedResponse"); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) return; DCHECK(!request_info->navigation_response_override); request_info->local_response_start = base::TimeTicks::Now(); - request_info->remote_request_start = response_head.load_timing.request_start; + request_info->remote_request_start = response_head->load_timing.request_start; // Now that response_start has been set, we can properly set the TimeTicks in - // the ResourceResponseHead. - network::ResourceResponseHead renderer_response_head; - ToResourceResponseHead(*request_info, response_head, &renderer_response_head); - request_info->load_timing_info = renderer_response_head.load_timing; + // the URLResponseHead. + ToLocalURLResponseHead(*request_info, *response_head); + request_info->load_timing_info = response_head->load_timing; if (delegate_) { std::unique_ptr<RequestPeer> new_peer = delegate_->OnReceivedResponse( - std::move(request_info->peer), response_head.mime_type, + std::move(request_info->peer), response_head->mime_type, request_info->url); DCHECK(new_peer); request_info->peer = std::move(new_peer); } - // Unfortunately, calling OnReceivedResponse on the peer can delete - // pending request and/or passed |response_head| reference. - // Make a copy of |response_head| for later use. - network::ResourceResponseHead response_head_copy = renderer_response_head; - request_info->peer->OnReceivedResponse(renderer_response_head); + request_info->peer->OnReceivedResponse( + network::ResourceResponseHead(response_head)); if (!GetPendingRequestInfo(request_id)) return; NotifyResourceResponseReceived( request_info->render_frame_id, request_info->resource_load_info.get(), - response_head_copy, request_info->previews_state); + std::move(response_head), request_info->previews_state); } void ResourceDispatcher::OnReceivedCachedMetadata(int request_id, @@ -199,7 +196,7 @@ void ResourceDispatcher::OnReceivedRedirect( int request_id, const net::RedirectInfo& redirect_info, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, scoped_refptr<base::SingleThreadTaskRunner> task_runner) { TRACE_EVENT0("loading", "ResourceDispatcher::OnReceivedRedirect"); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); @@ -211,22 +208,22 @@ // URL. Handle this in a posted task, as we don't have the loader // pointer yet. base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ResourceDispatcher::OnReceivedRedirect, - weak_factory_.GetWeakPtr(), request_id, - redirect_info, response_head, task_runner)); + FROM_HERE, + base::BindOnce(&ResourceDispatcher::OnReceivedRedirect, + weak_factory_.GetWeakPtr(), request_id, redirect_info, + std::move(response_head), task_runner)); return; } request_info->local_response_start = base::TimeTicks::Now(); - request_info->remote_request_start = response_head.load_timing.request_start; + request_info->remote_request_start = response_head->load_timing.request_start; request_info->redirect_requires_loader_restart = RedirectRequiresLoaderRestart(request_info->response_url, redirect_info.new_url); - network::ResourceResponseHead renderer_response_head; - ToResourceResponseHead(*request_info, response_head, &renderer_response_head); - if (request_info->peer->OnReceivedRedirect(redirect_info, - renderer_response_head)) { + ToLocalURLResponseHead(*request_info, *response_head); + if (request_info->peer->OnReceivedRedirect( + redirect_info, network::ResourceResponseHead(response_head))) { // Double-check if the request is still around. The call above could // potentially remove it. request_info = GetPendingRequestInfo(request_id); @@ -236,7 +233,7 @@ request_info->has_pending_redirect = true; NotifyResourceRedirectReceived(request_info->render_frame_id, request_info->resource_load_info.get(), - redirect_info, response_head); + redirect_info, std::move(response_head)); if (!request_info->is_deferred) FollowPendingRedirect(request_info); } else { @@ -571,26 +568,24 @@ return request_id; } -void ResourceDispatcher::ToResourceResponseHead( +void ResourceDispatcher::ToLocalURLResponseHead( const PendingRequestInfo& request_info, - const network::ResourceResponseHead& browser_info, - network::ResourceResponseHead* renderer_info) const { - *renderer_info = browser_info; + network::mojom::URLResponseHead& response_head) const { if (base::TimeTicks::IsConsistentAcrossProcesses() || request_info.local_request_start.is_null() || request_info.local_response_start.is_null() || - browser_info.request_start.is_null() || - browser_info.response_start.is_null() || - browser_info.load_timing.request_start.is_null()) { + response_head.request_start.is_null() || + response_head.response_start.is_null() || + response_head.load_timing.request_start.is_null()) { return; } InterProcessTimeTicksConverter converter( LocalTimeTicks::FromTimeTicks(request_info.local_request_start), LocalTimeTicks::FromTimeTicks(request_info.local_response_start), - RemoteTimeTicks::FromTimeTicks(browser_info.request_start), - RemoteTimeTicks::FromTimeTicks(browser_info.response_start)); + RemoteTimeTicks::FromTimeTicks(response_head.request_start), + RemoteTimeTicks::FromTimeTicks(response_head.response_start)); - net::LoadTimingInfo* load_timing = &renderer_info->load_timing; + net::LoadTimingInfo* load_timing = &response_head.load_timing; RemoteToLocalTimeTicks(converter, &load_timing->request_start); RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_start); RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_end); @@ -606,8 +601,8 @@ RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end); RemoteToLocalTimeTicks(converter, &load_timing->push_start); RemoteToLocalTimeTicks(converter, &load_timing->push_end); - RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_start_time); - RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_ready_time); + RemoteToLocalTimeTicks(converter, &response_head.service_worker_start_time); + RemoteToLocalTimeTicks(converter, &response_head.service_worker_ready_time); } // TODO(dgozman): this is not used for navigation anymore, only for worker @@ -626,7 +621,7 @@ request_info->should_follow_redirect = false; URLLoaderClientImpl* client_ptr = request_info->url_loader_client.get(); - // During navigations, the ResourceResponse has already been received on the + // During navigations, the Response has already been received on the // browser side, and has been passed down to the renderer. Replay the // redirects that happened during navigation. DCHECK_EQ(response_override->redirect_responses.size(),
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h index 38e654e..c5908b2 100644 --- a/content/renderer/loader/resource_dispatcher.h +++ b/content/renderer/loader/resource_dispatcher.h
@@ -31,6 +31,7 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/mojom/url_loader.mojom.h" +#include "services/network/public/mojom/url_response_head.mojom-forward.h" #include "third_party/blink/public/common/loader/url_loader_throttle.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" #include "third_party/blink/public/platform/web_url_request.h" @@ -46,7 +47,6 @@ namespace network { struct ResourceRequest; -struct ResourceResponseHead; struct URLLoaderCompletionStatus; namespace mojom { class URLLoaderFactory; @@ -221,22 +221,21 @@ // Message response handlers, called by the message handler for this process. void OnUploadProgress(int request_id, int64_t position, int64_t size); - void OnReceivedResponse(int request_id, const network::ResourceResponseHead&); + void OnReceivedResponse(int request_id, network::mojom::URLResponseHeadPtr); void OnReceivedCachedMetadata(int request_id, mojo_base::BigBuffer data); void OnReceivedRedirect( int request_id, const net::RedirectInfo& redirect_info, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, scoped_refptr<base::SingleThreadTaskRunner> task_runner); void OnStartLoadingResponseBody(int request_id, mojo::ScopedDataPipeConsumerHandle body); void OnRequestComplete(int request_id, const network::URLLoaderCompletionStatus& status); - void ToResourceResponseHead( + void ToLocalURLResponseHead( const PendingRequestInfo& request_info, - const network::ResourceResponseHead& browser_info, - network::ResourceResponseHead* renderer_info) const; + network::mojom::URLResponseHead& response_head) const; void ContinueForNavigation(int request_id);
diff --git a/content/renderer/loader/resource_load_stats.cc b/content/renderer/loader/resource_load_stats.cc index 774cd4c..6323d50 100644 --- a/content/renderer/loader/resource_load_stats.cc +++ b/content/renderer/loader/resource_load_stats.cc
@@ -41,21 +41,20 @@ } #endif -void ResourceResponseReceived( - int render_frame_id, - int request_id, - const GURL& response_url, - const network::ResourceResponseHead& response_head, - content::ResourceType resource_type, - PreviewsState previews_state) { +void ResourceResponseReceived(int render_frame_id, + int request_id, + const GURL& response_url, + network::mojom::URLResponseHeadPtr response_head, + content::ResourceType resource_type, + PreviewsState previews_state) { RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id); if (!frame) return; if (!IsResourceTypeFrame(resource_type)) { frame->GetFrameHost()->SubresourceResponseStarted( - response_url, response_head.cert_status); + response_url, response_head->cert_status); } - frame->DidStartResponse(response_url, request_id, response_head, + frame->DidStartResponse(response_url, request_id, std::move(response_head), resource_type, previews_state); } @@ -124,7 +123,7 @@ int render_frame_id, mojom::ResourceLoadInfo* resource_load_info, const net::RedirectInfo& redirect_info, - const network::ResourceResponseHead& redirect_response) { + network::mojom::URLResponseHeadPtr redirect_response) { resource_load_info->url = redirect_info.new_url; resource_load_info->method = redirect_info.new_method; resource_load_info->referrer = GURL(redirect_info.new_referrer); @@ -132,11 +131,11 @@ net_redirect_info->url = redirect_info.new_url; net_redirect_info->network_info = mojom::CommonNetworkInfo::New(); net_redirect_info->network_info->network_accessed = - redirect_response.network_accessed; + redirect_response->network_accessed; net_redirect_info->network_info->always_access_network = - AlwaysAccessNetwork(redirect_response.headers); + AlwaysAccessNetwork(redirect_response->headers); net_redirect_info->network_info->remote_endpoint = - redirect_response.remote_endpoint; + redirect_response->remote_endpoint; resource_load_info->redirect_info_chain.push_back( std::move(net_redirect_info)); } @@ -144,48 +143,49 @@ void NotifyResourceResponseReceived( int render_frame_id, mojom::ResourceLoadInfo* resource_load_info, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, PreviewsState previews_state) { - if (response_head.network_accessed) { + if (response_head->network_accessed) { if (resource_load_info->resource_type == ResourceType::kMainFrame) { UMA_HISTOGRAM_ENUMERATION("Net.ConnectionInfo.MainFrame", - response_head.connection_info, + response_head->connection_info, net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS); } else { UMA_HISTOGRAM_ENUMERATION("Net.ConnectionInfo.SubResource", - response_head.connection_info, + response_head->connection_info, net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS); } } - resource_load_info->mime_type = response_head.mime_type; - resource_load_info->load_timing_info = response_head.load_timing; + resource_load_info->mime_type = response_head->mime_type; + resource_load_info->load_timing_info = response_head->load_timing; resource_load_info->network_info->network_accessed = - response_head.network_accessed; + response_head->network_accessed; resource_load_info->network_info->always_access_network = - AlwaysAccessNetwork(response_head.headers); + AlwaysAccessNetwork(response_head->headers); resource_load_info->network_info->remote_endpoint = - response_head.remote_endpoint; + response_head->remote_endpoint; auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner(); if (!task_runner) return; if (task_runner->BelongsToCurrentThread()) { ResourceResponseReceived(render_frame_id, resource_load_info->request_id, - resource_load_info->url, response_head, + resource_load_info->url, std::move(response_head), resource_load_info->resource_type, previews_state); return; } - // Make a deep copy of ResourceResponseHead before passing it cross-thread. - auto resource_response = base::MakeRefCounted<network::ResourceResponse>(); - resource_response->head = response_head; - auto deep_copied_response = resource_response->DeepCopy(); + // Make a deep copy of URLResponseHead before passing it cross-thread. + if (response_head->headers) { + response_head->headers = + new net::HttpResponseHeaders(response_head->headers->raw_headers()); + } task_runner->PostTask( FROM_HERE, base::BindOnce(ResourceResponseReceived, render_frame_id, resource_load_info->request_id, resource_load_info->url, - deep_copied_response->head, + std::move(response_head), resource_load_info->resource_type, previews_state)); }
diff --git a/content/renderer/loader/resource_load_stats.h b/content/renderer/loader/resource_load_stats.h index df0b175..5c99d14 100644 --- a/content/renderer/loader/resource_load_stats.h +++ b/content/renderer/loader/resource_load_stats.h
@@ -9,6 +9,7 @@ #include "content/public/common/previews_state.h" #include "content/public/common/resource_load_info.mojom.h" #include "content/public/common/resource_type.h" +#include "services/network/public/mojom/url_response_head.mojom-forward.h" class GURL; @@ -17,7 +18,6 @@ } // namespace net namespace network { -struct ResourceResponseHead; struct URLLoaderCompletionStatus; } // namespace network @@ -47,12 +47,12 @@ int render_frame_id, mojom::ResourceLoadInfo* resource_load_info, const net::RedirectInfo& redirect_info, - const network::ResourceResponseHead& redirect_response); + network::mojom::URLResponseHeadPtr redirect_response); void NotifyResourceResponseReceived( int render_frame_id, mojom::ResourceLoadInfo* resource_load_info, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, PreviewsState previews_state); void NotifyResourceTransferSizeUpdated(
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc index 3bf05c3..70d6e06 100644 --- a/content/renderer/loader/url_loader_client_impl.cc +++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -15,7 +15,7 @@ #include "content/renderer/loader/resource_dispatcher.h" #include "net/url_request/redirect_info.h" #include "services/network/public/cpp/features.h" -#include "services/network/public/cpp/resource_response.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "third_party/blink/public/common/features.h" namespace content { @@ -46,16 +46,16 @@ : public DeferredMessage { public: explicit DeferredOnReceiveResponse( - const network::ResourceResponseHead& response_head) - : response_head_(response_head) {} + network::mojom::URLResponseHeadPtr response_head) + : response_head_(std::move(response_head)) {} void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override { - dispatcher->OnReceivedResponse(request_id, response_head_); + dispatcher->OnReceivedResponse(request_id, std::move(response_head_)); } bool IsCompletionMessage() const override { return false; } private: - const network::ResourceResponseHead response_head_; + network::mojom::URLResponseHeadPtr response_head_; }; class URLLoaderClientImpl::DeferredOnReceiveRedirect final @@ -63,21 +63,21 @@ public: DeferredOnReceiveRedirect( const net::RedirectInfo& redirect_info, - const network::ResourceResponseHead& response_head, + network::mojom::URLResponseHeadPtr response_head, scoped_refptr<base::SingleThreadTaskRunner> task_runner) : redirect_info_(redirect_info), - response_head_(response_head), + response_head_(std::move(response_head)), task_runner_(std::move(task_runner)) {} void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override { - dispatcher->OnReceivedRedirect(request_id, redirect_info_, response_head_, - task_runner_); + dispatcher->OnReceivedRedirect(request_id, redirect_info_, + std::move(response_head_), task_runner_); } bool IsCompletionMessage() const override { return false; } private: const net::RedirectInfo redirect_info_; - const network::ResourceResponseHead response_head_; + network::mojom::URLResponseHeadPtr response_head_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; }; @@ -241,7 +241,7 @@ has_received_response_head_ = true; if (NeedsStoringMessage()) { StoreAndDispatch( - std::make_unique<DeferredOnReceiveResponse>(response_head)); + std::make_unique<DeferredOnReceiveResponse>(std::move(response_head))); } else { resource_dispatcher_->OnReceivedResponse(request_id_, std::move(response_head)); @@ -261,7 +261,7 @@ last_loaded_url_ = redirect_info.new_url; if (NeedsStoringMessage()) { StoreAndDispatch(std::make_unique<DeferredOnReceiveRedirect>( - redirect_info, response_head, task_runner_)); + redirect_info, std::move(response_head), task_runner_)); } else { resource_dispatcher_->OnReceivedRedirect( request_id_, redirect_info, std::move(response_head), task_runner_);
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc index 78a33600..7df006b 100644 --- a/content/renderer/loader/url_loader_client_impl_unittest.cc +++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -14,9 +14,9 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/redirect_info.h" -#include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -108,9 +108,7 @@ }; TEST_F(URLLoaderClientImplTest, OnReceiveResponse) { - network::ResourceResponseHead response_head; - - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); EXPECT_FALSE(request_peer_context_.received_response); base::RunLoop().RunUntilIdle(); @@ -118,9 +116,7 @@ } TEST_F(URLLoaderClientImplTest, ResponseBody) { - network::ResourceResponseHead response_head; - - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); EXPECT_FALSE(request_peer_context_.received_response); base::RunLoop().RunUntilIdle(); @@ -140,10 +136,10 @@ } TEST_F(URLLoaderClientImplTest, OnReceiveRedirect) { - network::ResourceResponseHead response_head; net::RedirectInfo redirect_info; - url_loader_client_->OnReceiveRedirect(redirect_info, response_head); + url_loader_client_->OnReceiveRedirect(redirect_info, + network::mojom::URLResponseHead::New()); EXPECT_EQ(0, request_peer_context_.seen_redirects); base::RunLoop().RunUntilIdle(); @@ -151,12 +147,11 @@ } TEST_F(URLLoaderClientImplTest, OnReceiveCachedMetadata) { - network::ResourceResponseHead response_head; std::vector<uint8_t> data; data.push_back('a'); mojo_base::BigBuffer metadata(data); - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); url_loader_client_->OnReceiveCachedMetadata(std::move(metadata)); EXPECT_FALSE(request_peer_context_.received_response); @@ -168,9 +163,7 @@ } TEST_F(URLLoaderClientImplTest, OnTransferSizeUpdated) { - network::ResourceResponseHead response_head; - - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); url_loader_client_->OnTransferSizeUpdated(4); url_loader_client_->OnTransferSizeUpdated(4); @@ -182,10 +175,9 @@ } TEST_F(URLLoaderClientImplTest, OnCompleteWithResponseBody) { - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); url_loader_client_->OnStartLoadingResponseBody( std::move(data_pipe.consumer_handle)); @@ -216,10 +208,9 @@ // bytes arrives after the completion message. URLLoaderClientImpl should // restore the order. TEST_F(URLLoaderClientImplTest, OnCompleteShouldBeTheLastMessage) { - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); url_loader_client_->OnStartLoadingResponseBody( std::move(data_pipe.consumer_handle)); @@ -242,10 +233,9 @@ TEST_F(URLLoaderClientImplTest, CancelOnReceiveResponse) { request_peer_context_.cancel_on_receive_response = true; - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); url_loader_client_->OnStartLoadingResponseBody( std::move(data_pipe.consumer_handle)); @@ -262,10 +252,9 @@ } TEST_F(URLLoaderClientImplTest, Defer) { - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe; data_pipe.producer_handle.reset(); // Empty body. url_loader_client_->OnStartLoadingResponseBody( @@ -291,10 +280,9 @@ } TEST_F(URLLoaderClientImplTest, DeferWithResponseBody) { - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); uint32_t size = 5; MojoResult result = data_pipe.producer_handle->WriteData( @@ -332,10 +320,9 @@ // As "transfer size update" message is handled specially in the implementation, // we have a separate test. TEST_F(URLLoaderClientImplTest, DeferWithTransferSizeUpdated) { - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); uint32_t size = 5; MojoResult result = data_pipe.producer_handle->WriteData( @@ -379,11 +366,11 @@ request_peer_context_.defer_on_redirect = true; net::RedirectInfo redirect_info; - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveRedirect(redirect_info, response_head); - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveRedirect(redirect_info, + network::mojom::URLResponseHead::New()); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe(DataPipeOptions()); uint32_t size = 5; MojoResult result = data_pipe.producer_handle->WriteData( @@ -441,10 +428,9 @@ SetDeferredDuringFlushingDeferredMessageOnTransferSizeUpdated) { request_peer_context_.defer_on_transfer_size_updated = true; - network::ResourceResponseHead response_head; network::URLLoaderCompletionStatus status; - url_loader_client_->OnReceiveResponse(response_head); + url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New()); mojo::DataPipe data_pipe; data_pipe.producer_handle.reset(); // Empty body. url_loader_client_->OnStartLoadingResponseBody(
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc index 8c6b4675..1929454 100644 --- a/content/renderer/loader/web_url_loader_impl.cc +++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -1147,6 +1147,13 @@ } } +void WebURLLoaderImpl::PopulateURLResponse( + const WebURL& url, + const network::ResourceResponseHead& head, + WebURLResponse* response, + bool report_security_info, + int request_id) {} + // static WebURLError WebURLLoaderImpl::PopulateURLError( const network::URLLoaderCompletionStatus& status,
diff --git a/content/renderer/loader/web_url_loader_impl.h b/content/renderer/loader/web_url_loader_impl.h index 27d56c26..837447e 100644 --- a/content/renderer/loader/web_url_loader_impl.h +++ b/content/renderer/loader/web_url_loader_impl.h
@@ -20,6 +20,10 @@ #include "third_party/blink/public/platform/web_url_loader.h" #include "third_party/blink/public/platform/web_url_loader_factory.h" +namespace network { +struct ResourceResponseHead; +} + namespace content { class ResourceDispatcher; @@ -57,6 +61,11 @@ ~WebURLLoaderImpl() override; static void PopulateURLResponse(const blink::WebURL& url, + const network::ResourceResponseHead& head, + blink::WebURLResponse* response, + bool report_security_info, + int request_id); + static void PopulateURLResponse(const blink::WebURL& url, const network::mojom::URLResponseHead& head, blink::WebURLResponse* response, bool report_security_info,
diff --git a/content/renderer/pepper/ppb_video_decoder_impl.cc b/content/renderer/pepper/ppb_video_decoder_impl.cc index b3892053..735637b 100644 --- a/content/renderer/pepper/ppb_video_decoder_impl.cc +++ b/content/renderer/pepper/ppb_video_decoder_impl.cc
@@ -166,7 +166,7 @@ // but only after PPB_Buffer_Impl is updated to deal with that. media::BitstreamBuffer decode_buffer(bitstream_buffer->id, buffer->shared_memory().Duplicate(), - buffer->shared_memory().GetSize()); + bitstream_buffer->size); if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback)) return PP_ERROR_BADARGUMENT;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 2ad31d8..aa5f214 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1628,21 +1628,21 @@ // create the RenderWidget if the RenderFrame owned it instead of having the // RenderWidget live for eternity on the RenderView (after setting up the // WebFrameWidget since that would be part of creating the RenderWidget). - render_view->ReviveUndeadMainFrameRenderWidget( - widget_params->visual_properties.screen_info); - - // The RenderViewImpl and its RenderWidget already exist by the time we - // get here (we get them from the RenderFrameProxy). - // TODO(crbug.com/419087): We probably want to create the RenderWidget - // here though (when we make the WebFrameWidget?). - RenderWidget* render_widget = render_view->GetWidget(); + // + // This is equivalent to creating a new RenderWidget if it wasn't undead. + RenderWidget* render_widget = + render_view->ReviveUndeadMainFrameRenderWidget(); + DCHECK(!render_widget->GetWebWidget()); // Non-owning pointer that is self-referencing and destroyed by calling // Close(). The RenderViewImpl has a RenderWidget already, but not a // WebFrameWidget, which is now attached here. auto* web_frame_widget = blink::WebFrameWidget::CreateForMainFrame( render_view->GetWidget(), web_frame); - render_view->AttachWebFrameWidget(web_frame_widget); + // This is equivalent to calling InitForMainFrame() on a new RenderWidget + // if it wasn't undead. + render_widget->InitForRevivedMainFrame( + web_frame_widget, widget_params->visual_properties.screen_info); // Note that we do *not* call WebViewImpl's DidAttachLocalMainFrame() here // yet because this frame is provisional and not attached to the Page yet. @@ -3468,7 +3468,7 @@ } else { NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader( std::move(common_params), std::move(commit_params), request_id, - response_head, std::move(response_body), + response_head.Clone(), std::move(response_body), std::move(url_loader_client_endpoints), GetTaskRunner(blink::TaskType::kInternalLoading), GetRoutingID(), !frame_->Parent(), navigation_params.get()); @@ -4413,12 +4413,11 @@ if (is_main_frame_) { DCHECK(!owned_render_widget_); // TODO(crbug.com/419087): The RenderWidget for the main frame can't be - // closed/destroyed since there is no way to recreate it without also - // fixing the lifetimes of the related browser side objects. To simulate - // this "swap out", the pointer is moved off to the side until it is - // swapped back in. The renderer is then told that the WebFrameWidget is - // dropped which should remove all reference to this object. - render_view_->DetachWebFrameWidget(); + // closed/destroyed here, since there is no way to recreate it without also + // fixing the lifetimes of the related browser side objects. Closing is + // delegated to the RenderViewImpl which will stash the RenderWidget away + // as undead if needed. + render_view_->CloseMainFrameRenderWidget(); } else if (render_widget_) { DCHECK(owned_render_widget_); // This closes/deletes the RenderWidget if this frame was a local root.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index bc69d3b..db4ecc92 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1536,46 +1536,6 @@ render_widget->input_handler().handling_input_event()); } -void RenderViewImpl::AttachWebFrameWidget(blink::WebFrameWidget* frame_widget) { - // The previous WebFrameWidget must already be detached by - // DetachWebFrameWidget(). - DCHECK(!render_widget_->GetWebWidget()); - render_widget_->SetWebWidgetInternal(frame_widget); - - // Note that when a main frame RenderWidget is created with a main frame, then - // this method is not used, so other initialization should not be done here. -} - -void RenderViewImpl::DetachWebFrameWidget() { - // There is a WebFrameWidget previously attached by AttachWebFrameWidget(). - DCHECK(render_widget_->GetWebWidget()); - - if (destroying_) { - // We are inside RenderViewImpl::Destroy() and the main frame is being - // detached as part of shutdown. So we can destroy the RenderWidget. - - // We pass ownership of |render_widget_| to itself. Grab a raw pointer to - // call the Close() method on so we don't have to be a C++ expert to know - // whether we will end up with a nullptr where we didn't intend due to order - // of execution. - RenderWidget* closing_widget = render_widget_.get(); - closing_widget->CloseForFrame(std::move(render_widget_)); - } else { - // We are not inside RenderViewImpl::Destroy(), the main frame is being - // detached and replaced with a remote frame proxy. We can't close the - // RenderWidget, and it is marked undead instead, but we do need to close - // the WebFrameWidget and remove it from the RenderWidget. - render_widget_->SetIsUndead(); - // The WebWidget needs to be closed even though the RenderWidget won't be - // closed here (since it is marked undead instead). - render_widget_->GetWebWidget()->Close(); - // This just clears the webwidget_internal_ member from RenderWidget. - render_widget_->SetWebWidgetInternal(nullptr); - - undead_render_widget_ = std::move(render_widget_); - } -} - bool RenderViewImpl::SetZoomLevel(double zoom_level) { if (zoom_level == page_zoom_level_) return false; @@ -1916,10 +1876,34 @@ // does not change when tests override the visibility of the Page. } -void RenderViewImpl::ReviveUndeadMainFrameRenderWidget( - const ScreenInfo& screen_info) { +RenderWidget* RenderViewImpl::ReviveUndeadMainFrameRenderWidget() { render_widget_ = std::move(undead_render_widget_); - render_widget_->SetIsRevivedFromUndead(screen_info); + render_widget_->SetIsUndead(false); + return render_widget_.get(); +} + +void RenderViewImpl::CloseMainFrameRenderWidget() { + // There is a WebFrameWidget previously attached by AttachWebFrameWidget(). + DCHECK(render_widget_->GetWebWidget()); + + if (destroying_) { + // We are inside RenderViewImpl::Destroy() and the main frame is being + // detached as part of shutdown. So we can destroy the RenderWidget. + + // We pass ownership of |render_widget_| to itself. Grab a raw pointer to + // call the Close() method on so we don't have to be a C++ expert to know + // whether we will end up with a nullptr where we didn't intend due to order + // of execution. + RenderWidget* closing_widget = render_widget_.get(); + closing_widget->CloseForFrame(std::move(render_widget_)); + } else { + // We are not inside RenderViewImpl::Destroy(), the main frame is being + // detached and replaced with a remote frame proxy. We can't close the + // RenderWidget, and it is marked undead instead. + render_widget_->SetIsUndead(true); + + undead_render_widget_ = std::move(render_widget_); + } } void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 2710fa61..6dd9b0b 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -60,7 +60,6 @@ #include "ui/surface/transport_dib.h" namespace blink { -class WebFrameWidget; class WebURLRequest; struct PluginAction; struct WebWindowFeatures; @@ -186,20 +185,6 @@ // FocusController. void SetFocus(bool enable); - // Attaches a WebFrameWidget that will provide a WebFrameWidget interface to - // the WebView. Called as part of initialization or when the main frame - // RenderWidget is becoming not undead, to connect it to the new local main - // frame. - void AttachWebFrameWidget(blink::WebFrameWidget* frame_widget); - // Detaches the current WebFrameWidget, disconnecting it from the main frame. - // Called when the RenderWidget is becoming undead, because the local main - // frame is going away. - void DetachWebFrameWidget(); - - // Called early before detaching begins for the main frame, and objects begin - // tearing down. - void PrepareForDetach(); - // Starts a timer to send an UpdateState message on behalf of |frame|, if the // timer isn't already running. This allows multiple state changing events to // be coalesced into one update. @@ -324,9 +309,12 @@ // be able to specify |initial_setting| where IPC handlers do not. void ApplyPageHidden(bool hidden, bool initial_setting); - // Instead of creating a new RenderWidget, this revives the undead - // RenderWidget for use with a new local main frame. - void ReviveUndeadMainFrameRenderWidget(const ScreenInfo& screen_info); + // Instead of creating a new RenderWidget, a RenderFrame for a main frame + // revives the undead RenderWidget; + RenderWidget* ReviveUndeadMainFrameRenderWidget(); + // Closes the main frame RenderWidget. If not shutting down, this will close + // my marking it undead, to be revived later. + void CloseMainFrameRenderWidget(); private: // For unit tests.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 3897998..1dd61f7 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -499,7 +499,8 @@ blink::WebPagePopup* web_page_popup, const ScreenInfo& screen_info) { popup_ = true; - Init(std::move(show_callback), web_page_popup, &screen_info); + UnconditionalInit(std::move(show_callback)); + LivingInit(web_page_popup, screen_info); if (opener_widget->device_emulator_) { opener_widget_screen_origin_ = @@ -514,20 +515,39 @@ blink::WebWidget* web_widget, const ScreenInfo& screen_info) { pepper_fullscreen_ = true; - Init(std::move(show_callback), web_widget, &screen_info); + UnconditionalInit(std::move(show_callback)); + LivingInit(web_widget, screen_info); } void RenderWidget::InitForMainFrame(ShowCallback show_callback, blink::WebFrameWidget* web_frame_widget, const ScreenInfo* screen_info) { - Init(std::move(show_callback), web_frame_widget, screen_info); + UnconditionalInit(std::move(show_callback)); + // Main frame widgets can be created as undead. Then LivingInit() is deferred. + DCHECK_EQ(is_undead_, !web_frame_widget); + if (web_frame_widget) + LivingInit(web_frame_widget, *screen_info); +} + +void RenderWidget::InitForRevivedMainFrame( + blink::WebFrameWidget* web_frame_widget, + const ScreenInfo& screen_info) { + DCHECK(web_frame_widget); + DCHECK(!is_undead_); + + // UnconditionalInit() has already been done. LivingInit() may have previously + // occured if the RenderWidget was living previously, but we call it each time + // the RenderWidget transitions out of an undead state. + LivingInit(web_frame_widget, screen_info); } void RenderWidget::InitForChildLocalRoot( blink::WebFrameWidget* web_frame_widget, const ScreenInfo& screen_info) { for_child_local_root_frame_ = true; - Init(base::NullCallback(), web_frame_widget, &screen_info); + UnconditionalInit(base::NullCallback()); + // Child local roots can not be undead. + LivingInit(web_frame_widget, screen_info); } void RenderWidget::CloseForFrame(std::unique_ptr<RenderWidget> widget) { @@ -537,28 +557,11 @@ Close(std::move(widget)); } -void RenderWidget::Init(ShowCallback show_callback, - WebWidget* web_widget, - const ScreenInfo* screen_info) { - DCHECK_EQ(is_undead_, !web_widget); // There is a WebWidget when not undead. - DCHECK(!webwidget_); +void RenderWidget::UnconditionalInit(ShowCallback show_callback) { DCHECK_NE(routing_id_, MSG_ROUTING_NONE); input_handler_ = std::make_unique<RenderWidgetInputHandler>(this, this); - if (!is_undead_) { - InitCompositing(*screen_info); - - // If the widget is hidden, delay starting the compositor until the user - // shows it. Also if the RenderWidget is undead, we delay starting the - // compositor until we expect to use the widget, which will be signaled - // through reviving the undead RenderWidget. - if (!is_hidden_) - StartStopCompositor(); - - web_widget->SetAnimationHost(layer_tree_view_->animation_host()); - } - show_callback_ = std::move(show_callback); #if defined(OS_MACOSX) @@ -566,13 +569,38 @@ std::make_unique<TextInputClientObserver>(for_frame() ? this : nullptr); #endif - webwidget_ = web_widget; webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(this)); mouse_lock_dispatcher_.reset(new RenderWidgetMouseLockDispatcher(this)); RenderThread::Get()->AddRoute(routing_id_, this); } +void RenderWidget::LivingInit(WebWidget* web_widget, + const ScreenInfo& screen_info) { + DCHECK(!is_undead_); + DCHECK(!webwidget_); + DCHECK(web_widget); + + if (!layer_tree_view_) + InitCompositing(screen_info); + + const auto& command_line = *base::CommandLine::ForCurrentProcess(); + SetShowFPSCounter(command_line.HasSwitch(cc::switches::kShowFPSCounter)); + + // If the widget is hidden, delay starting the compositor until the user + // shows it. Also if the RenderWidget is undead, we delay starting the + // compositor until we expect to use the widget, which will be signaled + // through reviving the undead RenderWidget. + if (!is_hidden_) + StartStopCompositor(); + + webwidget_ = web_widget; + web_widget->SetAnimationHost(layer_tree_view_->animation_host()); + // Note that this calls into the WebWidget. + UpdateSurfaceAndScreenInfo(local_surface_id_allocation_from_parent_, + CompositorViewportRect(), screen_info); +} + bool RenderWidget::OnMessageReceived(const IPC::Message& message) { // TODO(https://crbug.com/1000502): Don't process IPC messages on undead // RenderWidgets. We would like to eventually remove them altogether, so they @@ -647,12 +675,8 @@ CHECK(!is_undead_); // Provisional frames don't send IPCs until they are swapped in/committed. CHECK(!IsForProvisionalFrame()); - - // Don't send any messages after the browser has told us to close. - if (closing_) { - delete message; - return false; - } + // Don't send any messages during shutdown. + DCHECK(!closing_); // If given a messsage without a routing ID, then assign our routing ID. if (message->routing_id() == MSG_ROUTING_NONE) @@ -661,11 +685,6 @@ return RenderThread::Get()->Send(message); } -void RenderWidget::SendOrCrash(IPC::Message* message) { - bool result = Send(message); - CHECK(closing_ || result) << "Failed to send message"; -} - bool RenderWidget::ShouldHandleImeEvents() const { if (delegate()) return has_focus_; @@ -850,25 +869,20 @@ new_compositor_viewport_pixel_rect, visual_properties.screen_info); if (for_frame()) { - // TODO(danakj): This should not need to go through RenderFrame to set - // Page-level properties. - blink::WebFrameWidget* frame_widget = GetFrameWidget(); - // TODO(danakj): Stop doing SynchronizeVisualProperties() (due to - // emulation) while undead, and change this to a DCHECK. - if (frame_widget) { - RenderFrameImpl* render_frame = - RenderFrameImpl::FromWebFrame(frame_widget->LocalRoot()); - - // This causes compositing state to be modified which dirties the - // document lifecycle. Android Webview relies on the document - // lifecycle being clean after the RenderWidget is initialized, in - // order to send IPCs that query and change compositing state. So - // ResizeWebWidget() must come after this call, as it runs the entire - // document lifecycle. - render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( - ComputePreferCompositingToLCDText( - compositor_deps_, page_properties_->GetDeviceScaleFactor())); - } + RenderFrameImpl* render_frame = + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); + // This causes compositing state to be modified which dirties the + // document lifecycle. Android Webview relies on the document + // lifecycle being clean after the RenderWidget is initialized, in + // order to send IPCs that query and change compositing state. So + // ResizeWebWidget() must come after this call, as it runs the entire + // document lifecycle. + // + // TODO(danakj): Only the top-most RenderWidget per RenderView should + // be responsible for setting values onto the RenderView. + render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( + ComputePreferCompositingToLCDText( + compositor_deps_, page_properties_->GetDeviceScaleFactor())); } if (!auto_resize_mode_) { @@ -992,17 +1006,17 @@ } void RenderWidget::SetZoomLevel(double zoom_level) { - // TODO(danakj): This should not need to go through RenderFrame to set - // Page-level properties. - blink::WebFrameWidget* frame_widget = GetFrameWidget(); - DCHECK(frame_widget); RenderFrameImpl* render_frame = - RenderFrameImpl::FromWebFrame(frame_widget->LocalRoot()); + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); + // TODO(danakj): Only the top-most RenderWidget per RenderView should be + // responsible for setting values onto the RenderView. bool zoom_level_changed = render_frame->SetZoomLevelOnRenderView(zoom_level); if (zoom_level_changed) { // Hide popups when the zoom changes. - blink::WebView* web_view = frame_widget->LocalRoot()->View(); + // TODO(danakj): This should go through RenderFrame, and the Delegate path + // should be replaced. + blink::WebView* web_view = GetFrameWidget()->LocalRoot()->View(); web_view->CancelPagePopup(); // Propagate changes down to child local root RenderWidgets and @@ -1098,8 +1112,6 @@ const blink::WebCoalescedInputEvent& input_event, const ui::LatencyInfo& latency_info, HandledEventCallback callback) { - if (closing_) - return false; if (IsUndeadOrProvisional()) return false; input_handler_->HandleInputEvent(input_event, latency_info, @@ -1120,8 +1132,7 @@ if (IsUndeadOrProvisional()) return; - if (GetWebWidget()) - GetWebWidget()->SetCursorVisibilityState(is_visible); + GetWebWidget()->SetCursorVisibilityState(is_visible); } void RenderWidget::OnFallbackCursorModeToggled(bool is_on) { @@ -1129,8 +1140,7 @@ if (IsUndeadOrProvisional()) return; - if (GetWebWidget()) - GetWebWidget()->OnFallbackCursorModeToggled(is_on); + GetWebWidget()->OnFallbackCursorModeToggled(is_on); } void RenderWidget::OnMouseCaptureLost() { @@ -1138,8 +1148,7 @@ if (IsUndeadOrProvisional()) return; - if (GetWebWidget()) - GetWebWidget()->MouseCaptureLost(); + GetWebWidget()->MouseCaptureLost(); } void RenderWidget::OnSetEditCommandsForNextKeyEvent( @@ -1163,19 +1172,15 @@ if (delegate()) delegate()->DidReceiveSetFocusEventForWidget(); - SetFocus(enable); -} -void RenderWidget::SetFocus(bool enable) { has_focus_ = enable; - if (GetWebWidget()) - GetWebWidget()->SetFocus(enable); + GetWebWidget()->SetFocus(enable); for (auto& observer : render_frames_) observer.RenderWidgetSetFocus(enable); - // Notify all BrowserPlugins of the RenderView's focus state. + // Notify all BrowserPlugins of the RenderWidget's focus state. if (BrowserPluginManager::Get()) BrowserPluginManager::Get()->UpdateFocusState(); } @@ -1185,46 +1190,25 @@ void RenderWidget::ApplyViewportChanges( const cc::ApplyViewportChangesArgs& args) { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; GetWebWidget()->ApplyViewportChanges(args); } void RenderWidget::RecordManipulationTypeCounts(cc::ManipulationInfo info) { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; GetWebWidget()->RecordManipulationTypeCounts(info); } void RenderWidget::SendOverscrollEventFromImplSide( const gfx::Vector2dF& overscroll_delta, cc::ElementId scroll_latched_element_id) { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; GetWebWidget()->SendOverscrollEventFromImplSide(overscroll_delta, scroll_latched_element_id); } void RenderWidget::SendScrollEndEventFromImplSide( cc::ElementId scroll_latched_element_id) { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; GetWebWidget()->SendScrollEndEventFromImplSide(scroll_latched_element_id); } void RenderWidget::BeginMainFrame(base::TimeTicks frame_time) { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; - DCHECK(!is_undead_); DCHECK(!IsForProvisionalFrame()); @@ -1244,29 +1228,30 @@ } void RenderWidget::OnDeferMainFrameUpdatesChanged(bool deferral_state) { + // LayerTreeHost::CreateThreaded() will defer main frame updates immediately + // until it gets a LocalSurfaceIdAllocation. That's before the + // |widget_input_handler_manager_| is created, so it can be null here. We + // detect that by seeing a null LayerTreeHost. + // TODO(schenney): To avoid ping-ponging between defer main frame states + // during initialization, and requiring null checks here, we should probably + // pass the LocalSurfaceIdAllocation to the compositor while it is + // initialized so that it doesn't have to immediately switch into deferred + // mode without being requested to. + if (!layer_tree_host_) + return; + // The input handler wants to know about the mainframe update status to // enable/disable input and for metrics. - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (widget_input_handler_manager_) - widget_input_handler_manager_->OnDeferMainFrameUpdatesChanged( - deferral_state); + widget_input_handler_manager_->OnDeferMainFrameUpdatesChanged(deferral_state); } void RenderWidget::OnDeferCommitsChanged(bool deferral_state) { // The input handler wants to know about the commit status for metric purposes // and to enable/disable input. - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (widget_input_handler_manager_) - widget_input_handler_manager_->OnDeferCommitsChanged(deferral_state); + widget_input_handler_manager_->OnDeferCommitsChanged(deferral_state); } void RenderWidget::DidBeginMainFrame() { - // TODO(danakj): This should never be null now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; GetWebWidget()->DidBeginFrame(); } @@ -1279,18 +1264,6 @@ // widgets for provisional frames do start their compositor. DCHECK(!is_undead_); - // If we early out, we drop the request which means the compositor waits - // forever, which is fine since we're going to destroy it soon. - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (closing_) - return; - - // TODO:(https://crbug.com/995981): If there is no WebWidget, then the - // RenderWidget should also be destroyed, and this DCHECK should not be - // necessary. - DCHECK(GetWebWidget()); - // TODO(jonross): have this generated by the LayerTreeFrameSink itself, which // would then handle binding. mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer_remote; @@ -1332,24 +1305,19 @@ } void RenderWidget::WillCommitCompositorFrame() { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->BeginCommitCompositorFrame(); + DCHECK(!is_undead_); + GetWebWidget()->BeginCommitCompositorFrame(); } void RenderWidget::DidCommitCompositorFrame() { + DCHECK(!is_undead_); if (delegate()) delegate()->DidCommitCompositorFrameForWidget(); - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->EndCommitCompositorFrame(); + GetWebWidget()->EndCommitCompositorFrame(); } void RenderWidget::DidCompletePageScaleAnimation() { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). + DCHECK(!is_undead_); if (delegate()) delegate()->DidCompletePageScaleAnimationForWidget(); } @@ -1421,9 +1389,6 @@ } void RenderWidget::UpdateVisualState() { - if (!GetWebWidget()) - return; - DCHECK(!is_undead_); DCHECK(!IsForProvisionalFrame()); @@ -1467,47 +1432,34 @@ } void RenderWidget::RecordStartOfFrameMetrics() { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->RecordStartOfFrameMetrics(); + DCHECK(!is_undead_); + GetWebWidget()->RecordStartOfFrameMetrics(); } void RenderWidget::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->RecordEndOfFrameMetrics(frame_begin_time); + DCHECK(!is_undead_); + GetWebWidget()->RecordEndOfFrameMetrics(frame_begin_time); } std::unique_ptr<cc::BeginMainFrameMetrics> RenderWidget::GetBeginMainFrameMetrics() { - if (GetWebWidget()) - return GetWebWidget()->GetBeginMainFrameMetrics(); - return nullptr; + DCHECK(!is_undead_); + return GetWebWidget()->GetBeginMainFrameMetrics(); } void RenderWidget::BeginUpdateLayers() { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->BeginUpdateLayers(); + DCHECK(!is_undead_); + GetWebWidget()->BeginUpdateLayers(); } void RenderWidget::EndUpdateLayers() { - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (GetWebWidget()) - GetWebWidget()->EndUpdateLayers(); + DCHECK(!is_undead_); + GetWebWidget()->EndUpdateLayers(); } void RenderWidget::WillBeginCompositorFrame() { TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame"); - - // TODO(danakj): This should never be true now that LayerTreeView disconnects - // during Close(). - if (!GetWebWidget()) - return; + DCHECK(!is_undead_); GetWebWidget()->SetSuppressFrameRequestsWorkaroundFor704763Only(true); @@ -1580,10 +1532,6 @@ } void RenderWidget::ShowVirtualKeyboard() { - // Blink can continue running and change input state between the Close IPC - // and the task that actually closes this class. - if (closing_) - return; UpdateTextInputStateInternal(true, false); } @@ -1597,10 +1545,6 @@ } void RenderWidget::UpdateTextInputState() { - // Blink can continue running and change input state between the Close IPC - // and the task that actually closes this class. - if (closing_) - return; UpdateTextInputStateInternal(false, false); } @@ -1777,29 +1721,22 @@ UpdateSurfaceAndScreenInfo(local_surface_id_allocation_from_parent_, CompositorViewportRect(), screen_info); + RenderFrameImpl* render_frame = + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); // UpdateSurfaceAndScreenInfo() changes PageProperties including the device // scale factor, which changes PreferCompositingToLCDText decisions. // TODO(danakj): Do this in UpdateSurfaceAndScreenInfo? But requires a Resize // to happen after (see comment on // SetPreferCompositingToLCDTextEnabledOnRenderView). - // TODO(danakj): This should not need to go through RenderFrame to set - // Page-level properties. - blink::WebFrameWidget* frame_widget = GetFrameWidget(); - // TODO(danakj): Stop handling emulation changes while undead, and change this - // to a DCHECK. - if (frame_widget) { - RenderFrameImpl* render_frame = - RenderFrameImpl::FromWebFrame(frame_widget->LocalRoot()); - - // This causes compositing state to be modified which dirties the document - // lifecycle. Android Webview relies on the document lifecycle being clean - // after the RenderWidget is initialized, in order to send IPCs that query - // and change compositing state. So ResizeWebWidget() must come after this - // call, as it runs the entire document lifecycle. - render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( - ComputePreferCompositingToLCDText( - compositor_deps_, page_properties_->GetDeviceScaleFactor())); - } + // + // This causes compositing state to be modified which dirties the document + // lifecycle. Android Webview relies on the document lifecycle being clean + // after the RenderWidget is initialized, in order to send IPCs that query + // and change compositing state. So ResizeWebWidget() must come after this + // call, as it runs the entire document lifecycle. + render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( + ComputePreferCompositingToLCDText( + compositor_deps_, page_properties_->GetDeviceScaleFactor())); visible_viewport_size_ = visible_viewport_size; size_ = widget_size; @@ -1858,9 +1795,6 @@ } void RenderWidget::QueueMessage(std::unique_ptr<IPC::Message> msg) { - if (closing_) - return; - // RenderThreadImpl::current() is NULL in some tests. if (!RenderThreadImpl::current()) { Send(msg.release()); @@ -1944,9 +1878,6 @@ compositor_deps_->CreateUkmRecorderFactory()); layer_tree_host_ = layer_tree_view_->layer_tree_host(); - UpdateSurfaceAndScreenInfo(local_surface_id_allocation_from_parent_, - CompositorViewportRect(), screen_info); - blink::scheduler::WebThreadScheduler* main_thread_scheduler = compositor_deps_->GetWebMainThreadScheduler(); @@ -2003,43 +1934,24 @@ } } -void RenderWidget::SetIsUndead() { - DCHECK(!is_undead_); - is_undead_ = true; - // If hidden, then changing undead state doesn't change anything with the - // compositor since when hidden the compositor is always stopped. - if (!is_hidden_) +void RenderWidget::SetIsUndead(bool is_undead) { + DCHECK_NE(is_undead, is_undead_); + is_undead_ = is_undead; + + if (is_undead_) { StartStopCompositor(); - // Remove undead RenderWidgets from the routing map so that they cannot be - // looked up with FromRoutingId(). - g_routing_id_widget_map.Get().erase(routing_id_); -} - -void RenderWidget::SetIsRevivedFromUndead(const ScreenInfo& screen_info) { - DCHECK(is_undead_); - is_undead_ = false; - // If started as undead, the compositor was not created yet. - if (!layer_tree_view_) - InitCompositing(screen_info); - // If hidden, then changing undead state doesn't change anything with the - // compositor since when hidden the compositor is always stopped. - if (!is_hidden_) - StartStopCompositor(); - - // Put revived RenderWidgets back into the routing id map so they can be - // looked up with FromRoutingId(). - g_routing_id_widget_map.Get().emplace(routing_id_, this); - - // Reviving from undead is like making a "new" RenderWidget, initialization - // that should not bleed across from the last local main frame can happen - // here. - // TODO(crbug.com/419087): This initialization can be done during - // InitCompositing() or when constructing the RenderWidget once there are - // no undead RenderWidgets. - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - SetShowFPSCounter(command_line.HasSwitch(cc::switches::kShowFPSCounter)); + webwidget_->Close(); + webwidget_ = nullptr; + // Remove undead RenderWidgets from the routing map so that they cannot be + // looked up with FromRoutingId(). + g_routing_id_widget_map.Get().erase(routing_id_); + } else { + // When revived from undead, act like a "new RenderWidget". This method is + // equivalent to the constructor, and initialization comes separately + // through InitForRevivedMainFrame(). + g_routing_id_widget_map.Get().emplace(routing_id_, this); + } } // static @@ -2127,10 +2039,6 @@ // TODO(danakj): Remove this check and don't call this method for non-frames. if (!for_frame()) return nullptr; - // TODO(danakj): Is this needed? IPCs stop after closing, but code used to - // check for a null WebWidget. - if (closing_) - return nullptr; return static_cast<blink::WebFrameWidget*>(webwidget_); } @@ -2421,24 +2329,20 @@ OnOrientationChange(); if (for_frame()) { - // TODO(danakj): This should not need to go through RenderFrame to set - // Page-level properties. - blink::WebFrameWidget* frame_widget = GetFrameWidget(); - // TODO(danakj): Stop sending/receiving visual properties while undead, and - // change this to a DCHECK. - if (frame_widget) { - RenderFrameImpl* render_frame = - RenderFrameImpl::FromWebFrame(frame_widget->LocalRoot()); - // TODO(danakj): RenderWidget knows the DSF and could avoid calling into - // blink when it hasn't changed, but it sets an initial |screen_info_| - // during construction, so it is hard to tell if the value is not the - // default value once we get to OnSynchronizeVisualProperties. Thus we - // call into blink unconditionally and let it early out if it's already - // set. - render_frame->SetDeviceScaleFactorOnRenderView( - compositor_deps_->IsUseZoomForDSFEnabled(), - page_properties_->GetDeviceScaleFactor()); - } + RenderFrameImpl* render_frame = + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); + // TODO(danakj): RenderWidget knows the DSF and could avoid calling into + // blink when it hasn't changed, but it sets an initial |screen_info_| + // during construction, so it is hard to tell if the value is not the + // default value once we get to OnSynchronizeVisualProperties. Thus we + // call into blink unconditionally and let it early out if it's already + // set. + // + // TODO(danakj): Only the top-most RenderWidget per RenderView should + // be responsible for setting values onto the RenderView. + render_frame->SetDeviceScaleFactorOnRenderView( + compositor_deps_->IsUseZoomForDSFEnabled(), + page_properties_->GetDeviceScaleFactor()); } // Propagate changes down to child local root RenderWidgets and BrowserPlugins @@ -2696,10 +2600,6 @@ void RenderWidget::OnRequestTextInputStateUpdate() { #if defined(OS_ANDROID) - // This task may run between the Close IPC and the task that actually closes - // this class. - if (closing_) - return; DCHECK(!ime_event_guard_); UpdateSelectionBounds(); UpdateTextInputStateInternal(false, true /* reply_to_request */); @@ -2841,11 +2741,6 @@ } void RenderWidget::DidAutoResize(const gfx::Size& new_size) { - // Blink can continue running and do a layout/resize between the Close IPC - // and the task that actually closes this class. - if (closing_) - return; - WebRect new_size_in_window(0, 0, new_size.width(), new_size.height()); ConvertViewportToWindow(&new_size_in_window); if (size_.width() != new_size_in_window.width || @@ -3858,12 +3753,6 @@ } void RenderWidget::DidNavigate() { - // Blink may be navigating still between the Close IPC and the task that - // actually closes this class, and for a main frame that would come through - // this method. But since we are closing we can skip it. - if (closing_) - return; - // The input handler wants to know about navigation so that it can // suppress input until the newly navigated page has a committed frame. // It also resets the state for UMA reporting of input arrival with respect @@ -3923,11 +3812,8 @@ if (!auto_resize_mode_) ResizeWebWidget(); // This picks up the new device scale factor in |info|. - // TODO(danakj): This should not need to go through RenderFrame to set - // Page-level properties. - blink::WebFrameWidget* frame_widget = GetFrameWidget(); RenderFrameImpl* render_frame = - RenderFrameImpl::FromWebFrame(frame_widget->LocalRoot()); + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( ComputePreferCompositingToLCDText( compositor_deps_, page_properties_->GetDeviceScaleFactor())); @@ -4031,14 +3917,4 @@ return weak_ptr_factory_.GetWeakPtr(); } -void RenderWidget::SetWebWidgetInternal(blink::WebWidget* webwidget) { - // Undead state is changed first, and the WebWidget is set accordingly. That - // means the compositor is always initialized before we get here. - DCHECK_EQ(is_undead_, !webwidget); - - webwidget_ = webwidget; - if (webwidget_) - webwidget_->SetAnimationHost(layer_tree_view_->animation_host()); -} - } // namespace content
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index c98ddbf2..92e4661 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -250,6 +250,11 @@ blink::WebFrameWidget* web_frame_widget, const ScreenInfo* screen_info); + // Initialize (or re-initialize) a main frame RenderWidget that has been + // revived from undead state. + void InitForRevivedMainFrame(blink::WebFrameWidget* web_frame_widget, + const ScreenInfo& screen_info); + // Initialize a new RenderWidget that will be attached to a RenderFrame (via // the WebFrameWidget), for a frame that is a local root, but not the main // frame. @@ -308,8 +313,7 @@ // otherwise act as if it is dead. Only whitelisted new IPC messages will be // sent, and it does no compositing. The process is free to exit when there // are no other non-undead RenderWidgets. - void SetIsUndead(); - void SetIsRevivedFromUndead(const ScreenInfo& screen_info); + void SetIsUndead(bool is_undead); // A main frame RenderWidget is made undead instead of being deleted. Then // when a provisional frame is created, the RenderWidget is recycled and @@ -650,10 +654,6 @@ int relative_cursor_pos); void OnImeFinishComposingText(bool keep_selection); - // This does the actual focus change, but is called in more situations than - // just as an IPC message. - void SetFocus(bool enable); - // Called by the browser process to update text input state. void OnRequestTextInputStateUpdate(); @@ -694,12 +694,6 @@ base::WeakPtr<RenderWidget> AsWeakPtr(); - // TODO(https://crbug.com/995981): Eventually, the lifetime of RenderWidget - // should be tied to the lifetime of the WebWidget. In the short term, for - // main frames, the RenderView has to explicitly set/unset the WebWidget on - // attach/detach. - void SetWebWidgetInternal(blink::WebWidget* webwidget); - protected: // Notify subclasses that we initiated the paint operation. virtual void DidInitiatePaint() {} @@ -725,14 +719,16 @@ FRIEND_TEST_ALL_PREFIXES(RenderWidgetPopupUnittest, EmulatingPopupRect); FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, EmulatingPopupRect); - // Called by Create() functions and subclasses to finish initialization. - // |show_callback| will be invoked once WebWidgetClient::Show() occurs, and - // should be null if Show() won't be triggered for this widget. The WebWidget - // and ScreenInfo are both null or both not. - void Init(ShowCallback show_callback, - blink::WebWidget* web_widget, - const ScreenInfo* screen_info); + // Called by InitFor*() methods on a new RenderWidget. This contains + // initialization that occurs whether the RenderWidget is created as undead or + // not. + void UnconditionalInit(ShowCallback show_callback); + // Called by InitFor*() methods when a new RenderWidget is created that is not + // undead, or when it is being revived from undead. + void LivingInit(blink::WebWidget* web_widget, const ScreenInfo& screen_info); + // Initializes the compositor and dependent systems, as part of the + // LivingInit() process. void InitCompositing(const ScreenInfo& screen_info); // If appropriate, initiates the compositor to set up IPC channels and begin @@ -879,13 +875,6 @@ // Used to force the size of a window when running web tests. void SetWindowRectSynchronously(const gfx::Rect& new_window_rect); - // A variant of Send but is fatal if it fails. The browser may - // be waiting for this IPC Message and if the send fails the browser will - // be left in a state waiting for something that never comes. And if it - // never comes then it may later determine this is a hung renderer; so - // instead fail right away. - void SendOrCrash(IPC::Message* msg); - // Determines whether or not RenderWidget should process IME events from the // browser. It always returns true unless there is no WebFrameWidget to // handle the event, or there is no page focus.
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc index 458c3ae..16a721c 100644 --- a/content/renderer/render_widget_unittest.cc +++ b/content/renderer/render_widget_unittest.cc
@@ -174,13 +174,13 @@ compositor_deps, page_properties, blink::mojom::DisplayMode::kUndefined, - false, - false, - false, + /*is_undead=*/false, + /*is_hidden=*/false, + /*never_visible=*/false, mojo::NullReceiver()), always_overscroll_(false) { - Init(base::NullCallback(), &mock_webwidget_, - &page_properties->GetScreenInfo()); + UnconditionalInit(base::NullCallback()); + LivingInit(&mock_webwidget_, page_properties->GetScreenInfo()); mock_input_handler_host_ = std::make_unique<MockWidgetInputHandlerHost>();
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc index 9e7b54e5..a5a196f 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -137,8 +137,8 @@ } // mojom::ServiceWorkerStreamCallback implementations: - void OnCompleted() override { owner_->CommitCompleted(net::OK); } - void OnAborted() override { owner_->CommitCompleted(net::ERR_ABORTED); } + void OnCompleted() override { owner_->OnBodyReadingComplete(net::OK); } + void OnAborted() override { owner_->OnBodyReadingComplete(net::ERR_ABORTED); } private: ServiceWorkerSubresourceLoader* owner_; @@ -166,7 +166,7 @@ body_as_blob_size_(blink::BlobUtils::kUnknownSize), controller_connector_(std::move(controller_connector)), fetch_request_restarted_(false), - blob_reading_complete_(false), + body_reading_complete_(false), side_data_reading_complete_(false), routing_id_(routing_id), request_id_(request_id), @@ -477,14 +477,26 @@ // We have a non-redirect response. Send the headers to the client. CommitResponseHeaders(); + bool body_stream_is_valid = + !body_as_stream.is_null() && body_as_stream->stream.is_valid(); + + // Handle the case where there is no body content. + if (!body_stream_is_valid && !response->blob) { + CommitEmptyResponseAndComplete(); + return; + } + + mojo::ScopedDataPipeConsumerHandle data_pipe; + // Handle a stream response body. - if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) { + if (body_stream_is_valid) { DCHECK(!response->blob); + if (response->side_data_blob) + DCHECK(base::FeatureList::IsEnabled(features::kCacheStorageEagerReading)); DCHECK(url_loader_client_.is_bound()); stream_waiter_ = std::make_unique<StreamWaiter>( this, std::move(body_as_stream->callback_receiver)); - CommitResponseBody(std::move(body_as_stream->stream)); - return; + data_pipe = std::move(body_as_stream->stream); } // Handle a blob response body. @@ -497,31 +509,33 @@ // Start reading the body blob immediately. This will allow the body to // start buffering in the pipe while the side data is read. - mojo::ScopedDataPipeConsumerHandle data_pipe; int error = StartBlobReading(&data_pipe); if (error != net::OK) { CommitCompleted(error); return; } + } - // Read side data if necessary. - auto resource_type = - static_cast<content::ResourceType>(resource_request_.resource_type); - if (resource_type == content::ResourceType::kScript) { - body_as_blob_->ReadSideData(base::BindOnce( - &ServiceWorkerSubresourceLoader::OnBlobSideDataReadingComplete, - weak_factory_.GetWeakPtr(), std::move(data_pipe))); - } else { - // Bypass reading side data when the request isn't for script. Currently - // side data only exists for scripts (as cached metadata). - OnBlobSideDataReadingComplete(std::move(data_pipe), - base::Optional<mojo_base::BigBuffer>()); - } + DCHECK(data_pipe.is_valid()); + // Read side data if necessary. We only do this if both the + // |side_data_blob| is available to read and the request is destined + // for a script. + auto resource_type = + static_cast<content::ResourceType>(resource_request_.resource_type); + if (response->side_data_blob && + resource_type == content::ResourceType::kScript) { + side_data_as_blob_.Bind(std::move(response->side_data_blob->blob)); + side_data_as_blob_->ReadSideData(base::BindOnce( + &ServiceWorkerSubresourceLoader::OnSideDataReadingComplete, + weak_factory_.GetWeakPtr(), std::move(data_pipe))); return; } - CommitEmptyResponseAndComplete(); + // Otherwise we can immediately complete side data reading so that the + // entire resource completes when the main body is read. + OnSideDataReadingComplete(std::move(data_pipe), + base::Optional<mojo_base::BigBuffer>()); } void ServiceWorkerSubresourceLoader::CommitResponseHeaders() { @@ -701,35 +715,32 @@ TRACE_ID_LOCAL(request_id_)), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); DCHECK(body_pipe); - DCHECK(!blob_reading_complete_); + DCHECK(!body_reading_complete_); return ServiceWorkerLoaderHelpers::ReadBlobResponseBody( &body_as_blob_, body_as_blob_size_, - base::BindOnce(&ServiceWorkerSubresourceLoader::OnBlobReadingComplete, + base::BindOnce(&ServiceWorkerSubresourceLoader::OnBodyReadingComplete, weak_factory_.GetWeakPtr()), body_pipe); } -void ServiceWorkerSubresourceLoader::OnBlobSideDataReadingComplete( +void ServiceWorkerSubresourceLoader::OnSideDataReadingComplete( mojo::ScopedDataPipeConsumerHandle data_pipe, base::Optional<mojo_base::BigBuffer> metadata) { TRACE_EVENT_WITH_FLOW1( "ServiceWorker", - "ServiceWorkerSubresourceLoader::OnBlobSideDataReadingComplete", + "ServiceWorkerSubresourceLoader::OnSideDataReadingComplete", TRACE_ID_WITH_SCOPE(kServiceWorkerSubresourceLoaderScope, TRACE_ID_LOCAL(request_id_)), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "metadata size", (metadata ? metadata->size() : 0)); DCHECK(url_loader_client_); - DCHECK(body_as_blob_); DCHECK(!side_data_reading_complete_); side_data_reading_complete_ = true; if (metadata.has_value()) url_loader_client_->OnReceiveCachedMetadata(std::move(metadata.value())); - // We should have started reading the body in parallel before trying to load - // side data. DCHECK(data_pipe.is_valid()); base::TimeDelta delay = @@ -742,24 +753,23 @@ // If the blob reading completed before the side data reading, then we // must manually finalize the blob reading now. - if (blob_reading_complete_) { - OnBlobReadingComplete(net::OK); + if (body_reading_complete_) { + OnBodyReadingComplete(net::OK); } // Otherwise we asyncly continue in OnBlobReadingComplete(). } -void ServiceWorkerSubresourceLoader::OnBlobReadingComplete(int net_error) { +void ServiceWorkerSubresourceLoader::OnBodyReadingComplete(int net_error) { TRACE_EVENT_WITH_FLOW0( - "ServiceWorker", "ServiceWorkerSubresourceLoader::OnBlobReadingComplete", + "ServiceWorker", "ServiceWorkerSubresourceLoader::OnBodyReadingComplete", TRACE_ID_WITH_SCOPE(kServiceWorkerSubresourceLoaderScope, TRACE_ID_LOCAL(request_id_)), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - DCHECK(body_as_blob_); - blob_reading_complete_ = true; + body_reading_complete_ = true; // If the side data has not completed reading yet, then we need to delay // calling CommitCompleted. This method will be called again from - // OnBlobSideDataReadingComplete(). Only delay for successful reads, though. + // OnSideDataReadingComplete(). Only delay for successful reads, though. // Abort immediately on error. if (!side_data_reading_complete_ && net_error == net::OK) return;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h index 47f27edd..f8ad0ba 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader.h +++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -116,10 +116,9 @@ void ResumeReadingBodyFromNet() override; int StartBlobReading(mojo::ScopedDataPipeConsumerHandle* body_pipe); - void OnBlobSideDataReadingComplete( - mojo::ScopedDataPipeConsumerHandle data_pipe, - base::Optional<mojo_base::BigBuffer> metadata); - void OnBlobReadingComplete(int net_error); + void OnSideDataReadingComplete(mojo::ScopedDataPipeConsumerHandle data_pipe, + base::Optional<mojo_base::BigBuffer> metadata); + void OnBodyReadingComplete(int net_error); // Calls url_loader_client_->OnReceiveResponse() with |response_head_|. void CommitResponseHeaders(); @@ -157,6 +156,8 @@ // The blob needs to be held while it's read to keep it alive. mojo::Remote<blink::mojom::Blob> body_as_blob_; uint64_t body_as_blob_size_; + // The blob needs to be held while it's read to keep it alive. + mojo::Remote<blink::mojom::Blob> side_data_as_blob_; scoped_refptr<ControllerServiceWorkerConnector> controller_connector_; @@ -167,7 +168,7 @@ ControllerServiceWorkerConnector::Observer> controller_connector_observer_{this}; bool fetch_request_restarted_; - bool blob_reading_complete_; + bool body_reading_complete_; bool side_data_reading_complete_; // These are given by the constructor (as the params for
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc index 2a3b80f..e34ee0e 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -53,8 +53,8 @@ private: // Implements blink::mojom::Blob. - void Clone(mojo::PendingReceiver<blink::mojom::Blob>) override { - NOTREACHED(); + void Clone(mojo::PendingReceiver<blink::mojom::Blob> receiver) override { + receivers_.Add(this, std::move(receiver)); } void AsDataPipeGetter( mojo::PendingReceiver<network::mojom::DataPipeGetter>) override { @@ -85,6 +85,7 @@ NOTREACHED(); } + mojo::ReceiverSet<blink::mojom::Blob> receivers_; base::Optional<std::vector<uint8_t>> side_data_; std::string body_; }; @@ -107,6 +108,14 @@ if (response->blob) { response->headers.emplace("Content-Length", base::NumberToString(response->blob->size)); + + // Clone the blob into the side_data_blob to match cache_storage behavior. + mojo::Remote<blink::mojom::Blob> blob_remote( + std::move(response->blob->blob)); + blob_remote->Clone(response->blob->blob.InitWithNewPipeAndPassReceiver()); + response->side_data_blob = blink::mojom::SerializedBlob::New( + response->blob->uuid, response->blob->content_type, + response->blob->size, blob_remote.Unbind()); } return response; }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index beb7c4a..115c59cd 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -67,6 +67,10 @@ "../browser/native_file_system/mock_native_file_system_permission_context.h", "../browser/native_file_system/mock_native_file_system_permission_grant.cc", "../browser/native_file_system/mock_native_file_system_permission_grant.h", + "../browser/portal/portal_created_observer.cc", + "../browser/portal/portal_created_observer.h", + "../browser/portal/portal_interceptor_for_testing.cc", + "../browser/portal/portal_interceptor_for_testing.h", "../browser/renderer_host/input/mock_input_router.cc", "../browser/renderer_host/input/mock_input_router.h", "../browser/renderer_host/mock_render_widget_host.cc",
diff --git a/content/test/data/accessibility/display-locking/activatable-activated.html b/content/test/data/accessibility/display-locking/activatable-activated.html index 8682b67..6be1c7e 100644 --- a/content/test/data/accessibility/display-locking/activatable-activated.html +++ b/content/test/data/accessibility/display-locking/activatable-activated.html
@@ -2,10 +2,10 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" rendersubtree="invisible activatable"> + <div id="locked" rendersubtree="invisible"> <div>child</div> - <div id="nested" rendersubtree="invisible activatable">nested locked element!</div> - <div id="nonActivatable" rendersubtree="invisible">nested non activatable locked element</div> + <div id="nested" rendersubtree="invisible">nested locked element!</div> + <div id="nonActivatable" rendersubtree="invisible skip-activation">nested non activatable locked element</div> </div> </div>
diff --git a/content/test/data/accessibility/display-locking/activatable.html b/content/test/data/accessibility/display-locking/activatable.html index dca7e48..49a5d52f 100644 --- a/content/test/data/accessibility/display-locking/activatable.html +++ b/content/test/data/accessibility/display-locking/activatable.html
@@ -2,9 +2,9 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" rendersubtree="invisible activatable"> + <div id="locked" rendersubtree="invisible"> <div>child</div> - <div id="nested" rendersubtree="invisible activatable">nested locked element!</div> - <div id="nonActivatable" rendersubtree="invisible">nested non activatable locked element</div> + <div id="nested" rendersubtree="invisible">nested locked element!</div> + <div id="nonActivatable" rendersubtree="invisible skip-activation">nested non activatable locked element</div> </div> </div>
diff --git a/content/test/data/accessibility/display-locking/all-committed.html b/content/test/data/accessibility/display-locking/all-committed.html index 81eb5c1..2266d984 100644 --- a/content/test/data/accessibility/display-locking/all-committed.html +++ b/content/test/data/accessibility/display-locking/all-committed.html
@@ -2,10 +2,10 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" rendersubtree="invisible-activatable"> + <div id="locked" rendersubtree="invisible skip-activation"> <div>child</div> - <div id="nested" rendersubtree="invisible-activatable">nested locked element!</div> - <div id="nonActivatable" rendersubtree="invisible">nested non activatable locked element</div> + <div id="nested" rendersubtree="invisible skip-activation">nested locked element!</div> + <div id="nonActivatable" rendersubtree="invisible skip-activation">nested non activatable locked element</div> <!-- TODO(rakina): Make display:none, visibility:hidden, aria-hidden nodes in locked subtrees get ignored for accessibility/marked invisible.
diff --git a/content/test/data/accessibility/display-locking/all.html b/content/test/data/accessibility/display-locking/all.html index fc60826..32bee4b 100644 --- a/content/test/data/accessibility/display-locking/all.html +++ b/content/test/data/accessibility/display-locking/all.html
@@ -2,10 +2,10 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" rendersubtree="invisible activatable"> + <div id="locked" rendersubtree="invisible"> <div>child</div> - <div id="nested" rendersubtree="invisible activatable">nested locked element!</div> - <div id="nonActivatable" rendersubtree="invisible">nested non activatable locked element</div> + <div id="nested" rendersubtree="invisible">nested locked element!</div> + <div id="nonActivatable" rendersubtree="invisible skip-activation">nested non activatable locked element</div> <!-- TODO(rakina): Make display:none, visibility:hidden, aria-hidden nodes in locked subtrees get ignored for accessibility/marked invisible.
diff --git a/content/test/data/accessibility/display-locking/non-activatable.html b/content/test/data/accessibility/display-locking/non-activatable.html index 029fc15d..15f436e 100644 --- a/content/test/data/accessibility/display-locking/non-activatable.html +++ b/content/test/data/accessibility/display-locking/non-activatable.html
@@ -2,9 +2,9 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" rendersubtree="invisible"> + <div id="locked" rendersubtree="invisible skip-activation"> <div>child</div> - <div id="nested" rendersubtree="invisible">nested locked element!</div> - <div id="activatable" rendersubtree="invisible-activatable">non activatable locked element</div> + <div id="nested" rendersubtree="invisible skip-activation">nested locked element!</div> + <div id="activatable" rendersubtree="invisible skip-activation">non activatable locked element</div> </div> </div>
diff --git a/content/test/data/service_worker/cached_fetch_event.js b/content/test/data/service_worker/cached_fetch_event.js new file mode 100644 index 0000000..890e51f --- /dev/null +++ b/content/test/data/service_worker/cached_fetch_event.js
@@ -0,0 +1,20 @@ +// 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. + +const name = 'test_cache'; +const resource = '/service_worker/v8_cache_test.js'; + +self.addEventListener('install', evt => { + evt.waitUntil(async function() { + const c = await caches.open(name); + await c.addAll([resource]); + }()); +}); + +self.addEventListener('fetch', evt => { + evt.respondWith(async function() { + const c = await caches.open(name); + return c.match(resource); + }()); +});
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom index 3b250a1..9edd6e04 100644 --- a/device/vr/public/mojom/vr_service.mojom +++ b/device/vr/public/mojom/vr_service.mojom
@@ -289,6 +289,31 @@ bool wait_for_gpu_fence; }; +// Native origins that are reference spaces are identified by their category. +// Currently, the device needs to know about 3 reference space categories. +enum XRReferenceSpaceCategory { + LOCAL, + LOCAL_FLOOR, + VIEWER, + BOUNDED_FLOOR, + UNBOUNDED +}; + +// Native origin represents a reference space that is known to the device and +// whose position can be tracked over time. There are multiple different types +// of native origins (planes, anchors, reference spaces, input sources), each of +// them roughly corresponds to something that either is an XRSpace (for example +// XRReferenceSpaceType, XRBoundedReferenceSpace) or returns an XRSpace (for +// example XRAnchor, XRPlane, XRInputSource). Native origin can be identified, +// depending on its type, by the id of the entity (this is the case for planes, +// anchors and input sources), or by reference space category. +union XRNativeOriginInformation { + uint32 input_source_id; + uint32 plane_id; + uint32 anchor_id; + XRReferenceSpaceCategory reference_space_category; +}; + enum XRPlaneOrientation { UNKNOWN = 0, HORIZONTAL = 1, @@ -359,6 +384,18 @@ array<XRAnchorData> updated_anchors_data; }; +// Information about results for a single subscription for the current frame. +struct XRHitTestSubscriptionResultData { + uint32 subscription_id; + array<XRHitResult> hit_test_results; +}; + +// Struct containing data about results of all hit test subscriptions for the +// current frame. +struct XRHitTestSubscriptionResultsData { + array<XRHitTestSubscriptionResultData> results; +}; + // The data needed for each animation frame of an XRSession. struct XRFrameData { // General XRSession value @@ -408,6 +445,10 @@ // Tracked anchors information. XRAnchorsData? anchors_data; + + // Hit test subscription results. Only present if the session supports + // environment integration. + XRHitTestSubscriptionResultsData? hit_test_subscription_results; }; enum VRDisplayEventReason { @@ -478,6 +519,11 @@ FAILURE = 1, }; +enum SubscribeToHitTestResult { + SUCCESS = 0, + FAILURE_GENERIC = 1, +}; + // Provides functionality for integrating environment information into an // XRSession. For example, some AR sessions would implement hit test to allow // developers to get the information about the world that its sensors supply. @@ -493,6 +539,24 @@ // there was an error. RequestHitTest(XRRay ray) => (array<XRHitResult>? results); + // Establishes a hit test subscription on the device. The subscription results + // will be computed taking into account latest state of the native origin + // identified by passed in |native_origin_information|. I.e., in each frame, + // the ray used to subscribe to hit test will be transformed to device + // coordinate system using the device's current knowledge of the state of the + // native origin. The returned |subscription_id| uniquely identifies the + // subscription within an immersive session. Lifetime of the subscription is + // tied to the lifetime of the immersive session. + SubscribeToHitTest( + XRNativeOriginInformation native_origin_information, XRRay ray) => + (SubscribeToHitTestResult result, uint32 subscription_id); + + // Notifies the device that subscription with the passed in |subscription_id| + // is no longer needed and should be removed. The |subscription_id| must be a + // valid id of a subscription returned by one of the SubscribeToHitTest calls, + // otherwise the call will be ignored. + UnsubscribeFromHitTest(uint32 subscription_id); + // Issues a request to create an anchor attached to a session. // |result| will contain status code of the request. |anchor_id| will be valid // only if the |result| is SUCCESS.
diff --git a/fuchsia/engine/context_provider_impl.cc b/fuchsia/engine/context_provider_impl.cc index 858805b9..a5d9a48 100644 --- a/fuchsia/engine/context_provider_impl.cc +++ b/fuchsia/engine/context_provider_impl.cc
@@ -33,6 +33,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "build/build_config.h" #include "components/viz/common/features.h" #include "content/public/common/content_switches.h" #include "fuchsia/engine/common/web_engine_content_client.h" @@ -103,6 +104,20 @@ return true; } +// Returns true if DRM is supported in current configuration. Currently we +// assume that it is supported on ARM64, but not on x64. +// +// TODO(crbug.com/1013412): Detect support for all features required for +// FuchsiaCdm. Specifically we need to verify that protected memory is supported +// and that mediacodec API provides hardware video decoders. +bool IsFuchsiaCdmSupported() { +#if defined(ARCH_CPU_ARM64) + return true; +#else + return false; +#endif +} + } // namespace const uint32_t ContextProviderImpl::kContextRequestHandleId = @@ -212,7 +227,17 @@ bool enable_widevine = (features & fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM) == fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM; + if (enable_widevine && !IsFuchsiaCdmSupported()) { + LOG(WARNING) << "Widevine is not supported on this device."; + enable_widevine = false; + } + bool enable_playready = params.has_playready_key_system(); + if (enable_playready && !IsFuchsiaCdmSupported()) { + LOG(WARNING) << "PlayReady is not supported on this device."; + enable_playready = false; + } + bool enable_protected_graphics = enable_widevine || enable_playready; if (enable_protected_graphics && !enable_vulkan) {
diff --git a/fuchsia/engine/renderer/web_engine_content_renderer_client.cc b/fuchsia/engine/renderer/web_engine_content_renderer_client.cc index 141f41b..1804d217 100644 --- a/fuchsia/engine/renderer/web_engine_content_renderer_client.cc +++ b/fuchsia/engine/renderer/web_engine_content_renderer_client.cc
@@ -22,8 +22,8 @@ // Returns true if the specified video format can be decoded on hardware. bool IsSupportedHardwareVideoCodec(const media::VideoType& type) { - // TODO(fxb/36000): Replace these hardcoded checks with a query to the - // fuchsia.mediacodec FIDL service. + // TODO(crbug.com/1013412): Replace these hardcoded checks with a query to the + // fuchsia.mediacodec FIDL service when fxb/36000 is resolved. if (type.codec == media::kCodecH264 && type.level <= 41) return true;
diff --git a/headless/test/data/protocol/helpers/virtual-time-controller.js b/headless/test/data/protocol/helpers/virtual-time-controller.js index 1a330dcb5..4928eeb5 100644 --- a/headless/test/data/protocol/helpers/virtual-time-controller.js +++ b/headless/test/data/protocol/helpers/virtual-time-controller.js
@@ -93,6 +93,33 @@ } } + /** + * Capture screenshot of the entire screen and return a 2d graphics context + * that has the resulting screenshot painted. + */ + async captureScreenshot() { + const frameTimeTicks = this.currentFrameTime(); + const screenshotData = + (await this.dp_.HeadlessExperimental.beginFrame( + {frameTimeTicks, screenshot: {format: 'png'}})) + .result.screenshotData; + // Advance virtual time a bit so that next frame timestamp is greater. + this.virtualTimeBase_ += 0.01; + const image = new Image(); + await new Promise(fulfill => { + image.onload = fulfill; + image.src = `data:image/png;base64,${screenshotData}`; + }); + this.testRunner_.log( + `Screenshot size: ${image.naturalWidth} x ${image.naturalHeight}`); + const canvas = document.createElement('canvas'); + canvas.width = image.naturalWidth; + canvas.height = image.naturalHeight; + const ctx = canvas.getContext('2d'); + ctx.drawImage(image, 0, 0); + return ctx; + } + async issueAnimationFrameAndScheduleNextChunk_() { if (this.totalElapsedTime_ > 0 && this.remainingBudget_ > 0) { const remainder = this.totalElapsedTime_ % this.animationFrameInterval_;
diff --git a/headless/test/data/protocol/sanity/renderer-canvas.js b/headless/test/data/protocol/sanity/renderer-canvas.js index dfcea27..f438b69 100644 --- a/headless/test/data/protocol/sanity/renderer-canvas.js +++ b/headless/test/data/protocol/sanity/renderer-canvas.js
@@ -34,41 +34,15 @@ await virtualTimeController.grantInitialTime(500, 1000, null, async () => { - const frameTimeTicks = virtualTimeController.currentFrameTime(); - const screenshotData = - (await dp.HeadlessExperimental.beginFrame( - {frameTimeTicks, screenshot: {format: 'png'}})) - .result.screenshotData; - await logScreenShotData(screenshotData); - testRunner.completeTest(); - } - ); - - function logScreenShotData(pngBase64) { - const image = new Image(); - - let callback; - let promise = new Promise(fulfill => callback = fulfill); - image.onload = function() { - testRunner.log(`Screenshot size: ` - + `${image.naturalWidth} x ${image.naturalHeight}`); - const canvas = document.createElement('canvas'); - canvas.width = image.naturalWidth; - canvas.height = image.naturalHeight; - const ctx = canvas.getContext('2d'); - ctx.drawImage(image, 0, 0); - // Expected rgba @(0,0): 255,255,255,255 + const ctx = await virtualTimeController.captureScreenshot(); const rgba = ctx.getImageData(0, 0, 1, 1).data; testRunner.log(`rgba @(0,0): ${rgba}`); // Expected rgba @(25,25): 255,0,0,255 const rgba2 = ctx.getImageData(25, 25, 1, 1).data; testRunner.log(`rgba @(25,25): ${rgba2}`); - callback(); + testRunner.completeTest(); } + ); - image.src = `data:image/png;base64,${pngBase64}`; - - return promise; - } await frameNavigationHelper.navigate('http://example.com/'); })
diff --git a/headless/test/data/protocol/sanity/renderer-opacity-animation-expected.txt b/headless/test/data/protocol/sanity/renderer-opacity-animation-expected.txt new file mode 100644 index 0000000..e8348d8 --- /dev/null +++ b/headless/test/data/protocol/sanity/renderer-opacity-animation-expected.txt
@@ -0,0 +1,6 @@ +Tests that animating layer transparency produces correct pixels +requested url: http://example.com/ +Screenshot size: 800 x 600 +rgba @(25,25) before animaion started: 255,255,255,255 +Screenshot size: 800 x 600 +rgba @(25,25) after animation started: 1,128,1,255 \ No newline at end of file
diff --git a/headless/test/data/protocol/sanity/renderer-opacity-animation.js b/headless/test/data/protocol/sanity/renderer-opacity-animation.js new file mode 100644 index 0000000..7cb6995 --- /dev/null +++ b/headless/test/data/protocol/sanity/renderer-opacity-animation.js
@@ -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. + +(async function(testRunner) { + let {page, session, dp} = await testRunner.startWithFrameControl( + 'Tests that animating layer transparency produces correct pixels'); + + await dp.Runtime.enable(); + await dp.HeadlessExperimental.enable(); + + let RendererTestHelper = + await testRunner.loadScript('../helpers/renderer-test-helper.js'); + let {httpInterceptor, frameNavigationHelper, virtualTimeController} = + await (new RendererTestHelper(testRunner, dp, page)).init(); + + // Animate the opacity of the div from 0 to 1 after a 1s delay. + httpInterceptor.addResponse( + `http://example.com/`, + `<style> + body { margin: 0 } + div { + animation-delay: 1s; + opacity: 0; + animation-name: animation; + animation-fill-mode: forwards; + animation-duration: 1s; + background-color: green; + width: 100vw; + height: 100vh; + } + @keyframes animation { + 0% { opacity: 1; } + 100% { opacity: 1; } + } + </style> + <div></div>`); + + let ctx = await new Promise(async fulfill => { + // Give page 500ms before capturing first screenshot. The screenshot + // should fall into animamtion-delay interval, so no animation effects + // should be present and the point shoule be white. + await virtualTimeController.grantInitialTime(500, 100, + null, + async () => fulfill(await virtualTimeController.captureScreenshot()) + ); + frameNavigationHelper.navigate('http://example.com/'); + }); + let rgba = ctx.getImageData(25, 25, 1, 1).data; + testRunner.log(`rgba @(25,25) before animaion started: ${rgba}`); + // After additional 550ms, the animation should have started and the test + // point shoule be green. + await new Promise(fulfill => virtualTimeController.grantTime(550, fulfill)); + ctx = await virtualTimeController.captureScreenshot(); + rgba = ctx.getImageData(25, 25, 1, 1).data; + testRunner.log(`rgba @(25,25) after animation started: ${rgba}`); + testRunner.completeTest(); + })
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc index e984333..707d495 100644 --- a/headless/test/headless_protocol_browsertest.cc +++ b/headless/test/headless_protocol_browsertest.cc
@@ -422,4 +422,7 @@ "sanity/renderer-css-url-filter.js") HEADLESS_PROTOCOL_COMPOSITOR_TEST(RendererCanvas, "sanity/renderer-canvas.js") +HEADLESS_PROTOCOL_COMPOSITOR_TEST(RendererOpacityAnimation, + "sanity/renderer-opacity-animation.js") + } // namespace headless
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 9029121..0e589f1 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -2167,7 +2167,7 @@ builders { mixins: "ios-ci" name: "ios-simulator-xcode-clang" } builders { mixins: "ios-ci" name: "ios-slimnav" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios-simulator-cronet" } - builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios12-beta-simulator" } + builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios-webkit-tot" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-beta-simulator" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-sdk-device" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-sdk-simulator" } @@ -4669,7 +4669,6 @@ builders { mixins: "ios-try" name: "ios-device-xcode-clang" } builders { mixins: "ios-try" name: "ios-simulator" } builders { mixins: "ios-try" name: "ios-simulator-cronet" } - builders { mixins: "ios-try" name: "ios12-beta-simulator" } builders { mixins: "ios-try" name: "ios13-beta-simulator" } builders { mixins: "ios-try" name: "ios13-sdk-simulator" } builders { mixins: "ios-try" name: "ios-simulator-full-configs" }
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 9029121..0e589f1 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -2167,7 +2167,7 @@ builders { mixins: "ios-ci" name: "ios-simulator-xcode-clang" } builders { mixins: "ios-ci" name: "ios-slimnav" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios-simulator-cronet" } - builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios12-beta-simulator" } + builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios-webkit-tot" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-beta-simulator" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-sdk-device" } builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios13-sdk-simulator" } @@ -4669,7 +4669,6 @@ builders { mixins: "ios-try" name: "ios-device-xcode-clang" } builders { mixins: "ios-try" name: "ios-simulator" } builders { mixins: "ios-try" name: "ios-simulator-cronet" } - builders { mixins: "ios-try" name: "ios12-beta-simulator" } builders { mixins: "ios-try" name: "ios13-beta-simulator" } builders { mixins: "ios-try" name: "ios13-sdk-simulator" } builders { mixins: "ios-try" name: "ios-simulator-full-configs" }
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index 5f23b67..47f6edc 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -2319,9 +2319,9 @@ category: "goma|ios" } builders { - name: "buildbucket/luci.chromium.ci/ios12-beta-simulator" - category: "iOS|iOS12" - short_name: "beta" + name: "buildbucket/luci.chromium.ci/ios-webkit-tot" + category: "iOS" + short_name: "wk" } builders { name: "buildbucket/luci.chromium.ci/ios13-sdk-device" @@ -4559,9 +4559,6 @@ name: "buildbucket/luci.chromium.try/ios-simulator-xcode-clang" } builders { - name: "buildbucket/luci.chromium.try/ios12-beta-simulator" - } - builders { name: "buildbucket/luci.chromium.try/ios13-beta-simulator" } builders { @@ -5401,11 +5398,6 @@ short_name: "slim" } builders { - name: "buildbucket/luci.chromium.ci/ios12-beta-simulator" - category: "chromium.fyi|12" - short_name: "beta" - } - builders { name: "buildbucket/luci.chromium.ci/ios13-sdk-device" category: "chromium.fyi|13" short_name: "dev"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index 52555b7..31e3e15 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg
@@ -362,7 +362,6 @@ triggers: "ios-simulator-noncq" triggers: "ios-simulator-xcode-clang" triggers: "ios-slimnav" - triggers: "ios12-beta-simulator" triggers: "ios13-beta-simulator" triggers: "ios13-sdk-device" triggers: "ios13-sdk-simulator" @@ -1362,12 +1361,13 @@ } job { - id: "ios12-beta-simulator" + id: "ios-webkit-tot" acl_sets: "default" + schedule: "0 1-23/6 * * *" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "ios12-beta-simulator" + builder: "ios-webkit-tot" } }
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index 5f23b67..47f6edc 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg
@@ -2319,9 +2319,9 @@ category: "goma|ios" } builders { - name: "buildbucket/luci.chromium.ci/ios12-beta-simulator" - category: "iOS|iOS12" - short_name: "beta" + name: "buildbucket/luci.chromium.ci/ios-webkit-tot" + category: "iOS" + short_name: "wk" } builders { name: "buildbucket/luci.chromium.ci/ios13-sdk-device" @@ -4559,9 +4559,6 @@ name: "buildbucket/luci.chromium.try/ios-simulator-xcode-clang" } builders { - name: "buildbucket/luci.chromium.try/ios12-beta-simulator" - } - builders { name: "buildbucket/luci.chromium.try/ios13-beta-simulator" } builders { @@ -5401,11 +5398,6 @@ short_name: "slim" } builders { - name: "buildbucket/luci.chromium.ci/ios12-beta-simulator" - category: "chromium.fyi|12" - short_name: "beta" - } - builders { name: "buildbucket/luci.chromium.ci/ios13-sdk-device" category: "chromium.fyi|13" short_name: "dev"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg index 52555b7..31e3e15 100644 --- a/infra/config/luci-scheduler.cfg +++ b/infra/config/luci-scheduler.cfg
@@ -362,7 +362,6 @@ triggers: "ios-simulator-noncq" triggers: "ios-simulator-xcode-clang" triggers: "ios-slimnav" - triggers: "ios12-beta-simulator" triggers: "ios13-beta-simulator" triggers: "ios13-sdk-device" triggers: "ios13-sdk-simulator" @@ -1362,12 +1361,13 @@ } job { - id: "ios12-beta-simulator" + id: "ios-webkit-tot" acl_sets: "default" + schedule: "0 1-23/6 * * *" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "ios12-beta-simulator" + builder: "ios-webkit-tot" } }
diff --git a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json b/ios/build/bots/chromium.fyi/ios-webkit-tot.json similarity index 98% rename from ios/build/bots/chromium.fyi/ios12-beta-simulator.json rename to ios/build/bots/chromium.fyi/ios-webkit-tot.json index 9ba6335..6ca32bf 100644 --- a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json +++ b/ios/build/bots/chromium.fyi/ios-webkit-tot.json
@@ -12,6 +12,7 @@ "target_os=\"ios\"", "use_goma=true" ], + "configuration": "Debug", "tests": [ { "include": "common_tests.json", @@ -45,7 +46,6 @@ "test args": [ "--run-with-custom-webkit" ] - }, { "include": "eg_cq_tests.json", @@ -90,7 +90,6 @@ "test args": [ "--run-with-custom-webkit" ] - }, { "include": "eg_cq_tests.json",
diff --git a/ios/build/bots/chromium.mac/ios12-beta-simulator.json b/ios/build/bots/chromium.mac/ios12-beta-simulator.json deleted file mode 100644 index f9f6224..0000000 --- a/ios/build/bots/chromium.mac/ios12-beta-simulator.json +++ /dev/null
@@ -1,20 +0,0 @@ -{ - "comments": [ - "Run tests on iOS12beta track on 64-bit iOS 12 simulators.", - "Note: Xcode 10 requires OSX 10.13.4 hence 'host os'", - "Note: This file exists only to support the trybot.", - "It should be kept in sync with the CI configuration in ../chromium.fyi/." - ], - "xcode build version": "10b61", - "gn_args": [ - "goma_dir=\"$(goma_dir)\"", - "is_component_build=false", - "is_debug=true", - "symbol_level=1", - "target_cpu=\"x64\"", - "target_os=\"ios\"", - "use_goma=true" - ], - "tests": [ - ] -}
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc index 6a43bc0..c1a404d 100644 --- a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc +++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -12,7 +12,6 @@ #include "components/dom_distiller/core/article_entry.h" #include "components/dom_distiller/core/distiller.h" #include "components/dom_distiller/core/dom_distiller_service.h" -#include "components/dom_distiller/core/dom_distiller_store.h" #include "components/dom_distiller/ios/distiller_page_factory_ios.h" #include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" @@ -31,13 +30,11 @@ public dom_distiller::DomDistillerService { public: DomDistillerKeyedService( - std::unique_ptr<dom_distiller::DomDistillerStoreInterface> store, std::unique_ptr<dom_distiller::DistillerFactory> distiller_factory, std::unique_ptr<dom_distiller::DistillerPageFactory> distiller_page_factory, std::unique_ptr<dom_distiller::DistilledPagePrefs> distilled_page_prefs) - : DomDistillerService(std::move(store), - std::move(distiller_factory), + : DomDistillerService(std::move(distiller_factory), std::move(distiller_page_factory), std::move(distilled_page_prefs)) {} @@ -90,7 +87,7 @@ ios::ChromeBrowserState::FromBrowserState(context)->GetPrefs()); return std::make_unique<DomDistillerKeyedService>( - nullptr, std::move(distiller_factory), std::move(distiller_page_factory), + std::move(distiller_factory), std::move(distiller_page_factory), std::move(distilled_page_prefs)); }
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm index 1e5cb1c..23745d8 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl.mm +++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -1107,6 +1107,16 @@ } } + // TODO(crbug.com/1003680) This seems to happen if a restored navigation fails + // provisionally before the NavigationContext associates with the original + // navigation. Rather than expose the internal placeholder to the UI and to + // URL-sensing components outside of //ios/web layer, set virtual URL to the + // placeholder original URL here. + if (wk_navigation_util::IsPlaceholderUrl(url)) { + new_item->SetVirtualURL( + wk_navigation_util::ExtractUrlFromPlaceholderUrl(url)); + } + SetNavigationItemInWKItem(wk_item, std::move(new_item)); return GetNavigationItemFromWKItem(wk_item); }
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm index 4b3fd23..6bbaad20 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm +++ b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
@@ -754,6 +754,19 @@ EXPECT_EQ(url, item->GetURL()); } +// Tests that the virtual URL of a placeholder item is updated to the original +// URL. +TEST_F(WKBasedNavigationManagerTest, HideInternalPlaceholderUrl) { + GURL original_url = GURL("http://www.1.com?query=special%26chars"); + GURL url = wk_navigation_util::CreatePlaceholderUrlForUrl(original_url); + NSString* url_spec = base::SysUTF8ToNSString(url.spec()); + [mock_wk_list_ setCurrentURL:url_spec]; + NavigationItem* item = manager_->GetItemAtIndex(0); + ASSERT_TRUE(item); + EXPECT_EQ(original_url, item->GetVirtualURL()); + EXPECT_EQ(url, item->GetURL()); +} + // Tests that all NavigationManager APIs return reasonable values in the Empty // Window Open Navigation edge case. See comments in header file for details. TEST_F(WKBasedNavigationManagerTest, EmptyWindowOpenNavigation) {
diff --git a/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json index e51f5bd..d5c127d 100644 --- a/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json +++ b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
@@ -1,212 +1,196 @@ { "win": { - "css_value_type_shadow": { - "avg": 51.69078, - "ci_095": 8.021214076 + "balls_css_transition_2_properties": { + "avg": 107.983, + "ci_095": 100 }, - "yahoo_sports_2018": { - "avg": 17.91754, - "ci_095": 1.7831799 + "many_planets_deep": { + "avg": 25.015, + "ci_095": 100 }, - "mix_10k": { - "avg": 29.339723, - "ci_095": 3.462980077 + "web_animation_value_type_transform_complex": { + "avg": 42.981, + "ci_095": 100 }, - "microsoft_fish_ie_tank": { - "avg": 17.15968, - "ci_095": 2.448468729 + "nvidia_vertex_buffer_object": { + "avg": 25.166, + "ci_095": 100 }, - "css_animations_staggered_infinite_iterations": { - "avg": 17.53428, - "ci_095": 1.15466265 + "runway": { + "avg": 74.211, + "ci_095": 100 }, - "pinterest_2018": { - "avg": 17.17876, - "ci_095": 1.990684136 + "css_animations_simultaneous_inline_style": { + "avg": 25.100, + "ci_095": 100 }, - "background_color_animation_with_gradient": { - "avg": 18.91196, - "ci_095": 5.3955209 + "aquarium_20k": { + "avg": 113.156, + "ci_095": 100 }, - "motion_mark_canvas_fill_shapes": { - "avg": 35.30084, - "ci_095": 3.092656437 + "canvas_to_blob": { + "avg": 39.239, + "ci_095": 100 }, - "particles": { - "avg": 16.683, - "ci_095": 0.4367177926 + "cc_poster_circle": { + "avg": 25.111, + "ci_095": 100 }, - "second_batch_js_light": { - "avg": 19.81702, - "ci_095": 10.392606 + "js_poster_circle": { + "avg": 25.016, + "ci_095": 100 }, - "microsoft_video_city": { - "avg": 17.49898, - "ci_095": 1.506935193 - }, - "infinite_scroll_root_fixed_n_layers_99": { - "avg": 16.80068, - "ci_095": 0.9999470106 - }, - "css_value_type_length_complex": { - "avg": 36.60576, - "ci_095": 3.783401913 - }, - "css_opacity_plus_n_layers_99": { - "avg": 16.681, - "ci_095": 0.49490275 - }, - "canvas_90000_pixels_per_second": { - "avg": 16.68387, - "ci_095": 2.985124255 - }, - "google_web_search_2018": { - "avg": 16.95106, - "ci_095": 1.387013433 + "web_animations_staggered_triggering_page": { + "avg": 25.033, + "ci_095": 100 }, "aquarium": { - "avg": 17.68626, - "ci_095": 1.080606843 + "avg": 25.014, + "ci_095": 100 + }, + "css_value_type_shadow": { + "avg": 31.638, + "ci_095": 100 + }, + "filter_terrain_svg": { + "avg": 41.496, + "ci_095": 100 + }, + "css_transitions_inline_style": { + "avg": 25.312, + "ci_095": 100 } }, "mac": { - "yuv_decoding": { - "avg": 92.465, - "ci_095": 36.599 + "mix_blend_mode_animation_screen": { + "avg": 148.760, + "ci_095": 100 }, - "canvas_animation_no_clear": { - "avg": 18.323, - "ci_095": 1.239 + "twitch_2018": { + "avg": 28.110, + "ci_095": 100 }, - "compositor_heavy_animation": { - "avg": 36.002, - "ci_095": 3.635 + "balls_javascript_canvas": { + "avg": 40.563, + "ci_095": 100 }, - "web_animation_value_type_length_3d": { - "avg": 40.999, - "ci_095": 1.897 + "transform_transitions_js_block": { + "avg": 25.090, + "ci_095": 100 }, - "stroke_shapes": { - "avg": 60.378, - "ci_095": 2.860 - }, - "wordpress_2018": { - "avg": 16.980, - "ci_095": 0.477 - }, - "web_animation_value_type_path": { - "avg": 33.060, - "ci_095": 2.225 - }, - "web_animations_many_keyframes": { - "avg": 20.543, - "ci_095": 1.602 - }, - "twitter_pinch_2018": { - "avg": 20.395, - "ci_095": 5.386 - }, - "web_animation_value_type_length_complex": { - "avg": 39.018, - "ci_095": 2.856 - }, - "smash_cat": { - "avg": 16.748, - "ci_095": 0.772 - }, - "cc_poster_circle": { - "avg": 16.697, - "ci_095": 0.166 - }, - "infinite_scroll_root_fixed_n_layers_99": { - "avg": 16.760, - "ci_095": 1.100 - }, - "amazon_pinch_2018": { - "avg": 21.250, - "ci_095": 7.103 - }, - "youtube_pinch_2018": { - "avg": 21.467, - "ci_095": 7.431 - }, - "earth": { - "avg": 16.687, - "ci_095": 0.284 - }, - "css_value_type_shadow": { - "avg": 76.775, - "ci_095": 16.809 - }, - "js_opacity_plus_n_layers_99": { - "avg": 16.725, - "ci_095": 0.200 + "web_animations_staggered_infinite_iterations": { + "avg": 25.006, + "ci_095": 100 }, "fill_shapes": { - "avg": 43.377, - "ci_095": 3.220 + "avg": 41.667, + "ci_095": 100 }, - "raf": { - "avg": 16.692, - "ci_095": 0.218 + "css_value_type_shadow": { + "avg": 69.304, + "ci_095": 100 }, - "canvas_lines": { - "avg": 25.519, - "ci_095": 0.866 + "animometer_webgl_attrib_arrays": { + "avg": 27.124, + "ci_095": 100 }, - "megi_dish": { - "avg": 114.515, - "ci_095": 41.168 + "web_animation_value_type_transform_simple": { + "avg": 55.002, + "ci_095": 100 + }, + "canvas_05000_pixels_per_second": { + "avg": 24.997, + "ci_095": 100 + }, + "bouncing_clipped_rectangles": { + "avg": 592.146, + "ci_095": 100 + }, + "ie_chalkboard": { + "avg": 68.514, + "ci_095": 100 + }, + "new_tilings": { + "avg": 31.733, + "ci_095": 100 + }, + "chip_tune": { + "avg": 25.006, + "ci_095": 100 + }, + "extra_large_texture_uploads": { + "avg": 77.757, + "ci_095": 100 + }, + "css_value_type_filter": { + "avg": 92.894, + "ci_095": 100 } }, "android": { - "motionmark_html_css_bouncing_blend_circles_25": { - "avg": 48.35483, - "ci_095": 3.21386 + "mix_blend_mode_animation_screen": { + "avg": 400.414, + "ci_095": 100 }, - "yahoo_news_desktop_gpu_raster_2018": { - "avg": 66.0, - "ci_095": 7.0 + "twitch_2018": { + "avg": 34.498, + "ci_095": 100 }, - "microsoft_performance": { - "avg": 30.8767, - "ci_095": 3.40595 + "balls_javascript_canvas": { + "avg": 276.974, + "ci_095": 100 }, - "geo_apis": { - "avg": 17, - "ci_095": 0.5 + "transform_transitions_js_block": { + "avg": 25.179, + "ci_095": 100 }, - "kevs_3d": { - "avg": 46.79165, - "ci_095": 40.90851 + "web_animations_staggered_infinite_iterations": { + "avg": 48.752, + "ci_095": 100 }, - "ie_pirate_mark": { - "avg": 27.96598, - "ci_095": 6.35233 + "text_10000_pixels_per_second": { + "avg": 25.470, + "ci_095": 100 }, - "linkedin_mobile_pinch": { - "avg": 23.64056, - "ci_095": 10.45832 + "motion_mark_canvas_fill_shapes": { + "avg": 243.536, + "ci_095": 100 }, - "text_constant_full_page_raster_10000_pixels_per_second": { - "avg": 16.68138, - "ci_095": 0.52503 + "css_value_type_shadow": { + "avg": 591.356, + "ci_095": 100 }, - "canvas_10000_pixels_per_second": { - "avg": 16.76975, - "ci_095": 0.68845 + "animometer_webgl_attrib_arrays": { + "avg": 337.719, + "ci_095": 300 }, - "canvas_20000_pixels_per_second": { - "avg": 16.77075, - "ci_095": 0.63189 + "canvas_05000_pixels_per_second": { + "avg": 25.322, + "ci_095": 100 }, - "canvas_40000_pixels_per_second": { - "avg": 16.86242, - "ci_095": 0.73009 + "bouncing_clipped_rectangles": { + "avg": 481.911, + "ci_095": 100 }, - "canvas_75000_pixels_per_second": { - "avg": 16.98984, - "ci_095": 0.88247 + "ie_chalkboard": { + "avg": 217.131, + "ci_095": 100 + }, + "new_tilings": { + "avg": 25.052, + "ci_095": 100 + }, + "extra_large_texture_uploads": { + "avg": 452.959, + "ci_095": 100 + }, + "web_animation_value_type_transform_simple": { + "avg": 331.928, + "ci_095": 100 + }, + "css_value_type_filter": { + "avg": 909.449, + "ci_095": 100 } } } \ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 276614b..6523bc4 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -766,24 +766,6 @@ ] } ], - "AutofillEnableToolbarStatusChip": [ - { - "platforms": [ - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "AutofillCreditCardUploadFeedback", - "AutofillEnableToolbarStatusChip" - ] - } - ] - } - ], "AutofillFieldMetadata": [ { "platforms": [ @@ -1974,11 +1956,11 @@ "DefaultPassthroughCommandDecoder": [ { "platforms": [ - "windows" + "linux" ], "experiments": [ { - "name": "Enabled", + "name": "Enabled_20191004", "enable_features": [ "DefaultPassthroughCommandDecoder" ] @@ -2852,24 +2834,6 @@ ] } ], - "GridLayoutForNtpShortcuts": [ - { - "platforms": [ - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "GridLayoutForNtpShortcuts" - ] - } - ] - } - ], "GwpAsanAndroid": [ { "platforms": [ @@ -6701,11 +6665,7 @@ "VizHitTest": [ { "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "windows" + "chromeos" ], "experiments": [ {
diff --git a/third_party/blink/public/mojom/cache_storage/cache_storage.mojom b/third_party/blink/public/mojom/cache_storage/cache_storage.mojom index ffac72e..da1c6bd 100644 --- a/third_party/blink/public/mojom/cache_storage/cache_storage.mojom +++ b/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
@@ -5,6 +5,7 @@ module blink.mojom; import "mojo/public/mojom/base/read_only_buffer.mojom"; +import "third_party/blink/public/mojom/blob/blob.mojom"; import "third_party/blink/public/mojom/fetch/fetch_api_response.mojom"; import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom"; import "mojo/public/mojom/base/string16.mojom"; @@ -76,11 +77,20 @@ pending_associated_remote<CacheStorageCache> cache; }; +// EagerResponse: A blob response where the source has eagerly started reading +// the body into a DataPipe. +struct EagerResponse { + blink.mojom.FetchAPIResponse response; + handle<data_pipe_consumer> pipe; + pending_receiver<BlobReaderClient> client_receiver; +}; + // Result of Match for both interfaces CacheStorage and CacheStorageCache // method. |status| is only set if there is a failure. union MatchResult { CacheStorageError status; blink.mojom.FetchAPIResponse response; + EagerResponse eager_response; }; // Result of MatchAll method |status| is only set if there is a failure. @@ -100,8 +110,11 @@ // defined on spec: https://w3c.github.io/ServiceWorker/#cache-interface interface CacheStorageCache { // Returns the first cached response that matches |request| according to - // options specified on |query_options|. - Match(blink.mojom.FetchAPIRequest request, CacheQueryOptions query_options, int64 trace_id) + // options specified on |query_options|. |in_related_fetch_event| will be + // true if the operation was initiated within a FetchEvent handler with + // a matching request URL. + Match(blink.mojom.FetchAPIRequest request, CacheQueryOptions query_options, + bool in_related_fetch_event, int64 trace_id) => (MatchResult result); // Returns all cached responses that match |request| according to options @@ -133,8 +146,10 @@ // Returns the first cached response that matches |request| and // |match_options|. It can search on all caches if |cache_name| isn't provided - // on |match_options|. - Match(blink.mojom.FetchAPIRequest request, MultiCacheQueryOptions match_options, int64 trace_id) + // on |match_options|. |in_related_fetch_event| will be true if the operation + // was initiated within a FetchEvent handler with a matching request URL. + Match(blink.mojom.FetchAPIRequest request, MultiCacheQueryOptions match_options, + bool in_related_fetch_event, int64 trace_id) => (MatchResult result); // Opens and returns a mojo interface to a cache, it creates if doesn't exist.
diff --git a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom index 34ea2a4..2d9be3f 100644 --- a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom +++ b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
@@ -60,9 +60,15 @@ // set of headers that should be exposed. array<string> cors_exposed_header_names; - // Side data is used to pass the metadata of the response (eg. V8 code cache). + // Used to pass code cache for responses produced by cache_storage. The code + // cache will be stored in the side data stream of the blob. SerializedBlob? side_data_blob; + // Used to pass code cache for a response that is being newly stored in + // cache_storage. This blob is created from a memory buffer in the renderer + // and the code cache is contained in the primary data stream of the blob. + SerializedBlob? side_data_blob_for_cache_put; + // In case this response had a Content-Security-Policy header, this is the // parsed CSP. network.mojom.ContentSecurityPolicy? content_security_policy;
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h index 66e8a6d..2e0a8fae 100644 --- a/third_party/blink/public/platform/web_runtime_features.h +++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -196,6 +196,7 @@ BLINK_PLATFORM_EXPORT static void EnableWebXRARModule(bool); BLINK_PLATFORM_EXPORT static void EnableWebXRARDOMOverlay(bool); BLINK_PLATFORM_EXPORT static void EnableWebXRAnchors(bool); + BLINK_PLATFORM_EXPORT static void EnableWebXrGamepadModule(bool); BLINK_PLATFORM_EXPORT static void EnableWebXRHitTest(bool); BLINK_PLATFORM_EXPORT static void EnableWebXRPlaneDetection(bool); BLINK_PLATFORM_EXPORT static void EnableXSLT(bool);
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index 78e31941..2ca537f6 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -63,6 +63,7 @@ #include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/html_body_element.h" +#include "third_party/blink/renderer/core/html/html_html_element.h" #include "third_party/blink/renderer/core/html/html_iframe_element.h" #include "third_party/blink/renderer/core/html/html_link_element.h" #include "third_party/blink/renderer/core/html/html_slot_element.h" @@ -1753,6 +1754,7 @@ ancestor->ClearChildNeedsStyleRecalc(); } style_recalc_root_.Clear(); + PropagateWritingModeAndDirectionToHTMLRoot(); } void StyleEngine::RebuildLayoutTree() { @@ -1982,6 +1984,12 @@ IsViewportStyleDirty(); } +void StyleEngine::PropagateWritingModeAndDirectionToHTMLRoot() { + if (HTMLHtmlElement* root_element = + DynamicTo<HTMLHtmlElement>(GetDocument().documentElement())) + root_element->PropagateWritingModeAndDirectionFromBody(); +} + void StyleEngine::Trace(blink::Visitor* visitor) { visitor->Trace(document_); visitor->Trace(injected_user_style_sheets_);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h index 1580b590..200011e 100644 --- a/third_party/blink/renderer/core/css/style_engine.h +++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -463,6 +463,7 @@ bool SupportsDarkColorScheme(); void ViewportDefiningElementDidChange(); + void PropagateWritingModeAndDirectionToHTMLRoot(); Member<Document> document_; bool is_master_;
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index 1f4f17e..737f44d 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -2277,4 +2277,24 @@ EXPECT_EQ(outer, GetStyleRecalcRoot()); } +TEST_F(StyleEngineTest, RecalcPropagatedWritingMode) { + GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kWritingMode, + "vertical-lr"); + + UpdateAllLifecyclePhases(); + + // Make sure that recalculating style for the root element does not trigger a + // visual diff that requires layout. That is, we take the body -> root + // propagation of writing-mode into account before setting ComputedStyle on + // the root LayoutObject. + GetDocument().documentElement()->SetInlineStyleProperty( + CSSPropertyID::kWritingMode, "horizontal-tb"); + + GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc); + GetDocument().GetStyleEngine().RecalcStyle(); + + EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild()); + EXPECT_FALSE(GetDocument().View()->NeedsLayout()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc index 077c8c7..4ef3089 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -118,7 +118,9 @@ return; } - bool should_observe = IsLocked() && IsActivatable() && ConnectedToView(); + bool should_observe = IsLocked() && + IsActivatable(DisplayLockActivationReason::kViewport) && + ConnectedToView(); if (should_observe && !is_observed_) { document_->RegisterDisplayLockActivationObservation(element_); } else if (!should_observe && is_observed_) { @@ -127,14 +129,16 @@ is_observed_ = should_observe; } -void DisplayLockContext::SetActivatable(bool activatable) { +void DisplayLockContext::SetActivatable(unsigned char activatable_mask) { if (IsLocked()) { - // If we're locked, the activatable flag might change the activation + // If we're locked, the activatable mask might change the activation // blocking lock count. If we're not locked, the activation blocking lock // count will be updated when we changed the state. - state_.UpdateActivationBlockingCount(activatable_, activatable); + // Note that we record this only if we're blocking all activation. That is, + // the lock is considered activatable if any bit is set. + state_.UpdateActivationBlockingCount(activatable_mask_, activatable_mask); } - activatable_ = activatable; + activatable_mask_ = activatable_mask; UpdateActivationObservationIfNeeded(); } @@ -367,8 +371,10 @@ // This is here for symmetry, but could be removed if necessary. } -bool DisplayLockContext::IsActivatable() const { - return activatable_ || !IsLocked(); +bool DisplayLockContext::IsActivatable( + DisplayLockActivationReason reason) const { + return !IsLocked() || + (activatable_mask_ & static_cast<unsigned char>(reason)); } void DisplayLockContext::CommitForActivationWithSignal( @@ -384,7 +390,7 @@ DCHECK(element_); DCHECK(ConnectedToView()); - DCHECK(ShouldCommitForActivation()); + DCHECK(ShouldCommitForActivation(DisplayLockActivationReason::kAny)); StartCommit(); // Since setting the attribute might trigger a commit if we are still locked, // we set it after we start the commit. @@ -392,8 +398,9 @@ element_->setAttribute(html_names::kRendersubtreeAttr, ""); } -bool DisplayLockContext::ShouldCommitForActivation() const { - return IsActivatable() && IsLocked(); +bool DisplayLockContext::ShouldCommitForActivation( + DisplayLockActivationReason reason) const { + return IsActivatable(reason) && IsLocked(); } void DisplayLockContext::DidAttachLayoutTree() { @@ -655,7 +662,7 @@ document_->View()->RegisterForLifecycleNotifications(this); } - if (!IsActivatable()) { + if (!IsActivatable(DisplayLockActivationReason::kAny)) { old_document.RemoveActivationBlockingDisplayLock(); document_->AddActivationBlockingDisplayLock(); } @@ -859,7 +866,8 @@ "LockedDisplayLock", this); } - bool was_activatable = context_->IsActivatable(); + bool was_activatable = + context_->IsActivatable(DisplayLockActivationReason::kAny); bool was_locked = context_->IsLocked(); state_ = new_state; @@ -872,7 +880,9 @@ if (!context_->document_) return *this; - UpdateActivationBlockingCount(was_activatable, context_->IsActivatable()); + UpdateActivationBlockingCount( + was_activatable, + context_->IsActivatable(DisplayLockActivationReason::kAny)); // Adjust the total number of locked display locks. auto& document = *context_->document_;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h index f429d05..0484345 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -21,6 +21,25 @@ class DisplayLockScopedLogger; enum class DisplayLockLifecycleTarget { kSelf, kChildren }; +enum class DisplayLockActivationReason { + // This represents activations triggered by intersection observer when the + // element intersects the viewport. + kViewport = 1 << 0, + // This represents activations triggered by script or user actions, such as + // find-in-page or scrollIntoView(). + kUser = 1 << 1, + // This represents any activation, and should be result of all other flags + // combined. + kAny = + static_cast<unsigned char>(kViewport) | static_cast<unsigned char>(kUser) +}; + +// Instead of specifying an underlying type, which would propagate throughout +// forward declarations, we static assert that the activation reasons enum is +// small. +static_assert(static_cast<int>(DisplayLockActivationReason::kAny) < + std::numeric_limits<unsigned char>::max(), + "DisplayLockActivationReason is too large"); class CORE_EXPORT DisplayLockContext final : public GarbageCollected<DisplayLockContext>, @@ -93,7 +112,8 @@ // ContextLifecycleObserver overrides. void ContextDestroyed(ExecutionContext*) override; - void SetActivatable(bool activatable); + // Set which reasons activate, as a mask of DisplayLockActivationReason enums. + void SetActivatable(unsigned char activatable_mask); // Acquire the lock, should only be called when unlocked. void StartAcquire(); @@ -119,8 +139,10 @@ } // Returns true if the contents of the associated element should be visible - // from and activatable by find-in-page, tab order, anchor links, etc. - bool IsActivatable() const; + // from and activatable by a specified reason. Note that passing + // kAny will return true if the lock is activatable for any + // reason. + bool IsActivatable(DisplayLockActivationReason reason) const; // Trigger commit because of activation from tab order, url fragment, // find-in-page, scrolling, etc. @@ -128,7 +150,7 @@ // activated element. void CommitForActivationWithSignal(Element* activated_element); - bool ShouldCommitForActivation() const; + bool ShouldCommitForActivation(DisplayLockActivationReason reason) const; // Returns true if this lock is locked. Note from the outside perspective, the // lock is locked any time the state is not kUnlocked or kCommitting. @@ -304,7 +326,6 @@ StateChangeHelper state_; bool update_forced_ = false; - bool activatable_ = false; StyleType blocked_style_traversal_type_ = kStyleUpdateNotRequired; // Signifies whether we've blocked a layout tree reattachment on |element_|'s @@ -325,6 +346,9 @@ // Tracks whether the element associated with this lock is being tracked by a // document level intersection observer. bool is_observed_ = false; + + unsigned char activatable_mask_ = + static_cast<unsigned char>(DisplayLockActivationReason::kAny); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index 1084802..371d8a0 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -131,8 +131,8 @@ bool update_lifecycle = true) { StringBuilder value; value.Append("invisible"); - if (activatable) - value.Append(" activatable"); + if (!activatable) + value.Append(" skip-activation"); element.setAttribute(html_names::kRendersubtreeAttr, value.ToAtomicString()); if (update_lifecycle) @@ -706,8 +706,10 @@ auto* host = GetDocument().getElementById("shadowHost"); auto* slotted = GetDocument().getElementById("slotted"); - ASSERT_FALSE(host->DisplayLockPreventsActivation()); - ASSERT_FALSE(slotted->DisplayLockPreventsActivation()); + ASSERT_FALSE( + host->DisplayLockPreventsActivation(DisplayLockActivationReason::kAny)); + ASSERT_FALSE(slotted->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); ShadowRoot& shadow_root = host->AttachShadowRootInternal(ShadowRootType::kOpen); @@ -717,17 +719,23 @@ UpdateAllLifecyclePhasesForTest(); auto* container = shadow_root.getElementById("container"); - EXPECT_FALSE(host->DisplayLockPreventsActivation()); - EXPECT_FALSE(container->DisplayLockPreventsActivation()); - EXPECT_FALSE(slotted->DisplayLockPreventsActivation()); + EXPECT_FALSE( + host->DisplayLockPreventsActivation(DisplayLockActivationReason::kAny)); + EXPECT_FALSE(container->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); + EXPECT_FALSE(slotted->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); LockElement(*container, false, false); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1); - EXPECT_FALSE(host->DisplayLockPreventsActivation()); - EXPECT_TRUE(container->DisplayLockPreventsActivation()); - EXPECT_TRUE(slotted->DisplayLockPreventsActivation()); + EXPECT_FALSE( + host->DisplayLockPreventsActivation(DisplayLockActivationReason::kAny)); + EXPECT_TRUE(container->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); + EXPECT_TRUE(slotted->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); // Ensure that we resolve the acquire callback, thus finishing the acquire // step. @@ -737,17 +745,23 @@ EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_FALSE(host->DisplayLockPreventsActivation()); - EXPECT_FALSE(container->DisplayLockPreventsActivation()); - EXPECT_FALSE(slotted->DisplayLockPreventsActivation()); + EXPECT_FALSE( + host->DisplayLockPreventsActivation(DisplayLockActivationReason::kAny)); + EXPECT_FALSE(container->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); + EXPECT_FALSE(slotted->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); UpdateAllLifecyclePhasesForTest(); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_FALSE(host->DisplayLockPreventsActivation()); - EXPECT_FALSE(container->DisplayLockPreventsActivation()); - EXPECT_FALSE(slotted->DisplayLockPreventsActivation()); + EXPECT_FALSE( + host->DisplayLockPreventsActivation(DisplayLockActivationReason::kAny)); + EXPECT_FALSE(container->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); + EXPECT_FALSE(slotted->DisplayLockPreventsActivation( + DisplayLockActivationReason::kAny)); } TEST_F(DisplayLockContextTest, @@ -884,35 +898,41 @@ EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable()); + EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); LockElement(*non_activatable, false); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 2); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1); - EXPECT_FALSE(non_activatable->GetDisplayLockContext()->IsActivatable()); + EXPECT_FALSE(non_activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); // Now commit the lock for |non_ctivatable|. CommitElement(*non_activatable); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable()); - EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable()); + EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); + EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); // Re-acquire the lock for |activatable|, but without the activatable flag. LockElement(*activatable, false); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1); - EXPECT_FALSE(activatable->GetDisplayLockContext()->IsActivatable()); + EXPECT_FALSE(activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); // Re-acquire the lock for |activatable| again with the activatable flag. LockElement(*activatable, true); EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable()); + EXPECT_TRUE(activatable->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)); } TEST_F(DisplayLockContextTest, ElementInTemplate) {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc index 763e9ea..88e3fa6 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -28,6 +28,33 @@ return child->GetDocument().GetFrame()->OwnerLayoutObject()->GetNode(); } +bool UpdateStyleAndLayoutForRangeIfNeeded(const EphemeralRangeInFlatTree& range, + DisplayLockActivationReason reason) { + if (range.IsNull() || range.IsCollapsed()) + return false; + if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&range.GetDocument()) || + range.GetDocument().LockedDisplayLockCount() == + range.GetDocument().ActivationBlockingDisplayLockCount()) + return false; + Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_; + for (Node& node : range.Nodes()) { + for (Element* locked_activatable_ancestor : + DisplayLockUtilities::ActivatableLockedInclusiveAncestors(node, + reason)) { + DCHECK(locked_activatable_ancestor->GetDisplayLockContext()); + DCHECK(locked_activatable_ancestor->GetDisplayLockContext()->IsLocked()); + if (locked_activatable_ancestor->GetDisplayLockContext()->UpdateForced()) + break; + scoped_forced_update_list_.push_back( + locked_activatable_ancestor->GetDisplayLockContext() + ->GetScopedForcedUpdate()); + } + } + if (!scoped_forced_update_list_.IsEmpty()) + range.GetDocument().UpdateStyleAndLayout(); + return !scoped_forced_update_list_.IsEmpty(); +} + } // namespace bool DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded( @@ -49,7 +76,8 @@ DCHECK(enclosing_block); DCHECK_EQ(enclosing_block, EnclosingBlock(range.EndPosition(), kCannotCrossEditingBoundary)); - return enclosing_block->ActivateDisplayLockIfNeeded(); + return enclosing_block->ActivateDisplayLockIfNeeded( + DisplayLockActivationReason::kUser); } bool DisplayLockUtilities::ActivateSelectionRangeIfNeeded( @@ -60,7 +88,8 @@ range.GetDocument().LockedDisplayLockCount() == range.GetDocument().ActivationBlockingDisplayLockCount()) return false; - UpdateStyleAndLayoutForRangeIfNeeded(range); + UpdateStyleAndLayoutForRangeIfNeeded(range, + DisplayLockActivationReason::kUser); HeapHashSet<Member<Element>> elements_to_activate; for (Node& node : range.Nodes()) { DCHECK(!node.GetDocument().NeedsLayoutTreeUpdateForNode(node)); @@ -70,39 +99,16 @@ if (auto* nearest_locked_ancestor = NearestLockedExclusiveAncestor(node)) elements_to_activate.insert(nearest_locked_ancestor); } - for (Element* element : elements_to_activate) - element->ActivateDisplayLockIfNeeded(); + for (Element* element : elements_to_activate) { + element->ActivateDisplayLockIfNeeded(DisplayLockActivationReason::kUser); + } return !elements_to_activate.IsEmpty(); } -bool DisplayLockUtilities::UpdateStyleAndLayoutForRangeIfNeeded( - const EphemeralRangeInFlatTree& range) { - if (range.IsNull() || range.IsCollapsed()) - return false; - if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&range.GetDocument()) || - range.GetDocument().LockedDisplayLockCount() == - range.GetDocument().ActivationBlockingDisplayLockCount()) - return false; - Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_; - for (Node& node : range.Nodes()) { - for (Element* locked_activatable_ancestor : - ActivatableLockedInclusiveAncestors(node)) { - DCHECK(locked_activatable_ancestor->GetDisplayLockContext()); - DCHECK(locked_activatable_ancestor->GetDisplayLockContext()->IsLocked()); - if (locked_activatable_ancestor->GetDisplayLockContext()->UpdateForced()) - break; - scoped_forced_update_list_.push_back( - locked_activatable_ancestor->GetDisplayLockContext() - ->GetScopedForcedUpdate()); - } - } - if (!scoped_forced_update_list_.IsEmpty()) - range.GetDocument().UpdateStyleAndLayout(); - return !scoped_forced_update_list_.IsEmpty(); -} - const HeapVector<Member<Element>> -DisplayLockUtilities::ActivatableLockedInclusiveAncestors(const Node& node) { +DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + const Node& node, + DisplayLockActivationReason reason) { HeapVector<Member<Element>> elements_to_activate; const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal(); if (!RuntimeEnabledFeatures::DisplayLockingEnabled( @@ -118,7 +124,7 @@ if (auto* context = ancestor_element->GetDisplayLockContext()) { if (!context->IsLocked()) continue; - if (!context->IsActivatable()) { + if (!context->IsActivatable(reason)) { // If we find a non-activatable locked ancestor, then we shouldn't // activate anything. elements_to_activate.clear(); @@ -300,8 +306,10 @@ for (auto* element = NearestLockedExclusiveAncestor(node); element; element = NearestLockedExclusiveAncestor(*element)) { - if (!element->GetDisplayLockContext()->IsActivatable()) + if (!element->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kAny)) { return true; + } } return false; }
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h index ca23fa3f..b9b4bf33 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
@@ -44,17 +44,13 @@ static bool ActivateSelectionRangeIfNeeded( const EphemeralRangeInFlatTree& range); - // Updates style for all locked nodes in |range|. Returns true if there's at - // least one locked node encountered. - static bool UpdateStyleAndLayoutForRangeIfNeeded( - const EphemeralRangeInFlatTree& range); - // Returns activatable-locked inclusive ancestors of |node|. // Note that this function will return an empty list if |node| is inside a // non-activatable locked subtree (e.g. at least one ancestor is not // activatable-locked). static const HeapVector<Member<Element>> ActivatableLockedInclusiveAncestors( - const Node& node); + const Node& node, + DisplayLockActivationReason reason); // Returns the nearest inclusive ancestor of |node| that is display locked. static const Element* NearestLockedInclusiveAncestor(const Node& node);
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc index d849394..154a07eb5 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc
@@ -25,8 +25,8 @@ bool update_lifecycle = true) { StringBuilder value; value.Append("invisible"); - if (activatable) - value.Append(" activatable"); + if (!activatable) + value.Append(" skip-activation"); element.setAttribute(html_names::kRendersubtreeAttr, value.ToAtomicString()); if (update_lifecycle) @@ -73,27 +73,32 @@ EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); // Querying from every element gives |outer|. HeapVector<Member<Element>> result_for_outer = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + outer, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_outer.size(), 1u); EXPECT_EQ(result_for_outer.at(0), outer); HeapVector<Member<Element>> result_for_inner_a = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_a, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_inner_a.size(), 1u); EXPECT_EQ(result_for_inner_a.at(0), outer); HeapVector<Member<Element>> result_for_innermost = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + innermost, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_innermost.size(), 1u); EXPECT_EQ(result_for_innermost.at(0), outer); HeapVector<Member<Element>> result_for_inner_b = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_b, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_inner_b.size(), 1u); EXPECT_EQ(result_for_inner_b.at(0), outer); HeapVector<Member<Element>> result_for_shadow_div = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + shadow_div, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_shadow_div.size(), 1u); EXPECT_EQ(result_for_shadow_div.at(0), outer); @@ -102,29 +107,33 @@ EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 2); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - result_for_outer = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer); + result_for_outer = DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + outer, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_outer.size(), 1u); EXPECT_EQ(result_for_outer.at(0), outer); result_for_inner_a = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_a, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_inner_a.size(), 1u); EXPECT_EQ(result_for_inner_a.at(0), outer); result_for_innermost = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + innermost, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_innermost.size(), 2u); EXPECT_EQ(result_for_innermost.at(0), innermost); EXPECT_EQ(result_for_innermost.at(1), outer); result_for_inner_b = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_b, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_inner_b.size(), 1u); EXPECT_EQ(result_for_inner_b.at(0), outer); result_for_shadow_div = - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div); + DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + shadow_div, DisplayLockActivationReason::kAny); EXPECT_EQ(result_for_shadow_div.size(), 1u); EXPECT_EQ(result_for_shadow_div.at(0), outer); @@ -134,22 +143,26 @@ EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0); EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); - EXPECT_EQ( - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer).size(), - 0u); - EXPECT_EQ( - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a).size(), - 0u); - EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost) + EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + outer, DisplayLockActivationReason::kAny) .size(), 0u); - EXPECT_EQ( - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b).size(), - 0u); - EXPECT_EQ( - DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div) - .size(), - 0u); + EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_a, DisplayLockActivationReason::kAny) + .size(), + 0u); + EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + innermost, DisplayLockActivationReason::kAny) + .size(), + 0u); + EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + inner_b, DisplayLockActivationReason::kAny) + .size(), + 0u); + EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors( + shadow_div, DisplayLockActivationReason::kAny) + .size(), + 0u); } TEST_F(DisplayLockUtilitiesTest, LockedSubtreeCrossingFrames) {
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 26a4f29..5a62770d 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8523,7 +8523,8 @@ if (entry->isIntersecting()) { auto* context = entry->target()->GetDisplayLockContext(); DCHECK(context); - DCHECK(context->ShouldCommitForActivation()); + DCHECK(context->ShouldCommitForActivation( + DisplayLockActivationReason::kViewport)); context->CommitForActivationWithSignal(entry->target()); } }
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 8e391cf..6f03eb1f 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -121,6 +121,7 @@ #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/html/html_frame_element_base.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" +#include "third_party/blink/renderer/core/html/html_html_element.h" #include "third_party/blink/renderer/core/html/html_plugin_element.h" #include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/html/html_table_rows_collection.h" @@ -1054,7 +1055,7 @@ } void Element::scrollIntoViewWithOptions(const ScrollIntoViewOptions* options) { - ActivateDisplayLockIfNeeded(); + ActivateDisplayLockIfNeeded(DisplayLockActivationReason::kUser); GetDocument().EnsurePaintLocationDataValidForNode(this); ScrollIntoViewNoVisualUpdate(options); } @@ -1064,7 +1065,7 @@ if (!GetLayoutObject() || !GetDocument().GetPage()) return; - if (DisplayLockPreventsActivation()) + if (DisplayLockPreventsActivation(DisplayLockActivationReason::kUser)) return; ScrollBehavior behavior = (options->behavior() == "smooth") @@ -2362,8 +2363,18 @@ SetNeedsStyleRecalc(kLocalStyleChange, StyleChangeReasonForTracing::FromAttribute(name)); SpaceSplitString tokens(params.new_value.LowerASCII()); - const bool should_be_activatable = tokens.Contains("activatable"); - EnsureDisplayLockContext().SetActivatable(should_be_activatable); + unsigned char activation_mask = + static_cast<unsigned char>(DisplayLockActivationReason::kAny); + + // Figure out the activation mask. + if (tokens.Contains("skip-activation")) + activation_mask = 0; + if (tokens.Contains("skip-viewport-activation")) { + activation_mask &= + ~static_cast<unsigned char>(DisplayLockActivationReason::kViewport); + } + + EnsureDisplayLockContext().SetActivatable(activation_mask); const bool should_be_invisible = tokens.Contains("invisible"); if (should_be_invisible) { if (!GetDisplayLockContext()->IsLocked()) @@ -3206,9 +3217,14 @@ if (LayoutObject* layout_object = GetLayoutObject()) { DCHECK(new_style); - auto* this_element = DynamicTo<PseudoElement>(this); - if (this_element && new_style->Display() == EDisplay::kContents) { - new_style = this_element->LayoutStyleForDisplayContents(*new_style); + scoped_refptr<const ComputedStyle> layout_style(std::move(new_style)); + if (auto* pseudo_element = DynamicTo<PseudoElement>(this)) { + if (layout_style->Display() == EDisplay::kContents) { + layout_style = + pseudo_element->LayoutStyleForDisplayContents(*layout_style); + } + } else if (auto* html_element = DynamicTo<HTMLHtmlElement>(this)) { + layout_style = html_element->LayoutStyleForElement(layout_style); } // kEqual means that the computed style didn't change, but there are // additional flags in ComputedStyle which may have changed. For instance, @@ -3219,7 +3235,7 @@ diff == ComputedStyle::Difference::kEqual ? LayoutObject::ApplyStyleChanges::kNo : LayoutObject::ApplyStyleChanges::kYes; - layout_object->SetStyle(new_style.get(), apply_changes); + layout_object->SetStyle(layout_style.get(), apply_changes); } return child_change; } @@ -4025,7 +4041,7 @@ return; } } - ActivateDisplayLockIfNeeded(); + ActivateDisplayLockIfNeeded(DisplayLockActivationReason::kUser); DispatchActivateInvisibleEventIfNeeded(); if (IsInsideInvisibleSubtree()) { // The element stays invisible because the default event action is @@ -4179,7 +4195,7 @@ ((SupportsFocus() && tabIndex() >= 0) || (RuntimeEnabledFeatures::KeyboardFocusableScrollersEnabled() && IsScrollableNode(this))) && - !DisplayLockPreventsActivation(); + !DisplayLockPreventsActivation(DisplayLockActivationReason::kUser); } bool Element::IsMouseFocusable() const { @@ -4188,7 +4204,7 @@ DCHECK(!GetDocument().IsActive() || !GetDocument().NeedsLayoutTreeUpdateForNode(*this)); return isConnected() && !IsInert() && IsFocusableStyle() && SupportsFocus() && - !DisplayLockPreventsActivation(); + !DisplayLockPreventsActivation(DisplayLockActivationReason::kUser); } bool Element::IsAutofocusable() const { @@ -4198,7 +4214,7 @@ FastHasAttribute(html_names::kAutofocusAttr); } -bool Element::ActivateDisplayLockIfNeeded() { +bool Element::ActivateDisplayLockIfNeeded(DisplayLockActivationReason reason) { if (!RuntimeEnabledFeatures::DisplayLockingEnabled(GetExecutionContext()) || GetDocument().LockedDisplayLockCount() == GetDocument().ActivationBlockingDisplayLockCount()) @@ -4211,8 +4227,9 @@ if (!ancestor_element) continue; if (auto* context = ancestor_element->GetDisplayLockContext()) { - // If any of the ancestors is not activatable, we can't activate. - if (!context->IsActivatable()) + // If any of the ancestors is not activatable for the given reason, we + // can't activate. + if (!context->IsActivatable(reason)) return false; activatable_targets.push_back(std::make_pair( ancestor_element, &ancestor.GetTreeScope().Retarget(*this))); @@ -4224,7 +4241,7 @@ // Dispatch event on activatable ancestor (target.first), with // the retargeted element (target.second) as the |activatedElement|. if (auto* context = target.first->GetDisplayLockContext()) { - if (context->ShouldCommitForActivation()) { + if (context->ShouldCommitForActivation(reason)) { activated = true; context->CommitForActivationWithSignal(target.second); } @@ -4233,7 +4250,8 @@ return activated; } -bool Element::DisplayLockPreventsActivation() const { +bool Element::DisplayLockPreventsActivation( + DisplayLockActivationReason reason) const { if (!RuntimeEnabledFeatures::DisplayLockingEnabled(GetExecutionContext())) return false; @@ -4252,7 +4270,7 @@ if (!current_element) continue; if (auto* context = current_element->GetDisplayLockContext()) { - if (!context->IsActivatable()) + if (!context->IsActivatable(reason)) return true; } }
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index da7c8f1..d73f2f7 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -95,6 +95,7 @@ enum class CSSPropertyID; enum class CSSValueID; +enum class DisplayLockActivationReason; enum class DisplayLockLifecycleTarget; using ScrollOffset = FloatSize; @@ -935,9 +936,10 @@ bool StyleRecalcBlockedByDisplayLock(DisplayLockLifecycleTarget) const; - // Activates all activatable locked ancestors for this element. Return true if - // we activated at least one previously locked element. - bool ActivateDisplayLockIfNeeded(); + // Activates all activatable (for a given reason) locked ancestors for this + // element. Return true if we activated at least one previously locked + // element. + bool ActivateDisplayLockIfNeeded(DisplayLockActivationReason reason); virtual void SetActive(bool active); virtual void SetHovered(bool hovered); @@ -1149,7 +1151,7 @@ void DetachAttrNodeFromElementWithValue(Attr*, const AtomicString& value); void DetachAttrNodeAtIndex(Attr*, wtf_size_t index); - bool DisplayLockPreventsActivation() const; + bool DisplayLockPreventsActivation(DisplayLockActivationReason reason) const; FRIEND_TEST_ALL_PREFIXES(DisplayLockContextTest, DisplayLockPreventsActivation);
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index a4f6e78..c7bebcbd 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2783,7 +2783,7 @@ SimulatedClickMouseEventOptions event_options, SimulatedClickCreationScope scope) { if (auto* element = IsElementNode() ? ToElement(this) : parentElement()) - element->ActivateDisplayLockIfNeeded(); + element->ActivateDisplayLockIfNeeded(DisplayLockActivationReason::kUser); EventDispatcher::DispatchSimulatedClick(*this, underlying_event, event_options, scope); }
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc index a0948ff..b04f994 100644 --- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc +++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -110,7 +110,8 @@ IsHTMLStyleElement(*element) || IsHTMLScriptElement(*element) || IsHTMLVideoElement(*element) || IsA<HTMLAudioElement>(*element) || (element->GetDisplayLockContext() && - !element->GetDisplayLockContext()->IsActivatable()); + !element->GetDisplayLockContext()->IsActivatable( + DisplayLockActivationReason::kUser)); } Node* GetNonSearchableAncestor(const Node& node) { @@ -234,7 +235,7 @@ bool FindBuffer::PushScopedForcedUpdateIfNeeded(const Element& element) { if (auto* context = element.GetDisplayLockContext()) { - DCHECK(context->IsActivatable()); + DCHECK(context->IsActivatable(DisplayLockActivationReason::kUser)); scoped_forced_update_list_.push_back(context->GetScopedForcedUpdate()); return true; }
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc index 62879e2..490c9fd 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -179,8 +179,9 @@ return false; if (auto* element = DynamicTo<Element>(node)) { - if (auto* context = element->GetDisplayLockContext()) - return context->IsActivatable(); + if (auto* context = element->GetDisplayLockContext()) { + return context->IsActivatable(DisplayLockActivationReason::kUser); + } } return true; }
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 99413a1..cc15530 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -564,6 +564,13 @@ if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView()) break; + if (event.GetType() == WebInputEvent::kGestureLongTap && + !MainFrameImpl() + ->GetFrame() + ->GetEventHandler() + .LongTapShouldInvokeContextMenu()) + break; + AsView().page->GetContextMenuController().ClearContextMenu(); { ContextMenuAllowedScope scope;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index 84ea34bd..234e079 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -425,6 +425,8 @@ FRIEND_TEST_ALL_PREFIXES(WebFrameTest, DivScrollIntoEditableTestWithDeviceScaleFactor); FRIEND_TEST_ALL_PREFIXES(WebViewTest, SetBaseBackgroundColorBeforeMainFrame); + FRIEND_TEST_ALL_PREFIXES(WebViewTest, LongPressImage); + FRIEND_TEST_ALL_PREFIXES(WebViewTest, LongPressImageAndThenLongTapImage); friend class frame_test_helpers::WebViewHelper; friend class SimCompositor; friend class WebView; // So WebView::Create can call our constructor
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index 1a0720bd..3359f86 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -108,6 +108,7 @@ #include "third_party/blink/renderer/core/loader/frame_load_request.h" #include "third_party/blink/renderer/core/loader/interactive_detector.h" #include "third_party/blink/renderer/core/page/chrome_client.h" +#include "third_party/blink/renderer/core/page/context_menu_controller.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page_hidden_state.h" @@ -2775,6 +2776,10 @@ EXPECT_EQ(WebInputEventResult::kHandledSystem, web_view->MainFrameWidget()->HandleInputEvent( WebCoalescedInputEvent(event))); + EXPECT_TRUE( + web_view->AsView() + .page->GetContextMenuController() + .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame())); } TEST_F(WebViewTest, LongPressVideo) { @@ -5781,4 +5786,44 @@ EXPECT_TRUE(document->GetLayoutView()->ShouldDoFullPaintInvalidation()); } +// Regression test for https://crbug.com/1012068 +TEST_F(WebViewTest, LongPressImageAndThenLongTapImage) { + RegisterMockedHttpURLLoad("long_press_image.html"); + + WebViewImpl* web_view = + web_view_helper_.InitializeAndLoad(base_url_ + "long_press_image.html"); + web_view->SettingsImpl()->SetAlwaysShowContextMenuOnTouch(false); + web_view->MainFrameWidget()->Resize(WebSize(500, 300)); + UpdateAllLifecyclePhases(); + RunPendingTasks(); + + WebGestureEvent event(WebInputEvent::kGestureLongPress, + WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests(), + WebGestureDevice::kTouchscreen); + event.SetPositionInWidget(WebFloatPoint(10, 10)); + + EXPECT_EQ(WebInputEventResult::kHandledSystem, + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(event))); + EXPECT_TRUE( + web_view->AsView() + .page->GetContextMenuController() + .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame())); + + WebGestureEvent tap_event(WebInputEvent::kGestureLongTap, + WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests(), + WebGestureDevice::kTouchscreen); + tap_event.SetPositionInWidget(WebFloatPoint(10, 10)); + + EXPECT_EQ(WebInputEventResult::kNotHandled, + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(tap_event))); + EXPECT_TRUE( + web_view->AsView() + .page->GetContextMenuController() + .ContextMenuNodeForFrame(web_view->MainFrameImpl()->GetFrame())); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc index e8dfb169..18dbcd3 100644 --- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc +++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -256,6 +256,7 @@ response->cache_storage_cache_name = cache_storage_cache_name_; response->cors_exposed_header_names = HeaderSetToVector(cors_exposed_header_names_); + response->side_data_blob = side_data_blob_; for (const auto& header : HeaderList()->List()) response->headers.insert(header.first, header.second);
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.h b/third_party/blink/renderer/core/fetch/fetch_response_data.h index 20910a9..67b11db 100644 --- a/third_party/blink/renderer/core/fetch/fetch_response_data.h +++ b/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -101,6 +101,9 @@ void SetCorsExposedHeaderNames(const WebHTTPHeaderSet& header_names) { cors_exposed_header_names_ = header_names; } + void SetSideDataBlob(scoped_refptr<BlobDataHandle> blob) { + side_data_blob_ = std::move(blob); + } // If the type is Default, replaces |buffer_|. // If the type is Basic or CORS, replaces |buffer_| and @@ -127,6 +130,7 @@ base::Time response_time_; String cache_storage_cache_name_; WebHTTPHeaderSet cors_exposed_header_names_; + scoped_refptr<BlobDataHandle> side_data_blob_; DISALLOW_COPY_AND_ASSIGN(FetchResponseData); };
diff --git a/third_party/blink/renderer/core/fetch/response.cc b/third_party/blink/renderer/core/fetch/response.cc index 900bab4..55fd745 100644 --- a/third_party/blink/renderer/core/fetch/response.cc +++ b/third_party/blink/renderer/core/fetch/response.cc
@@ -8,7 +8,6 @@ #include "base/memory/scoped_refptr.h" #include "base/optional.h" -#include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/dictionary.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" @@ -46,7 +45,7 @@ namespace { template <typename CorsHeadersContainer> -FetchResponseData* FilterResponseData( +FetchResponseData* FilterResponseDataInternal( network::mojom::FetchResponseType response_type, FetchResponseData* response, CorsHeadersContainer& headers) { @@ -81,30 +80,9 @@ FetchResponseData* CreateFetchResponseDataFromFetchAPIResponse( ScriptState* script_state, mojom::blink::FetchAPIResponse& fetch_api_response) { - FetchResponseData* response = nullptr; - if (fetch_api_response.status_code > 0) - response = FetchResponseData::Create(); - else - response = FetchResponseData::CreateNetworkErrorResponse(); - - response->SetResponseSource(fetch_api_response.response_source); - response->SetURLList(fetch_api_response.url_list); - response->SetStatus(fetch_api_response.status_code); - response->SetStatusMessage(WTF::AtomicString(fetch_api_response.status_text)); - response->SetResponseTime(fetch_api_response.response_time); - response->SetCacheStorageCacheName( - fetch_api_response.cache_storage_cache_name); - - for (const auto& header : fetch_api_response.headers) - response->HeaderList()->Append(header.key, header.value); - - // TODO(wanderview): This sets the mime type of the Response based on the - // current headers. This should be correct for most cases, but technically - // the mime type should really be frozen at the initial Response - // construction. We should plumb the value through the cache_storage - // persistence layer and include the explicit mime type in FetchAPIResponse - // to set here. See: crbug.com/938939 - response->SetMimeType(response->HeaderList()->ExtractMIMEType()); + FetchResponseData* response = + Response::CreateUnfilteredFetchResponseDataWithoutBody( + script_state, fetch_api_response); if (fetch_api_response.blob) { response->ReplaceBodyStreamBuffer(MakeGarbageCollected<BodyStreamBuffer>( @@ -115,8 +93,9 @@ } // Filter the response according to |fetch_api_response|'s ResponseType. - response = FilterResponseData(fetch_api_response.response_type, response, - fetch_api_response.cors_exposed_header_names); + response = + FilterResponseDataInternal(fetch_api_response.response_type, response, + fetch_api_response.cors_exposed_header_names); return response; } @@ -375,6 +354,45 @@ return r; } +FetchResponseData* Response::CreateUnfilteredFetchResponseDataWithoutBody( + ScriptState* script_state, + mojom::blink::FetchAPIResponse& fetch_api_response) { + FetchResponseData* response = nullptr; + if (fetch_api_response.status_code > 0) + response = FetchResponseData::Create(); + else + response = FetchResponseData::CreateNetworkErrorResponse(); + + response->SetResponseSource(fetch_api_response.response_source); + response->SetURLList(fetch_api_response.url_list); + response->SetStatus(fetch_api_response.status_code); + response->SetStatusMessage(WTF::AtomicString(fetch_api_response.status_text)); + response->SetResponseTime(fetch_api_response.response_time); + response->SetCacheStorageCacheName( + fetch_api_response.cache_storage_cache_name); + response->SetSideDataBlob(fetch_api_response.side_data_blob); + + for (const auto& header : fetch_api_response.headers) + response->HeaderList()->Append(header.key, header.value); + + // TODO(wanderview): This sets the mime type of the Response based on the + // current headers. This should be correct for most cases, but technically + // the mime type should really be frozen at the initial Response + // construction. We should plumb the value through the cache_storage + // persistence layer and include the explicit mime type in FetchAPIResponse + // to set here. See: crbug.com/938939 + response->SetMimeType(response->HeaderList()->ExtractMIMEType()); + + return response; +} + +FetchResponseData* Response::FilterResponseData( + network::mojom::FetchResponseType response_type, + FetchResponseData* response, + WTF::Vector<WTF::String>& headers) { + return FilterResponseDataInternal(response_type, response, headers); +} + String Response::type() const { // "The type attribute's getter must return response's type." switch (response_->GetType()) {
diff --git a/third_party/blink/renderer/core/fetch/response.h b/third_party/blink/renderer/core/fetch/response.h index 6199ca68..3d389ec 100644 --- a/third_party/blink/renderer/core/fetch/response.h +++ b/third_party/blink/renderer/core/fetch/response.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_RESPONSE_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_RESPONSE_H_ +#include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink-forward.h" #include "third_party/blink/renderer/bindings/core/v8/dictionary.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" @@ -54,6 +55,15 @@ uint16_t status, ExceptionState&); + static FetchResponseData* CreateUnfilteredFetchResponseDataWithoutBody( + ScriptState*, + mojom::blink::FetchAPIResponse&); + + static FetchResponseData* FilterResponseData( + network::mojom::FetchResponseType response_type, + FetchResponseData* response, + WTF::Vector<WTF::String>& headers); + explicit Response(ExecutionContext*); Response(ExecutionContext*, FetchResponseData*); Response(ExecutionContext*, FetchResponseData*, Headers*);
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl index bdc7ae96..0e43da8f 100644 --- a/third_party/blink/renderer/core/frame/window.idl +++ b/third_party/blink/renderer/core/frame/window.idl
@@ -213,7 +213,7 @@ attribute DOMMatrixConstructor WebKitCSSMatrix; // TrustedTypes API: http://github.com/wicg/trusted-types - [RuntimeEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory TrustedTypes; + [RuntimeEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory trustedTypes; }; Window includes GlobalEventHandlers;
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.idl b/third_party/blink/renderer/core/html/custom/custom_element_registry.idl index 6403c3e2..986991b7 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_registry.idl +++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
@@ -6,7 +6,7 @@ [Exposed=Window] interface CustomElementRegistry { - [CallWith=ScriptState, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=CustomElementRegistryDefine] void define(DOMString name, CustomElementConstructor _constructor, optional ElementDefinitionOptions options); + [CallWith=ScriptState, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=CustomElementRegistryDefine] void define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options); any get(DOMString name); [CallWith=ScriptState,RaisesException] Promise<void> whenDefined(DOMString name); [CEReactions] void upgrade(Node root);
diff --git a/third_party/blink/renderer/core/html/html_html_element.cc b/third_party/blink/renderer/core/html/html_html_element.cc index 50416b0..e66a2d4 100644 --- a/third_party/blink/renderer/core/html/html_html_element.cc +++ b/third_party/blink/renderer/core/html/html_html_element.cc
@@ -26,13 +26,16 @@ #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document_parser.h" +#include "third_party/blink/renderer/core/dom/node_computed_style.h" #include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h" #include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/core/loader/frame_loader.h" +#include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -116,4 +119,69 @@ return nullptr; } +namespace { + +bool NeedsLayoutStylePropagation(const ComputedStyle& layout_style, + const ComputedStyle& propagated_style) { + return layout_style.GetWritingMode() != propagated_style.GetWritingMode() || + layout_style.Direction() != propagated_style.Direction(); +} + +scoped_refptr<ComputedStyle> CreateLayoutStyle( + const ComputedStyle& style, + const ComputedStyle& propagated_style) { + scoped_refptr<ComputedStyle> layout_style = ComputedStyle::Clone(style); + layout_style->SetDirection(propagated_style.Direction()); + layout_style->SetWritingMode(propagated_style.GetWritingMode()); + return layout_style; +} + +} // namespace + +scoped_refptr<const ComputedStyle> HTMLHtmlElement::LayoutStyleForElement( + scoped_refptr<const ComputedStyle> style) { + DCHECK(style); + DCHECK(GetDocument().InStyleRecalc()); + if (const Element* body_element = GetDocument().body()) { + if (const ComputedStyle* body_style = body_element->GetComputedStyle()) { + if (NeedsLayoutStylePropagation(*style, *body_style)) + return CreateLayoutStyle(*style, *body_style); + } + } + return style; +} + +void HTMLHtmlElement::PropagateWritingModeAndDirectionFromBody() { + // Will be propagated in HTMLHtmlElement::AttachLayoutTree(). + if (NeedsReattachLayoutTree()) + return; + LayoutObject* layout_object = GetLayoutObject(); + if (!layout_object) + return; + const ComputedStyle* style = GetComputedStyle(); + // If we have a layout object, and we are not marked for re-attachment, we are + // guaranteed to have a non-null ComputedStyle. + DCHECK(style); + const ComputedStyle* propagated_style = nullptr; + if (const Element* body = GetDocument().body()) + propagated_style = body->GetComputedStyle(); + if (!propagated_style) + propagated_style = style; + if (NeedsLayoutStylePropagation(layout_object->StyleRef(), + *propagated_style)) { + layout_object->SetStyle(CreateLayoutStyle(*style, *propagated_style)); + } +} + +void HTMLHtmlElement::AttachLayoutTree(AttachContext& context) { + scoped_refptr<const ComputedStyle> original_style = GetComputedStyle(); + if (original_style) + SetComputedStyle(LayoutStyleForElement(original_style)); + + Element::AttachLayoutTree(context); + + if (original_style) + SetComputedStyle(original_style); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_html_element.h b/third_party/blink/renderer/core/html/html_html_element.h index 66abdee..a9054de 100644 --- a/third_party/blink/renderer/core/html/html_html_element.h +++ b/third_party/blink/renderer/core/html/html_html_element.h
@@ -38,12 +38,16 @@ void InsertedByParser(); bool HasNonInBodyInsertionMode() const override { return true; } + void PropagateWritingModeAndDirectionFromBody(); + scoped_refptr<const ComputedStyle> LayoutStyleForElement( + scoped_refptr<const ComputedStyle> style); private: void MaybeSetupApplicationCache(); bool IsURLAttribute(const Attribute&) const override; const CSSPropertyValueSet* AdditionalPresentationAttributeStyle() override; + void AttachLayoutTree(AttachContext&) override; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_progress_element.cc b/third_party/blink/renderer/core/html/html_progress_element.cc index 40dbeb8..99d1410b 100644 --- a/third_party/blink/renderer/core/html/html_progress_element.cc +++ b/third_party/blink/renderer/core/html/html_progress_element.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h" #include "third_party/blink/renderer/core/html/shadow/progress_shadow_element.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/layout/layout_object_factory.h" #include "third_party/blink/renderer/core/layout/layout_progress.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/heap.h" @@ -55,7 +56,7 @@ } UseCounter::Count(GetDocument(), WebFeature::kProgressElementWithProgressBarAppearance); - return new LayoutProgress(this); + return LayoutObjectFactory::CreateLayoutProgress(this, style, legacy); } LayoutProgress* HTMLProgressElement::GetLayoutProgress() const {
diff --git a/third_party/blink/renderer/core/html/html_progress_element.h b/third_party/blink/renderer/core/html/html_progress_element.h index 3b7dab2f..1473489 100644 --- a/third_party/blink/renderer/core/html/html_progress_element.h +++ b/third_party/blink/renderer/core/html/html_progress_element.h
@@ -56,7 +56,6 @@ bool AreAuthorShadowsAllowed() const override { return false; } bool ShouldAppearIndeterminate() const override; bool IsLabelable() const override { return true; } - bool TypeShouldForceLegacyLayout() const final { return true; } LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override; LayoutProgress* GetLayoutProgress() const;
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 5930a3c..22d0b28 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -1427,6 +1427,10 @@ pointer_event_manager_->RemoveLastMousePosition(); } +bool EventHandler::LongTapShouldInvokeContextMenu() { + return gesture_manager_->LongTapShouldInvokeContextMenu(); +} + WebInputEventResult EventHandler::DispatchMousePointerEvent( const WebInputEvent::Type event_type, Element* target_element,
diff --git a/third_party/blink/renderer/core/input/event_handler.h b/third_party/blink/renderer/core/input/event_handler.h index 69d25d0..fc5d5244 100644 --- a/third_party/blink/renderer/core/input/event_handler.h +++ b/third_party/blink/renderer/core/input/event_handler.h
@@ -298,6 +298,8 @@ // restart from the lock position. void ResetMousePositionForPointerUnlock(); + bool LongTapShouldInvokeContextMenu(); + private: enum NoCursorChangeType { kNoCursorChange }; @@ -460,8 +462,6 @@ double max_mouse_moved_duration_; - bool long_tap_should_invoke_context_menu_; - TaskRunnerTimer<EventHandler> active_interval_timer_; // last_show_press_timestamp_ prevents the active state rewrited by
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc index 7fdb009a..58d9032 100644 --- a/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -1292,7 +1292,7 @@ gsb.data.scroll_begin.delta_x_hint = -gsb_data.delta.width; gsb.data.scroll_begin.delta_y_hint = -gsb_data.delta.height; gsb.data.scroll_begin.scrollable_area_element_id = - gsb_data.scrollable_area_element_id.GetInternalValue(); + gsb_data.scrollable_area_element_id.GetStableId(); GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(gsb); WebGestureEvent gsu{WebInputEvent::kGestureScrollUpdate, WebInputEvent::kNoModifiers, @@ -1655,8 +1655,8 @@ LocalFrameView* frame_view = GetDocument().View(); constexpr float delta_y = 500; InjectScrollFromGestureEvents( - frame_view->LayoutViewport()->GetCompositorElementId().GetInternalValue(), - 0, delta_y); + frame_view->LayoutViewport()->GetCompositorElementId().GetStableId(), 0, + delta_y); ASSERT_EQ(500, frame_view->LayoutViewport()->GetScrollOffset().Height()); EXPECT_EQ("currently hovered", element1.InnerHTML().Utf8()); EXPECT_EQ("hover over me", element2.InnerHTML().Utf8()); @@ -1730,7 +1730,7 @@ // and mark hover state dirty in ScrollManager. constexpr float delta_y = 1000; InjectScrollFromGestureEvents( - iframe_scrollable_area->GetCompositorElementId().GetInternalValue(), 0, + iframe_scrollable_area->GetCompositorElementId().GetStableId(), 0, delta_y); LocalFrameView* frame_view = GetDocument().View(); ASSERT_EQ(0, frame_view->LayoutViewport()->GetScrollOffset().Height()); @@ -1862,7 +1862,7 @@ scroller->GetLayoutBox()->GetScrollableArea(); constexpr float delta_y = 300; InjectScrollFromGestureEvents( - scrollable_area->GetCompositorElementId().GetInternalValue(), 0, delta_y); + scrollable_area->GetCompositorElementId().GetStableId(), 0, delta_y); ASSERT_EQ(300, scrollable_area->GetScrollOffset().Height()); EXPECT_TRUE(target1->IsHovered()); EXPECT_FALSE(target2->IsHovered()); @@ -2351,7 +2351,7 @@ ScrollableArea* scrollable_area = scroller->GetLayoutBox()->GetScrollableArea(); gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = - scrollable_area->GetCompositorElementId().GetInternalValue(); + scrollable_area->GetCompositorElementId().GetStableId(); GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( gesture_scroll_begin); @@ -2411,7 +2411,7 @@ gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0; gesture_scroll_begin.data.scroll_begin.delta_y_hint = -delta_y; gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = - scrollable_area->GetCompositorElementId().GetInternalValue(); + scrollable_area->GetCompositorElementId().GetStableId(); GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( gesture_scroll_begin); @@ -2462,7 +2462,7 @@ gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0; gesture_scroll_begin.data.scroll_begin.delta_y_hint = -delta_y; gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = - visual_viewport.GetCompositorElementId().GetInternalValue(); + visual_viewport.GetCompositorElementId().GetStableId(); GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( gesture_scroll_begin);
diff --git a/third_party/blink/renderer/core/input/gesture_manager.cc b/third_party/blink/renderer/core/input/gesture_manager.cc index ebf43f8..76b7d7b 100644 --- a/third_party/blink/renderer/core/input/gesture_manager.cc +++ b/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -140,6 +140,10 @@ return WebInputEventResult::kNotHandled; } +bool GestureManager::LongTapShouldInvokeContextMenu() const { + return long_tap_should_invoke_context_menu_; +} + WebInputEventResult GestureManager::HandleGestureTapDown( const GestureEventWithHitTestResults& targeted_event) { suppress_mouse_events_from_gestures_ = @@ -372,12 +376,10 @@ WebInputEventResult GestureManager::HandleGestureLongTap( const GestureEventWithHitTestResults& targeted_event) { -#if !defined(OS_ANDROID) - if (long_tap_should_invoke_context_menu_) { + if (LongTapShouldInvokeContextMenu()) { long_tap_should_invoke_context_menu_ = false; return SendContextMenuEventForGesture(targeted_event); } -#endif return WebInputEventResult::kNotHandled; }
diff --git a/third_party/blink/renderer/core/input/gesture_manager.h b/third_party/blink/renderer/core/input/gesture_manager.h index 6499ba3..69a18d78 100644 --- a/third_party/blink/renderer/core/input/gesture_manager.h +++ b/third_party/blink/renderer/core/input/gesture_manager.h
@@ -38,6 +38,7 @@ WebInputEvent::Type); WebInputEventResult HandleGestureEventInFrame( const GestureEventWithHitTestResults&); + bool LongTapShouldInvokeContextMenu() const; private: WebInputEventResult HandleGestureShowPress();
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn index 0cd72b4..be29a9c 100644 --- a/third_party/blink/renderer/core/layout/BUILD.gn +++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -401,6 +401,8 @@ "ng/layout_ng_flexible_box.h", "ng/layout_ng_mixin.cc", "ng/layout_ng_mixin.h", + "ng/layout_ng_progress.cc", + "ng/layout_ng_progress.h", "ng/layout_ng_table_caption.cc", "ng/layout_ng_table_caption.h", "ng/layout_ng_table_cell.cc",
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc index b052acc1..ef2d61f7 100644 --- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -69,6 +69,11 @@ growth_limit_cap_ = growth_limit_cap; } +void GridTrack::SetSizeDistributionWeight(double size_distribution_weight) { + DCHECK_GE(size_distribution_weight, 0); + size_distribution_weight_ = size_distribution_weight; +} + bool GridTrack::IsGrowthLimitBiggerThanBaseSize() const { return GrowthLimitIsInfinite() || growth_limit_ >= base_size_; } @@ -521,7 +526,8 @@ void GridTrackSizingAlgorithmStrategy::DistributeSpaceToTracks( Vector<GridTrack*>& tracks, LayoutUnit& available_logical_space) const { - algorithm_.DistributeSpaceToTracks<kMaximizeTracks>(tracks, nullptr, + algorithm_.DistributeSpaceToTracks<kNotCrossingIntrinsicFlexibleTracks, + kMaximizeTracks>(tracks, nullptr, available_logical_space); } @@ -962,8 +968,10 @@ const GridTrackSize& track_size, LayoutUnit base_size) const { const GridLength& grid_length = track_size.MaxTrackBreadth(); - if (grid_length.IsFlex()) - return base_size; + if (grid_length.IsFlex()) { + return track_size.MinTrackBreadth().IsContentSized() ? LayoutUnit(kInfinity) + : base_size; + } const Length& track_length = grid_length.length(); if (track_length.IsSpecified()) { @@ -1000,8 +1008,11 @@ if (track_size.IsContentSized()) content_sized_tracks_index_.push_back(i); - if (track_size.MaxTrackBreadth().IsFlex()) + if (track_size.MaxTrackBreadth().IsFlex()) { flexible_sized_tracks_index_.push_back(i); + if (track_size.MinTrackBreadth().IsContentSized()) + track.SetSizeDistributionWeight(track_size.MaxTrackBreadth().Flex()); + } if (track_size.HasAutoMaxTrackBreadth() && !track_size.IsFitContent()) auto_sized_tracks_for_stretch_index_.push_back(i); @@ -1047,12 +1058,12 @@ } } -bool GridTrackSizingAlgorithm::SpanningItemCrossesFlexibleSizedTracks( +bool GridTrackSizingAlgorithm::SpanningItemCrossesIntrinsicFlexibleSizedTracks( const GridSpan& span) const { for (const auto& track_position : span) { const GridTrackSize& track_size = GetGridTrackSize(direction_, track_position); - if (track_size.MinTrackBreadth().IsFlex() || + if (track_size.HasIntrinsicMinTrackBreadth() && track_size.MaxTrackBreadth().IsFlex()) return true; } @@ -1114,9 +1125,13 @@ return track.BaseSize(); } -static bool ShouldProcessTrackForTrackSizeComputationPhase( +static bool ShouldProcessTrackForTrackSizeComputationVariantAndPhase( + TrackSizeComputationVariant variant, TrackSizeComputationPhase phase, const GridTrackSize& track_size) { + if (variant == kCrossingIntrinsicFlexibleTracks && + !track_size.MaxTrackBreadth().IsFlex()) + return false; switch (phase) { case kResolveIntrinsicMinimums: return track_size.HasIntrinsicMinTrackBreadth(); @@ -1245,6 +1260,12 @@ track2_has_infinite_growth_potential_without_cap) return track2_has_infinite_growth_potential_without_cap; + // We don't have to take weights into account when comparing growth potentials + // because they must be 0 at this point. Flexible tracks with a greater + // weight have already been handled due to their infinite growth limit. + DCHECK_EQ(track1->SizeDistributionWeight(), 0); + DCHECK_EQ(track2->SizeDistributionWeight(), 0); + LayoutUnit track1_limit = track1->GrowthLimitCap().value_or(track1->GrowthLimit()); LayoutUnit track2_limit = @@ -1267,7 +1288,21 @@ growth_share = std::min(growth_share, distance_to_cap); } -template <TrackSizeComputationPhase phase> +static Vector<double> FractionsOfRemainingSpace( + const Vector<GridTrack*>& tracks) { + size_t tracks_size = tracks.size(); + Vector<double> fractions_of_remaining_space(tracks_size); + double weight_sum = 0; + for (size_t i = tracks_size; i-- > 0;) { + double weight = tracks[i]->SizeDistributionWeight(); + weight_sum += weight; + fractions_of_remaining_space[i] = + weight_sum > 0 ? weight / weight_sum : 1.0 / (tracks_size - i); + } + return fractions_of_remaining_space; +} + +template <TrackSizeComputationVariant variant, TrackSizeComputationPhase phase> void GridTrackSizingAlgorithm::DistributeSpaceToTracks( Vector<GridTrack*>& tracks, Vector<GridTrack*>* grow_beyond_growth_limits_tracks, @@ -1280,13 +1315,23 @@ } if (available_logical_space > 0) { - std::sort(tracks.begin(), tracks.end(), SortByGridTrackGrowthPotential); + // No need to sort when distributing intrinsic contributions among flexible + // tracks, because all of them have an infinite growth potential. + if (variant == kNotCrossingIntrinsicFlexibleTracks) + std::sort(tracks.begin(), tracks.end(), SortByGridTrackGrowthPotential); + auto fractions_of_remaining_space = FractionsOfRemainingSpace(tracks); size_t tracks_size = tracks.size(); for (size_t i = 0; i < tracks_size; ++i) { GridTrack& track = *tracks[i]; - LayoutUnit available_logical_space_share = - available_logical_space / (tracks_size - i); +#if DCHECK_IS_ON() + if (variant == kCrossingIntrinsicFlexibleTracks) + DCHECK(track.GrowthLimitIsInfinite()); + else + DCHECK_EQ(track.SizeDistributionWeight(), 0); +#endif + LayoutUnit available_logical_space_share(available_logical_space * + fractions_of_remaining_space[i]); const LayoutUnit& track_breadth = TrackSizeForTrackSizeComputationPhase(phase, track, kForbidInfinity); LayoutUnit growth_share = @@ -1304,6 +1349,9 @@ } if (available_logical_space > 0 && grow_beyond_growth_limits_tracks) { + // We never grow flex tracks beyond growth limits, since they are infinite. + DCHECK_NE(variant, kCrossingIntrinsicFlexibleTracks); + // We need to sort them because there might be tracks with growth limit caps // (like the ones with fit-content()) which cannot indefinitely grow over // the limits. @@ -1313,12 +1361,15 @@ SortByGridTrackGrowthPotential); } + auto fractions_of_remaining_space = + FractionsOfRemainingSpace(*grow_beyond_growth_limits_tracks); size_t tracks_growing_above_max_breadth_size = grow_beyond_growth_limits_tracks->size(); for (size_t i = 0; i < tracks_growing_above_max_breadth_size; ++i) { GridTrack* track = grow_beyond_growth_limits_tracks->at(i); - LayoutUnit growth_share = - available_logical_space / (tracks_growing_above_max_breadth_size - i); + LayoutUnit growth_share(available_logical_space * + fractions_of_remaining_space[i]); + ClampGrowthShareIfNeeded(phase, *track, growth_share); DCHECK_GE(growth_share, 0) << "We must never shrink any grid track or " "else we can't guarantee we abide by our " @@ -1336,7 +1387,7 @@ } } -template <TrackSizeComputationPhase phase> +template <TrackSizeComputationVariant variant, TrackSizeComputationPhase phase> void GridTrackSizingAlgorithm::IncreaseSizesToAccommodateSpanningItems( const GridItemsSpanGroupRange& grid_items_with_span) { Vector<GridTrack>& all_tracks = Tracks(direction_); @@ -1351,8 +1402,9 @@ for (auto* it = grid_items_with_span.range_start; it != grid_items_with_span.range_end; ++it) { GridItemWithSpan& grid_item_with_span = *it; - DCHECK_GT(grid_item_with_span.GetGridSpan().IntegerSpan(), 1u); const GridSpan& item_span = grid_item_with_span.GetGridSpan(); + DCHECK(variant == kCrossingIntrinsicFlexibleTracks || + item_span.IntegerSpan() > 1u); grow_beyond_growth_limits_tracks.Shrink(0); filtered_tracks.Shrink(0); @@ -1362,7 +1414,8 @@ GridTrack& track = Tracks(direction_)[track_position]; spanning_tracks_size += TrackSizeForTrackSizeComputationPhase(phase, track, kForbidInfinity); - if (!ShouldProcessTrackForTrackSizeComputationPhase(phase, track_size)) + if (!ShouldProcessTrackForTrackSizeComputationVariantAndPhase( + variant, phase, track_size)) continue; filtered_tracks.push_back(&track); @@ -1387,7 +1440,7 @@ grow_beyond_growth_limits_tracks.IsEmpty() ? filtered_tracks : grow_beyond_growth_limits_tracks; - DistributeSpaceToTracks<phase>( + DistributeSpaceToTracks<variant, phase>( filtered_tracks, &tracks_to_grow_beyond_growth_limits, extra_space); } @@ -1398,8 +1451,25 @@ } } +template <TrackSizeComputationVariant variant> +void GridTrackSizingAlgorithm::IncreaseSizesToAccommodateSpanningItems( + const GridItemsSpanGroupRange& grid_items_with_span) { + IncreaseSizesToAccommodateSpanningItems<variant, kResolveIntrinsicMinimums>( + grid_items_with_span); + IncreaseSizesToAccommodateSpanningItems<variant, + kResolveContentBasedMinimums>( + grid_items_with_span); + IncreaseSizesToAccommodateSpanningItems<variant, kResolveMaxContentMinimums>( + grid_items_with_span); + IncreaseSizesToAccommodateSpanningItems<variant, kResolveIntrinsicMaximums>( + grid_items_with_span); + IncreaseSizesToAccommodateSpanningItems<variant, kResolveMaxContentMaximums>( + grid_items_with_span); +} + void GridTrackSizingAlgorithm::ResolveIntrinsicTrackSizes() { Vector<GridItemWithSpan> items_sorted_by_increasing_span; + Vector<GridItemWithSpan> items_crossing_flexible_tracks; if (grid_.HasGridItems()) { HashSet<LayoutBox*> items_set; for (const auto& track_index : content_sized_tracks_index_) { @@ -1408,9 +1478,12 @@ while (auto* grid_item = iterator->NextGridItem()) { if (items_set.insert(grid_item).is_new_entry) { const GridSpan& span = grid_.GridItemSpan(*grid_item, direction_); - if (span.IntegerSpan() == 1) { + if (SpanningItemCrossesIntrinsicFlexibleSizedTracks(span)) { + items_crossing_flexible_tracks.push_back( + GridItemWithSpan(*grid_item, span)); + } else if (span.IntegerSpan() == 1) { SizeTrackToFitNonSpanningItem(span, *grid_item, track); - } else if (!SpanningItemCrossesFlexibleSizedTracks(span)) { + } else { items_sorted_by_increasing_span.push_back( GridItemWithSpan(*grid_item, span)); } @@ -1426,24 +1499,23 @@ while (it != end) { GridItemsSpanGroupRange span_group_range = {it, std::upper_bound(it, end, *it)}; - IncreaseSizesToAccommodateSpanningItems<kResolveIntrinsicMinimums>( - span_group_range); - IncreaseSizesToAccommodateSpanningItems<kResolveContentBasedMinimums>( - span_group_range); - IncreaseSizesToAccommodateSpanningItems<kResolveMaxContentMinimums>( - span_group_range); - IncreaseSizesToAccommodateSpanningItems<kResolveIntrinsicMaximums>( - span_group_range); - IncreaseSizesToAccommodateSpanningItems<kResolveMaxContentMaximums>( - span_group_range); + IncreaseSizesToAccommodateSpanningItems< + kNotCrossingIntrinsicFlexibleTracks>(span_group_range); it = span_group_range.range_end; } + IncreaseSizesToAccommodateSpanningItems<kCrossingIntrinsicFlexibleTracks>( + {items_crossing_flexible_tracks.begin(), + items_crossing_flexible_tracks.end()}); + + Vector<GridTrack>& track_list = Tracks(direction_); for (const auto& track_index : content_sized_tracks_index_) { - GridTrack& track = Tracks(direction_)[track_index]; + GridTrack& track = track_list[track_index]; if (track.GrowthLimit() == kInfinity) track.SetGrowthLimit(track.BaseSize()); } + for (const auto& track_index : flexible_sized_tracks_index_) + track_list[track_index].SetSizeDistributionWeight(0); } void GridTrackSizingAlgorithm::ComputeGridContainerIntrinsicSizes() { @@ -1451,8 +1523,12 @@ Vector<GridTrack>& all_tracks = Tracks(direction_); for (auto& track : all_tracks) { - DCHECK(strategy_->IsComputingSizeContainment() || - !track.InfiniteGrowthPotential()); +#if DCHECK_IS_ON() + if (!strategy_->IsComputingSizeContainment()) { + DCHECK(!track.InfiniteGrowthPotential()); + DCHECK_EQ(track.SizeDistributionWeight(), 0); + } +#endif min_content_size_ += track.BaseSize(); max_content_size_ += track.GrowthLimitIsInfinite() ? track.BaseSize() : track.GrowthLimit();
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h index 6107043..2fb7574 100644 --- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h +++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
@@ -24,6 +24,11 @@ class GridTrackSizingAlgorithmStrategy; class LayoutGrid; +enum TrackSizeComputationVariant { + kNotCrossingIntrinsicFlexibleTracks, + kCrossingIntrinsicFlexibleTracks, +}; + enum TrackSizeComputationPhase { kResolveIntrinsicMinimums, kResolveContentBasedMinimums, @@ -66,6 +71,14 @@ } void SetGrowthLimitCap(base::Optional<LayoutUnit>); + // For flexible tracks, intrinsic contributions are distributed according to + // the ratios of the flex fractions. At that point we will only have some + // GridTracks, but we won't know their index, so we won't be able to call + // GetGridTrackSize in order to obtain their flex fraction. Therefore we cache + // them instead of computing on demand. + double SizeDistributionWeight() const { return size_distribution_weight_; } + void SetSizeDistributionWeight(double); + private: bool IsGrowthLimitBiggerThanBaseSize() const; void EnsureGrowthLimitIsBiggerThanBaseSize(); @@ -76,6 +89,7 @@ LayoutUnit size_during_distribution_; base::Optional<LayoutUnit> growth_limit_cap_; bool infinitely_growable_; + double size_distribution_weight_{0}; }; class GridTrackSizingAlgorithm final { @@ -150,14 +164,19 @@ void SizeTrackToFitNonSpanningItem(const GridSpan&, LayoutBox& grid_item, GridTrack&); - bool SpanningItemCrossesFlexibleSizedTracks(const GridSpan&) const; + bool SpanningItemCrossesIntrinsicFlexibleSizedTracks(const GridSpan&) const; typedef struct GridItemsSpanGroupRange GridItemsSpanGroupRange; - template <TrackSizeComputationPhase phase> + template <TrackSizeComputationVariant variant, + TrackSizeComputationPhase phase> + void IncreaseSizesToAccommodateSpanningItems( + const GridItemsSpanGroupRange& grid_items_with_span); + template <TrackSizeComputationVariant variant> void IncreaseSizesToAccommodateSpanningItems( const GridItemsSpanGroupRange& grid_items_with_span); LayoutUnit ItemSizeForTrackSizeComputationPhase(TrackSizeComputationPhase, LayoutBox&) const; - template <TrackSizeComputationPhase phase> + template <TrackSizeComputationVariant variant, + TrackSizeComputationPhase phase> void DistributeSpaceToTracks( Vector<GridTrack*>& tracks, Vector<GridTrack*>* grow_beyond_growth_limits_tracks,
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 098c883..11256b7 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -661,6 +661,7 @@ bool IsLayoutNGListMarkerImage() const { return IsOfType(kLayoutObjectNGListMarkerImage); } + bool IsLayoutNGProgress() const { return IsOfType(kLayoutObjectNGProgress); } bool IsLayoutNGText() const { return IsOfType(kLayoutObjectNGText); } bool IsLayoutTableCol() const { return IsOfType(kLayoutObjectLayoutTableCol); @@ -2498,6 +2499,7 @@ kLayoutObjectNGListMarker, kLayoutObjectNGInsideListMarker, kLayoutObjectNGListMarkerImage, + kLayoutObjectNGProgress, kLayoutObjectNGText, kLayoutObjectProgress, kLayoutObjectQuote,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc index 9b6024f..bc47670 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.cc +++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -19,6 +19,7 @@ #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h" +#include "third_party/blink/renderer/core/layout/ng/layout_ng_progress.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h" #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h" @@ -146,4 +147,11 @@ return layout_text_fragment; } +LayoutProgress* LayoutObjectFactory::CreateLayoutProgress( + Node* node, + const ComputedStyle& style, + LegacyLayout legacy) { + return CreateObject<LayoutProgress, LayoutNGProgress>(*node, style, legacy); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h index a9596a42..9425007 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.h +++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -15,6 +15,7 @@ class LayoutBlock; class LayoutBlockFlow; enum class LegacyLayout; +class LayoutProgress; class LayoutTableCaption; class LayoutTableCell; class LayoutText; @@ -55,6 +56,9 @@ int start_offset, int length, LegacyLayout); + static LayoutProgress* CreateLayoutProgress(Node* node, + const ComputedStyle& style, + LegacyLayout legacy); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_progress.cc b/third_party/blink/renderer/core/layout/layout_progress.cc index e2cdda71..6b285eb 100644 --- a/third_party/blink/renderer/core/layout/layout_progress.cc +++ b/third_party/blink/renderer/core/layout/layout_progress.cc
@@ -27,14 +27,16 @@ namespace blink { -LayoutProgress::LayoutProgress(HTMLProgressElement* element) +LayoutProgress::LayoutProgress(Element* element) : LayoutBlockFlow(element), position_(HTMLProgressElement::kInvalidPosition), animating_(false), animation_timer_( element->GetDocument().GetTaskRunner(TaskType::kInternalDefault), this, - &LayoutProgress::AnimationTimerFired) {} + &LayoutProgress::AnimationTimerFired) { + DCHECK(IsHTMLProgressElement(element)); +} LayoutProgress::~LayoutProgress() = default;
diff --git a/third_party/blink/renderer/core/layout/layout_progress.h b/third_party/blink/renderer/core/layout/layout_progress.h index 7430461..0c24c53 100644 --- a/third_party/blink/renderer/core/layout/layout_progress.h +++ b/third_party/blink/renderer/core/layout/layout_progress.h
@@ -28,9 +28,9 @@ class HTMLProgressElement; -class CORE_EXPORT LayoutProgress final : public LayoutBlockFlow { +class CORE_EXPORT LayoutProgress : public LayoutBlockFlow { public: - explicit LayoutProgress(HTMLProgressElement*); + explicit LayoutProgress(Element* element); ~LayoutProgress() override; double GetPosition() const { return position_; } @@ -45,15 +45,14 @@ protected: void WillBeDestroyed() override; + bool IsOfType(LayoutObjectType type) const override { + return type == kLayoutObjectProgress || LayoutBlockFlow::IsOfType(type); + } bool IsAnimating() const; bool IsAnimationTimerActive() const; private: - bool IsOfType(LayoutObjectType type) const override { - return type == kLayoutObjectProgress || LayoutBlockFlow::IsOfType(type); - } - void AnimationTimerFired(TimerBase*); void UpdateAnimationState();
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc index b5fc291..feb0ff6 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -4,14 +4,7 @@ #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" -#include "third_party/blink/renderer/core/layout/layout_analyzer.h" -#include "third_party/blink/renderer/core/layout/layout_view.h" -#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" -#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" -#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" -#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" -#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" namespace blink { @@ -26,47 +19,7 @@ } void LayoutNGBlockFlow::UpdateBlockLayout(bool relayout_children) { - LayoutAnalyzer::BlockScope analyzer(*this); - - if (IsOutOfFlowPositioned()) { - UpdateOutOfFlowBlockLayout(); - return; - } - - NGConstraintSpace constraint_space = - NGConstraintSpace::CreateFromLayoutObject( - *this, !View()->GetLayoutState()->Next() /* is_layout_root */); - - scoped_refptr<const NGLayoutResult> result = - NGBlockNode(this).Layout(constraint_space); - - for (const auto& descendant : - result->PhysicalFragment().OutOfFlowPositionedDescendants()) - descendant.node.UseLegacyOutOfFlowPositioning(); - - UpdateMargins(constraint_space); -} - -void LayoutNGBlockFlow::UpdateMargins(const NGConstraintSpace& space) { - const LayoutBlock* containing_block = ContainingBlock(); - if (!containing_block || !containing_block->IsLayoutBlockFlow()) - return; - - // In the legacy engine, for regular block container layout, children - // calculate and store margins on themselves, while in NG that's done by the - // container. Since this object is a LayoutNG entry-point, we'll have to do it - // on ourselves, since that's what the legacy container expects. - const ComputedStyle& style = StyleRef(); - const ComputedStyle& cb_style = containing_block->StyleRef(); - const auto writing_mode = cb_style.GetWritingMode(); - const auto direction = cb_style.Direction(); - LayoutUnit percentage_resolution_size = - space.PercentageResolutionInlineSizeForParentWritingMode(); - NGBoxStrut margins = ComputePhysicalMargins(style, percentage_resolution_size) - .ConvertToLogical(writing_mode, direction); - ResolveInlineMargins(style, cb_style, space.AvailableSize().inline_size, - LogicalWidth(), &margins); - SetMargin(margins.ConvertToPhysical(writing_mode, direction)); + UpdateNGBlockLayout(); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h index 37fafae2..c17a0ca 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
@@ -24,9 +24,6 @@ protected: bool IsOfType(LayoutObjectType) const override; - - private: - void UpdateMargins(const NGConstraintSpace&); }; DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGBlockFlow, IsLayoutNGBlockFlow());
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc index 4f49e5f3..0939dc6 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -9,6 +9,8 @@ #include "third_party/blink/renderer/core/editing/position_with_affinity.h" #include "third_party/blink/renderer/core/layout/hit_test_location.h" +#include "third_party/blink/renderer/core/layout/layout_analyzer.h" +#include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h" @@ -187,8 +189,9 @@ const PhysicalOffset& additional_offset, NGOutlineType include_block_overflows) const { if (PaintFragment()) { - PaintFragment()->AddSelfOutlineRects(&rects, additional_offset, - include_block_overflows); + To<NGPhysicalBoxFragment>(PaintFragment()->PhysicalFragment()) + .AddSelfOutlineRects(additional_offset, include_block_overflows, + &rects); } else { Base::AddOutlineRects(rects, additional_offset, include_block_overflows); } @@ -357,8 +360,55 @@ NGPaintFragment::DirtyLinesFromChangedChild(child); } +template <typename Base> +void LayoutNGBlockFlowMixin<Base>::UpdateNGBlockLayout() { + LayoutAnalyzer::BlockScope analyzer(*this); + + if (Base::IsOutOfFlowPositioned()) { + this->UpdateOutOfFlowBlockLayout(); + return; + } + + NGConstraintSpace constraint_space = + NGConstraintSpace::CreateFromLayoutObject( + *this, !Base::View()->GetLayoutState()->Next() /* is_layout_root */); + + scoped_refptr<const NGLayoutResult> result = + NGBlockNode(this).Layout(constraint_space); + + for (const auto& descendant : + result->PhysicalFragment().OutOfFlowPositionedDescendants()) + descendant.node.UseLegacyOutOfFlowPositioning(); + this->UpdateMargins(constraint_space); +} + +template <typename Base> +void LayoutNGBlockFlowMixin<Base>::UpdateMargins( + const NGConstraintSpace& space) { + const LayoutBlock* containing_block = Base::ContainingBlock(); + if (!containing_block || !containing_block->IsLayoutBlockFlow()) + return; + + // In the legacy engine, for regular block container layout, children + // calculate and store margins on themselves, while in NG that's done by the + // container. Since this object is a LayoutNG entry-point, we'll have to do it + // on ourselves, since that's what the legacy container expects. + const ComputedStyle& style = Base::StyleRef(); + const ComputedStyle& cb_style = containing_block->StyleRef(); + const auto writing_mode = cb_style.GetWritingMode(); + const auto direction = cb_style.Direction(); + LayoutUnit percentage_resolution_size = + space.PercentageResolutionInlineSizeForParentWritingMode(); + NGBoxStrut margins = ComputePhysicalMargins(style, percentage_resolution_size) + .ConvertToLogical(writing_mode, direction); + ResolveInlineMargins(style, cb_style, space.AvailableSize().inline_size, + Base::LogicalWidth(), &margins); + this->SetMargin(margins.ConvertToPhysical(writing_mode, direction)); +} + +template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutBlockFlow>; +template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutProgress>; template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCaption>; template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCell>; -template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutBlockFlow>; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h index 8e67360..6b5d874 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" +#include "third_party/blink/renderer/core/layout/layout_progress.h" #include "third_party/blink/renderer/core/layout/layout_table_caption.h" #include "third_party/blink/renderer/core/layout/layout_table_cell.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h" @@ -77,6 +78,10 @@ void DirtyLinesFromChangedChild(LayoutObject* child, MarkingBehavior marking_behavior) final; + // Intended to be called from UpdateLayout() for subclasses that want the same + // behavior as LayoutNGBlockFlow. + void UpdateNGBlockLayout(); + std::unique_ptr<NGInlineNodeData> ng_inline_node_data_; scoped_refptr<NGPaintFragment> paint_fragment_; @@ -84,6 +89,7 @@ private: void AddScrollingOverflowFromChildren(); + void UpdateMargins(const NGConstraintSpace& space); }; // If you edit these export templates, also update templates in @@ -91,6 +97,8 @@ extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutBlockFlow>; extern template class CORE_EXTERN_TEMPLATE_EXPORT + LayoutNGBlockFlowMixin<LayoutProgress>; +extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCaption>; extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutTableCell>;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc index 88bafe7a..bc31a16 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -192,6 +192,7 @@ template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>; template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>; +template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutProgress>; template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCaption>; template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCell>;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h index 7234dcf..e75f321 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/core/layout/layout_progress.h" #include "third_party/blink/renderer/core/layout/layout_table_caption.h" #include "third_party/blink/renderer/core/layout/layout_table_cell.h" @@ -37,6 +38,7 @@ extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>; extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>; +extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutProgress>; extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutTableCaption>; extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_progress.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_progress.cc new file mode 100644 index 0000000..9ad9421 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_progress.cc
@@ -0,0 +1,25 @@ +// 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 "third_party/blink/renderer/core/layout/ng/layout_ng_progress.h" + +#include "third_party/blink/renderer/core/layout/layout_object.h" + +namespace blink { + +LayoutNGProgress::LayoutNGProgress(Element* element) + : LayoutNGBlockFlowMixin<LayoutProgress>(element) {} + +LayoutNGProgress::~LayoutNGProgress() = default; + +void LayoutNGProgress::UpdateBlockLayout(bool relayout_children) { + UpdateNGBlockLayout(); +} + +bool LayoutNGProgress::IsOfType(LayoutObjectType type) const { + return type == kLayoutObjectNGProgress || + LayoutNGMixin<LayoutProgress>::IsOfType(type); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h b/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h new file mode 100644 index 0000000..7ad4c0c1 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h
@@ -0,0 +1,32 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_PROGRESS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_PROGRESS_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/layout_progress.h" +#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h" + +namespace blink { + +class CORE_EXPORT LayoutNGProgress + : public LayoutNGBlockFlowMixin<LayoutProgress> { + public: + explicit LayoutNGProgress(Element*); + ~LayoutNGProgress() override; + + void UpdateBlockLayout(bool relayout_children) override; + + const char* GetName() const override { return "LayoutNGProgress"; } + + protected: + bool IsOfType(LayoutObjectType type) const override; +}; + +DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGProgress, IsLayoutNGProgress()); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_PROGRESS_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 07f5dcc..ac2cc67 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1984,6 +1984,33 @@ return block_offset >= FragmentainerSpaceAvailable(); } +LayoutUnit NGBlockLayoutAlgorithm::OffsetFromFragmentainerStart() const { + DCHECK(container_builder_.BfcBlockOffset()); + return ConstraintSpace().FragmentainerOffsetAtBfc() + + *container_builder_.BfcBlockOffset(); +} + +LayoutUnit NGBlockLayoutAlgorithm::PortionIntersectingWithFragmentainer( + LayoutUnit block_offset, + LayoutUnit block_size) const { + LayoutUnit offset_from_fragmentainer_start = + OffsetFromFragmentainerStart() + block_offset; + // Whatever is before the block-start of the fragmentainer isn't considered to + // intersect with the fragmentainer, so subtract it (by adding the negative + // offset). + if (offset_from_fragmentainer_start < LayoutUnit()) + block_size += offset_from_fragmentainer_start; + return block_size; +} + +void NGBlockLayoutAlgorithm::PropagateUnbreakableBlockSize( + LayoutUnit block_offset, + LayoutUnit block_size) { + DCHECK(ConstraintSpace().IsInitialColumnBalancingPass()); + block_size = PortionIntersectingWithFragmentainer(block_offset, block_size); + container_builder_.PropagateTallestUnbreakableBlockSize(block_size); +} + bool NGBlockLayoutAlgorithm::FinalizeForFragmentation() { if (Node().ChildrenInline() && !early_break_) { if (container_builder_.DidBreak() || first_overflowing_line_) { @@ -2105,8 +2132,7 @@ // If this is the initial column balancing pass, attempt to make the // column block-size at least as large as the tallest piece of // monolithic content and/or block with break-inside:avoid. - container_builder_.PropagateTallestUnbreakableBlockSize( - fragment.BlockSize()); + PropagateUnbreakableBlockSize(block_offset, fragment.BlockSize()); } } // We only care about soft breaks if we have a fragmentainer block-size.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h index 1fa4901..231d698 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -221,6 +221,21 @@ // whether fits within the fragmentainer or not. bool IsFragmentainerOutOfSpace(LayoutUnit block_offset) const; + // Return the block-offset from the start of the fragmentainer, to this node. + LayoutUnit OffsetFromFragmentainerStart() const; + + // Return the block-size of the portion that intersects with the + // fragmentainer. The block-offset is relative to this node. + LayoutUnit PortionIntersectingWithFragmentainer(LayoutUnit block_offset, + LayoutUnit block_size) const; + + // Propagate the block-size of unbreakable content. This is used to inflate + // the initial minimal column block-size when balancing columns. Unbreakable + // content will actually fragment if the columns aren't large enough, and we + // want to prevent that, if possible. + void PropagateUnbreakableBlockSize(LayoutUnit block_offset, + LayoutUnit block_size); + // Final adjustments before fragment creation. We need to prevent the fragment // from crossing fragmentainer boundaries, and rather create a break token if // we're out of space. As part of finalizing we may also discover that we need
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc index dc6ad62f..d70d4fe27 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -3243,6 +3243,32 @@ EXPECT_EQ(expectation, dump); } +TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingUnderflow) { + SetBodyInnerHTML(R"HTML( + <style> + #parent { + columns: 3; + column-gap: 10px; + width: 320px; + } + </style> + <div id="container"> + <div id="parent"> + <div style="break-inside:avoid; margin-top:-100px; width:55px; height:110px;"></div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x10 + offset:0,0 size:320x10 + offset:0,0 size:100x10 + offset:0,-100 size:55x110 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeBfc) { SetBodyInnerHTML(R"HTML( <style>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 898d05f4..1424071 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -194,8 +194,9 @@ Vector<PhysicalRect> outline_rects; // The result rects are in coordinates of this object's border box. AddSelfOutlineRects( - &outline_rects, PhysicalOffset(), - GetLayoutObject()->OutlineRectsShouldIncludeBlockVisualOverflow()); + PhysicalOffset(), + GetLayoutObject()->OutlineRectsShouldIncludeBlockVisualOverflow(), + &outline_rects); PhysicalRect rect = UnionRectEvenIfEmpty(outline_rects); rect.Inflate(LayoutUnit(style.OutlineOutsetExtent())); ink_overflow.Unite(rect); @@ -205,11 +206,11 @@ } void NGPhysicalBoxFragment::AddSelfOutlineRects( - Vector<PhysicalRect>* outline_rects, const PhysicalOffset& additional_offset, - NGOutlineType outline_type) const { - // TODO(kojii): Needs inline_element_continuation logic from - // LayoutBlockFlow::AddOutlineRects? + NGOutlineType outline_type, + Vector<PhysicalRect>* outline_rects) const { + if (NGOutlineUtils::IsInlineOutlineNonpaintingFragment(*this)) + return; const LayoutObject* layout_object = GetLayoutObject(); DCHECK(layout_object);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h index 999537f7..6bb45d5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -81,9 +81,9 @@ // Fragment offset is this fragment's offset from parent. // Needed to compensate for LayoutInline Legacy code offsets. - void AddSelfOutlineRects(Vector<PhysicalRect>* outline_rects, - const PhysicalOffset& additional_offset, - NGOutlineType include_block_overflows) const; + void AddSelfOutlineRects(const PhysicalOffset& additional_offset, + NGOutlineType include_block_overflows, + Vector<PhysicalRect>* outline_rects) const; UBiDiLevel BidiLevel() const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc index 4eb0b44..30d48e9 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -131,8 +131,8 @@ // may have transforms and so we have to go through LocalToAncestorRects? if (descendant_box->HasLayer()) { Vector<PhysicalRect> layer_outline_rects; - descendant_box->AddSelfOutlineRects(&layer_outline_rects, - PhysicalOffset(), outline_type); + descendant_box->AddSelfOutlineRects(PhysicalOffset(), outline_type, + &layer_outline_rects); // Don't pass additional_offset because LocalToAncestorRects will itself // apply it. @@ -145,7 +145,7 @@ if (descendant_layout_object->IsBox()) { descendant_box->AddSelfOutlineRects( - outline_rects, additional_offset + descendant.Offset(), outline_type); + additional_offset + descendant.Offset(), outline_type, outline_rects); return; }
diff --git a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc index 6cea119..6a35ba8 100644 --- a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc +++ b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" +#include "third_party/blink/renderer/core/display_lock/display_lock_context.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/node.h" @@ -72,7 +73,7 @@ } if (target) { - target->ActivateDisplayLockIfNeeded(); + target->ActivateDisplayLockIfNeeded(DisplayLockActivationReason::kUser); target->DispatchActivateInvisibleEventIfNeeded(); }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc index 0e873ecf..3fcbfa6 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
@@ -21,23 +21,22 @@ if (!NGOutlineUtils::HasPaintedOutline(fragment.Style(), fragment.GetNode())) return; - // TODO(kojii): Eliminate paint_fragment_ if this is used for block-children - if (!paint_fragment_) - return; - Vector<PhysicalRect> outline_rects; - paint_fragment_->AddSelfOutlineRects( - &outline_rects, paint_offset, + fragment.AddSelfOutlineRects( + paint_offset, fragment.GetLayoutObject() - ->OutlineRectsShouldIncludeBlockVisualOverflow()); + ->OutlineRectsShouldIncludeBlockVisualOverflow(), + &outline_rects); + if (outline_rects.IsEmpty()) return; + const DisplayItemClient& display_item_client = GetDisplayItemClient(); if (DrawingRecorder::UseCachedDrawingIfPossible( - paint_info.context, *paint_fragment_, paint_info.phase)) + paint_info.context, display_item_client, paint_info.phase)) return; - DrawingRecorder recorder(paint_info.context, *paint_fragment_, + DrawingRecorder recorder(paint_info.context, display_item_client, paint_info.phase); PaintOutlineRects(paint_info, outline_rects, fragment.Style()); }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc index a5d4187..0af714e8 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -859,20 +859,6 @@ return visual_rect; } -void NGPaintFragment::AddSelfOutlineRects( - Vector<PhysicalRect>* outline_rects, - const PhysicalOffset& additional_offset, - NGOutlineType outline_type) const { - DCHECK(outline_rects); - const NGPhysicalFragment& fragment = PhysicalFragment(); - if (auto* box_fragment = DynamicTo<NGPhysicalBoxFragment>(fragment)) { - if (NGOutlineUtils::IsInlineOutlineNonpaintingFragment(PhysicalFragment())) - return; - box_fragment->AddSelfOutlineRects(outline_rects, additional_offset, - outline_type); - } -} - const NGPaintFragment* NGPaintFragment::ContainerLineBox() const { DCHECK(PhysicalFragment().IsInline()); for (const NGPaintFragment* fragment :
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h index 254f65b..6458de1 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -172,10 +172,6 @@ void RecalcInlineChildrenInkOverflow() const; - void AddSelfOutlineRects(Vector<PhysicalRect>*, - const PhysicalOffset& offset, - NGOutlineType) const; - // TODO(layout-dev): Implement when we have oveflow support. // TODO(eae): Switch to using NG geometry types. bool HasOverflowClip() const { return PhysicalFragment().HasOverflowClip(); }
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc index 43a05be2..cecdf63 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.cc +++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -817,7 +817,7 @@ ? CompositorElementIdNamespace::kHorizontalScrollbar : CompositorElementIdNamespace::kVerticalScrollbar; return CompositorElementIdFromUniqueObjectId( - scrollable_element_id.GetInternalValue(), element_id_namespace); + scrollable_element_id.GetStableId(), element_id_namespace); } void ScrollableArea::OnScrollFinished() {
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h index f11a137e..0c6b99b 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -203,9 +203,7 @@ void queueMicrotask(V8VoidFunction*); TrustedTypePolicyFactory* GetTrustedTypes() const override; - TrustedTypePolicyFactory* trustedTypesWorkers() const { - return GetTrustedTypes(); - } + TrustedTypePolicyFactory* trustedTypes() const { return GetTrustedTypes(); } protected: WorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.idl b/third_party/blink/renderer/core/workers/worker_global_scope.idl index d88dadaf..a6d5607 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.idl +++ b/third_party/blink/renderer/core/workers/worker_global_scope.idl
@@ -74,7 +74,7 @@ readonly attribute FontFaceSet fonts; // TrustedTypes API: http://github.com/wicg/trusted-types - [RuntimeEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory TrustedTypesWorkers; + [RuntimeEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory trustedTypes; }; WorkerGlobalScope includes WindowOrWorkerGlobalScope;
diff --git a/third_party/blink/renderer/devtools/.eslintignore b/third_party/blink/renderer/devtools/.eslintignore index 79b5ff8a..9e04d37 100644 --- a/third_party/blink/renderer/devtools/.eslintignore +++ b/third_party/blink/renderer/devtools/.eslintignore
@@ -12,7 +12,6 @@ front_end/cm_web_modes/ front_end/diff/diff_match_patch.js front_end/formatter_worker/acorn/ -front_end/terminal/xterm.js/ front_end/protocol_externs.js front_end/javascript_metadata/NativeFunctions.js scripts/ \ No newline at end of file
diff --git a/third_party/blink/renderer/devtools/BUILD.gn b/third_party/blink/renderer/devtools/BUILD.gn index c2aaa57..0127da1e 100644 --- a/third_party/blink/renderer/devtools/BUILD.gn +++ b/third_party/blink/renderer/devtools/BUILD.gn
@@ -639,12 +639,6 @@ "front_end/sources_test_runner/SearchTestRunner.js", "front_end/sources_test_runner/SourcesTestRunner.js", "front_end/sources_test_runner/module.json", - "front_end/terminal/module.json", - "front_end/terminal/terminal.css", - "front_end/terminal/TerminalWidget.js", - "front_end/terminal/xterm.js/addons/fit/fit.js", - "front_end/terminal/xterm.js/build/xterm.css", - "front_end/terminal/xterm.js/build/xterm.js", "front_end/test_runner/module.json", "front_end/test_runner/TestRunner.js", "front_end/text_editor/autocompleteTooltip.css",
diff --git a/third_party/blink/renderer/devtools/front_end/langpacks/devtools_ui_strings.grd b/third_party/blink/renderer/devtools/front_end/langpacks/devtools_ui_strings.grd index e6cb21bc..f1305d6 100644 --- a/third_party/blink/renderer/devtools/front_end/langpacks/devtools_ui_strings.grd +++ b/third_party/blink/renderer/devtools/front_end/langpacks/devtools_ui_strings.grd
@@ -63,7 +63,6 @@ <part file="../snippets/snippets_strings.grdp" /> <part file="../source_frame/source_frame_strings.grdp" /> <part file="../sources/sources_strings.grdp" /> - <part file="../terminal/terminal_strings.grdp" /> <part file="../text_editor/text_editor_strings.grdp" /> <part file="../timeline/timeline_strings.grdp" /> <part file="../timeline_model/timeline_model_strings.grdp" />
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js index e7a5ec1b..7d62c1a 100644 --- a/third_party/blink/renderer/devtools/front_end/main/Main.js +++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -138,7 +138,6 @@ Root.Runtime.experiments.register('sourceDiff', 'Source diff'); Root.Runtime.experiments.register('splitInDrawer', 'Split in drawer', true); Root.Runtime.experiments.register('spotlight', 'Spotlight', true); - Root.Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true); // Timeline Root.Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/CPUProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/CPUProfileView.js index 9feb28cb..ef16a3c 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/CPUProfileView.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/CPUProfileView.js
@@ -282,6 +282,15 @@ /** * @override * @param {number} value + * @return {string} + */ + formatValueAccessibleText(value) { + return this.formatValue(value); + } + + /** + * @override + * @param {number} value * @param {!Profiler.ProfileDataGridNode} node * @return {string} */
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js index b3d87f7..6cb924f 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
@@ -723,6 +723,15 @@ /** * @override * @param {number} value + * @return {string} + */ + formatValueAccessibleText(value) { + return ls`${value} bytes`; + } + + /** + * @override + * @param {number} value * @param {!Profiler.ProfileDataGridNode} node * @return {string} */
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/ProfileDataGrid.js b/third_party/blink/renderer/devtools/front_end/profiler/ProfileDataGrid.js index ca88d477..7e7ca9d6 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/ProfileDataGrid.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/ProfileDataGrid.js
@@ -205,8 +205,16 @@ _createValueCell(value, percent) { const cell = createElementWithClass('td', 'numeric-column'); const div = cell.createChild('div', 'profile-multiple-values'); - div.createChild('span').textContent = this.tree._formatter.formatValue(value, this); - div.createChild('span', 'percent-column').textContent = this.tree._formatter.formatPercent(percent, this); + const valueSpan = div.createChild('span'); + const valueText = this.tree._formatter.formatValue(value, this); + valueSpan.textContent = valueText; + const percentSpan = div.createChild('span', 'percent-column'); + const percentText = this.tree._formatter.formatPercent(percent, this); + percentSpan.textContent = percentText; + UI.ARIAUtils.markAsHidden(valueSpan); + UI.ARIAUtils.markAsHidden(percentSpan); + const valueAccessibleText = this.tree._formatter.formatValueAccessibleText(value, this); + UI.ARIAUtils.setAccessibleName(div, ls`${valueAccessibleText}, ${percentText}`); return cell; } @@ -688,6 +696,12 @@ /** * @param {number} value + * @return {string} + */ + formatValueAccessibleText(value) {}, + + /** + * @param {number} value * @param {!Profiler.ProfileDataGridNode} node * @return {string} */
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp index 81163ae..d5a959b 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
@@ -12,6 +12,9 @@ <message name="IDS_DEVTOOLS_030361ea56fa177ebcbefe708a45b0f2" desc="Text in Heap Snapshot Data Grids of a profiler tool"> # Deleted </message> + <message name="IDS_DEVTOOLS_03301bd5f0d1517cf88b2f8348b82dfc" desc="Accessible text for the value in bytes of a Memory allocation."> + <ph name="VALUE">$1s<ex>12345</ex></ph> bytes + </message> <message name="IDS_DEVTOOLS_04042b5589b3d4fd4e1e7e44265ad247" desc="Total trend div title in Isolate Selector of a profiler tool"> Total page JS heap size change trend over the last <ph name="TRENDINTERVALMINUTES">$1s<ex>3</ex></ph> minutes. </message>
diff --git a/third_party/blink/renderer/devtools/front_end/shell.json b/third_party/blink/renderer/devtools/front_end/shell.json index eaeb2dd..98efbd3 100644 --- a/third_party/blink/renderer/devtools/front_end/shell.json +++ b/third_party/blink/renderer/devtools/front_end/shell.json
@@ -41,7 +41,6 @@ { "name": "snippets" }, { "name": "source_frame" }, { "name": "sources" }, - { "name": "terminal", "type": "remote" }, { "name": "text_editor" }, { "name": "workspace_diff" }, { "name": "protocol_monitor"}
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/TerminalWidget.js b/third_party/blink/renderer/devtools/front_end/terminal/TerminalWidget.js deleted file mode 100644 index 4ec72111..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/TerminalWidget.js +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -/** - * @unrestricted - */ -Terminal.TerminalWidget = class extends UI.VBox { - constructor() { - super(true); - this.registerRequiredCSS('terminal/xterm.js/build/xterm.css'); - this.registerRequiredCSS('terminal/terminal.css'); - this.element.classList.add('terminal-root'); - this._init(); - this._linkifier = new Components.Linkifier(); - this._config = {attributes: true, childList: true, characterData: true, subtree: true}; - } - - async _init() { - const backend = await Services.serviceManager.createRemoteService('Terminal'); - this._initialized(backend); - } - - /** - * @param {?Services.ServiceManager.Service} backend - */ - _initialized(backend) { - if (!backend) { - if (!this._unavailableLabel) { - this._unavailableLabel = this.contentElement.createChild('div', 'terminal-error-message fill'); - this._unavailableLabel.createChild('div').textContent = Common.UIString('Terminal service is not available'); - } - setTimeout(this._init.bind(this), 2000); - return; - } - - if (this._unavailableLabel) { - this._unavailableLabel.remove(); - delete this._unavailableLabel; - } - - this._backend = backend; - - if (!this._term) { - this._term = new Terminal({cursorBlink: true}); - this._term.open(this.contentElement); - this._mutationObserver = new MutationObserver(this._linkify.bind(this)); - this._mutationObserver.observe(this.contentElement, this._config); - this._term.on('data', data => { - this._backend.send('write', {data: data}); - }); - this._term.fit(); - this._term.on('resize', size => { - this._backend.send('resize', {cols: size.cols, rows: size.rows}); - }); - } - - this._backend.send('init', {cols: this._term.cols, rows: this._term.rows}); - this._backend.on('data', result => { - this._term.write(result.data); - }); - this._backend.on('disposed', this._disposed.bind(this)); - } - - /** - * @override - */ - onResize() { - if (this._term) { - this._term.fit(); - } - } - - _disposed() { - this._initialized(null); - } - - /** - * @override - */ - ownerViewDisposed() { - if (this._backend) { - this._backend.dispose(); - } - } - - _linkify() { - this._mutationObserver.takeRecords(); - this._mutationObserver.disconnect(); - this._linkifier.reset(); - const rows = this._term['rowContainer'].children; - for (let i = 0; i < rows.length; i++) { - this._linkifyTerminalLine(rows[i]); - } - this._mutationObserver.observe(this.contentElement, this._config); - } - - /** - * @param {string} string - */ - _linkifyText(string) { - const regex1 = /([/\w\.-]*)+\:([\d]+)(?:\:([\d]+))?/; - const regex2 = /([/\w\.-]*)+\(([\d]+),([\d]+)\)/; - const container = createDocumentFragment(); - - while (string) { - const linkString = regex1.exec(string) || regex2.exec(string); - if (!linkString) { - break; - } - - const text = linkString[0]; - const path = linkString[1]; - const lineNumber = parseInt(linkString[2], 10) - 1 || 0; - const columnNumber = parseInt(linkString[3], 10) - 1 || 0; - - const uiSourceCode = Workspace.workspace.uiSourceCodes().find(uisc => uisc.url().endsWith(path)); - const linkIndex = string.indexOf(text); - const nonLink = string.substring(0, linkIndex); - container.appendChild(createTextNode(nonLink)); - - if (uiSourceCode) { - container.appendChild(Components.Linkifier.linkifyURL( - uiSourceCode.url(), - {text, lineNumber, columnNumber, maxLengh: Number.MAX_VALUE, className: 'terminal-link'})); - } else { - container.appendChild(createTextNode(text)); - } - string = string.substring(linkIndex + text.length); - } - - if (string) { - container.appendChild(createTextNode(string)); - } - return container; - } - - /** - * @param {!Node} line - */ - _linkifyTerminalLine(line) { - let node = line.firstChild; - while (node) { - if (node.nodeType !== Node.TEXT_NODE) { - node = node.nextSibling; - continue; - } - const nextNode = node.nextSibling; - node.remove(); - const linkified = this._linkifyText(node.textContent); - line.insertBefore(linkified, nextNode); - node = nextNode; - } - } -};
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/module.json b/third_party/blink/renderer/devtools/front_end/terminal/module.json deleted file mode 100644 index 6802e2b4..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/module.json +++ /dev/null
@@ -1,31 +0,0 @@ -{ - "extensions": [ - { - "type": "view", - "location": "drawer-sidebar", - "id": "drawer.xterm", - "title": "Terminal", - "order": 10, - "factoryName": "Terminal.TerminalWidget" - } - ], - "dependencies": [ - "components", - "ui", - "services" - ], - "experiment": "terminalInDrawer", - "scripts": [ - "xterm.js/build/xterm.js", - "xterm.js/addons/fit/fit.js", - "TerminalWidget.js" - ], - "skip_compilation": [ - "xterm.js/build/xterm.js", - "xterm.js/addons/fit/fit.js" - ], - "resources": [ - "terminal.css", - "xterm.js/build/xterm.css" - ] -}
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/terminal.css b/third_party/blink/renderer/devtools/front_end/terminal/terminal.css deleted file mode 100644 index 17fa5a9..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/terminal.css +++ /dev/null
@@ -1,37 +0,0 @@ -/* - * Copyright 2016 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -.terminal-root { - background-color: #111; - color: #fafafa; - padding: 2px; - -webkit-user-select: text; - white-space: nowrap; -} - -.terminal-error-message { - display: flex; - align-items: center; - padding: 10px; - background-color: rgba(255, 255, 255, 0.8); - justify-content: center; - font-size: 16px; - color: #222; -} - -.terminal-error-message div { - padding-right: 10px; -} - -.terminal-link { - color: inherit; - text-decoration: inherit; -} - -.terminal-link:hover { - text-decoration: underline; - cursor: pointer; -}
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/terminal_strings.grdp b/third_party/blink/renderer/devtools/front_end/terminal/terminal_strings.grdp deleted file mode 100644 index 5561a9f..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/terminal_strings.grdp +++ /dev/null
@@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<grit-part> - <message name="IDS_DEVTOOLS_514d8a494f087c0d549b9536c2ef3bd9" desc="Title of the 'Terminal' tool in the sidebar of the drawer tool"> - Terminal - </message> - <message name="IDS_DEVTOOLS_69685b2a57646d0d0bc125b5f94f3931" desc="Text in Terminal Widget of the web version terminal"> - Terminal service is not available - </message> -</grit-part> \ No newline at end of file
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/LICENSE b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/LICENSE deleted file mode 100644 index 1ed6f2a..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/LICENSE +++ /dev/null
@@ -1,20 +0,0 @@ -Copyright (c) 2014, sourceLair Limited (https://github.com/sourcelair/) -Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/README.chromium b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/README.chromium deleted file mode 100644 index 662bc38..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/README.chromium +++ /dev/null
@@ -1,7 +0,0 @@ -Name: Xterm.js is a terminal front-end component written in JavaScript that works in the browser. -Short Name: xterm.js -URL: https://github.com/sourcelair/xterm.js -License: MIT -Security Critical: no - -This directory contains Chrome's version of xterm.js with tests, demo and some addons folders removed.
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/fit.js b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/fit.js deleted file mode 100644 index 46b79e9b..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/fit.js +++ /dev/null
@@ -1,86 +0,0 @@ -/** - * Fit terminal columns and rows to the dimensions of its DOM element. - * - * ## Approach - * - Rows: Truncate the division of the terminal parent element height by the terminal row height. - * - * - Columns: Truncate the division of the terminal parent element width by the terminal character - * width (apply display: inline at the terminal row and truncate its width with the current - * number of columns). - * @module xterm/addons/fit/fit - * @license MIT - */ - -(function (fit) { - if (typeof exports === 'object' && typeof module === 'object') { - /* - * CommonJS environment - */ - module.exports = fit(require('../../xterm')); - } else if (typeof define == 'function') { - /* - * Require.js is available - */ - define(['../../xterm'], fit); - } else { - /* - * Plain browser environment - */ - fit(window.Terminal); - } -})(function (Xterm) { - var exports = {}; - - exports.proposeGeometry = function (term) { - if (!term.element.parentElement) { - return null; - } - var parentElementStyle = window.getComputedStyle(term.element.parentElement), - parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), - parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), - elementStyle = window.getComputedStyle(term.element), - elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), - elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), - availableHeight = parentElementHeight - elementPaddingVer, - availableWidth = parentElementWidth - elementPaddingHor, - container = term.rowContainer, - subjectRow = term.rowContainer.firstElementChild, - contentBuffer = subjectRow.innerHTML, - characterHeight, - rows, - characterWidth, - cols, - geometry; - - subjectRow.style.display = 'inline'; - subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace - characterWidth = subjectRow.getBoundingClientRect().width; - subjectRow.style.display = ''; // Revert style before calculating height, since they differ. - characterHeight = subjectRow.getBoundingClientRect().height; - subjectRow.innerHTML = contentBuffer; - - rows = parseInt(availableHeight / characterHeight); - cols = parseInt(availableWidth / characterWidth); - - geometry = {cols: cols, rows: rows}; - return geometry; - }; - - exports.fit = function (term) { - var geometry = exports.proposeGeometry(term); - - if (geometry) { - term.resize(geometry.cols, geometry.rows); - } - }; - - Xterm.prototype.proposeGeometry = function () { - return exports.proposeGeometry(this); - }; - - Xterm.prototype.fit = function () { - return exports.fit(this); - }; - - return exports; -});
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/package.json b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/package.json deleted file mode 100644 index f7cb5bc..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/addons/fit/package.json +++ /dev/null
@@ -1,5 +0,0 @@ -{ - "name": "xterm.fit", - "main": "fit.js", - "private": true -}
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.css b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.css deleted file mode 100644 index efdc016..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.css +++ /dev/null
@@ -1,2248 +0,0 @@ -/** - * xterm.js: xterm, in the browser - * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * https://github.com/chjj/term.js - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * Originally forked from (with the author's permission): - * Fabrice Bellard's javascript vt100 for jslinux: - * http://bellard.org/jslinux/ - * Copyright (c) 2011 Fabrice Bellard - * The original design remains. The terminal itself - * has been extended to include xterm CSI codes, among - * other features. - */ - -/* - * Default style for xterm.js - */ - -.terminal { - background-color: #000; - color: #fff; - font-family: courier-new, courier, monospace; - font-feature-settings: "liga" 0; - position: relative; -} - -.terminal.focus, -.terminal:focus { - outline: none; -} - -.terminal .xterm-helpers { - position: absolute; - top: 0; -} - -.terminal .xterm-helper-textarea { - /* - * HACK: to fix IE's blinking cursor - * Move textarea out of the screen to the far left, so that the cursor is not visible. - */ - position: absolute; - opacity: 0; - left: -9999em; - top: 0; - width: 0; - height: 0; - z-index: -10; - /** Prevent wrapping so the IME appears against the textarea at the correct position */ - white-space: nowrap; - overflow: hidden; - resize: none; -} - -.terminal a { - color: inherit; - text-decoration: none; -} - -.terminal a:hover { - cursor: pointer; - text-decoration: underline; -} - -.terminal a.xterm-invalid-link:hover { - cursor: text; - text-decoration: none; -} - -.terminal.focus:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor { - background-color: #fff; - color: #000; -} - -.terminal:not(.focus) .terminal-cursor { - outline: 1px solid #fff; - outline-offset: -1px; - background-color: transparent; -} - -.terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus.xterm-cursor-blink-on .terminal-cursor { - background-color: transparent; - color: inherit; -} - -.terminal.xterm-cursor-style-bar .terminal-cursor, -.terminal.xterm-cursor-style-underline .terminal-cursor { - position: relative; -} -.terminal.xterm-cursor-style-bar .terminal-cursor::before, -.terminal.xterm-cursor-style-underline .terminal-cursor::before { - content: ""; - display: block; - position: absolute; - background-color: #fff; -} -.terminal.xterm-cursor-style-bar .terminal-cursor::before { - top: 0; - bottom: 0; - left: 0; - width: 1px; -} -.terminal.xterm-cursor-style-underline .terminal-cursor::before { - bottom: 0; - left: 0; - right: 0; - height: 1px; -} -.terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before, -.terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before { - background-color: transparent; -} -.terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before, -.terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before { - background-color: #fff; -} - -.terminal .composition-view { - background: #000; - color: #FFF; - display: none; - position: absolute; - white-space: nowrap; - z-index: 1; -} - -.terminal .composition-view.active { - display: block; -} - -.terminal .xterm-viewport { - /* On OS X this is required in order for the scroll bar to appear fully opaque */ - background-color: #000; - overflow-y: scroll; -} - -.terminal .xterm-wide-char, -.terminal .xterm-normal-char { - display: inline-block; -} - -.terminal .xterm-rows { - position: absolute; - left: 0; - top: 0; -} - -.terminal .xterm-rows > div { - /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */ - white-space: nowrap; -} - -.terminal .xterm-scroll-area { - visibility: hidden; -} - -.terminal .xterm-char-measure-element { - display: inline-block; - visibility: hidden; - position: absolute; - left: -9999em; -} - -/* - * Determine default colors for xterm.js - */ -.terminal .xterm-bold { - font-weight: bold; -} - -.terminal .xterm-underline { - text-decoration: underline; -} - -.terminal .xterm-blink { - text-decoration: blink; -} - -.terminal .xterm-hidden { - visibility: hidden; -} - -.terminal .xterm-color-0 { - color: #2e3436; -} - -.terminal .xterm-bg-color-0 { - background-color: #2e3436; -} - -.terminal .xterm-color-1 { - color: #cc0000; -} - -.terminal .xterm-bg-color-1 { - background-color: #cc0000; -} - -.terminal .xterm-color-2 { - color: #4e9a06; -} - -.terminal .xterm-bg-color-2 { - background-color: #4e9a06; -} - -.terminal .xterm-color-3 { - color: #c4a000; -} - -.terminal .xterm-bg-color-3 { - background-color: #c4a000; -} - -.terminal .xterm-color-4 { - color: #3465a4; -} - -.terminal .xterm-bg-color-4 { - background-color: #3465a4; -} - -.terminal .xterm-color-5 { - color: #75507b; -} - -.terminal .xterm-bg-color-5 { - background-color: #75507b; -} - -.terminal .xterm-color-6 { - color: #06989a; -} - -.terminal .xterm-bg-color-6 { - background-color: #06989a; -} - -.terminal .xterm-color-7 { - color: #d3d7cf; -} - -.terminal .xterm-bg-color-7 { - background-color: #d3d7cf; -} - -.terminal .xterm-color-8 { - color: #555753; -} - -.terminal .xterm-bg-color-8 { - background-color: #555753; -} - -.terminal .xterm-color-9 { - color: #ef2929; -} - -.terminal .xterm-bg-color-9 { - background-color: #ef2929; -} - -.terminal .xterm-color-10 { - color: #8ae234; -} - -.terminal .xterm-bg-color-10 { - background-color: #8ae234; -} - -.terminal .xterm-color-11 { - color: #fce94f; -} - -.terminal .xterm-bg-color-11 { - background-color: #fce94f; -} - -.terminal .xterm-color-12 { - color: #729fcf; -} - -.terminal .xterm-bg-color-12 { - background-color: #729fcf; -} - -.terminal .xterm-color-13 { - color: #ad7fa8; -} - -.terminal .xterm-bg-color-13 { - background-color: #ad7fa8; -} - -.terminal .xterm-color-14 { - color: #34e2e2; -} - -.terminal .xterm-bg-color-14 { - background-color: #34e2e2; -} - -.terminal .xterm-color-15 { - color: #eeeeec; -} - -.terminal .xterm-bg-color-15 { - background-color: #eeeeec; -} - -.terminal .xterm-color-16 { - color: #000000; -} - -.terminal .xterm-bg-color-16 { - background-color: #000000; -} - -.terminal .xterm-color-17 { - color: #00005f; -} - -.terminal .xterm-bg-color-17 { - background-color: #00005f; -} - -.terminal .xterm-color-18 { - color: #000087; -} - -.terminal .xterm-bg-color-18 { - background-color: #000087; -} - -.terminal .xterm-color-19 { - color: #0000af; -} - -.terminal .xterm-bg-color-19 { - background-color: #0000af; -} - -.terminal .xterm-color-20 { - color: #0000d7; -} - -.terminal .xterm-bg-color-20 { - background-color: #0000d7; -} - -.terminal .xterm-color-21 { - color: #0000ff; -} - -.terminal .xterm-bg-color-21 { - background-color: #0000ff; -} - -.terminal .xterm-color-22 { - color: #005f00; -} - -.terminal .xterm-bg-color-22 { - background-color: #005f00; -} - -.terminal .xterm-color-23 { - color: #005f5f; -} - -.terminal .xterm-bg-color-23 { - background-color: #005f5f; -} - -.terminal .xterm-color-24 { - color: #005f87; -} - -.terminal .xterm-bg-color-24 { - background-color: #005f87; -} - -.terminal .xterm-color-25 { - color: #005faf; -} - -.terminal .xterm-bg-color-25 { - background-color: #005faf; -} - -.terminal .xterm-color-26 { - color: #005fd7; -} - -.terminal .xterm-bg-color-26 { - background-color: #005fd7; -} - -.terminal .xterm-color-27 { - color: #005fff; -} - -.terminal .xterm-bg-color-27 { - background-color: #005fff; -} - -.terminal .xterm-color-28 { - color: #008700; -} - -.terminal .xterm-bg-color-28 { - background-color: #008700; -} - -.terminal .xterm-color-29 { - color: #00875f; -} - -.terminal .xterm-bg-color-29 { - background-color: #00875f; -} - -.terminal .xterm-color-30 { - color: #008787; -} - -.terminal .xterm-bg-color-30 { - background-color: #008787; -} - -.terminal .xterm-color-31 { - color: #0087af; -} - -.terminal .xterm-bg-color-31 { - background-color: #0087af; -} - -.terminal .xterm-color-32 { - color: #0087d7; -} - -.terminal .xterm-bg-color-32 { - background-color: #0087d7; -} - -.terminal .xterm-color-33 { - color: #0087ff; -} - -.terminal .xterm-bg-color-33 { - background-color: #0087ff; -} - -.terminal .xterm-color-34 { - color: #00af00; -} - -.terminal .xterm-bg-color-34 { - background-color: #00af00; -} - -.terminal .xterm-color-35 { - color: #00af5f; -} - -.terminal .xterm-bg-color-35 { - background-color: #00af5f; -} - -.terminal .xterm-color-36 { - color: #00af87; -} - -.terminal .xterm-bg-color-36 { - background-color: #00af87; -} - -.terminal .xterm-color-37 { - color: #00afaf; -} - -.terminal .xterm-bg-color-37 { - background-color: #00afaf; -} - -.terminal .xterm-color-38 { - color: #00afd7; -} - -.terminal .xterm-bg-color-38 { - background-color: #00afd7; -} - -.terminal .xterm-color-39 { - color: #00afff; -} - -.terminal .xterm-bg-color-39 { - background-color: #00afff; -} - -.terminal .xterm-color-40 { - color: #00d700; -} - -.terminal .xterm-bg-color-40 { - background-color: #00d700; -} - -.terminal .xterm-color-41 { - color: #00d75f; -} - -.terminal .xterm-bg-color-41 { - background-color: #00d75f; -} - -.terminal .xterm-color-42 { - color: #00d787; -} - -.terminal .xterm-bg-color-42 { - background-color: #00d787; -} - -.terminal .xterm-color-43 { - color: #00d7af; -} - -.terminal .xterm-bg-color-43 { - background-color: #00d7af; -} - -.terminal .xterm-color-44 { - color: #00d7d7; -} - -.terminal .xterm-bg-color-44 { - background-color: #00d7d7; -} - -.terminal .xterm-color-45 { - color: #00d7ff; -} - -.terminal .xterm-bg-color-45 { - background-color: #00d7ff; -} - -.terminal .xterm-color-46 { - color: #00ff00; -} - -.terminal .xterm-bg-color-46 { - background-color: #00ff00; -} - -.terminal .xterm-color-47 { - color: #00ff5f; -} - -.terminal .xterm-bg-color-47 { - background-color: #00ff5f; -} - -.terminal .xterm-color-48 { - color: #00ff87; -} - -.terminal .xterm-bg-color-48 { - background-color: #00ff87; -} - -.terminal .xterm-color-49 { - color: #00ffaf; -} - -.terminal .xterm-bg-color-49 { - background-color: #00ffaf; -} - -.terminal .xterm-color-50 { - color: #00ffd7; -} - -.terminal .xterm-bg-color-50 { - background-color: #00ffd7; -} - -.terminal .xterm-color-51 { - color: #00ffff; -} - -.terminal .xterm-bg-color-51 { - background-color: #00ffff; -} - -.terminal .xterm-color-52 { - color: #5f0000; -} - -.terminal .xterm-bg-color-52 { - background-color: #5f0000; -} - -.terminal .xterm-color-53 { - color: #5f005f; -} - -.terminal .xterm-bg-color-53 { - background-color: #5f005f; -} - -.terminal .xterm-color-54 { - color: #5f0087; -} - -.terminal .xterm-bg-color-54 { - background-color: #5f0087; -} - -.terminal .xterm-color-55 { - color: #5f00af; -} - -.terminal .xterm-bg-color-55 { - background-color: #5f00af; -} - -.terminal .xterm-color-56 { - color: #5f00d7; -} - -.terminal .xterm-bg-color-56 { - background-color: #5f00d7; -} - -.terminal .xterm-color-57 { - color: #5f00ff; -} - -.terminal .xterm-bg-color-57 { - background-color: #5f00ff; -} - -.terminal .xterm-color-58 { - color: #5f5f00; -} - -.terminal .xterm-bg-color-58 { - background-color: #5f5f00; -} - -.terminal .xterm-color-59 { - color: #5f5f5f; -} - -.terminal .xterm-bg-color-59 { - background-color: #5f5f5f; -} - -.terminal .xterm-color-60 { - color: #5f5f87; -} - -.terminal .xterm-bg-color-60 { - background-color: #5f5f87; -} - -.terminal .xterm-color-61 { - color: #5f5faf; -} - -.terminal .xterm-bg-color-61 { - background-color: #5f5faf; -} - -.terminal .xterm-color-62 { - color: #5f5fd7; -} - -.terminal .xterm-bg-color-62 { - background-color: #5f5fd7; -} - -.terminal .xterm-color-63 { - color: #5f5fff; -} - -.terminal .xterm-bg-color-63 { - background-color: #5f5fff; -} - -.terminal .xterm-color-64 { - color: #5f8700; -} - -.terminal .xterm-bg-color-64 { - background-color: #5f8700; -} - -.terminal .xterm-color-65 { - color: #5f875f; -} - -.terminal .xterm-bg-color-65 { - background-color: #5f875f; -} - -.terminal .xterm-color-66 { - color: #5f8787; -} - -.terminal .xterm-bg-color-66 { - background-color: #5f8787; -} - -.terminal .xterm-color-67 { - color: #5f87af; -} - -.terminal .xterm-bg-color-67 { - background-color: #5f87af; -} - -.terminal .xterm-color-68 { - color: #5f87d7; -} - -.terminal .xterm-bg-color-68 { - background-color: #5f87d7; -} - -.terminal .xterm-color-69 { - color: #5f87ff; -} - -.terminal .xterm-bg-color-69 { - background-color: #5f87ff; -} - -.terminal .xterm-color-70 { - color: #5faf00; -} - -.terminal .xterm-bg-color-70 { - background-color: #5faf00; -} - -.terminal .xterm-color-71 { - color: #5faf5f; -} - -.terminal .xterm-bg-color-71 { - background-color: #5faf5f; -} - -.terminal .xterm-color-72 { - color: #5faf87; -} - -.terminal .xterm-bg-color-72 { - background-color: #5faf87; -} - -.terminal .xterm-color-73 { - color: #5fafaf; -} - -.terminal .xterm-bg-color-73 { - background-color: #5fafaf; -} - -.terminal .xterm-color-74 { - color: #5fafd7; -} - -.terminal .xterm-bg-color-74 { - background-color: #5fafd7; -} - -.terminal .xterm-color-75 { - color: #5fafff; -} - -.terminal .xterm-bg-color-75 { - background-color: #5fafff; -} - -.terminal .xterm-color-76 { - color: #5fd700; -} - -.terminal .xterm-bg-color-76 { - background-color: #5fd700; -} - -.terminal .xterm-color-77 { - color: #5fd75f; -} - -.terminal .xterm-bg-color-77 { - background-color: #5fd75f; -} - -.terminal .xterm-color-78 { - color: #5fd787; -} - -.terminal .xterm-bg-color-78 { - background-color: #5fd787; -} - -.terminal .xterm-color-79 { - color: #5fd7af; -} - -.terminal .xterm-bg-color-79 { - background-color: #5fd7af; -} - -.terminal .xterm-color-80 { - color: #5fd7d7; -} - -.terminal .xterm-bg-color-80 { - background-color: #5fd7d7; -} - -.terminal .xterm-color-81 { - color: #5fd7ff; -} - -.terminal .xterm-bg-color-81 { - background-color: #5fd7ff; -} - -.terminal .xterm-color-82 { - color: #5fff00; -} - -.terminal .xterm-bg-color-82 { - background-color: #5fff00; -} - -.terminal .xterm-color-83 { - color: #5fff5f; -} - -.terminal .xterm-bg-color-83 { - background-color: #5fff5f; -} - -.terminal .xterm-color-84 { - color: #5fff87; -} - -.terminal .xterm-bg-color-84 { - background-color: #5fff87; -} - -.terminal .xterm-color-85 { - color: #5fffaf; -} - -.terminal .xterm-bg-color-85 { - background-color: #5fffaf; -} - -.terminal .xterm-color-86 { - color: #5fffd7; -} - -.terminal .xterm-bg-color-86 { - background-color: #5fffd7; -} - -.terminal .xterm-color-87 { - color: #5fffff; -} - -.terminal .xterm-bg-color-87 { - background-color: #5fffff; -} - -.terminal .xterm-color-88 { - color: #870000; -} - -.terminal .xterm-bg-color-88 { - background-color: #870000; -} - -.terminal .xterm-color-89 { - color: #87005f; -} - -.terminal .xterm-bg-color-89 { - background-color: #87005f; -} - -.terminal .xterm-color-90 { - color: #870087; -} - -.terminal .xterm-bg-color-90 { - background-color: #870087; -} - -.terminal .xterm-color-91 { - color: #8700af; -} - -.terminal .xterm-bg-color-91 { - background-color: #8700af; -} - -.terminal .xterm-color-92 { - color: #8700d7; -} - -.terminal .xterm-bg-color-92 { - background-color: #8700d7; -} - -.terminal .xterm-color-93 { - color: #8700ff; -} - -.terminal .xterm-bg-color-93 { - background-color: #8700ff; -} - -.terminal .xterm-color-94 { - color: #875f00; -} - -.terminal .xterm-bg-color-94 { - background-color: #875f00; -} - -.terminal .xterm-color-95 { - color: #875f5f; -} - -.terminal .xterm-bg-color-95 { - background-color: #875f5f; -} - -.terminal .xterm-color-96 { - color: #875f87; -} - -.terminal .xterm-bg-color-96 { - background-color: #875f87; -} - -.terminal .xterm-color-97 { - color: #875faf; -} - -.terminal .xterm-bg-color-97 { - background-color: #875faf; -} - -.terminal .xterm-color-98 { - color: #875fd7; -} - -.terminal .xterm-bg-color-98 { - background-color: #875fd7; -} - -.terminal .xterm-color-99 { - color: #875fff; -} - -.terminal .xterm-bg-color-99 { - background-color: #875fff; -} - -.terminal .xterm-color-100 { - color: #878700; -} - -.terminal .xterm-bg-color-100 { - background-color: #878700; -} - -.terminal .xterm-color-101 { - color: #87875f; -} - -.terminal .xterm-bg-color-101 { - background-color: #87875f; -} - -.terminal .xterm-color-102 { - color: #878787; -} - -.terminal .xterm-bg-color-102 { - background-color: #878787; -} - -.terminal .xterm-color-103 { - color: #8787af; -} - -.terminal .xterm-bg-color-103 { - background-color: #8787af; -} - -.terminal .xterm-color-104 { - color: #8787d7; -} - -.terminal .xterm-bg-color-104 { - background-color: #8787d7; -} - -.terminal .xterm-color-105 { - color: #8787ff; -} - -.terminal .xterm-bg-color-105 { - background-color: #8787ff; -} - -.terminal .xterm-color-106 { - color: #87af00; -} - -.terminal .xterm-bg-color-106 { - background-color: #87af00; -} - -.terminal .xterm-color-107 { - color: #87af5f; -} - -.terminal .xterm-bg-color-107 { - background-color: #87af5f; -} - -.terminal .xterm-color-108 { - color: #87af87; -} - -.terminal .xterm-bg-color-108 { - background-color: #87af87; -} - -.terminal .xterm-color-109 { - color: #87afaf; -} - -.terminal .xterm-bg-color-109 { - background-color: #87afaf; -} - -.terminal .xterm-color-110 { - color: #87afd7; -} - -.terminal .xterm-bg-color-110 { - background-color: #87afd7; -} - -.terminal .xterm-color-111 { - color: #87afff; -} - -.terminal .xterm-bg-color-111 { - background-color: #87afff; -} - -.terminal .xterm-color-112 { - color: #87d700; -} - -.terminal .xterm-bg-color-112 { - background-color: #87d700; -} - -.terminal .xterm-color-113 { - color: #87d75f; -} - -.terminal .xterm-bg-color-113 { - background-color: #87d75f; -} - -.terminal .xterm-color-114 { - color: #87d787; -} - -.terminal .xterm-bg-color-114 { - background-color: #87d787; -} - -.terminal .xterm-color-115 { - color: #87d7af; -} - -.terminal .xterm-bg-color-115 { - background-color: #87d7af; -} - -.terminal .xterm-color-116 { - color: #87d7d7; -} - -.terminal .xterm-bg-color-116 { - background-color: #87d7d7; -} - -.terminal .xterm-color-117 { - color: #87d7ff; -} - -.terminal .xterm-bg-color-117 { - background-color: #87d7ff; -} - -.terminal .xterm-color-118 { - color: #87ff00; -} - -.terminal .xterm-bg-color-118 { - background-color: #87ff00; -} - -.terminal .xterm-color-119 { - color: #87ff5f; -} - -.terminal .xterm-bg-color-119 { - background-color: #87ff5f; -} - -.terminal .xterm-color-120 { - color: #87ff87; -} - -.terminal .xterm-bg-color-120 { - background-color: #87ff87; -} - -.terminal .xterm-color-121 { - color: #87ffaf; -} - -.terminal .xterm-bg-color-121 { - background-color: #87ffaf; -} - -.terminal .xterm-color-122 { - color: #87ffd7; -} - -.terminal .xterm-bg-color-122 { - background-color: #87ffd7; -} - -.terminal .xterm-color-123 { - color: #87ffff; -} - -.terminal .xterm-bg-color-123 { - background-color: #87ffff; -} - -.terminal .xterm-color-124 { - color: #af0000; -} - -.terminal .xterm-bg-color-124 { - background-color: #af0000; -} - -.terminal .xterm-color-125 { - color: #af005f; -} - -.terminal .xterm-bg-color-125 { - background-color: #af005f; -} - -.terminal .xterm-color-126 { - color: #af0087; -} - -.terminal .xterm-bg-color-126 { - background-color: #af0087; -} - -.terminal .xterm-color-127 { - color: #af00af; -} - -.terminal .xterm-bg-color-127 { - background-color: #af00af; -} - -.terminal .xterm-color-128 { - color: #af00d7; -} - -.terminal .xterm-bg-color-128 { - background-color: #af00d7; -} - -.terminal .xterm-color-129 { - color: #af00ff; -} - -.terminal .xterm-bg-color-129 { - background-color: #af00ff; -} - -.terminal .xterm-color-130 { - color: #af5f00; -} - -.terminal .xterm-bg-color-130 { - background-color: #af5f00; -} - -.terminal .xterm-color-131 { - color: #af5f5f; -} - -.terminal .xterm-bg-color-131 { - background-color: #af5f5f; -} - -.terminal .xterm-color-132 { - color: #af5f87; -} - -.terminal .xterm-bg-color-132 { - background-color: #af5f87; -} - -.terminal .xterm-color-133 { - color: #af5faf; -} - -.terminal .xterm-bg-color-133 { - background-color: #af5faf; -} - -.terminal .xterm-color-134 { - color: #af5fd7; -} - -.terminal .xterm-bg-color-134 { - background-color: #af5fd7; -} - -.terminal .xterm-color-135 { - color: #af5fff; -} - -.terminal .xterm-bg-color-135 { - background-color: #af5fff; -} - -.terminal .xterm-color-136 { - color: #af8700; -} - -.terminal .xterm-bg-color-136 { - background-color: #af8700; -} - -.terminal .xterm-color-137 { - color: #af875f; -} - -.terminal .xterm-bg-color-137 { - background-color: #af875f; -} - -.terminal .xterm-color-138 { - color: #af8787; -} - -.terminal .xterm-bg-color-138 { - background-color: #af8787; -} - -.terminal .xterm-color-139 { - color: #af87af; -} - -.terminal .xterm-bg-color-139 { - background-color: #af87af; -} - -.terminal .xterm-color-140 { - color: #af87d7; -} - -.terminal .xterm-bg-color-140 { - background-color: #af87d7; -} - -.terminal .xterm-color-141 { - color: #af87ff; -} - -.terminal .xterm-bg-color-141 { - background-color: #af87ff; -} - -.terminal .xterm-color-142 { - color: #afaf00; -} - -.terminal .xterm-bg-color-142 { - background-color: #afaf00; -} - -.terminal .xterm-color-143 { - color: #afaf5f; -} - -.terminal .xterm-bg-color-143 { - background-color: #afaf5f; -} - -.terminal .xterm-color-144 { - color: #afaf87; -} - -.terminal .xterm-bg-color-144 { - background-color: #afaf87; -} - -.terminal .xterm-color-145 { - color: #afafaf; -} - -.terminal .xterm-bg-color-145 { - background-color: #afafaf; -} - -.terminal .xterm-color-146 { - color: #afafd7; -} - -.terminal .xterm-bg-color-146 { - background-color: #afafd7; -} - -.terminal .xterm-color-147 { - color: #afafff; -} - -.terminal .xterm-bg-color-147 { - background-color: #afafff; -} - -.terminal .xterm-color-148 { - color: #afd700; -} - -.terminal .xterm-bg-color-148 { - background-color: #afd700; -} - -.terminal .xterm-color-149 { - color: #afd75f; -} - -.terminal .xterm-bg-color-149 { - background-color: #afd75f; -} - -.terminal .xterm-color-150 { - color: #afd787; -} - -.terminal .xterm-bg-color-150 { - background-color: #afd787; -} - -.terminal .xterm-color-151 { - color: #afd7af; -} - -.terminal .xterm-bg-color-151 { - background-color: #afd7af; -} - -.terminal .xterm-color-152 { - color: #afd7d7; -} - -.terminal .xterm-bg-color-152 { - background-color: #afd7d7; -} - -.terminal .xterm-color-153 { - color: #afd7ff; -} - -.terminal .xterm-bg-color-153 { - background-color: #afd7ff; -} - -.terminal .xterm-color-154 { - color: #afff00; -} - -.terminal .xterm-bg-color-154 { - background-color: #afff00; -} - -.terminal .xterm-color-155 { - color: #afff5f; -} - -.terminal .xterm-bg-color-155 { - background-color: #afff5f; -} - -.terminal .xterm-color-156 { - color: #afff87; -} - -.terminal .xterm-bg-color-156 { - background-color: #afff87; -} - -.terminal .xterm-color-157 { - color: #afffaf; -} - -.terminal .xterm-bg-color-157 { - background-color: #afffaf; -} - -.terminal .xterm-color-158 { - color: #afffd7; -} - -.terminal .xterm-bg-color-158 { - background-color: #afffd7; -} - -.terminal .xterm-color-159 { - color: #afffff; -} - -.terminal .xterm-bg-color-159 { - background-color: #afffff; -} - -.terminal .xterm-color-160 { - color: #d70000; -} - -.terminal .xterm-bg-color-160 { - background-color: #d70000; -} - -.terminal .xterm-color-161 { - color: #d7005f; -} - -.terminal .xterm-bg-color-161 { - background-color: #d7005f; -} - -.terminal .xterm-color-162 { - color: #d70087; -} - -.terminal .xterm-bg-color-162 { - background-color: #d70087; -} - -.terminal .xterm-color-163 { - color: #d700af; -} - -.terminal .xterm-bg-color-163 { - background-color: #d700af; -} - -.terminal .xterm-color-164 { - color: #d700d7; -} - -.terminal .xterm-bg-color-164 { - background-color: #d700d7; -} - -.terminal .xterm-color-165 { - color: #d700ff; -} - -.terminal .xterm-bg-color-165 { - background-color: #d700ff; -} - -.terminal .xterm-color-166 { - color: #d75f00; -} - -.terminal .xterm-bg-color-166 { - background-color: #d75f00; -} - -.terminal .xterm-color-167 { - color: #d75f5f; -} - -.terminal .xterm-bg-color-167 { - background-color: #d75f5f; -} - -.terminal .xterm-color-168 { - color: #d75f87; -} - -.terminal .xterm-bg-color-168 { - background-color: #d75f87; -} - -.terminal .xterm-color-169 { - color: #d75faf; -} - -.terminal .xterm-bg-color-169 { - background-color: #d75faf; -} - -.terminal .xterm-color-170 { - color: #d75fd7; -} - -.terminal .xterm-bg-color-170 { - background-color: #d75fd7; -} - -.terminal .xterm-color-171 { - color: #d75fff; -} - -.terminal .xterm-bg-color-171 { - background-color: #d75fff; -} - -.terminal .xterm-color-172 { - color: #d78700; -} - -.terminal .xterm-bg-color-172 { - background-color: #d78700; -} - -.terminal .xterm-color-173 { - color: #d7875f; -} - -.terminal .xterm-bg-color-173 { - background-color: #d7875f; -} - -.terminal .xterm-color-174 { - color: #d78787; -} - -.terminal .xterm-bg-color-174 { - background-color: #d78787; -} - -.terminal .xterm-color-175 { - color: #d787af; -} - -.terminal .xterm-bg-color-175 { - background-color: #d787af; -} - -.terminal .xterm-color-176 { - color: #d787d7; -} - -.terminal .xterm-bg-color-176 { - background-color: #d787d7; -} - -.terminal .xterm-color-177 { - color: #d787ff; -} - -.terminal .xterm-bg-color-177 { - background-color: #d787ff; -} - -.terminal .xterm-color-178 { - color: #d7af00; -} - -.terminal .xterm-bg-color-178 { - background-color: #d7af00; -} - -.terminal .xterm-color-179 { - color: #d7af5f; -} - -.terminal .xterm-bg-color-179 { - background-color: #d7af5f; -} - -.terminal .xterm-color-180 { - color: #d7af87; -} - -.terminal .xterm-bg-color-180 { - background-color: #d7af87; -} - -.terminal .xterm-color-181 { - color: #d7afaf; -} - -.terminal .xterm-bg-color-181 { - background-color: #d7afaf; -} - -.terminal .xterm-color-182 { - color: #d7afd7; -} - -.terminal .xterm-bg-color-182 { - background-color: #d7afd7; -} - -.terminal .xterm-color-183 { - color: #d7afff; -} - -.terminal .xterm-bg-color-183 { - background-color: #d7afff; -} - -.terminal .xterm-color-184 { - color: #d7d700; -} - -.terminal .xterm-bg-color-184 { - background-color: #d7d700; -} - -.terminal .xterm-color-185 { - color: #d7d75f; -} - -.terminal .xterm-bg-color-185 { - background-color: #d7d75f; -} - -.terminal .xterm-color-186 { - color: #d7d787; -} - -.terminal .xterm-bg-color-186 { - background-color: #d7d787; -} - -.terminal .xterm-color-187 { - color: #d7d7af; -} - -.terminal .xterm-bg-color-187 { - background-color: #d7d7af; -} - -.terminal .xterm-color-188 { - color: #d7d7d7; -} - -.terminal .xterm-bg-color-188 { - background-color: #d7d7d7; -} - -.terminal .xterm-color-189 { - color: #d7d7ff; -} - -.terminal .xterm-bg-color-189 { - background-color: #d7d7ff; -} - -.terminal .xterm-color-190 { - color: #d7ff00; -} - -.terminal .xterm-bg-color-190 { - background-color: #d7ff00; -} - -.terminal .xterm-color-191 { - color: #d7ff5f; -} - -.terminal .xterm-bg-color-191 { - background-color: #d7ff5f; -} - -.terminal .xterm-color-192 { - color: #d7ff87; -} - -.terminal .xterm-bg-color-192 { - background-color: #d7ff87; -} - -.terminal .xterm-color-193 { - color: #d7ffaf; -} - -.terminal .xterm-bg-color-193 { - background-color: #d7ffaf; -} - -.terminal .xterm-color-194 { - color: #d7ffd7; -} - -.terminal .xterm-bg-color-194 { - background-color: #d7ffd7; -} - -.terminal .xterm-color-195 { - color: #d7ffff; -} - -.terminal .xterm-bg-color-195 { - background-color: #d7ffff; -} - -.terminal .xterm-color-196 { - color: #ff0000; -} - -.terminal .xterm-bg-color-196 { - background-color: #ff0000; -} - -.terminal .xterm-color-197 { - color: #ff005f; -} - -.terminal .xterm-bg-color-197 { - background-color: #ff005f; -} - -.terminal .xterm-color-198 { - color: #ff0087; -} - -.terminal .xterm-bg-color-198 { - background-color: #ff0087; -} - -.terminal .xterm-color-199 { - color: #ff00af; -} - -.terminal .xterm-bg-color-199 { - background-color: #ff00af; -} - -.terminal .xterm-color-200 { - color: #ff00d7; -} - -.terminal .xterm-bg-color-200 { - background-color: #ff00d7; -} - -.terminal .xterm-color-201 { - color: #ff00ff; -} - -.terminal .xterm-bg-color-201 { - background-color: #ff00ff; -} - -.terminal .xterm-color-202 { - color: #ff5f00; -} - -.terminal .xterm-bg-color-202 { - background-color: #ff5f00; -} - -.terminal .xterm-color-203 { - color: #ff5f5f; -} - -.terminal .xterm-bg-color-203 { - background-color: #ff5f5f; -} - -.terminal .xterm-color-204 { - color: #ff5f87; -} - -.terminal .xterm-bg-color-204 { - background-color: #ff5f87; -} - -.terminal .xterm-color-205 { - color: #ff5faf; -} - -.terminal .xterm-bg-color-205 { - background-color: #ff5faf; -} - -.terminal .xterm-color-206 { - color: #ff5fd7; -} - -.terminal .xterm-bg-color-206 { - background-color: #ff5fd7; -} - -.terminal .xterm-color-207 { - color: #ff5fff; -} - -.terminal .xterm-bg-color-207 { - background-color: #ff5fff; -} - -.terminal .xterm-color-208 { - color: #ff8700; -} - -.terminal .xterm-bg-color-208 { - background-color: #ff8700; -} - -.terminal .xterm-color-209 { - color: #ff875f; -} - -.terminal .xterm-bg-color-209 { - background-color: #ff875f; -} - -.terminal .xterm-color-210 { - color: #ff8787; -} - -.terminal .xterm-bg-color-210 { - background-color: #ff8787; -} - -.terminal .xterm-color-211 { - color: #ff87af; -} - -.terminal .xterm-bg-color-211 { - background-color: #ff87af; -} - -.terminal .xterm-color-212 { - color: #ff87d7; -} - -.terminal .xterm-bg-color-212 { - background-color: #ff87d7; -} - -.terminal .xterm-color-213 { - color: #ff87ff; -} - -.terminal .xterm-bg-color-213 { - background-color: #ff87ff; -} - -.terminal .xterm-color-214 { - color: #ffaf00; -} - -.terminal .xterm-bg-color-214 { - background-color: #ffaf00; -} - -.terminal .xterm-color-215 { - color: #ffaf5f; -} - -.terminal .xterm-bg-color-215 { - background-color: #ffaf5f; -} - -.terminal .xterm-color-216 { - color: #ffaf87; -} - -.terminal .xterm-bg-color-216 { - background-color: #ffaf87; -} - -.terminal .xterm-color-217 { - color: #ffafaf; -} - -.terminal .xterm-bg-color-217 { - background-color: #ffafaf; -} - -.terminal .xterm-color-218 { - color: #ffafd7; -} - -.terminal .xterm-bg-color-218 { - background-color: #ffafd7; -} - -.terminal .xterm-color-219 { - color: #ffafff; -} - -.terminal .xterm-bg-color-219 { - background-color: #ffafff; -} - -.terminal .xterm-color-220 { - color: #ffd700; -} - -.terminal .xterm-bg-color-220 { - background-color: #ffd700; -} - -.terminal .xterm-color-221 { - color: #ffd75f; -} - -.terminal .xterm-bg-color-221 { - background-color: #ffd75f; -} - -.terminal .xterm-color-222 { - color: #ffd787; -} - -.terminal .xterm-bg-color-222 { - background-color: #ffd787; -} - -.terminal .xterm-color-223 { - color: #ffd7af; -} - -.terminal .xterm-bg-color-223 { - background-color: #ffd7af; -} - -.terminal .xterm-color-224 { - color: #ffd7d7; -} - -.terminal .xterm-bg-color-224 { - background-color: #ffd7d7; -} - -.terminal .xterm-color-225 { - color: #ffd7ff; -} - -.terminal .xterm-bg-color-225 { - background-color: #ffd7ff; -} - -.terminal .xterm-color-226 { - color: #ffff00; -} - -.terminal .xterm-bg-color-226 { - background-color: #ffff00; -} - -.terminal .xterm-color-227 { - color: #ffff5f; -} - -.terminal .xterm-bg-color-227 { - background-color: #ffff5f; -} - -.terminal .xterm-color-228 { - color: #ffff87; -} - -.terminal .xterm-bg-color-228 { - background-color: #ffff87; -} - -.terminal .xterm-color-229 { - color: #ffffaf; -} - -.terminal .xterm-bg-color-229 { - background-color: #ffffaf; -} - -.terminal .xterm-color-230 { - color: #ffffd7; -} - -.terminal .xterm-bg-color-230 { - background-color: #ffffd7; -} - -.terminal .xterm-color-231 { - color: #ffffff; -} - -.terminal .xterm-bg-color-231 { - background-color: #ffffff; -} - -.terminal .xterm-color-232 { - color: #080808; -} - -.terminal .xterm-bg-color-232 { - background-color: #080808; -} - -.terminal .xterm-color-233 { - color: #121212; -} - -.terminal .xterm-bg-color-233 { - background-color: #121212; -} - -.terminal .xterm-color-234 { - color: #1c1c1c; -} - -.terminal .xterm-bg-color-234 { - background-color: #1c1c1c; -} - -.terminal .xterm-color-235 { - color: #262626; -} - -.terminal .xterm-bg-color-235 { - background-color: #262626; -} - -.terminal .xterm-color-236 { - color: #303030; -} - -.terminal .xterm-bg-color-236 { - background-color: #303030; -} - -.terminal .xterm-color-237 { - color: #3a3a3a; -} - -.terminal .xterm-bg-color-237 { - background-color: #3a3a3a; -} - -.terminal .xterm-color-238 { - color: #444444; -} - -.terminal .xterm-bg-color-238 { - background-color: #444444; -} - -.terminal .xterm-color-239 { - color: #4e4e4e; -} - -.terminal .xterm-bg-color-239 { - background-color: #4e4e4e; -} - -.terminal .xterm-color-240 { - color: #585858; -} - -.terminal .xterm-bg-color-240 { - background-color: #585858; -} - -.terminal .xterm-color-241 { - color: #626262; -} - -.terminal .xterm-bg-color-241 { - background-color: #626262; -} - -.terminal .xterm-color-242 { - color: #6c6c6c; -} - -.terminal .xterm-bg-color-242 { - background-color: #6c6c6c; -} - -.terminal .xterm-color-243 { - color: #767676; -} - -.terminal .xterm-bg-color-243 { - background-color: #767676; -} - -.terminal .xterm-color-244 { - color: #808080; -} - -.terminal .xterm-bg-color-244 { - background-color: #808080; -} - -.terminal .xterm-color-245 { - color: #8a8a8a; -} - -.terminal .xterm-bg-color-245 { - background-color: #8a8a8a; -} - -.terminal .xterm-color-246 { - color: #949494; -} - -.terminal .xterm-bg-color-246 { - background-color: #949494; -} - -.terminal .xterm-color-247 { - color: #9e9e9e; -} - -.terminal .xterm-bg-color-247 { - background-color: #9e9e9e; -} - -.terminal .xterm-color-248 { - color: #a8a8a8; -} - -.terminal .xterm-bg-color-248 { - background-color: #a8a8a8; -} - -.terminal .xterm-color-249 { - color: #b2b2b2; -} - -.terminal .xterm-bg-color-249 { - background-color: #b2b2b2; -} - -.terminal .xterm-color-250 { - color: #bcbcbc; -} - -.terminal .xterm-bg-color-250 { - background-color: #bcbcbc; -} - -.terminal .xterm-color-251 { - color: #c6c6c6; -} - -.terminal .xterm-bg-color-251 { - background-color: #c6c6c6; -} - -.terminal .xterm-color-252 { - color: #d0d0d0; -} - -.terminal .xterm-bg-color-252 { - background-color: #d0d0d0; -} - -.terminal .xterm-color-253 { - color: #dadada; -} - -.terminal .xterm-bg-color-253 { - background-color: #dadada; -} - -.terminal .xterm-color-254 { - color: #e4e4e4; -} - -.terminal .xterm-bg-color-254 { - background-color: #e4e4e4; -} - -.terminal .xterm-color-255 { - color: #eeeeee; -} - -.terminal .xterm-bg-color-255 { - background-color: #eeeeee; -}
diff --git a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.js b/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.js deleted file mode 100644 index 7dfaab5..0000000 --- a/third_party/blink/renderer/devtools/front_end/terminal/xterm.js/build/xterm.js +++ /dev/null
@@ -1,4318 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Terminal = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.CHARSETS = {}; -exports.DEFAULT_CHARSET = exports.CHARSETS['B']; -exports.CHARSETS['0'] = { - '`': '\u25c6', - 'a': '\u2592', - 'b': '\u0009', - 'c': '\u000c', - 'd': '\u000d', - 'e': '\u000a', - 'f': '\u00b0', - 'g': '\u00b1', - 'h': '\u2424', - 'i': '\u000b', - 'j': '\u2518', - 'k': '\u2510', - 'l': '\u250c', - 'm': '\u2514', - 'n': '\u253c', - 'o': '\u23ba', - 'p': '\u23bb', - 'q': '\u2500', - 'r': '\u23bc', - 's': '\u23bd', - 't': '\u251c', - 'u': '\u2524', - 'v': '\u2534', - 'w': '\u252c', - 'x': '\u2502', - 'y': '\u2264', - 'z': '\u2265', - '{': '\u03c0', - '|': '\u2260', - '}': '\u00a3', - '~': '\u00b7' -}; -exports.CHARSETS['A'] = { - '#': '£' -}; -exports.CHARSETS['B'] = null; -exports.CHARSETS['4'] = { - '#': '£', - '@': '¾', - '[': 'ij', - '\\': '½', - ']': '|', - '{': '¨', - '|': 'f', - '}': '¼', - '~': '´' -}; -exports.CHARSETS['C'] = - exports.CHARSETS['5'] = { - '[': 'Ä', - '\\': 'Ö', - ']': 'Å', - '^': 'Ü', - '`': 'é', - '{': 'ä', - '|': 'ö', - '}': 'å', - '~': 'ü' - }; -exports.CHARSETS['R'] = { - '#': '£', - '@': 'à', - '[': '°', - '\\': 'ç', - ']': '§', - '{': 'é', - '|': 'ù', - '}': 'è', - '~': '¨' -}; -exports.CHARSETS['Q'] = { - '@': 'à', - '[': 'â', - '\\': 'ç', - ']': 'ê', - '^': 'î', - '`': 'ô', - '{': 'é', - '|': 'ù', - '}': 'è', - '~': 'û' -}; -exports.CHARSETS['K'] = { - '@': '§', - '[': 'Ä', - '\\': 'Ö', - ']': 'Ü', - '{': 'ä', - '|': 'ö', - '}': 'ü', - '~': 'ß' -}; -exports.CHARSETS['Y'] = { - '#': '£', - '@': '§', - '[': '°', - '\\': 'ç', - ']': 'é', - '`': 'ù', - '{': 'à', - '|': 'ò', - '}': 'è', - '~': 'ì' -}; -exports.CHARSETS['E'] = - exports.CHARSETS['6'] = { - '@': 'Ä', - '[': 'Æ', - '\\': 'Ø', - ']': 'Å', - '^': 'Ü', - '`': 'ä', - '{': 'æ', - '|': 'ø', - '}': 'å', - '~': 'ü' - }; -exports.CHARSETS['Z'] = { - '#': '£', - '@': '§', - '[': '¡', - '\\': 'Ñ', - ']': '¿', - '{': '°', - '|': 'ñ', - '}': 'ç' -}; -exports.CHARSETS['H'] = - exports.CHARSETS['7'] = { - '@': 'É', - '[': 'Ä', - '\\': 'Ö', - ']': 'Å', - '^': 'Ü', - '`': 'é', - '{': 'ä', - '|': 'ö', - '}': 'å', - '~': 'ü' - }; -exports.CHARSETS['='] = { - '#': 'ù', - '@': 'à', - '[': 'é', - '\\': 'ç', - ']': 'ê', - '^': 'î', - '_': 'è', - '`': 'ô', - '{': 'ä', - '|': 'ö', - '}': 'ü', - '~': 'û' -}; - - - -},{}],2:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var CompositionHelper = (function () { - function CompositionHelper(textarea, compositionView, terminal) { - this.textarea = textarea; - this.compositionView = compositionView; - this.terminal = terminal; - this.isComposing = false; - this.isSendingComposition = false; - this.compositionPosition = { start: null, end: null }; - } - CompositionHelper.prototype.compositionstart = function () { - this.isComposing = true; - this.compositionPosition.start = this.textarea.value.length; - this.compositionView.textContent = ''; - this.compositionView.classList.add('active'); - }; - CompositionHelper.prototype.compositionupdate = function (ev) { - var _this = this; - this.compositionView.textContent = ev.data; - this.updateCompositionElements(); - setTimeout(function () { - _this.compositionPosition.end = _this.textarea.value.length; - }, 0); - }; - CompositionHelper.prototype.compositionend = function () { - this.finalizeComposition(true); - }; - CompositionHelper.prototype.keydown = function (ev) { - if (this.isComposing || this.isSendingComposition) { - if (ev.keyCode === 229) { - return false; - } - else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { - return false; - } - else { - this.finalizeComposition(false); - } - } - if (ev.keyCode === 229) { - this.handleAnyTextareaChanges(); - return false; - } - return true; - }; - CompositionHelper.prototype.finalizeComposition = function (waitForPropogation) { - var _this = this; - this.compositionView.classList.remove('active'); - this.isComposing = false; - this.clearTextareaPosition(); - if (!waitForPropogation) { - this.isSendingComposition = false; - var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); - this.terminal.handler(input); - } - else { - var currentCompositionPosition_1 = { - start: this.compositionPosition.start, - end: this.compositionPosition.end, - }; - this.isSendingComposition = true; - setTimeout(function () { - if (_this.isSendingComposition) { - _this.isSendingComposition = false; - var input = void 0; - if (_this.isComposing) { - input = _this.textarea.value.substring(currentCompositionPosition_1.start, currentCompositionPosition_1.end); - } - else { - input = _this.textarea.value.substring(currentCompositionPosition_1.start); - } - _this.terminal.handler(input); - } - }, 0); - } - }; - CompositionHelper.prototype.handleAnyTextareaChanges = function () { - var _this = this; - var oldValue = this.textarea.value; - setTimeout(function () { - if (!_this.isComposing) { - var newValue = _this.textarea.value; - var diff = newValue.replace(oldValue, ''); - if (diff.length > 0) { - _this.terminal.handler(diff); - } - } - }, 0); - }; - CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) { - var _this = this; - if (!this.isComposing) { - return; - } - var cursor = this.terminal.element.querySelector('.terminal-cursor'); - if (cursor) { - var xtermRows = this.terminal.element.querySelector('.xterm-rows'); - var cursorTop = xtermRows.offsetTop + cursor.offsetTop; - this.compositionView.style.left = cursor.offsetLeft + 'px'; - this.compositionView.style.top = cursorTop + 'px'; - this.compositionView.style.height = cursor.offsetHeight + 'px'; - this.compositionView.style.lineHeight = cursor.offsetHeight + 'px'; - var compositionViewBounds = this.compositionView.getBoundingClientRect(); - this.textarea.style.left = cursor.offsetLeft + 'px'; - this.textarea.style.top = cursorTop + 'px'; - this.textarea.style.width = compositionViewBounds.width + 'px'; - this.textarea.style.height = compositionViewBounds.height + 'px'; - this.textarea.style.lineHeight = compositionViewBounds.height + 'px'; - } - if (!dontRecurse) { - setTimeout(function () { return _this.updateCompositionElements(true); }, 0); - } - }; - ; - CompositionHelper.prototype.clearTextareaPosition = function () { - this.textarea.style.left = ''; - this.textarea.style.top = ''; - }; - ; - return CompositionHelper; -}()); -exports.CompositionHelper = CompositionHelper; - - - -},{}],3:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var C0; -(function (C0) { - C0.NUL = '\x00'; - C0.SOH = '\x01'; - C0.STX = '\x02'; - C0.ETX = '\x03'; - C0.EOT = '\x04'; - C0.ENQ = '\x05'; - C0.ACK = '\x06'; - C0.BEL = '\x07'; - C0.BS = '\x08'; - C0.HT = '\x09'; - C0.LF = '\x0a'; - C0.VT = '\x0b'; - C0.FF = '\x0c'; - C0.CR = '\x0d'; - C0.SO = '\x0e'; - C0.SI = '\x0f'; - C0.DLE = '\x10'; - C0.DC1 = '\x11'; - C0.DC2 = '\x12'; - C0.DC3 = '\x13'; - C0.DC4 = '\x14'; - C0.NAK = '\x15'; - C0.SYN = '\x16'; - C0.ETB = '\x17'; - C0.CAN = '\x18'; - C0.EM = '\x19'; - C0.SUB = '\x1a'; - C0.ESC = '\x1b'; - C0.FS = '\x1c'; - C0.GS = '\x1d'; - C0.RS = '\x1e'; - C0.US = '\x1f'; - C0.SP = '\x20'; - C0.DEL = '\x7f'; -})(C0 = exports.C0 || (exports.C0 = {})); -; - - - -},{}],4:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -; -var EventEmitter = (function () { - function EventEmitter() { - this._events = this._events || {}; - } - EventEmitter.prototype.on = function (type, listener) { - this._events[type] = this._events[type] || []; - this._events[type].push(listener); - }; - EventEmitter.prototype.off = function (type, listener) { - if (!this._events[type]) { - return; - } - var obj = this._events[type]; - var i = obj.length; - while (i--) { - if (obj[i] === listener || obj[i].listener === listener) { - obj.splice(i, 1); - return; - } - } - }; - EventEmitter.prototype.removeAllListeners = function (type) { - if (this._events[type]) { - delete this._events[type]; - } - }; - EventEmitter.prototype.once = function (type, listener) { - function on() { - var args = Array.prototype.slice.call(arguments); - this.off(type, on); - return listener.apply(this, args); - } - on.listener = listener; - return this.on(type, on); - }; - EventEmitter.prototype.emit = function (type) { - var args = []; - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - if (!this._events[type]) { - return; - } - var obj = this._events[type]; - for (var i = 0; i < obj.length; i++) { - obj[i].apply(this, args); - } - }; - EventEmitter.prototype.listeners = function (type) { - return this._events[type] || []; - }; - return EventEmitter; -}()); -exports.EventEmitter = EventEmitter; - - - -},{}],5:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var EscapeSequences_1 = require("./EscapeSequences"); -var Charsets_1 = require("./Charsets"); -var InputHandler = (function () { - function InputHandler(_terminal) { - this._terminal = _terminal; - } - InputHandler.prototype.addChar = function (char, code) { - if (char >= ' ') { - var ch_width = wcwidth(code); - if (this._terminal.charset && this._terminal.charset[char]) { - char = this._terminal.charset[char]; - } - var row = this._terminal.y + this._terminal.ybase; - if (!ch_width && this._terminal.x) { - if (this._terminal.lines.get(row)[this._terminal.x - 1]) { - if (!this._terminal.lines.get(row)[this._terminal.x - 1][2]) { - if (this._terminal.lines.get(row)[this._terminal.x - 2]) - this._terminal.lines.get(row)[this._terminal.x - 2][1] += char; - } - else { - this._terminal.lines.get(row)[this._terminal.x - 1][1] += char; - } - this._terminal.updateRange(this._terminal.y); - } - return; - } - if (this._terminal.x + ch_width - 1 >= this._terminal.cols) { - if (this._terminal.wraparoundMode) { - this._terminal.x = 0; - this._terminal.y++; - if (this._terminal.y > this._terminal.scrollBottom) { - this._terminal.y--; - this._terminal.scroll(); - } - } - else { - if (ch_width === 2) - return; - } - } - row = this._terminal.y + this._terminal.ybase; - if (this._terminal.insertMode) { - for (var moves = 0; moves < ch_width; ++moves) { - var removed = this._terminal.lines.get(this._terminal.y + this._terminal.ybase).pop(); - if (removed[2] === 0 - && this._terminal.lines.get(row)[this._terminal.cols - 2] - && this._terminal.lines.get(row)[this._terminal.cols - 2][2] === 2) - this._terminal.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1]; - this._terminal.lines.get(row).splice(this._terminal.x, 0, [this._terminal.curAttr, ' ', 1]); - } - } - this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, char, ch_width]; - this._terminal.x++; - this._terminal.updateRange(this._terminal.y); - if (ch_width === 2) { - this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, '', 0]; - this._terminal.x++; - } - } - }; - InputHandler.prototype.bell = function () { - var _this = this; - if (!this._terminal.visualBell) { - return; - } - this._terminal.element.style.borderColor = 'white'; - setTimeout(function () { return _this._terminal.element.style.borderColor = ''; }, 10); - if (this._terminal.popOnBell) { - this._terminal.focus(); - } - }; - InputHandler.prototype.lineFeed = function () { - if (this._terminal.convertEol) { - this._terminal.x = 0; - } - this._terminal.y++; - if (this._terminal.y > this._terminal.scrollBottom) { - this._terminal.y--; - this._terminal.scroll(); - } - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; - } - }; - InputHandler.prototype.carriageReturn = function () { - this._terminal.x = 0; - }; - InputHandler.prototype.backspace = function () { - if (this._terminal.x > 0) { - this._terminal.x--; - } - }; - InputHandler.prototype.tab = function () { - this._terminal.x = this._terminal.nextStop(); - }; - InputHandler.prototype.shiftOut = function () { - this._terminal.setgLevel(1); - }; - InputHandler.prototype.shiftIn = function () { - this._terminal.setgLevel(0); - }; - InputHandler.prototype.insertChars = function (params) { - var param, row, j, ch; - param = params[0]; - if (param < 1) - param = 1; - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.x; - ch = [this._terminal.eraseAttr(), ' ', 1]; - while (param-- && j < this._terminal.cols) { - this._terminal.lines.get(row).splice(j++, 0, ch); - this._terminal.lines.get(row).pop(); - } - }; - InputHandler.prototype.cursorUp = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y -= param; - if (this._terminal.y < 0) { - this._terminal.y = 0; - } - }; - InputHandler.prototype.cursorDown = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; - } - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; - } - }; - InputHandler.prototype.cursorForward = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.x += param; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; - } - }; - InputHandler.prototype.cursorBackward = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; - } - this._terminal.x -= param; - if (this._terminal.x < 0) { - this._terminal.x = 0; - } - }; - InputHandler.prototype.cursorNextLine = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; - } - this._terminal.x = 0; - }; - ; - InputHandler.prototype.cursorPrecedingLine = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y -= param; - if (this._terminal.y < 0) { - this._terminal.y = 0; - } - this._terminal.x = 0; - }; - ; - InputHandler.prototype.cursorCharAbsolute = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.x = param - 1; - }; - InputHandler.prototype.cursorPosition = function (params) { - var row, col; - row = params[0] - 1; - if (params.length >= 2) { - col = params[1] - 1; - } - else { - col = 0; - } - if (row < 0) { - row = 0; - } - else if (row >= this._terminal.rows) { - row = this._terminal.rows - 1; - } - if (col < 0) { - col = 0; - } - else if (col >= this._terminal.cols) { - col = this._terminal.cols - 1; - } - this._terminal.x = col; - this._terminal.y = row; - }; - InputHandler.prototype.cursorForwardTab = function (params) { - var param = params[0] || 1; - while (param--) { - this._terminal.x = this._terminal.nextStop(); - } - }; - InputHandler.prototype.eraseInDisplay = function (params) { - var j; - switch (params[0]) { - case 0: - this._terminal.eraseRight(this._terminal.x, this._terminal.y); - j = this._terminal.y + 1; - for (; j < this._terminal.rows; j++) { - this._terminal.eraseLine(j); - } - break; - case 1: - this._terminal.eraseLeft(this._terminal.x, this._terminal.y); - j = this._terminal.y; - while (j--) { - this._terminal.eraseLine(j); - } - break; - case 2: - j = this._terminal.rows; - while (j--) - this._terminal.eraseLine(j); - break; - case 3: - var scrollBackSize = this._terminal.lines.length - this._terminal.rows; - if (scrollBackSize > 0) { - this._terminal.lines.trimStart(scrollBackSize); - this._terminal.ybase = Math.max(this._terminal.ybase - scrollBackSize, 0); - this._terminal.ydisp = Math.max(this._terminal.ydisp - scrollBackSize, 0); - } - break; - } - }; - InputHandler.prototype.eraseInLine = function (params) { - switch (params[0]) { - case 0: - this._terminal.eraseRight(this._terminal.x, this._terminal.y); - break; - case 1: - this._terminal.eraseLeft(this._terminal.x, this._terminal.y); - break; - case 2: - this._terminal.eraseLine(this._terminal.y); - break; - } - }; - InputHandler.prototype.insertLines = function (params) { - var param, row, j; - param = params[0]; - if (param < 1) { - param = 1; - } - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.rows - 1 - this._terminal.scrollBottom; - j = this._terminal.rows - 1 + this._terminal.ybase - j + 1; - while (param--) { - if (this._terminal.lines.length === this._terminal.lines.maxLength) { - this._terminal.lines.trimStart(1); - this._terminal.ybase--; - this._terminal.ydisp--; - row--; - j--; - } - this._terminal.lines.splice(row, 0, this._terminal.blankLine(true)); - this._terminal.lines.splice(j, 1); - } - this._terminal.updateRange(this._terminal.y); - this._terminal.updateRange(this._terminal.scrollBottom); - }; - InputHandler.prototype.deleteLines = function (params) { - var param, row, j; - param = params[0]; - if (param < 1) { - param = 1; - } - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.rows - 1 - this._terminal.scrollBottom; - j = this._terminal.rows - 1 + this._terminal.ybase - j; - while (param--) { - if (this._terminal.lines.length === this._terminal.lines.maxLength) { - this._terminal.lines.trimStart(1); - this._terminal.ybase -= 1; - this._terminal.ydisp -= 1; - } - this._terminal.lines.splice(j + 1, 0, this._terminal.blankLine(true)); - this._terminal.lines.splice(row, 1); - } - this._terminal.updateRange(this._terminal.y); - this._terminal.updateRange(this._terminal.scrollBottom); - }; - InputHandler.prototype.deleteChars = function (params) { - var param, row, ch; - param = params[0]; - if (param < 1) { - param = 1; - } - row = this._terminal.y + this._terminal.ybase; - ch = [this._terminal.eraseAttr(), ' ', 1]; - while (param--) { - this._terminal.lines.get(row).splice(this._terminal.x, 1); - this._terminal.lines.get(row).push(ch); - } - }; - InputHandler.prototype.scrollUp = function (params) { - var param = params[0] || 1; - while (param--) { - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 1); - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 0, this._terminal.blankLine()); - } - this._terminal.updateRange(this._terminal.scrollTop); - this._terminal.updateRange(this._terminal.scrollBottom); - }; - InputHandler.prototype.scrollDown = function (params) { - var param = params[0] || 1; - while (param--) { - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 1); - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 0, this._terminal.blankLine()); - } - this._terminal.updateRange(this._terminal.scrollTop); - this._terminal.updateRange(this._terminal.scrollBottom); - }; - InputHandler.prototype.eraseChars = function (params) { - var param, row, j, ch; - param = params[0]; - if (param < 1) { - param = 1; - } - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.x; - ch = [this._terminal.eraseAttr(), ' ', 1]; - while (param-- && j < this._terminal.cols) { - this._terminal.lines.get(row)[j++] = ch; - } - }; - InputHandler.prototype.cursorBackwardTab = function (params) { - var param = params[0] || 1; - while (param--) { - this._terminal.x = this._terminal.prevStop(); - } - }; - InputHandler.prototype.charPosAbsolute = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.x = param - 1; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; - } - }; - InputHandler.prototype.HPositionRelative = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.x += param; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; - } - }; - InputHandler.prototype.repeatPrecedingCharacter = function (params) { - var param = params[0] || 1, line = this._terminal.lines.get(this._terminal.ybase + this._terminal.y), ch = line[this._terminal.x - 1] || [this._terminal.defAttr, ' ', 1]; - while (param--) { - line[this._terminal.x++] = ch; - } - }; - InputHandler.prototype.sendDeviceAttributes = function (params) { - if (params[0] > 0) { - return; - } - if (!this._terminal.prefix) { - if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) { - this._terminal.send(EscapeSequences_1.C0.ESC + '[?1;2c'); - } - else if (this._terminal.is('linux')) { - this._terminal.send(EscapeSequences_1.C0.ESC + '[?6c'); - } - } - else if (this._terminal.prefix === '>') { - if (this._terminal.is('xterm')) { - this._terminal.send(EscapeSequences_1.C0.ESC + '[>0;276;0c'); - } - else if (this._terminal.is('rxvt-unicode')) { - this._terminal.send(EscapeSequences_1.C0.ESC + '[>85;95;0c'); - } - else if (this._terminal.is('linux')) { - this._terminal.send(params[0] + 'c'); - } - else if (this._terminal.is('screen')) { - this._terminal.send(EscapeSequences_1.C0.ESC + '[>83;40003;0c'); - } - } - }; - InputHandler.prototype.linePosAbsolute = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y = param - 1; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; - } - }; - InputHandler.prototype.VPositionRelative = function (params) { - var param = params[0]; - if (param < 1) { - param = 1; - } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; - } - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; - } - }; - InputHandler.prototype.HVPosition = function (params) { - if (params[0] < 1) - params[0] = 1; - if (params[1] < 1) - params[1] = 1; - this._terminal.y = params[0] - 1; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; - } - this._terminal.x = params[1] - 1; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; - } - }; - InputHandler.prototype.tabClear = function (params) { - var param = params[0]; - if (param <= 0) { - delete this._terminal.tabs[this._terminal.x]; - } - else if (param === 3) { - this._terminal.tabs = {}; - } - }; - InputHandler.prototype.setMode = function (params) { - if (params.length > 1) { - for (var i = 0; i < params.length; i++) { - this.setMode([params[i]]); - } - return; - } - if (!this._terminal.prefix) { - switch (params[0]) { - case 4: - this._terminal.insertMode = true; - break; - case 20: - break; - } - } - else if (this._terminal.prefix === '?') { - switch (params[0]) { - case 1: - this._terminal.applicationCursor = true; - break; - case 2: - this._terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET); - this._terminal.setgCharset(1, Charsets_1.DEFAULT_CHARSET); - this._terminal.setgCharset(2, Charsets_1.DEFAULT_CHARSET); - this._terminal.setgCharset(3, Charsets_1.DEFAULT_CHARSET); - break; - case 3: - this._terminal.savedCols = this._terminal.cols; - this._terminal.resize(132, this._terminal.rows); - break; - case 6: - this._terminal.originMode = true; - break; - case 7: - this._terminal.wraparoundMode = true; - break; - case 12: - break; - case 66: - this._terminal.log('Serial port requested application keypad.'); - this._terminal.applicationKeypad = true; - this._terminal.viewport.syncScrollArea(); - break; - case 9: - case 1000: - case 1002: - case 1003: - this._terminal.x10Mouse = params[0] === 9; - this._terminal.vt200Mouse = params[0] === 1000; - this._terminal.normalMouse = params[0] > 1000; - this._terminal.mouseEvents = true; - this._terminal.element.style.cursor = 'default'; - this._terminal.log('Binding to mouse events.'); - break; - case 1004: - this._terminal.sendFocus = true; - break; - case 1005: - this._terminal.utfMouse = true; - break; - case 1006: - this._terminal.sgrMouse = true; - break; - case 1015: - this._terminal.urxvtMouse = true; - break; - case 25: - this._terminal.cursorHidden = false; - break; - case 1049: - ; - case 47: - case 1047: - if (!this._terminal.normal) { - var normal = { - lines: this._terminal.lines, - ybase: this._terminal.ybase, - ydisp: this._terminal.ydisp, - x: this._terminal.x, - y: this._terminal.y, - scrollTop: this._terminal.scrollTop, - scrollBottom: this._terminal.scrollBottom, - tabs: this._terminal.tabs - }; - this._terminal.reset(); - this._terminal.viewport.syncScrollArea(); - this._terminal.normal = normal; - this._terminal.showCursor(); - } - break; - } - } - }; - InputHandler.prototype.resetMode = function (params) { - if (params.length > 1) { - for (var i = 0; i < params.length; i++) { - this.resetMode([params[i]]); - } - return; - } - if (!this._terminal.prefix) { - switch (params[0]) { - case 4: - this._terminal.insertMode = false; - break; - case 20: - break; - } - } - else if (this._terminal.prefix === '?') { - switch (params[0]) { - case 1: - this._terminal.applicationCursor = false; - break; - case 3: - if (this._terminal.cols === 132 && this._terminal.savedCols) { - this._terminal.resize(this._terminal.savedCols, this._terminal.rows); - } - delete this._terminal.savedCols; - break; - case 6: - this._terminal.originMode = false; - break; - case 7: - this._terminal.wraparoundMode = false; - break; - case 12: - break; - case 66: - this._terminal.log('Switching back to normal keypad.'); - this._terminal.applicationKeypad = false; - this._terminal.viewport.syncScrollArea(); - break; - case 9: - case 1000: - case 1002: - case 1003: - this._terminal.x10Mouse = false; - this._terminal.vt200Mouse = false; - this._terminal.normalMouse = false; - this._terminal.mouseEvents = false; - this._terminal.element.style.cursor = ''; - break; - case 1004: - this._terminal.sendFocus = false; - break; - case 1005: - this._terminal.utfMouse = false; - break; - case 1006: - this._terminal.sgrMouse = false; - break; - case 1015: - this._terminal.urxvtMouse = false; - break; - case 25: - this._terminal.cursorHidden = true; - break; - case 1049: - ; - case 47: - case 1047: - if (this._terminal.normal) { - this._terminal.lines = this._terminal.normal.lines; - this._terminal.ybase = this._terminal.normal.ybase; - this._terminal.ydisp = this._terminal.normal.ydisp; - this._terminal.x = this._terminal.normal.x; - this._terminal.y = this._terminal.normal.y; - this._terminal.scrollTop = this._terminal.normal.scrollTop; - this._terminal.scrollBottom = this._terminal.normal.scrollBottom; - this._terminal.tabs = this._terminal.normal.tabs; - this._terminal.normal = null; - this._terminal.refresh(0, this._terminal.rows - 1); - this._terminal.viewport.syncScrollArea(); - this._terminal.showCursor(); - } - break; - } - } - }; - InputHandler.prototype.charAttributes = function (params) { - if (params.length === 1 && params[0] === 0) { - this._terminal.curAttr = this._terminal.defAttr; - return; - } - var l = params.length, i = 0, flags = this._terminal.curAttr >> 18, fg = (this._terminal.curAttr >> 9) & 0x1ff, bg = this._terminal.curAttr & 0x1ff, p; - for (; i < l; i++) { - p = params[i]; - if (p >= 30 && p <= 37) { - fg = p - 30; - } - else if (p >= 40 && p <= 47) { - bg = p - 40; - } - else if (p >= 90 && p <= 97) { - p += 8; - fg = p - 90; - } - else if (p >= 100 && p <= 107) { - p += 8; - bg = p - 100; - } - else if (p === 0) { - flags = this._terminal.defAttr >> 18; - fg = (this._terminal.defAttr >> 9) & 0x1ff; - bg = this._terminal.defAttr & 0x1ff; - } - else if (p === 1) { - flags |= 1; - } - else if (p === 4) { - flags |= 2; - } - else if (p === 5) { - flags |= 4; - } - else if (p === 7) { - flags |= 8; - } - else if (p === 8) { - flags |= 16; - } - else if (p === 22) { - flags &= ~1; - } - else if (p === 24) { - flags &= ~2; - } - else if (p === 25) { - flags &= ~4; - } - else if (p === 27) { - flags &= ~8; - } - else if (p === 28) { - flags &= ~16; - } - else if (p === 39) { - fg = (this._terminal.defAttr >> 9) & 0x1ff; - } - else if (p === 49) { - bg = this._terminal.defAttr & 0x1ff; - } - else if (p === 38) { - if (params[i + 1] === 2) { - i += 2; - fg = this._terminal.matchColor(params[i] & 0xff, params[i + 1] & 0xff, params[i + 2] & 0xff); - if (fg === -1) - fg = 0x1ff; - i += 2; - } - else if (params[i + 1] === 5) { - i += 2; - p = params[i] & 0xff; - fg = p; - } - } - else if (p === 48) { - if (params[i + 1] === 2) { - i += 2; - bg = this._terminal.matchColor(params[i] & 0xff, params[i + 1] & 0xff, params[i + 2] & 0xff); - if (bg === -1) - bg = 0x1ff; - i += 2; - } - else if (params[i + 1] === 5) { - i += 2; - p = params[i] & 0xff; - bg = p; - } - } - else if (p === 100) { - fg = (this._terminal.defAttr >> 9) & 0x1ff; - bg = this._terminal.defAttr & 0x1ff; - } - else { - this._terminal.error('Unknown SGR attribute: %d.', p); - } - } - this._terminal.curAttr = (flags << 18) | (fg << 9) | bg; - }; - InputHandler.prototype.deviceStatus = function (params) { - if (!this._terminal.prefix) { - switch (params[0]) { - case 5: - this._terminal.send(EscapeSequences_1.C0.ESC + '[0n'); - break; - case 6: - this._terminal.send(EscapeSequences_1.C0.ESC + '[' - + (this._terminal.y + 1) - + ';' - + (this._terminal.x + 1) - + 'R'); - break; - } - } - else if (this._terminal.prefix === '?') { - switch (params[0]) { - case 6: - this._terminal.send(EscapeSequences_1.C0.ESC + '[?' - + (this._terminal.y + 1) - + ';' - + (this._terminal.x + 1) - + 'R'); - break; - case 15: - break; - case 25: - break; - case 26: - break; - case 53: - break; - } - } - }; - InputHandler.prototype.softReset = function (params) { - this._terminal.cursorHidden = false; - this._terminal.insertMode = false; - this._terminal.originMode = false; - this._terminal.wraparoundMode = true; - this._terminal.applicationKeypad = false; - this._terminal.viewport.syncScrollArea(); - this._terminal.applicationCursor = false; - this._terminal.scrollTop = 0; - this._terminal.scrollBottom = this._terminal.rows - 1; - this._terminal.curAttr = this._terminal.defAttr; - this._terminal.x = this._terminal.y = 0; - this._terminal.charset = null; - this._terminal.glevel = 0; - this._terminal.charsets = [null]; - }; - InputHandler.prototype.setCursorStyle = function (params) { - var param = params[0] < 1 ? 1 : params[0]; - switch (param) { - case 1: - case 2: - this._terminal.setOption('cursorStyle', 'block'); - break; - case 3: - case 4: - this._terminal.setOption('cursorStyle', 'underline'); - break; - case 5: - case 6: - this._terminal.setOption('cursorStyle', 'bar'); - break; - } - var isBlinking = param % 2 === 1; - this._terminal.setOption('cursorBlink', isBlinking); - }; - InputHandler.prototype.setScrollRegion = function (params) { - if (this._terminal.prefix) - return; - this._terminal.scrollTop = (params[0] || 1) - 1; - this._terminal.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1; - this._terminal.x = 0; - this._terminal.y = 0; - }; - InputHandler.prototype.saveCursor = function (params) { - this._terminal.savedX = this._terminal.x; - this._terminal.savedY = this._terminal.y; - }; - InputHandler.prototype.restoreCursor = function (params) { - this._terminal.x = this._terminal.savedX || 0; - this._terminal.y = this._terminal.savedY || 0; - }; - return InputHandler; -}()); -exports.InputHandler = InputHandler; -var wcwidth = (function (opts) { - var COMBINING = [ - [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489], - [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2], - [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603], - [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670], - [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED], - [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A], - [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902], - [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D], - [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981], - [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD], - [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C], - [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D], - [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC], - [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD], - [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C], - [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D], - [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0], - [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48], - [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC], - [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD], - [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D], - [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6], - [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E], - [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC], - [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35], - [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E], - [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97], - [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030], - [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039], - [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F], - [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753], - [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD], - [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD], - [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922], - [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B], - [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34], - [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42], - [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF], - [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063], - [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F], - [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B], - [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F], - [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB], - [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F], - [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169], - [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD], - [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F], - [0xE0100, 0xE01EF] - ]; - function bisearch(ucs) { - var min = 0; - var max = COMBINING.length - 1; - var mid; - if (ucs < COMBINING[0][0] || ucs > COMBINING[max][1]) - return false; - while (max >= min) { - mid = Math.floor((min + max) / 2); - if (ucs > COMBINING[mid][1]) - min = mid + 1; - else if (ucs < COMBINING[mid][0]) - max = mid - 1; - else - return true; - } - return false; - } - function wcwidth(ucs) { - if (ucs === 0) - return opts.nul; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) - return opts.control; - if (bisearch(ucs)) - return 0; - if (isWide(ucs)) { - return 2; - } - return 1; - } - function isWide(ucs) { - return (ucs >= 0x1100 && (ucs <= 0x115f || - ucs === 0x2329 || - ucs === 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs !== 0x303f) || - (ucs >= 0xac00 && ucs <= 0xd7a3) || - (ucs >= 0xf900 && ucs <= 0xfaff) || - (ucs >= 0xfe10 && ucs <= 0xfe19) || - (ucs >= 0xfe30 && ucs <= 0xfe6f) || - (ucs >= 0xff00 && ucs <= 0xff60) || - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); - } - return wcwidth; -})({ nul: 0, control: 0 }); - - - -},{"./Charsets":1,"./EscapeSequences":3}],6:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var INVALID_LINK_CLASS = 'xterm-invalid-link'; -var protocolClause = '(https?:\\/\\/)'; -var domainCharacterSet = '[\\da-z\\.-]+'; -var negatedDomainCharacterSet = '[^\\da-z\\.-]+'; -var domainBodyClause = '(' + domainCharacterSet + ')'; -var tldClause = '([a-z\\.]{2,6})'; -var ipClause = '((\\d{1,3}\\.){3}\\d{1,3})'; -var localHostClause = '(localhost)'; -var portClause = '(:\\d{1,5})'; -var hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + '|' + localHostClause + ')' + portClause + '?'; -var pathClause = '(\\/[\\/\\w\\.\\-%~]*)*'; -var queryStringHashFragmentCharacterSet = '[0-9\\w\\[\\]\\(\\)\\/\\?\\!#@$%&\'*+,:;~\\=\\.\\-]*'; -var queryStringClause = '(\\?' + queryStringHashFragmentCharacterSet + ')?'; -var hashFragmentClause = '(#' + queryStringHashFragmentCharacterSet + ')?'; -var negatedPathCharacterSet = '[^\\/\\w\\.\\-%]+'; -var bodyClause = hostClause + pathClause + queryStringClause + hashFragmentClause; -var start = '(?:^|' + negatedDomainCharacterSet + ')('; -var end = ')($|' + negatedPathCharacterSet + ')'; -var strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end); -var HYPERTEXT_LINK_MATCHER_ID = 0; -var Linkifier = (function () { - function Linkifier() { - this._nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID; - this._rowTimeoutIds = []; - this._linkMatchers = []; - this.registerLinkMatcher(strictUrlRegex, null, { matchIndex: 1 }); - } - Linkifier.prototype.attachToDom = function (document, rows) { - this._document = document; - this._rows = rows; - }; - Linkifier.prototype.linkifyRow = function (rowIndex) { - if (!this._document) { - return; - } - var timeoutId = this._rowTimeoutIds[rowIndex]; - if (timeoutId) { - clearTimeout(timeoutId); - } - this._rowTimeoutIds[rowIndex] = setTimeout(this._linkifyRow.bind(this, rowIndex), Linkifier.TIME_BEFORE_LINKIFY); - }; - Linkifier.prototype.setHypertextLinkHandler = function (handler) { - this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].handler = handler; - }; - Linkifier.prototype.setHypertextValidationCallback = function (callback) { - this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].validationCallback = callback; - }; - Linkifier.prototype.registerLinkMatcher = function (regex, handler, options) { - if (options === void 0) { options = {}; } - if (this._nextLinkMatcherId !== HYPERTEXT_LINK_MATCHER_ID && !handler) { - throw new Error('handler must be defined'); - } - var matcher = { - id: this._nextLinkMatcherId++, - regex: regex, - handler: handler, - matchIndex: options.matchIndex, - validationCallback: options.validationCallback, - priority: options.priority || 0 - }; - this._addLinkMatcherToList(matcher); - return matcher.id; - }; - Linkifier.prototype._addLinkMatcherToList = function (matcher) { - if (this._linkMatchers.length === 0) { - this._linkMatchers.push(matcher); - return; - } - for (var i = this._linkMatchers.length - 1; i >= 0; i--) { - if (matcher.priority <= this._linkMatchers[i].priority) { - this._linkMatchers.splice(i + 1, 0, matcher); - return; - } - } - this._linkMatchers.splice(0, 0, matcher); - }; - Linkifier.prototype.deregisterLinkMatcher = function (matcherId) { - for (var i = 1; i < this._linkMatchers.length; i++) { - if (this._linkMatchers[i].id === matcherId) { - this._linkMatchers.splice(i, 1); - return true; - } - } - return false; - }; - Linkifier.prototype._linkifyRow = function (rowIndex) { - var row = this._rows[rowIndex]; - if (!row) { - return; - } - var text = row.textContent; - for (var i = 0; i < this._linkMatchers.length; i++) { - var matcher = this._linkMatchers[i]; - var linkElements = this._doLinkifyRow(row, matcher); - if (linkElements.length > 0) { - if (matcher.validationCallback) { - var _loop_1 = function (j) { - var element = linkElements[j]; - matcher.validationCallback(element.textContent, element, function (isValid) { - if (!isValid) { - element.classList.add(INVALID_LINK_CLASS); - } - }); - }; - for (var j = 0; j < linkElements.length; j++) { - _loop_1(j); - } - } - return; - } - } - }; - Linkifier.prototype._doLinkifyRow = function (row, matcher) { - var result = []; - var isHttpLinkMatcher = matcher.id === HYPERTEXT_LINK_MATCHER_ID; - var nodes = row.childNodes; - var match = row.textContent.match(matcher.regex); - if (!match || match.length === 0) { - return result; - } - var uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex]; - var rowStartIndex = match.index + uri.length; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - var searchIndex = node.textContent.indexOf(uri); - if (searchIndex >= 0) { - var linkElement = this._createAnchorElement(uri, matcher.handler, isHttpLinkMatcher); - if (node.textContent.length === uri.length) { - if (node.nodeType === 3) { - this._replaceNode(node, linkElement); - } - else { - var element = node; - if (element.nodeName === 'A') { - return result; - } - element.innerHTML = ''; - element.appendChild(linkElement); - } - } - else { - var nodesAdded = this._replaceNodeSubstringWithNode(node, linkElement, uri, searchIndex); - i += nodesAdded; - } - result.push(linkElement); - match = row.textContent.substring(rowStartIndex).match(matcher.regex); - if (!match || match.length === 0) { - return result; - } - uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex]; - rowStartIndex += match.index + uri.length; - } - } - return result; - }; - Linkifier.prototype._createAnchorElement = function (uri, handler, isHypertextLinkHandler) { - var element = this._document.createElement('a'); - element.textContent = uri; - element.draggable = false; - if (isHypertextLinkHandler) { - element.href = uri; - element.target = '_blank'; - element.addEventListener('click', function (event) { - if (handler) { - return handler(event, uri); - } - }); - } - else { - element.addEventListener('click', function (event) { - if (element.classList.contains(INVALID_LINK_CLASS)) { - return; - } - return handler(event, uri); - }); - } - return element; - }; - Linkifier.prototype._replaceNode = function (oldNode) { - var newNodes = []; - for (var _i = 1; _i < arguments.length; _i++) { - newNodes[_i - 1] = arguments[_i]; - } - var parent = oldNode.parentNode; - for (var i = 0; i < newNodes.length; i++) { - parent.insertBefore(newNodes[i], oldNode); - } - parent.removeChild(oldNode); - }; - Linkifier.prototype._replaceNodeSubstringWithNode = function (targetNode, newNode, substring, substringIndex) { - var node = targetNode; - if (node.nodeType !== 3) { - node = node.childNodes[0]; - } - if (node.childNodes.length === 0 && node.nodeType !== 3) { - throw new Error('targetNode must be a text node or only contain a single text node'); - } - var fullText = node.textContent; - if (substringIndex === 0) { - var rightText_1 = fullText.substring(substring.length); - var rightTextNode_1 = this._document.createTextNode(rightText_1); - this._replaceNode(node, newNode, rightTextNode_1); - return 0; - } - if (substringIndex === targetNode.textContent.length - substring.length) { - var leftText_1 = fullText.substring(0, substringIndex); - var leftTextNode_1 = this._document.createTextNode(leftText_1); - this._replaceNode(node, leftTextNode_1, newNode); - return 0; - } - var leftText = fullText.substring(0, substringIndex); - var leftTextNode = this._document.createTextNode(leftText); - var rightText = fullText.substring(substringIndex + substring.length); - var rightTextNode = this._document.createTextNode(rightText); - this._replaceNode(node, leftTextNode, newNode, rightTextNode); - return 1; - }; - return Linkifier; -}()); -Linkifier.TIME_BEFORE_LINKIFY = 200; -exports.Linkifier = Linkifier; - - - -},{}],7:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var EscapeSequences_1 = require("./EscapeSequences"); -var Charsets_1 = require("./Charsets"); -var normalStateHandler = {}; -normalStateHandler[EscapeSequences_1.C0.BEL] = function (parser, handler) { return handler.bell(); }; -normalStateHandler[EscapeSequences_1.C0.LF] = function (parser, handler) { return handler.lineFeed(); }; -normalStateHandler[EscapeSequences_1.C0.VT] = normalStateHandler[EscapeSequences_1.C0.LF]; -normalStateHandler[EscapeSequences_1.C0.FF] = normalStateHandler[EscapeSequences_1.C0.LF]; -normalStateHandler[EscapeSequences_1.C0.CR] = function (parser, handler) { return handler.carriageReturn(); }; -normalStateHandler[EscapeSequences_1.C0.BS] = function (parser, handler) { return handler.backspace(); }; -normalStateHandler[EscapeSequences_1.C0.HT] = function (parser, handler) { return handler.tab(); }; -normalStateHandler[EscapeSequences_1.C0.SO] = function (parser, handler) { return handler.shiftOut(); }; -normalStateHandler[EscapeSequences_1.C0.SI] = function (parser, handler) { return handler.shiftIn(); }; -normalStateHandler[EscapeSequences_1.C0.ESC] = function (parser, handler) { return parser.setState(ParserState.ESCAPED); }; -var escapedStateHandler = {}; -escapedStateHandler['['] = function (parser, terminal) { - terminal.params = []; - terminal.currentParam = 0; - parser.setState(ParserState.CSI_PARAM); -}; -escapedStateHandler[']'] = function (parser, terminal) { - terminal.params = []; - terminal.currentParam = 0; - parser.setState(ParserState.OSC); -}; -escapedStateHandler['P'] = function (parser, terminal) { - terminal.params = []; - terminal.currentParam = 0; - parser.setState(ParserState.DCS); -}; -escapedStateHandler['_'] = function (parser, terminal) { - parser.setState(ParserState.IGNORE); -}; -escapedStateHandler['^'] = function (parser, terminal) { - parser.setState(ParserState.IGNORE); -}; -escapedStateHandler['c'] = function (parser, terminal) { - terminal.reset(); -}; -escapedStateHandler['E'] = function (parser, terminal) { - terminal.x = 0; - terminal.index(); - parser.setState(ParserState.NORMAL); -}; -escapedStateHandler['D'] = function (parser, terminal) { - terminal.index(); - parser.setState(ParserState.NORMAL); -}; -escapedStateHandler['M'] = function (parser, terminal) { - terminal.reverseIndex(); - parser.setState(ParserState.NORMAL); -}; -escapedStateHandler['%'] = function (parser, terminal) { - terminal.setgLevel(0); - terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET); - parser.setState(ParserState.NORMAL); - parser.skipNextChar(); -}; -escapedStateHandler[EscapeSequences_1.C0.CAN] = function (parser) { return parser.setState(ParserState.NORMAL); }; -var csiParamStateHandler = {}; -csiParamStateHandler['?'] = function (parser) { return parser.setPrefix('?'); }; -csiParamStateHandler['>'] = function (parser) { return parser.setPrefix('>'); }; -csiParamStateHandler['!'] = function (parser) { return parser.setPrefix('!'); }; -csiParamStateHandler['0'] = function (parser) { return parser.setParam(parser.getParam() * 10); }; -csiParamStateHandler['1'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 1); }; -csiParamStateHandler['2'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 2); }; -csiParamStateHandler['3'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 3); }; -csiParamStateHandler['4'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 4); }; -csiParamStateHandler['5'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 5); }; -csiParamStateHandler['6'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 6); }; -csiParamStateHandler['7'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 7); }; -csiParamStateHandler['8'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 8); }; -csiParamStateHandler['9'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 9); }; -csiParamStateHandler['$'] = function (parser) { return parser.setPostfix('$'); }; -csiParamStateHandler['"'] = function (parser) { return parser.setPostfix('"'); }; -csiParamStateHandler[' '] = function (parser) { return parser.setPostfix(' '); }; -csiParamStateHandler['\''] = function (parser) { return parser.setPostfix('\''); }; -csiParamStateHandler[';'] = function (parser) { return parser.finalizeParam(); }; -csiParamStateHandler[EscapeSequences_1.C0.CAN] = function (parser) { return parser.setState(ParserState.NORMAL); }; -var csiStateHandler = {}; -csiStateHandler['@'] = function (handler, params, prefix) { return handler.insertChars(params); }; -csiStateHandler['A'] = function (handler, params, prefix) { return handler.cursorUp(params); }; -csiStateHandler['B'] = function (handler, params, prefix) { return handler.cursorDown(params); }; -csiStateHandler['C'] = function (handler, params, prefix) { return handler.cursorForward(params); }; -csiStateHandler['D'] = function (handler, params, prefix) { return handler.cursorBackward(params); }; -csiStateHandler['E'] = function (handler, params, prefix) { return handler.cursorNextLine(params); }; -csiStateHandler['F'] = function (handler, params, prefix) { return handler.cursorPrecedingLine(params); }; -csiStateHandler['G'] = function (handler, params, prefix) { return handler.cursorCharAbsolute(params); }; -csiStateHandler['H'] = function (handler, params, prefix) { return handler.cursorPosition(params); }; -csiStateHandler['I'] = function (handler, params, prefix) { return handler.cursorForwardTab(params); }; -csiStateHandler['J'] = function (handler, params, prefix) { return handler.eraseInDisplay(params); }; -csiStateHandler['K'] = function (handler, params, prefix) { return handler.eraseInLine(params); }; -csiStateHandler['L'] = function (handler, params, prefix) { return handler.insertLines(params); }; -csiStateHandler['M'] = function (handler, params, prefix) { return handler.deleteLines(params); }; -csiStateHandler['P'] = function (handler, params, prefix) { return handler.deleteChars(params); }; -csiStateHandler['S'] = function (handler, params, prefix) { return handler.scrollUp(params); }; -csiStateHandler['T'] = function (handler, params, prefix) { - if (params.length < 2 && !prefix) { - handler.scrollDown(params); - } -}; -csiStateHandler['X'] = function (handler, params, prefix) { return handler.eraseChars(params); }; -csiStateHandler['Z'] = function (handler, params, prefix) { return handler.cursorBackwardTab(params); }; -csiStateHandler['`'] = function (handler, params, prefix) { return handler.charPosAbsolute(params); }; -csiStateHandler['a'] = function (handler, params, prefix) { return handler.HPositionRelative(params); }; -csiStateHandler['b'] = function (handler, params, prefix) { return handler.repeatPrecedingCharacter(params); }; -csiStateHandler['c'] = function (handler, params, prefix) { return handler.sendDeviceAttributes(params); }; -csiStateHandler['d'] = function (handler, params, prefix) { return handler.linePosAbsolute(params); }; -csiStateHandler['e'] = function (handler, params, prefix) { return handler.VPositionRelative(params); }; -csiStateHandler['f'] = function (handler, params, prefix) { return handler.HVPosition(params); }; -csiStateHandler['g'] = function (handler, params, prefix) { return handler.tabClear(params); }; -csiStateHandler['h'] = function (handler, params, prefix) { return handler.setMode(params); }; -csiStateHandler['l'] = function (handler, params, prefix) { return handler.resetMode(params); }; -csiStateHandler['m'] = function (handler, params, prefix) { return handler.charAttributes(params); }; -csiStateHandler['n'] = function (handler, params, prefix) { return handler.deviceStatus(params); }; -csiStateHandler['p'] = function (handler, params, prefix) { - switch (prefix) { - case '!': - handler.softReset(params); - break; - } -}; -csiStateHandler['q'] = function (handler, params, prefix, postfix) { - if (postfix === ' ') { - handler.setCursorStyle(params); - } -}; -csiStateHandler['r'] = function (handler, params) { return handler.setScrollRegion(params); }; -csiStateHandler['s'] = function (handler, params) { return handler.saveCursor(params); }; -csiStateHandler['u'] = function (handler, params) { return handler.restoreCursor(params); }; -csiStateHandler[EscapeSequences_1.C0.CAN] = function (handler, params, prefix, postfix, parser) { return parser.setState(ParserState.NORMAL); }; -var ParserState; -(function (ParserState) { - ParserState[ParserState["NORMAL"] = 0] = "NORMAL"; - ParserState[ParserState["ESCAPED"] = 1] = "ESCAPED"; - ParserState[ParserState["CSI_PARAM"] = 2] = "CSI_PARAM"; - ParserState[ParserState["CSI"] = 3] = "CSI"; - ParserState[ParserState["OSC"] = 4] = "OSC"; - ParserState[ParserState["CHARSET"] = 5] = "CHARSET"; - ParserState[ParserState["DCS"] = 6] = "DCS"; - ParserState[ParserState["IGNORE"] = 7] = "IGNORE"; -})(ParserState || (ParserState = {})); -var Parser = (function () { - function Parser(_inputHandler, _terminal) { - this._inputHandler = _inputHandler; - this._terminal = _terminal; - this._state = ParserState.NORMAL; - } - Parser.prototype.parse = function (data) { - var l = data.length, j, cs, ch, code, low; - this._position = 0; - if (this._terminal.surrogate_high) { - data = this._terminal.surrogate_high + data; - this._terminal.surrogate_high = ''; - } - for (; this._position < l; this._position++) { - ch = data[this._position]; - code = data.charCodeAt(this._position); - if (0xD800 <= code && code <= 0xDBFF) { - low = data.charCodeAt(this._position + 1); - if (isNaN(low)) { - this._terminal.surrogate_high = ch; - continue; - } - code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; - ch += data.charAt(this._position + 1); - } - if (0xDC00 <= code && code <= 0xDFFF) - continue; - switch (this._state) { - case ParserState.NORMAL: - if (ch in normalStateHandler) { - normalStateHandler[ch](this, this._inputHandler); - } - else { - this._inputHandler.addChar(ch, code); - } - break; - case ParserState.ESCAPED: - if (ch in escapedStateHandler) { - escapedStateHandler[ch](this, this._terminal); - break; - } - switch (ch) { - case '(': - case ')': - case '*': - case '+': - case '-': - case '.': - switch (ch) { - case '(': - this._terminal.gcharset = 0; - break; - case ')': - this._terminal.gcharset = 1; - break; - case '*': - this._terminal.gcharset = 2; - break; - case '+': - this._terminal.gcharset = 3; - break; - case '-': - this._terminal.gcharset = 1; - break; - case '.': - this._terminal.gcharset = 2; - break; - } - this._state = ParserState.CHARSET; - break; - case '/': - this._terminal.gcharset = 3; - this._state = ParserState.CHARSET; - this._position--; - break; - case 'N': - break; - case 'O': - break; - case 'n': - this._terminal.setgLevel(2); - break; - case 'o': - this._terminal.setgLevel(3); - break; - case '|': - this._terminal.setgLevel(3); - break; - case '}': - this._terminal.setgLevel(2); - break; - case '~': - this._terminal.setgLevel(1); - break; - case '7': - this._inputHandler.saveCursor(); - this._state = ParserState.NORMAL; - break; - case '8': - this._inputHandler.restoreCursor(); - this._state = ParserState.NORMAL; - break; - case '#': - this._state = ParserState.NORMAL; - this._position++; - break; - case 'H': - this._terminal.tabSet(); - this._state = ParserState.NORMAL; - break; - case '=': - this._terminal.log('Serial port requested application keypad.'); - this._terminal.applicationKeypad = true; - this._terminal.viewport.syncScrollArea(); - this._state = ParserState.NORMAL; - break; - case '>': - this._terminal.log('Switching back to normal keypad.'); - this._terminal.applicationKeypad = false; - this._terminal.viewport.syncScrollArea(); - this._state = ParserState.NORMAL; - break; - default: - this._state = ParserState.NORMAL; - this._terminal.error('Unknown ESC control: %s.', ch); - break; - } - break; - case ParserState.CHARSET: - if (ch in Charsets_1.CHARSETS) { - cs = Charsets_1.CHARSETS[ch]; - if (ch === '/') { - this.skipNextChar(); - } - } - else { - cs = Charsets_1.DEFAULT_CHARSET; - } - this._terminal.setgCharset(this._terminal.gcharset, cs); - this._terminal.gcharset = null; - this._state = ParserState.NORMAL; - break; - case ParserState.OSC: - if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) { - if (ch === EscapeSequences_1.C0.ESC) - this._position++; - this._terminal.params.push(this._terminal.currentParam); - switch (this._terminal.params[0]) { - case 0: - case 1: - case 2: - if (this._terminal.params[1]) { - this._terminal.title = this._terminal.params[1]; - this._terminal.handleTitle(this._terminal.title); - } - break; - case 3: - break; - case 4: - case 5: - break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - break; - case 46: - break; - case 50: - break; - case 51: - break; - case 52: - break; - case 104: - case 105: - case 110: - case 111: - case 112: - case 113: - case 114: - case 115: - case 116: - case 117: - case 118: - break; - } - this._terminal.params = []; - this._terminal.currentParam = 0; - this._state = ParserState.NORMAL; - } - else { - if (!this._terminal.params.length) { - if (ch >= '0' && ch <= '9') { - this._terminal.currentParam = - this._terminal.currentParam * 10 + ch.charCodeAt(0) - 48; - } - else if (ch === ';') { - this._terminal.params.push(this._terminal.currentParam); - this._terminal.currentParam = ''; - } - } - else { - this._terminal.currentParam += ch; - } - } - break; - case ParserState.CSI_PARAM: - if (ch in csiParamStateHandler) { - csiParamStateHandler[ch](this); - break; - } - this.finalizeParam(); - this._state = ParserState.CSI; - case ParserState.CSI: - if (ch in csiStateHandler) { - csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix, this._terminal.postfix, this); - } - else { - this._terminal.error('Unknown CSI code: %s.', ch); - } - this._state = ParserState.NORMAL; - this._terminal.prefix = ''; - this._terminal.postfix = ''; - break; - case ParserState.DCS: - if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) { - if (ch === EscapeSequences_1.C0.ESC) - this._position++; - var pt = void 0; - var valid = void 0; - switch (this._terminal.prefix) { - case '': - break; - case '$q': - pt = this._terminal.currentParam; - valid = false; - switch (pt) { - case '"q': - pt = '0"q'; - break; - case '"p': - pt = '61"p'; - break; - case 'r': - pt = '' - + (this._terminal.scrollTop + 1) - + ';' - + (this._terminal.scrollBottom + 1) - + 'r'; - break; - case 'm': - pt = '0m'; - break; - default: - this._terminal.error('Unknown DCS Pt: %s.', pt); - pt = ''; - break; - } - this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '$r' + pt + EscapeSequences_1.C0.ESC + '\\'); - break; - case '+p': - break; - case '+q': - pt = this._terminal.currentParam; - valid = false; - this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '+r' + pt + EscapeSequences_1.C0.ESC + '\\'); - break; - default: - this._terminal.error('Unknown DCS prefix: %s.', this._terminal.prefix); - break; - } - this._terminal.currentParam = 0; - this._terminal.prefix = ''; - this._state = ParserState.NORMAL; - } - else if (!this._terminal.currentParam) { - if (!this._terminal.prefix && ch !== '$' && ch !== '+') { - this._terminal.currentParam = ch; - } - else if (this._terminal.prefix.length === 2) { - this._terminal.currentParam = ch; - } - else { - this._terminal.prefix += ch; - } - } - else { - this._terminal.currentParam += ch; - } - break; - case ParserState.IGNORE: - if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) { - if (ch === EscapeSequences_1.C0.ESC) - this._position++; - this._state = ParserState.NORMAL; - } - break; - } - } - return this._state; - }; - Parser.prototype.setState = function (state) { - this._state = state; - }; - Parser.prototype.setPrefix = function (prefix) { - this._terminal.prefix = prefix; - }; - Parser.prototype.setPostfix = function (postfix) { - this._terminal.postfix = postfix; - }; - Parser.prototype.setParam = function (param) { - this._terminal.currentParam = param; - }; - Parser.prototype.getParam = function () { - return this._terminal.currentParam; - }; - Parser.prototype.finalizeParam = function () { - this._terminal.params.push(this._terminal.currentParam); - this._terminal.currentParam = 0; - }; - Parser.prototype.skipNextChar = function () { - this._position++; - }; - return Parser; -}()); -exports.Parser = Parser; - - - -},{"./Charsets":1,"./EscapeSequences":3}],8:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var DomElementObjectPool_1 = require("./utils/DomElementObjectPool"); -var MAX_REFRESH_FRAME_SKIP = 5; -var FLAGS; -(function (FLAGS) { - FLAGS[FLAGS["BOLD"] = 1] = "BOLD"; - FLAGS[FLAGS["UNDERLINE"] = 2] = "UNDERLINE"; - FLAGS[FLAGS["BLINK"] = 4] = "BLINK"; - FLAGS[FLAGS["INVERSE"] = 8] = "INVERSE"; - FLAGS[FLAGS["INVISIBLE"] = 16] = "INVISIBLE"; -})(FLAGS || (FLAGS = {})); -; -var brokenBold = null; -var Renderer = (function () { - function Renderer(_terminal) { - this._terminal = _terminal; - this._refreshRowsQueue = []; - this._refreshFramesSkipped = 0; - this._refreshAnimationFrame = null; - this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span'); - if (brokenBold === null) { - brokenBold = checkBoldBroken(this._terminal.element); - } - this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span'); - } - Renderer.prototype.queueRefresh = function (start, end) { - this._refreshRowsQueue.push({ start: start, end: end }); - if (!this._refreshAnimationFrame) { - this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this)); - } - }; - Renderer.prototype._refreshLoop = function () { - var skipFrame = this._terminal.writeBuffer.length > 0 && this._refreshFramesSkipped++ <= MAX_REFRESH_FRAME_SKIP; - if (skipFrame) { - this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this)); - return; - } - this._refreshFramesSkipped = 0; - var start; - var end; - if (this._refreshRowsQueue.length > 4) { - start = 0; - end = this._terminal.rows - 1; - } - else { - start = this._refreshRowsQueue[0].start; - end = this._refreshRowsQueue[0].end; - for (var i = 1; i < this._refreshRowsQueue.length; i++) { - if (this._refreshRowsQueue[i].start < start) { - start = this._refreshRowsQueue[i].start; - } - if (this._refreshRowsQueue[i].end > end) { - end = this._refreshRowsQueue[i].end; - } - } - } - this._refreshRowsQueue = []; - this._refreshAnimationFrame = null; - this._refresh(start, end); - }; - Renderer.prototype._refresh = function (start, end) { - var parent; - if (end - start >= this._terminal.rows / 2) { - parent = this._terminal.element.parentNode; - if (parent) { - this._terminal.element.removeChild(this._terminal.rowContainer); - } - } - var width = this._terminal.cols; - var y = start; - if (end >= this._terminal.rows) { - this._terminal.log('`end` is too large. Most likely a bad CSR.'); - end = this._terminal.rows - 1; - } - for (; y <= end; y++) { - var row = y + this._terminal.ydisp; - var line = this._terminal.lines.get(row); - var x = void 0; - if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) && - this._terminal.cursorState && - !this._terminal.cursorHidden) { - x = this._terminal.x; - } - else { - x = -1; - } - var attr = this._terminal.defAttr; - var documentFragment = document.createDocumentFragment(); - var innerHTML = ''; - var currentElement = void 0; - while (this._terminal.children[y].children.length) { - var child = this._terminal.children[y].children[0]; - this._terminal.children[y].removeChild(child); - this._spanElementObjectPool.release(child); - } - for (var i = 0; i < width; i++) { - var data = line[i][0]; - var ch = line[i][1]; - var ch_width = line[i][2]; - if (!ch_width) { - continue; - } - if (i === x) { - data = -1; - } - if (data !== attr) { - if (attr !== this._terminal.defAttr) { - if (innerHTML) { - currentElement.innerHTML = innerHTML; - innerHTML = ''; - } - documentFragment.appendChild(currentElement); - currentElement = null; - } - if (data !== this._terminal.defAttr) { - if (innerHTML && !currentElement) { - currentElement = this._spanElementObjectPool.acquire(); - } - if (currentElement) { - if (innerHTML) { - currentElement.innerHTML = innerHTML; - innerHTML = ''; - } - documentFragment.appendChild(currentElement); - } - currentElement = this._spanElementObjectPool.acquire(); - if (data === -1) { - currentElement.classList.add('reverse-video', 'terminal-cursor'); - } - else { - var bg = data & 0x1ff; - var fg = (data >> 9) & 0x1ff; - var flags = data >> 18; - if (flags & FLAGS.BOLD) { - if (!brokenBold) { - currentElement.classList.add('xterm-bold'); - } - if (fg < 8) { - fg += 8; - } - } - if (flags & FLAGS.UNDERLINE) { - currentElement.classList.add('xterm-underline'); - } - if (flags & FLAGS.BLINK) { - currentElement.classList.add('xterm-blink'); - } - if (flags & FLAGS.INVERSE) { - var temp = bg; - bg = fg; - fg = temp; - if ((flags & 1) && fg < 8) { - fg += 8; - } - } - if (flags & FLAGS.INVISIBLE) { - currentElement.classList.add('xterm-hidden'); - } - if (flags & FLAGS.INVERSE) { - if (bg === 257) { - bg = 15; - } - if (fg === 256) { - fg = 0; - } - } - if (bg < 256) { - currentElement.classList.add("xterm-bg-color-" + bg); - } - if (fg < 256) { - currentElement.classList.add("xterm-color-" + fg); - } - } - } - } - if (ch_width === 2) { - innerHTML += "<span class=\"xterm-wide-char\">" + ch + "</span>"; - } - else if (ch.charCodeAt(0) > 255) { - innerHTML += "<span class=\"xterm-normal-char\">" + ch + "</span>"; - } - else { - switch (ch) { - case '&': - innerHTML += '&'; - break; - case '<': - innerHTML += '<'; - break; - case '>': - innerHTML += '>'; - break; - default: - if (ch <= ' ') { - innerHTML += ' '; - } - else { - innerHTML += ch; - } - break; - } - } - attr = data; - } - if (innerHTML && !currentElement) { - currentElement = this._spanElementObjectPool.acquire(); - } - if (currentElement) { - if (innerHTML) { - currentElement.innerHTML = innerHTML; - innerHTML = ''; - } - documentFragment.appendChild(currentElement); - currentElement = null; - } - this._terminal.children[y].appendChild(documentFragment); - } - if (parent) { - this._terminal.element.appendChild(this._terminal.rowContainer); - } - this._terminal.emit('refresh', { element: this._terminal.element, start: start, end: end }); - }; - ; - return Renderer; -}()); -exports.Renderer = Renderer; -function checkBoldBroken(terminal) { - var document = terminal.ownerDocument; - var el = document.createElement('span'); - el.innerHTML = 'hello world'; - terminal.appendChild(el); - var w1 = el.offsetWidth; - var h1 = el.offsetHeight; - el.style.fontWeight = 'bold'; - var w2 = el.offsetWidth; - var h2 = el.offsetHeight; - terminal.removeChild(el); - return w1 !== w2 || h1 !== h2; -} - - - -},{"./utils/DomElementObjectPool":14}],9:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var Viewport = (function () { - function Viewport(terminal, viewportElement, scrollArea, charMeasure) { - var _this = this; - this.terminal = terminal; - this.viewportElement = viewportElement; - this.scrollArea = scrollArea; - this.charMeasure = charMeasure; - this.currentRowHeight = 0; - this.lastRecordedBufferLength = 0; - this.lastRecordedViewportHeight = 0; - this.terminal.on('scroll', this.syncScrollArea.bind(this)); - this.terminal.on('resize', this.syncScrollArea.bind(this)); - this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); - setTimeout(function () { return _this.syncScrollArea(); }, 0); - } - Viewport.prototype.refresh = function () { - if (this.charMeasure.height > 0) { - var rowHeightChanged = this.charMeasure.height !== this.currentRowHeight; - if (rowHeightChanged) { - this.currentRowHeight = this.charMeasure.height; - this.viewportElement.style.lineHeight = this.charMeasure.height + 'px'; - this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px'; - } - var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; - if (rowHeightChanged || viewportHeightChanged) { - this.lastRecordedViewportHeight = this.terminal.rows; - this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px'; - } - this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px'; - } - }; - Viewport.prototype.syncScrollArea = function () { - if (this.lastRecordedBufferLength !== this.terminal.lines.length) { - this.lastRecordedBufferLength = this.terminal.lines.length; - this.refresh(); - } - else if (this.lastRecordedViewportHeight !== this.terminal.rows) { - this.refresh(); - } - else { - if (this.charMeasure.height !== this.currentRowHeight) { - this.refresh(); - } - } - var scrollTop = this.terminal.ydisp * this.currentRowHeight; - if (this.viewportElement.scrollTop !== scrollTop) { - this.viewportElement.scrollTop = scrollTop; - } - }; - Viewport.prototype.onScroll = function (ev) { - var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); - var diff = newRow - this.terminal.ydisp; - this.terminal.scrollDisp(diff, true); - }; - Viewport.prototype.onWheel = function (ev) { - if (ev.deltaY === 0) { - return; - } - var multiplier = 1; - if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { - multiplier = this.currentRowHeight; - } - else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - multiplier = this.currentRowHeight * this.terminal.rows; - } - this.viewportElement.scrollTop += ev.deltaY * multiplier; - ev.preventDefault(); - }; - ; - return Viewport; -}()); -exports.Viewport = Viewport; - - - -},{}],10:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function prepareTextForClipboard(text) { - var space = String.fromCharCode(32), nonBreakingSpace = String.fromCharCode(160), allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'), processedText = text.split('\n').map(function (line) { - var processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space); - return processedLine; - }).join('\n'); - return processedText; -} -exports.prepareTextForClipboard = prepareTextForClipboard; -function prepareTextForTerminal(text, isMSWindows) { - if (isMSWindows) { - return text.replace(/\r?\n/g, '\n'); - } - return text; -} -exports.prepareTextForTerminal = prepareTextForTerminal; -function copyHandler(ev, term) { - var copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText); - if (term.browser.isMSIE) { - window.clipboardData.setData('Text', text); - } - else { - ev.clipboardData.setData('text/plain', text); - } - ev.preventDefault(); -} -exports.copyHandler = copyHandler; -function pasteHandler(ev, term) { - ev.stopPropagation(); - var text; - var dispatchPaste = function (text) { - text = prepareTextForTerminal(text, term.browser.isMSWindows); - term.handler(text); - term.textarea.value = ''; - term.emit('paste', text); - return term.cancel(ev); - }; - if (term.browser.isMSIE) { - if (window.clipboardData) { - text = window.clipboardData.getData('Text'); - dispatchPaste(text); - } - } - else { - if (ev.clipboardData) { - text = ev.clipboardData.getData('text/plain'); - dispatchPaste(text); - } - } -} -exports.pasteHandler = pasteHandler; -function rightClickHandler(ev, term) { - var s = document.getSelection(), selectedText = prepareTextForClipboard(s.toString()), clickIsOnSelection = false, x = ev.clientX, y = ev.clientY; - if (s.rangeCount) { - var r = s.getRangeAt(0), cr = r.getClientRects(); - for (var i = 0; i < cr.length; i++) { - var rect = cr[i]; - clickIsOnSelection = ((x > rect.left) && (x < rect.right) && - (y > rect.top) && (y < rect.bottom)); - if (clickIsOnSelection) { - break; - } - } - if (selectedText.match(/^\s$/) || !selectedText.length) { - clickIsOnSelection = false; - } - } - if (!clickIsOnSelection) { - term.textarea.style.position = 'fixed'; - term.textarea.style.width = '20px'; - term.textarea.style.height = '20px'; - term.textarea.style.left = (x - 10) + 'px'; - term.textarea.style.top = (y - 10) + 'px'; - term.textarea.style.zIndex = '1000'; - term.textarea.focus(); - setTimeout(function () { - term.textarea.style.position = null; - term.textarea.style.width = null; - term.textarea.style.height = null; - term.textarea.style.left = null; - term.textarea.style.top = null; - term.textarea.style.zIndex = null; - }, 4); - } -} -exports.rightClickHandler = rightClickHandler; - - - -},{}],11:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var Generic_1 = require("./Generic"); -var isNode = (typeof navigator === 'undefined') ? true : false; -var userAgent = (isNode) ? 'node' : navigator.userAgent; -var platform = (isNode) ? 'node' : navigator.platform; -exports.isFirefox = !!~userAgent.indexOf('Firefox'); -exports.isMSIE = !!~userAgent.indexOf('MSIE') || !!~userAgent.indexOf('Trident'); -exports.isMac = Generic_1.contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform); -exports.isIpad = platform === 'iPad'; -exports.isIphone = platform === 'iPhone'; -exports.isMSWindows = Generic_1.contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform); - - - -},{"./Generic":15}],12:[function(require,module,exports){ -"use strict"; -var __extends = (this && this.__extends) || (function () { - var extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var EventEmitter_js_1 = require("../EventEmitter.js"); -var CharMeasure = (function (_super) { - __extends(CharMeasure, _super); - function CharMeasure(document, parentElement) { - var _this = _super.call(this) || this; - _this._document = document; - _this._parentElement = parentElement; - return _this; - } - Object.defineProperty(CharMeasure.prototype, "width", { - get: function () { - return this._width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(CharMeasure.prototype, "height", { - get: function () { - return this._height; - }, - enumerable: true, - configurable: true - }); - CharMeasure.prototype.measure = function () { - var _this = this; - if (!this._measureElement) { - this._measureElement = this._document.createElement('span'); - this._measureElement.style.position = 'absolute'; - this._measureElement.style.top = '0'; - this._measureElement.style.left = '-9999em'; - this._measureElement.textContent = 'W'; - this._measureElement.setAttribute('aria-hidden', 'true'); - this._parentElement.appendChild(this._measureElement); - setTimeout(function () { return _this._doMeasure(); }, 0); - } - else { - this._doMeasure(); - } - }; - CharMeasure.prototype._doMeasure = function () { - var geometry = this._measureElement.getBoundingClientRect(); - if (geometry.width === 0 || geometry.height === 0) { - return; - } - if (this._width !== geometry.width || this._height !== geometry.height) { - this._width = geometry.width; - this._height = geometry.height; - this.emit('charsizechanged'); - } - }; - return CharMeasure; -}(EventEmitter_js_1.EventEmitter)); -exports.CharMeasure = CharMeasure; - - - -},{"../EventEmitter.js":4}],13:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var CircularList = (function () { - function CircularList(maxLength) { - this._array = new Array(maxLength); - this._startIndex = 0; - this._length = 0; - } - Object.defineProperty(CircularList.prototype, "maxLength", { - get: function () { - return this._array.length; - }, - set: function (newMaxLength) { - var newArray = new Array(newMaxLength); - for (var i = 0; i < Math.min(newMaxLength, this.length); i++) { - newArray[i] = this._array[this._getCyclicIndex(i)]; - } - this._array = newArray; - this._startIndex = 0; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(CircularList.prototype, "length", { - get: function () { - return this._length; - }, - set: function (newLength) { - if (newLength > this._length) { - for (var i = this._length; i < newLength; i++) { - this._array[i] = undefined; - } - } - this._length = newLength; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(CircularList.prototype, "forEach", { - get: function () { - return this._array.forEach; - }, - enumerable: true, - configurable: true - }); - CircularList.prototype.get = function (index) { - return this._array[this._getCyclicIndex(index)]; - }; - CircularList.prototype.set = function (index, value) { - this._array[this._getCyclicIndex(index)] = value; - }; - CircularList.prototype.push = function (value) { - this._array[this._getCyclicIndex(this._length)] = value; - if (this._length === this.maxLength) { - this._startIndex++; - if (this._startIndex === this.maxLength) { - this._startIndex = 0; - } - } - else { - this._length++; - } - }; - CircularList.prototype.pop = function () { - return this._array[this._getCyclicIndex(this._length-- - 1)]; - }; - CircularList.prototype.splice = function (start, deleteCount) { - var items = []; - for (var _i = 2; _i < arguments.length; _i++) { - items[_i - 2] = arguments[_i]; - } - if (deleteCount) { - for (var i = start; i < this._length - deleteCount; i++) { - this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)]; - } - this._length -= deleteCount; - } - if (items && items.length) { - for (var i = this._length - 1; i >= start; i--) { - this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)]; - } - for (var i = 0; i < items.length; i++) { - this._array[this._getCyclicIndex(start + i)] = items[i]; - } - if (this._length + items.length > this.maxLength) { - this._startIndex += (this._length + items.length) - this.maxLength; - this._length = this.maxLength; - } - else { - this._length += items.length; - } - } - }; - CircularList.prototype.trimStart = function (count) { - if (count > this._length) { - count = this._length; - } - this._startIndex += count; - this._length -= count; - }; - CircularList.prototype.shiftElements = function (start, count, offset) { - if (count <= 0) { - return; - } - if (start < 0 || start >= this._length) { - throw new Error('start argument out of range'); - } - if (start + offset < 0) { - throw new Error('Cannot shift elements in list beyond index 0'); - } - if (offset > 0) { - for (var i = count - 1; i >= 0; i--) { - this.set(start + i + offset, this.get(start + i)); - } - var expandListBy = (start + count + offset) - this._length; - if (expandListBy > 0) { - this._length += expandListBy; - while (this._length > this.maxLength) { - this._length--; - this._startIndex++; - } - } - } - else { - for (var i = 0; i < count; i++) { - this.set(start + i + offset, this.get(start + i)); - } - } - }; - CircularList.prototype._getCyclicIndex = function (index) { - return (this._startIndex + index) % this.maxLength; - }; - return CircularList; -}()); -exports.CircularList = CircularList; - - - -},{}],14:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var DomElementObjectPool = (function () { - function DomElementObjectPool(type) { - this.type = type; - this._type = type; - this._pool = []; - this._inUse = {}; - } - DomElementObjectPool.prototype.acquire = function () { - var element; - if (this._pool.length === 0) { - element = this._createNew(); - } - else { - element = this._pool.pop(); - } - this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)] = element; - return element; - }; - DomElementObjectPool.prototype.release = function (element) { - if (!this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]) { - throw new Error('Could not release an element not yet acquired'); - } - delete this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]; - this._cleanElement(element); - this._pool.push(element); - }; - DomElementObjectPool.prototype._createNew = function () { - var element = document.createElement(this._type); - var id = DomElementObjectPool._objectCount++; - element.setAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE, id.toString(10)); - return element; - }; - DomElementObjectPool.prototype._cleanElement = function (element) { - element.className = ''; - element.innerHTML = ''; - }; - return DomElementObjectPool; -}()); -DomElementObjectPool.OBJECT_ID_ATTRIBUTE = 'data-obj-id'; -DomElementObjectPool._objectCount = 0; -exports.DomElementObjectPool = DomElementObjectPool; - - - -},{}],15:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function contains(arr, el) { - return arr.indexOf(el) >= 0; -} -exports.contains = contains; -; - - - -},{}],16:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function getCoords(event, rowContainer, charMeasure) { - if (event.pageX == null) { - return null; - } - var x = event.pageX; - var y = event.pageY; - var el = rowContainer; - while (el && el !== self.document.documentElement) { - x -= el.offsetLeft; - y -= el.offsetTop; - el = 'offsetParent' in el ? el.offsetParent : el.parentElement; - } - x = Math.ceil(x / charMeasure.width); - y = Math.ceil(y / charMeasure.height); - return [x, y]; -} -exports.getCoords = getCoords; -function getRawByteCoords(event, rowContainer, charMeasure, colCount, rowCount) { - var coords = getCoords(event, rowContainer, charMeasure); - var x = coords[0]; - var y = coords[1]; - x = Math.min(Math.max(x, 0), colCount); - y = Math.min(Math.max(y, 0), rowCount); - x += 32; - y += 32; - return { x: x, y: y }; -} -exports.getRawByteCoords = getRawByteCoords; - - - -},{}],17:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var CompositionHelper_1 = require("./CompositionHelper"); -var EventEmitter_1 = require("./EventEmitter"); -var Viewport_1 = require("./Viewport"); -var Clipboard_1 = require("./handlers/Clipboard"); -var CircularList_1 = require("./utils/CircularList"); -var EscapeSequences_1 = require("./EscapeSequences"); -var InputHandler_1 = require("./InputHandler"); -var Parser_1 = require("./Parser"); -var Renderer_1 = require("./Renderer"); -var Linkifier_1 = require("./Linkifier"); -var CharMeasure_1 = require("./utils/CharMeasure"); -var Browser = require("./utils/Browser"); -var Mouse_1 = require("./utils/Mouse"); -var document = (typeof window != 'undefined') ? window.document : null; -var WRITE_BUFFER_PAUSE_THRESHOLD = 5; -var WRITE_BATCH_SIZE = 300; -var CURSOR_BLINK_INTERVAL = 600; -function Terminal(options) { - var self = this; - if (!(this instanceof Terminal)) { - return new Terminal(arguments[0], arguments[1], arguments[2]); - } - self.browser = Browser; - self.cancel = Terminal.cancel; - EventEmitter_1.EventEmitter.call(this); - if (typeof options === 'number') { - options = { - cols: arguments[0], - rows: arguments[1], - handler: arguments[2] - }; - } - options = options || {}; - Object.keys(Terminal.defaults).forEach(function (key) { - if (options[key] == null) { - options[key] = Terminal.options[key]; - if (Terminal[key] !== Terminal.defaults[key]) { - options[key] = Terminal[key]; - } - } - self[key] = options[key]; - }); - if (options.colors.length === 8) { - options.colors = options.colors.concat(Terminal._colors.slice(8)); - } - else if (options.colors.length === 16) { - options.colors = options.colors.concat(Terminal._colors.slice(16)); - } - else if (options.colors.length === 10) { - options.colors = options.colors.slice(0, -2).concat(Terminal._colors.slice(8, -2), options.colors.slice(-2)); - } - else if (options.colors.length === 18) { - options.colors = options.colors.concat(Terminal._colors.slice(16, -2), options.colors.slice(-2)); - } - this.colors = options.colors; - this.options = options; - this.parent = options.body || options.parent || (document ? document.getElementsByTagName('body')[0] : null); - this.cols = options.cols || options.geometry[0]; - this.rows = options.rows || options.geometry[1]; - this.geometry = [this.cols, this.rows]; - if (options.handler) { - this.on('data', options.handler); - } - this.ybase = 0; - this.ydisp = 0; - this.x = 0; - this.y = 0; - this.cursorState = 0; - this.cursorHidden = false; - this.convertEol; - this.queue = ''; - this.scrollTop = 0; - this.scrollBottom = this.rows - 1; - this.customKeydownHandler = null; - this.cursorBlinkInterval = null; - this.applicationKeypad = false; - this.applicationCursor = false; - this.originMode = false; - this.insertMode = false; - this.wraparoundMode = true; - this.normal = null; - this.charset = null; - this.gcharset = null; - this.glevel = 0; - this.charsets = [null]; - this.decLocator; - this.x10Mouse; - this.vt200Mouse; - this.vt300Mouse; - this.normalMouse; - this.mouseEvents; - this.sendFocus; - this.utfMouse; - this.sgrMouse; - this.urxvtMouse; - this.element; - this.children; - this.refreshStart; - this.refreshEnd; - this.savedX; - this.savedY; - this.savedCols; - this.readable = true; - this.writable = true; - this.defAttr = (0 << 18) | (257 << 9) | (256 << 0); - this.curAttr = this.defAttr; - this.params = []; - this.currentParam = 0; - this.prefix = ''; - this.postfix = ''; - this.inputHandler = new InputHandler_1.InputHandler(this); - this.parser = new Parser_1.Parser(this.inputHandler, this); - this.renderer = this.renderer || null; - this.linkifier = this.linkifier || new Linkifier_1.Linkifier(); - this.writeBuffer = []; - this.writeInProgress = false; - this.xoffSentToCatchUp = false; - this.writeStopped = false; - this.surrogate_high = ''; - this.lines = new CircularList_1.CircularList(this.scrollback); - var i = this.rows; - while (i--) { - this.lines.push(this.blankLine()); - } - this.tabs; - this.setupStops(); - this.userScrolling = false; -} -inherits(Terminal, EventEmitter_1.EventEmitter); -Terminal.prototype.eraseAttr = function () { - return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff); -}; -Terminal.tangoColors = [ - '#2e3436', - '#cc0000', - '#4e9a06', - '#c4a000', - '#3465a4', - '#75507b', - '#06989a', - '#d3d7cf', - '#555753', - '#ef2929', - '#8ae234', - '#fce94f', - '#729fcf', - '#ad7fa8', - '#34e2e2', - '#eeeeec' -]; -Terminal.colors = (function () { - var colors = Terminal.tangoColors.slice(), r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff], i; - i = 0; - for (; i < 216; i++) { - out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]); - } - i = 0; - for (; i < 24; i++) { - r = 8 + i * 10; - out(r, r, r); - } - function out(r, g, b) { - colors.push('#' + hex(r) + hex(g) + hex(b)); - } - function hex(c) { - c = c.toString(16); - return c.length < 2 ? '0' + c : c; - } - return colors; -})(); -Terminal._colors = Terminal.colors.slice(); -Terminal.vcolors = (function () { - var out = [], colors = Terminal.colors, i = 0, color; - for (; i < 256; i++) { - color = parseInt(colors[i].substring(1), 16); - out.push([ - (color >> 16) & 0xff, - (color >> 8) & 0xff, - color & 0xff - ]); - } - return out; -})(); -Terminal.defaults = { - colors: Terminal.colors, - theme: 'default', - convertEol: false, - termName: 'xterm', - geometry: [80, 24], - cursorBlink: false, - cursorStyle: 'block', - visualBell: false, - popOnBell: false, - scrollback: 1000, - screenKeys: false, - debug: false, - cancelEvents: false, - disableStdin: false, - useFlowControl: false, - tabStopWidth: 8 -}; -Terminal.options = {}; -Terminal.focus = null; -each(keys(Terminal.defaults), function (key) { - Terminal[key] = Terminal.defaults[key]; - Terminal.options[key] = Terminal.defaults[key]; -}); -Terminal.prototype.focus = function () { - return this.textarea.focus(); -}; -Terminal.prototype.getOption = function (key, value) { - if (!(key in Terminal.defaults)) { - throw new Error('No option with key "' + key + '"'); - } - if (typeof this.options[key] !== 'undefined') { - return this.options[key]; - } - return this[key]; -}; -Terminal.prototype.setOption = function (key, value) { - if (!(key in Terminal.defaults)) { - throw new Error('No option with key "' + key + '"'); - } - switch (key) { - case 'scrollback': - if (this.options[key] !== value) { - if (this.lines.length > value) { - var amountToTrim = this.lines.length - value; - var needsRefresh = (this.ydisp - amountToTrim < 0); - this.lines.trimStart(amountToTrim); - this.ybase = Math.max(this.ybase - amountToTrim, 0); - this.ydisp = Math.max(this.ydisp - amountToTrim, 0); - if (needsRefresh) { - this.refresh(0, this.rows - 1); - } - } - this.lines.maxLength = value; - this.viewport.syncScrollArea(); - } - break; - } - this[key] = value; - this.options[key] = value; - switch (key) { - case 'cursorBlink': - this.setCursorBlinking(value); - break; - case 'cursorStyle': - this.element.classList.toggle("xterm-cursor-style-underline", value === 'underline'); - this.element.classList.toggle("xterm-cursor-style-bar", value === 'bar'); - break; - case 'tabStopWidth': - this.setupStops(); - break; - } -}; -Terminal.prototype.restartCursorBlinking = function () { - this.setCursorBlinking(this.options.cursorBlink); -}; -Terminal.prototype.setCursorBlinking = function (enabled) { - this.element.classList.toggle('xterm-cursor-blink', enabled); - this.clearCursorBlinkingInterval(); - if (enabled) { - var self = this; - this.cursorBlinkInterval = setInterval(function () { - self.element.classList.toggle('xterm-cursor-blink-on'); - }, CURSOR_BLINK_INTERVAL); - } -}; -Terminal.prototype.clearCursorBlinkingInterval = function () { - this.element.classList.remove('xterm-cursor-blink-on'); - if (this.cursorBlinkInterval) { - clearInterval(this.cursorBlinkInterval); - this.cursorBlinkInterval = null; - } -}; -Terminal.bindFocus = function (term) { - on(term.textarea, 'focus', function (ev) { - if (term.sendFocus) { - term.send(EscapeSequences_1.C0.ESC + '[I'); - } - term.element.classList.add('focus'); - term.showCursor(); - term.restartCursorBlinking.apply(term); - Terminal.focus = term; - term.emit('focus', { terminal: term }); - }); -}; -Terminal.prototype.blur = function () { - return this.textarea.blur(); -}; -Terminal.bindBlur = function (term) { - on(term.textarea, 'blur', function (ev) { - term.refresh(term.y, term.y); - if (term.sendFocus) { - term.send(EscapeSequences_1.C0.ESC + '[O'); - } - term.element.classList.remove('focus'); - term.clearCursorBlinkingInterval.apply(term); - Terminal.focus = null; - term.emit('blur', { terminal: term }); - }); -}; -Terminal.prototype.initGlobal = function () { - var term = this; - Terminal.bindKeys(this); - Terminal.bindFocus(this); - Terminal.bindBlur(this); - on(this.element, 'copy', function (ev) { - Clipboard_1.copyHandler.call(this, ev, term); - }); - on(this.textarea, 'paste', function (ev) { - Clipboard_1.pasteHandler.call(this, ev, term); - }); - on(this.element, 'paste', function (ev) { - Clipboard_1.pasteHandler.call(this, ev, term); - }); - function rightClickHandlerWrapper(ev) { - Clipboard_1.rightClickHandler.call(this, ev, term); - } - if (term.browser.isFirefox) { - on(this.element, 'mousedown', function (ev) { - if (ev.button == 2) { - rightClickHandlerWrapper(ev); - } - }); - } - else { - on(this.element, 'contextmenu', rightClickHandlerWrapper); - } -}; -Terminal.bindKeys = function (term) { - on(term.element, 'keydown', function (ev) { - if (document.activeElement != this) { - return; - } - term.keyDown(ev); - }, true); - on(term.element, 'keypress', function (ev) { - if (document.activeElement != this) { - return; - } - term.keyPress(ev); - }, true); - on(term.element, 'keyup', function (ev) { - if (!wasMondifierKeyOnlyEvent(ev)) { - term.focus(term); - } - }, true); - on(term.textarea, 'keydown', function (ev) { - term.keyDown(ev); - }, true); - on(term.textarea, 'keypress', function (ev) { - term.keyPress(ev); - this.value = ''; - }, true); - on(term.textarea, 'compositionstart', term.compositionHelper.compositionstart.bind(term.compositionHelper)); - on(term.textarea, 'compositionupdate', term.compositionHelper.compositionupdate.bind(term.compositionHelper)); - on(term.textarea, 'compositionend', term.compositionHelper.compositionend.bind(term.compositionHelper)); - term.on('refresh', term.compositionHelper.updateCompositionElements.bind(term.compositionHelper)); - term.on('refresh', function (data) { - term.queueLinkification(data.start, data.end); - }); -}; -Terminal.prototype.insertRow = function (row) { - if (typeof row != 'object') { - row = document.createElement('div'); - } - this.rowContainer.appendChild(row); - this.children.push(row); - return row; -}; -Terminal.prototype.open = function (parent, focus) { - var self = this, i = 0, div; - this.parent = parent || this.parent; - if (!this.parent) { - throw new Error('Terminal requires a parent element.'); - } - this.context = this.parent.ownerDocument.defaultView; - this.document = this.parent.ownerDocument; - this.body = this.document.getElementsByTagName('body')[0]; - this.element = this.document.createElement('div'); - this.element.classList.add('terminal'); - this.element.classList.add('xterm'); - this.element.classList.add('xterm-theme-' + this.theme); - this.setCursorBlinking(this.options.cursorBlink); - this.element.style.height; - this.element.setAttribute('tabindex', 0); - this.viewportElement = document.createElement('div'); - this.viewportElement.classList.add('xterm-viewport'); - this.element.appendChild(this.viewportElement); - this.viewportScrollArea = document.createElement('div'); - this.viewportScrollArea.classList.add('xterm-scroll-area'); - this.viewportElement.appendChild(this.viewportScrollArea); - this.rowContainer = document.createElement('div'); - this.rowContainer.classList.add('xterm-rows'); - this.element.appendChild(this.rowContainer); - this.children = []; - this.linkifier.attachToDom(document, this.children); - this.helperContainer = document.createElement('div'); - this.helperContainer.classList.add('xterm-helpers'); - this.element.appendChild(this.helperContainer); - this.textarea = document.createElement('textarea'); - this.textarea.classList.add('xterm-helper-textarea'); - this.textarea.setAttribute('autocorrect', 'off'); - this.textarea.setAttribute('autocapitalize', 'off'); - this.textarea.setAttribute('spellcheck', 'false'); - this.textarea.tabIndex = 0; - this.textarea.addEventListener('focus', function () { - self.emit('focus', { terminal: self }); - }); - this.textarea.addEventListener('blur', function () { - self.emit('blur', { terminal: self }); - }); - this.helperContainer.appendChild(this.textarea); - this.compositionView = document.createElement('div'); - this.compositionView.classList.add('composition-view'); - this.compositionHelper = new CompositionHelper_1.CompositionHelper(this.textarea, this.compositionView, this); - this.helperContainer.appendChild(this.compositionView); - this.charSizeStyleElement = document.createElement('style'); - this.helperContainer.appendChild(this.charSizeStyleElement); - for (; i < this.rows; i++) { - this.insertRow(); - } - this.parent.appendChild(this.element); - this.charMeasure = new CharMeasure_1.CharMeasure(document, this.helperContainer); - this.charMeasure.on('charsizechanged', function () { - self.updateCharSizeCSS(); - }); - this.charMeasure.measure(); - this.viewport = new Viewport_1.Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); - this.renderer = new Renderer_1.Renderer(this); - this.refresh(0, this.rows - 1); - this.initGlobal(); - if (typeof focus == 'undefined') { - var message = 'You did not pass the `focus` argument in `Terminal.prototype.open()`.\n'; - message += 'The `focus` argument now defaults to `true` but starting with xterm.js 3.0 '; - message += 'it will default to `false`.'; - console.warn(message); - focus = true; - } - if (focus) { - this.focus(); - } - on(this.element, 'click', function () { - var selection = document.getSelection(), collapsed = selection.isCollapsed, isRange = typeof collapsed == 'boolean' ? !collapsed : selection.type == 'Range'; - if (!isRange) { - self.focus(); - } - }); - this.bindMouse(); - this.emit('open'); -}; -Terminal.loadAddon = function (addon, callback) { - if (typeof exports === 'object' && typeof module === 'object') { - return require('./addons/' + addon + '/' + addon); - } - else if (typeof define == 'function') { - return require(['./addons/' + addon + '/' + addon], callback); - } - else { - console.error('Cannot load a module without a CommonJS or RequireJS environment.'); - return false; - } -}; -Terminal.prototype.updateCharSizeCSS = function () { - this.charSizeStyleElement.textContent = - ".xterm-wide-char{width:" + this.charMeasure.width * 2 + "px;}" + - (".xterm-normal-char{width:" + this.charMeasure.width + "px;}"); -}; -Terminal.prototype.bindMouse = function () { - var el = this.element, self = this, pressed = 32; - function sendButton(ev) { - var button, pos; - button = getButton(ev); - pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows); - if (!pos) - return; - sendEvent(button, pos); - switch (ev.overrideType || ev.type) { - case 'mousedown': - pressed = button; - break; - case 'mouseup': - pressed = 32; - break; - case 'wheel': - break; - } - } - function sendMove(ev) { - var button = pressed, pos; - pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows); - if (!pos) - return; - button += 32; - sendEvent(button, pos); - } - function encode(data, ch) { - if (!self.utfMouse) { - if (ch === 255) - return data.push(0); - if (ch > 127) - ch = 127; - data.push(ch); - } - else { - if (ch === 2047) - return data.push(0); - if (ch < 127) { - data.push(ch); - } - else { - if (ch > 2047) - ch = 2047; - data.push(0xC0 | (ch >> 6)); - data.push(0x80 | (ch & 0x3F)); - } - } - } - function sendEvent(button, pos) { - if (self.vt300Mouse) { - button &= 3; - pos.x -= 32; - pos.y -= 32; - var data = EscapeSequences_1.C0.ESC + '[24'; - if (button === 0) - data += '1'; - else if (button === 1) - data += '3'; - else if (button === 2) - data += '5'; - else if (button === 3) - return; - else - data += '0'; - data += '~[' + pos.x + ',' + pos.y + ']\r'; - self.send(data); - return; - } - if (self.decLocator) { - button &= 3; - pos.x -= 32; - pos.y -= 32; - if (button === 0) - button = 2; - else if (button === 1) - button = 4; - else if (button === 2) - button = 6; - else if (button === 3) - button = 3; - self.send(EscapeSequences_1.C0.ESC + '[' - + button - + ';' - + (button === 3 ? 4 : 0) - + ';' - + pos.y - + ';' - + pos.x - + ';' - + (pos.page || 0) - + '&w'); - return; - } - if (self.urxvtMouse) { - pos.x -= 32; - pos.y -= 32; - pos.x++; - pos.y++; - self.send(EscapeSequences_1.C0.ESC + '[' + button + ';' + pos.x + ';' + pos.y + 'M'); - return; - } - if (self.sgrMouse) { - pos.x -= 32; - pos.y -= 32; - self.send(EscapeSequences_1.C0.ESC + '[<' - + (((button & 3) === 3 ? button & ~3 : button) - 32) - + ';' - + pos.x - + ';' - + pos.y - + ((button & 3) === 3 ? 'm' : 'M')); - return; - } - var data = []; - encode(data, button); - encode(data, pos.x); - encode(data, pos.y); - self.send(EscapeSequences_1.C0.ESC + '[M' + String.fromCharCode.apply(String, data)); - } - function getButton(ev) { - var button, shift, meta, ctrl, mod; - switch (ev.overrideType || ev.type) { - case 'mousedown': - button = ev.button != null - ? +ev.button - : ev.which != null - ? ev.which - 1 - : null; - if (self.browser.isMSIE) { - button = button === 1 ? 0 : button === 4 ? 1 : button; - } - break; - case 'mouseup': - button = 3; - break; - case 'DOMMouseScroll': - button = ev.detail < 0 - ? 64 - : 65; - break; - case 'wheel': - button = ev.wheelDeltaY > 0 - ? 64 - : 65; - break; - } - shift = ev.shiftKey ? 4 : 0; - meta = ev.metaKey ? 8 : 0; - ctrl = ev.ctrlKey ? 16 : 0; - mod = shift | meta | ctrl; - if (self.vt200Mouse) { - mod &= ctrl; - } - else if (!self.normalMouse) { - mod = 0; - } - button = (32 + (mod << 2)) + button; - return button; - } - on(el, 'mousedown', function (ev) { - if (!self.mouseEvents) - return; - sendButton(ev); - self.focus(); - if (self.vt200Mouse) { - ev.overrideType = 'mouseup'; - sendButton(ev); - return self.cancel(ev); - } - if (self.normalMouse) - on(self.document, 'mousemove', sendMove); - if (!self.x10Mouse) { - on(self.document, 'mouseup', function up(ev) { - sendButton(ev); - if (self.normalMouse) - off(self.document, 'mousemove', sendMove); - off(self.document, 'mouseup', up); - return self.cancel(ev); - }); - } - return self.cancel(ev); - }); - on(el, 'wheel', function (ev) { - if (!self.mouseEvents) - return; - if (self.x10Mouse - || self.vt300Mouse - || self.decLocator) - return; - sendButton(ev); - return self.cancel(ev); - }); - on(el, 'wheel', function (ev) { - if (self.mouseEvents) - return; - self.viewport.onWheel(ev); - return self.cancel(ev); - }); -}; -Terminal.prototype.destroy = function () { - this.readable = false; - this.writable = false; - this._events = {}; - this.handler = function () { }; - this.write = function () { }; - if (this.element && this.element.parentNode) { - this.element.parentNode.removeChild(this.element); - } -}; -Terminal.prototype.refresh = function (start, end) { - if (this.renderer) { - this.renderer.queueRefresh(start, end); - } -}; -Terminal.prototype.queueLinkification = function (start, end) { - if (this.linkifier) { - for (var i = start; i <= end; i++) { - this.linkifier.linkifyRow(i); - } - } -}; -Terminal.prototype.showCursor = function () { - if (!this.cursorState) { - this.cursorState = 1; - this.refresh(this.y, this.y); - } -}; -Terminal.prototype.scroll = function () { - var row; - if (this.lines.length === this.lines.maxLength) { - this.lines.trimStart(1); - this.ybase--; - if (this.ydisp !== 0) { - this.ydisp--; - } - } - this.ybase++; - if (!this.userScrolling) { - this.ydisp = this.ybase; - } - row = this.ybase + this.rows - 1; - row -= this.rows - 1 - this.scrollBottom; - if (row === this.lines.length) { - this.lines.push(this.blankLine()); - } - else { - this.lines.splice(row, 0, this.blankLine()); - } - if (this.scrollTop !== 0) { - if (this.ybase !== 0) { - this.ybase--; - if (!this.userScrolling) { - this.ydisp = this.ybase; - } - } - this.lines.splice(this.ybase + this.scrollTop, 1); - } - this.updateRange(this.scrollTop); - this.updateRange(this.scrollBottom); - this.emit('scroll', this.ydisp); -}; -Terminal.prototype.scrollDisp = function (disp, suppressScrollEvent) { - if (disp < 0) { - this.userScrolling = true; - } - else if (disp + this.ydisp >= this.ybase) { - this.userScrolling = false; - } - this.ydisp += disp; - if (this.ydisp > this.ybase) { - this.ydisp = this.ybase; - } - else if (this.ydisp < 0) { - this.ydisp = 0; - } - if (!suppressScrollEvent) { - this.emit('scroll', this.ydisp); - } - this.refresh(0, this.rows - 1); -}; -Terminal.prototype.scrollPages = function (pageCount) { - this.scrollDisp(pageCount * (this.rows - 1)); -}; -Terminal.prototype.scrollToTop = function () { - this.scrollDisp(-this.ydisp); -}; -Terminal.prototype.scrollToBottom = function () { - this.scrollDisp(this.ybase - this.ydisp); -}; -Terminal.prototype.write = function (data) { - this.writeBuffer.push(data); - if (this.options.useFlowControl && !this.xoffSentToCatchUp && this.writeBuffer.length >= WRITE_BUFFER_PAUSE_THRESHOLD) { - this.send(EscapeSequences_1.C0.DC3); - this.xoffSentToCatchUp = true; - } - if (!this.writeInProgress && this.writeBuffer.length > 0) { - this.writeInProgress = true; - var self = this; - setTimeout(function () { - self.innerWrite(); - }); - } -}; -Terminal.prototype.innerWrite = function () { - var writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE); - while (writeBatch.length > 0) { - var data = writeBatch.shift(); - var l = data.length, i = 0, j, cs, ch, code, low, ch_width, row; - if (this.xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) { - this.send(EscapeSequences_1.C0.DC1); - this.xoffSentToCatchUp = false; - } - this.refreshStart = this.y; - this.refreshEnd = this.y; - var state = this.parser.parse(data); - this.parser.setState(state); - this.updateRange(this.y); - this.refresh(this.refreshStart, this.refreshEnd); - } - if (this.writeBuffer.length > 0) { - var self = this; - setTimeout(function () { - self.innerWrite(); - }, 0); - } - else { - this.writeInProgress = false; - } -}; -Terminal.prototype.writeln = function (data) { - this.write(data + '\r\n'); -}; -Terminal.prototype.attachCustomKeydownHandler = function (customKeydownHandler) { - this.customKeydownHandler = customKeydownHandler; -}; -Terminal.prototype.setHypertextLinkHandler = function (handler) { - if (!this.linkifier) { - throw new Error('Cannot attach a hypertext link handler before Terminal.open is called'); - } - this.linkifier.setHypertextLinkHandler(handler); - this.refresh(0, this.rows - 1); -}; -Terminal.prototype.setHypertextValidationCallback = function (handler) { - if (!this.linkifier) { - throw new Error('Cannot attach a hypertext validation callback before Terminal.open is called'); - } - this.linkifier.setHypertextValidationCallback(handler); - this.refresh(0, this.rows - 1); -}; -Terminal.prototype.registerLinkMatcher = function (regex, handler, options) { - if (this.linkifier) { - var matcherId = this.linkifier.registerLinkMatcher(regex, handler, options); - this.refresh(0, this.rows - 1); - return matcherId; - } -}; -Terminal.prototype.deregisterLinkMatcher = function (matcherId) { - if (this.linkifier) { - if (this.linkifier.deregisterLinkMatcher(matcherId)) { - this.refresh(0, this.rows - 1); - } - } -}; -Terminal.prototype.keyDown = function (ev) { - if (this.customKeydownHandler && this.customKeydownHandler(ev) === false) { - return false; - } - this.restartCursorBlinking(); - if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) { - if (this.ybase !== this.ydisp) { - this.scrollToBottom(); - } - return false; - } - var self = this; - var result = this.evaluateKeyEscapeSequence(ev); - if (result.key === EscapeSequences_1.C0.DC3) { - this.writeStopped = true; - } - else if (result.key === EscapeSequences_1.C0.DC1) { - this.writeStopped = false; - } - if (result.scrollDisp) { - this.scrollDisp(result.scrollDisp); - return this.cancel(ev, true); - } - if (isThirdLevelShift(this, ev)) { - return true; - } - if (result.cancel) { - this.cancel(ev, true); - } - if (!result.key) { - return true; - } - this.emit('keydown', ev); - this.emit('key', result.key, ev); - this.showCursor(); - this.handler(result.key); - return this.cancel(ev, true); -}; -Terminal.prototype.evaluateKeyEscapeSequence = function (ev) { - var result = { - cancel: false, - key: undefined, - scrollDisp: undefined - }; - var modifiers = ev.shiftKey << 0 | ev.altKey << 1 | ev.ctrlKey << 2 | ev.metaKey << 3; - switch (ev.keyCode) { - case 8: - if (ev.shiftKey) { - result.key = EscapeSequences_1.C0.BS; - break; - } - result.key = EscapeSequences_1.C0.DEL; - break; - case 9: - if (ev.shiftKey) { - result.key = EscapeSequences_1.C0.ESC + '[Z'; - break; - } - result.key = EscapeSequences_1.C0.HT; - result.cancel = true; - break; - case 13: - result.key = EscapeSequences_1.C0.CR; - result.cancel = true; - break; - case 27: - result.key = EscapeSequences_1.C0.ESC; - result.cancel = true; - break; - case 37: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'D'; - if (result.key == EscapeSequences_1.C0.ESC + '[1;3D') { - result.key = (this.browser.isMac) ? EscapeSequences_1.C0.ESC + 'b' : EscapeSequences_1.C0.ESC + '[1;5D'; - } - } - else if (this.applicationCursor) { - result.key = EscapeSequences_1.C0.ESC + 'OD'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[D'; - } - break; - case 39: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'C'; - if (result.key == EscapeSequences_1.C0.ESC + '[1;3C') { - result.key = (this.browser.isMac) ? EscapeSequences_1.C0.ESC + 'f' : EscapeSequences_1.C0.ESC + '[1;5C'; - } - } - else if (this.applicationCursor) { - result.key = EscapeSequences_1.C0.ESC + 'OC'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[C'; - } - break; - case 38: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'A'; - if (result.key == EscapeSequences_1.C0.ESC + '[1;3A') { - result.key = EscapeSequences_1.C0.ESC + '[1;5A'; - } - } - else if (this.applicationCursor) { - result.key = EscapeSequences_1.C0.ESC + 'OA'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[A'; - } - break; - case 40: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'B'; - if (result.key == EscapeSequences_1.C0.ESC + '[1;3B') { - result.key = EscapeSequences_1.C0.ESC + '[1;5B'; - } - } - else if (this.applicationCursor) { - result.key = EscapeSequences_1.C0.ESC + 'OB'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[B'; - } - break; - case 45: - if (!ev.shiftKey && !ev.ctrlKey) { - result.key = EscapeSequences_1.C0.ESC + '[2~'; - } - break; - case 46: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[3;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[3~'; - } - break; - case 36: - if (modifiers) - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'H'; - else if (this.applicationCursor) - result.key = EscapeSequences_1.C0.ESC + 'OH'; - else - result.key = EscapeSequences_1.C0.ESC + '[H'; - break; - case 35: - if (modifiers) - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'F'; - else if (this.applicationCursor) - result.key = EscapeSequences_1.C0.ESC + 'OF'; - else - result.key = EscapeSequences_1.C0.ESC + '[F'; - break; - case 33: - if (ev.shiftKey) { - result.scrollDisp = -(this.rows - 1); - } - else { - result.key = EscapeSequences_1.C0.ESC + '[5~'; - } - break; - case 34: - if (ev.shiftKey) { - result.scrollDisp = this.rows - 1; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[6~'; - } - break; - case 112: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'P'; - } - else { - result.key = EscapeSequences_1.C0.ESC + 'OP'; - } - break; - case 113: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'Q'; - } - else { - result.key = EscapeSequences_1.C0.ESC + 'OQ'; - } - break; - case 114: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'R'; - } - else { - result.key = EscapeSequences_1.C0.ESC + 'OR'; - } - break; - case 115: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'S'; - } - else { - result.key = EscapeSequences_1.C0.ESC + 'OS'; - } - break; - case 116: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[15;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[15~'; - } - break; - case 117: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[17;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[17~'; - } - break; - case 118: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[18;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[18~'; - } - break; - case 119: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[19;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[19~'; - } - break; - case 120: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[20;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[20~'; - } - break; - case 121: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[21;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[21~'; - } - break; - case 122: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[23;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[23~'; - } - break; - case 123: - if (modifiers) { - result.key = EscapeSequences_1.C0.ESC + '[24;' + (modifiers + 1) + '~'; - } - else { - result.key = EscapeSequences_1.C0.ESC + '[24~'; - } - break; - default: - if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { - if (ev.keyCode >= 65 && ev.keyCode <= 90) { - result.key = String.fromCharCode(ev.keyCode - 64); - } - else if (ev.keyCode === 32) { - result.key = String.fromCharCode(0); - } - else if (ev.keyCode >= 51 && ev.keyCode <= 55) { - result.key = String.fromCharCode(ev.keyCode - 51 + 27); - } - else if (ev.keyCode === 56) { - result.key = String.fromCharCode(127); - } - else if (ev.keyCode === 219) { - result.key = String.fromCharCode(27); - } - else if (ev.keyCode === 220) { - result.key = String.fromCharCode(28); - } - else if (ev.keyCode === 221) { - result.key = String.fromCharCode(29); - } - } - else if (!this.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) { - if (ev.keyCode >= 65 && ev.keyCode <= 90) { - result.key = EscapeSequences_1.C0.ESC + String.fromCharCode(ev.keyCode + 32); - } - else if (ev.keyCode === 192) { - result.key = EscapeSequences_1.C0.ESC + '`'; - } - else if (ev.keyCode >= 48 && ev.keyCode <= 57) { - result.key = EscapeSequences_1.C0.ESC + (ev.keyCode - 48); - } - } - break; - } - return result; -}; -Terminal.prototype.setgLevel = function (g) { - this.glevel = g; - this.charset = this.charsets[g]; -}; -Terminal.prototype.setgCharset = function (g, charset) { - this.charsets[g] = charset; - if (this.glevel === g) { - this.charset = charset; - } -}; -Terminal.prototype.keyPress = function (ev) { - var key; - this.cancel(ev); - if (ev.charCode) { - key = ev.charCode; - } - else if (ev.which == null) { - key = ev.keyCode; - } - else if (ev.which !== 0 && ev.charCode !== 0) { - key = ev.which; - } - else { - return false; - } - if (!key || ((ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this, ev))) { - return false; - } - key = String.fromCharCode(key); - this.emit('keypress', key, ev); - this.emit('key', key, ev); - this.showCursor(); - this.handler(key); - return false; -}; -Terminal.prototype.send = function (data) { - var self = this; - if (!this.queue) { - setTimeout(function () { - self.handler(self.queue); - self.queue = ''; - }, 1); - } - this.queue += data; -}; -Terminal.prototype.bell = function () { - if (!this.visualBell) - return; - var self = this; - this.element.style.borderColor = 'white'; - setTimeout(function () { - self.element.style.borderColor = ''; - }, 10); - if (this.popOnBell) - this.focus(); -}; -Terminal.prototype.log = function () { - if (!this.debug) - return; - if (!this.context.console || !this.context.console.log) - return; - var args = Array.prototype.slice.call(arguments); - this.context.console.log.apply(this.context.console, args); -}; -Terminal.prototype.error = function () { - if (!this.debug) - return; - if (!this.context.console || !this.context.console.error) - return; - var args = Array.prototype.slice.call(arguments); - this.context.console.error.apply(this.context.console, args); -}; -Terminal.prototype.resize = function (x, y) { - if (isNaN(x) || isNaN(y)) { - return; - } - var line, el, i, j, ch, addToY; - if (x === this.cols && y === this.rows) { - return; - } - if (x < 1) - x = 1; - if (y < 1) - y = 1; - j = this.cols; - if (j < x) { - ch = [this.defAttr, ' ', 1]; - i = this.lines.length; - while (i--) { - while (this.lines.get(i).length < x) { - this.lines.get(i).push(ch); - } - } - } - this.cols = x; - this.setupStops(this.cols); - j = this.rows; - addToY = 0; - if (j < y) { - el = this.element; - while (j++ < y) { - if (this.lines.length < y + this.ybase) { - if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) { - this.ybase--; - addToY++; - if (this.ydisp > 0) { - this.ydisp--; - } - } - else { - this.lines.push(this.blankLine()); - } - } - if (this.children.length < y) { - this.insertRow(); - } - } - } - else { - while (j-- > y) { - if (this.lines.length > y + this.ybase) { - if (this.lines.length > this.ybase + this.y + 1) { - this.lines.pop(); - } - else { - this.ybase++; - this.ydisp++; - } - } - if (this.children.length > y) { - el = this.children.shift(); - if (!el) - continue; - el.parentNode.removeChild(el); - } - } - } - this.rows = y; - if (this.y >= y) { - this.y = y - 1; - } - if (addToY) { - this.y += addToY; - } - if (this.x >= x) { - this.x = x - 1; - } - this.scrollTop = 0; - this.scrollBottom = y - 1; - this.charMeasure.measure(); - this.refresh(0, this.rows - 1); - this.normal = null; - this.geometry = [this.cols, this.rows]; - this.emit('resize', { terminal: this, cols: x, rows: y }); -}; -Terminal.prototype.updateRange = function (y) { - if (y < this.refreshStart) - this.refreshStart = y; - if (y > this.refreshEnd) - this.refreshEnd = y; -}; -Terminal.prototype.maxRange = function () { - this.refreshStart = 0; - this.refreshEnd = this.rows - 1; -}; -Terminal.prototype.setupStops = function (i) { - if (i != null) { - if (!this.tabs[i]) { - i = this.prevStop(i); - } - } - else { - this.tabs = {}; - i = 0; - } - for (; i < this.cols; i += this.getOption('tabStopWidth')) { - this.tabs[i] = true; - } -}; -Terminal.prototype.prevStop = function (x) { - if (x == null) - x = this.x; - while (!this.tabs[--x] && x > 0) - ; - return x >= this.cols - ? this.cols - 1 - : x < 0 ? 0 : x; -}; -Terminal.prototype.nextStop = function (x) { - if (x == null) - x = this.x; - while (!this.tabs[++x] && x < this.cols) - ; - return x >= this.cols - ? this.cols - 1 - : x < 0 ? 0 : x; -}; -Terminal.prototype.eraseRight = function (x, y) { - var line = this.lines.get(this.ybase + y); - if (!line) { - return; - } - var ch = [this.eraseAttr(), ' ', 1]; - for (; x < this.cols; x++) { - line[x] = ch; - } - this.updateRange(y); -}; -Terminal.prototype.eraseLeft = function (x, y) { - var line = this.lines.get(this.ybase + y); - if (!line) { - return; - } - var ch = [this.eraseAttr(), ' ', 1]; - x++; - while (x--) { - line[x] = ch; - } - this.updateRange(y); -}; -Terminal.prototype.clear = function () { - if (this.ybase === 0 && this.y === 0) { - return; - } - this.lines.set(0, this.lines.get(this.ybase + this.y)); - this.lines.length = 1; - this.ydisp = 0; - this.ybase = 0; - this.y = 0; - for (var i = 1; i < this.rows; i++) { - this.lines.push(this.blankLine()); - } - this.refresh(0, this.rows - 1); - this.emit('scroll', this.ydisp); -}; -Terminal.prototype.eraseLine = function (y) { - this.eraseRight(0, y); -}; -Terminal.prototype.blankLine = function (cur) { - var attr = cur - ? this.eraseAttr() - : this.defAttr; - var ch = [attr, ' ', 1], line = [], i = 0; - for (; i < this.cols; i++) { - line[i] = ch; - } - return line; -}; -Terminal.prototype.ch = function (cur) { - return cur - ? [this.eraseAttr(), ' ', 1] - : [this.defAttr, ' ', 1]; -}; -Terminal.prototype.is = function (term) { - var name = this.termName; - return (name + '').indexOf(term) === 0; -}; -Terminal.prototype.handler = function (data) { - if (this.options.disableStdin) { - return; - } - if (this.ybase !== this.ydisp) { - this.scrollToBottom(); - } - this.emit('data', data); -}; -Terminal.prototype.handleTitle = function (title) { - this.emit('title', title); -}; -Terminal.prototype.index = function () { - this.y++; - if (this.y > this.scrollBottom) { - this.y--; - this.scroll(); - } - if (this.x >= this.cols) { - this.x--; - } -}; -Terminal.prototype.reverseIndex = function () { - var j; - if (this.y === this.scrollTop) { - this.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1); - this.lines.set(this.y + this.ybase, this.blankLine(true)); - this.updateRange(this.scrollTop); - this.updateRange(this.scrollBottom); - } - else { - this.y--; - } -}; -Terminal.prototype.reset = function () { - this.options.rows = this.rows; - this.options.cols = this.cols; - var customKeydownHandler = this.customKeydownHandler; - var cursorBlinkInterval = this.cursorBlinkInterval; - Terminal.call(this, this.options); - this.customKeydownHandler = customKeydownHandler; - this.cursorBlinkInterval = cursorBlinkInterval; - this.refresh(0, this.rows - 1); - this.viewport.syncScrollArea(); -}; -Terminal.prototype.tabSet = function () { - this.tabs[this.x] = true; -}; -function on(el, type, handler, capture) { - if (!Array.isArray(el)) { - el = [el]; - } - el.forEach(function (element) { - element.addEventListener(type, handler, capture || false); - }); -} -function off(el, type, handler, capture) { - el.removeEventListener(type, handler, capture || false); -} -function cancel(ev, force) { - if (!this.cancelEvents && !force) { - return; - } - ev.preventDefault(); - ev.stopPropagation(); - return false; -} -function inherits(child, parent) { - function f() { - this.constructor = child; - } - f.prototype = parent.prototype; - child.prototype = new f; -} -function indexOf(obj, el) { - var i = obj.length; - while (i--) { - if (obj[i] === el) - return i; - } - return -1; -} -function isThirdLevelShift(term, ev) { - var thirdLevelKey = (term.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) || - (term.browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey); - if (ev.type == 'keypress') { - return thirdLevelKey; - } - return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47); -} -Terminal.prototype.matchColor = matchColor; -function matchColor(r1, g1, b1) { - var hash = (r1 << 16) | (g1 << 8) | b1; - if (matchColor._cache[hash] != null) { - return matchColor._cache[hash]; - } - var ldiff = Infinity, li = -1, i = 0, c, r2, g2, b2, diff; - for (; i < Terminal.vcolors.length; i++) { - c = Terminal.vcolors[i]; - r2 = c[0]; - g2 = c[1]; - b2 = c[2]; - diff = matchColor.distance(r1, g1, b1, r2, g2, b2); - if (diff === 0) { - li = i; - break; - } - if (diff < ldiff) { - ldiff = diff; - li = i; - } - } - return matchColor._cache[hash] = li; -} -matchColor._cache = {}; -matchColor.distance = function (r1, g1, b1, r2, g2, b2) { - return Math.pow(30 * (r1 - r2), 2) - + Math.pow(59 * (g1 - g2), 2) - + Math.pow(11 * (b1 - b2), 2); -}; -function each(obj, iter, con) { - if (obj.forEach) - return obj.forEach(iter, con); - for (var i = 0; i < obj.length; i++) { - iter.call(con, obj[i], i, obj); - } -} -function wasMondifierKeyOnlyEvent(ev) { - return ev.keyCode === 16 || - ev.keyCode === 17 || - ev.keyCode === 18; -} -function keys(obj) { - if (Object.keys) - return Object.keys(obj); - var key, keys = []; - for (key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - keys.push(key); - } - } - return keys; -} -Terminal.EventEmitter = EventEmitter_1.EventEmitter; -Terminal.inherits = inherits; -Terminal.on = on; -Terminal.off = off; -Terminal.cancel = cancel; -module.exports = Terminal; - - - -},{"./CompositionHelper":2,"./EscapeSequences":3,"./EventEmitter":4,"./InputHandler":5,"./Linkifier":6,"./Parser":7,"./Renderer":8,"./Viewport":9,"./handlers/Clipboard":10,"./utils/Browser":11,"./utils/CharMeasure":12,"./utils/CircularList":13,"./utils/Mouse":16}]},{},[17])(17) -}); -//# sourceMappingURL=xterm.js.map
diff --git a/third_party/blink/renderer/devtools/services/devtools.js b/third_party/blink/renderer/devtools/services/devtools.js deleted file mode 100644 index 831acea..0000000 --- a/third_party/blink/renderer/devtools/services/devtools.js +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -var dispatcher = require("./dispatcher.js"); -var terminal = require("./terminal.js"); - -var d = new dispatcher.Dispatcher(); -d.registerObject("Terminal", terminal.Terminal); -d.start(9022); - -console.log("Run chrome as `chrome --devtools-flags='service-backend=ws://localhost:9022/endpoint'`");
diff --git a/third_party/blink/renderer/devtools/services/dispatcher.js b/third_party/blink/renderer/devtools/services/dispatcher.js deleted file mode 100644 index 3735931..0000000 --- a/third_party/blink/renderer/devtools/services/dispatcher.js +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -var http = require("http"); -var ws = require("ws"); - -function Dispatcher() -{ - this._constructors = new Map(); - this._connections = new Set(); -} - -Dispatcher.prototype = { - start: function(port) - { - var http_server = http.createServer(); - http_server.listen(port); - - var WebSocketServer = ws.Server; - var options = { server: http_server, path: "/endpoint" }; - var wss = new WebSocketServer(options); - wss.on("connection", (socket) => { - var connection = new Connection(this, socket); - this._connections.add(connection); - }); - }, - - registerObject: function(name, constructor) - { - this._constructors.set(name, constructor); - }, - - _connectionClosed: function(connection) - { - this._connections.delete(connection); - } -} - -exports.Dispatcher = Dispatcher; - -function Connection(dispatcher, socket) -{ - this._dispatcher = dispatcher; - this._objects = new Map(); - this._lastObjectId = 1; - this._socket = socket; - this._socket.on("message", this._dispatchMessageWrapped.bind(this)); - this._socket.on("close", this._connectionClosed.bind(this)); -} - -Connection.prototype = { - _dispatchMessageWrapped: function(data) - { - try { - var message = JSON.parse(data); - this._dispatchMessage(message); - } catch(e) { - this._sendErrorResponse(message.id, e.toString()); - } - }, - - _dispatchMessage: function(message) - { - var [objectName, method] = message.method.split("."); - var result = JSON.stringify({id: message.id}); - var constructor = this._dispatcher._constructors.get(objectName); - if (!constructor) { - this._sendErrorResponse(message.id, "Could not resolve service '" + objectName + "'"); - return; - } - if (method === "create") { - var id = String(this._lastObjectId++); - var object = new constructor(this._notify.bind(this, id, objectName)); - this._objects.set(id, object); - this._sendResponse(message.id, { id: id }); - } else if (method === "dispose") { - var object = this._objects.get(message.params.id); - if (!object) { - console.error("Could not look up object with id for " + JSON.stringify(message)); - return; - } - this._objects.delete(message.params.id); - object.dispose().then(() => this._sendResponse(message.id)); - } else { - if (!message.params) { - console.error("No params in the message: " + JSON.stringify(message)); - return; - } - var object = this._objects.get(message.params.id); - if (!object) { - console.error("Could not look up object with id for " + JSON.stringify(message)); - return; - } - var handler = object[method]; - if (!(handler instanceof Function)) { - console.error("Handler for '" + method + "' is missing."); - return; - } - object[method](message.params).then(result => this._sendResponse(message.id, result)); - } - }, - - _connectionClosed: function() - { - for (var object of this._objects.values()) - object.dispose(); - this._objects.clear(); - this._dispatcher._connectionClosed(this); - }, - - _notify: function(objectId, objectName, method, params) - { - params["id"] = objectId; - var message = { method: objectName + "." + method, params: params }; - this._socket.send(JSON.stringify(message)); - }, - - _sendResponse: function(messageId, result) - { - var message = { id: messageId, result: result }; - this._socket.send(JSON.stringify(message)); - }, - - _sendErrorResponse: function(messageId, error) - { - var message = { id: messageId, error: error }; - this._socket.send(JSON.stringify(message)); - }, -}
diff --git a/third_party/blink/renderer/devtools/services/package.json b/third_party/blink/renderer/devtools/services/package.json deleted file mode 100644 index 824851c..0000000 --- a/third_party/blink/renderer/devtools/services/package.json +++ /dev/null
@@ -1,11 +0,0 @@ -{ - "name": "devtools-backend", - "version": "1.0.0", - "ignore": [ - ".gitignore" - ], - "dependencies": { - "pty.js": "0.3.1", - "ws": "^1.1.1" - } -}
diff --git a/third_party/blink/renderer/devtools/services/terminal.js b/third_party/blink/renderer/devtools/services/terminal.js deleted file mode 100644 index 742b553..0000000 --- a/third_party/blink/renderer/devtools/services/terminal.js +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -var pty = require("pty.js"); - -function Terminal(notify) -{ - this._notify = notify; -} - -Terminal.prototype = { - init: function(params) - { - this._term = pty.spawn(process.platform === "win32" ? "cmd.exe" : "bash", [], { - name: "xterm-color", - cols: params.cols || 80, - rows: params.rows || 24, - cwd: process.env.PWD, - env: process.env - }); - - this._term.on("data", data => { - if (this._notify) - this._notify("data", { data: data }); - }); - return Promise.resolve({}); - }, - - resize: function(params) - { - if (this._term) - this._term.resize(params.cols, params.rows); - return Promise.resolve({}); - }, - - write: function(params) - { - this._term.write(params.data); - return Promise.resolve({}); - }, - - dispose: function(params) - { - this._notify = null; - if (this._term) - process.kill(this._term.pid); - return Promise.resolve({}); - }, -} - -exports.Terminal = Terminal;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 1d846232..55ecaed 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -3208,8 +3208,10 @@ if (!node) return false; if (Element* locked_ancestor = - DisplayLockUtilities::NearestLockedInclusiveAncestor(*node)) - locked_ancestor->ActivateDisplayLockIfNeeded(); + DisplayLockUtilities::NearestLockedInclusiveAncestor(*node)) { + locked_ancestor->ActivateDisplayLockIfNeeded( + DisplayLockActivationReason::kUser); + } LayoutObject* layout_object = node->GetLayoutObject(); if (!layout_object || !node->isConnected()) return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_slider.cc b/third_party/blink/renderer/modules/accessibility/ax_slider.cc index c15a9ed..a04a922 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_slider.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_slider.cc
@@ -113,6 +113,10 @@ // Fire change event manually, as LayoutSlider::setValueForPosition does. input->DispatchFormControlChangeEvent(); + + // Ensure the AX node is updated. + AXObjectCache().MarkAXObjectDirty(this, false); + return true; }
diff --git a/third_party/blink/renderer/modules/cache_storage/BUILD.gn b/third_party/blink/renderer/modules/cache_storage/BUILD.gn index b221c15..af99e71 100644 --- a/third_party/blink/renderer/modules/cache_storage/BUILD.gn +++ b/third_party/blink/renderer/modules/cache_storage/BUILD.gn
@@ -10,10 +10,14 @@ "cache.h", "cache_storage.cc", "cache_storage.h", + "cache_storage_blob_client_list.cc", + "cache_storage_blob_client_list.h", "cache_storage_error.cc", "cache_storage_error.h", "cache_storage_trace_utils.cc", "cache_storage_trace_utils.h", + "cache_utils.cc", + "cache_utils.h", "global_cache_storage.cc", "global_cache_storage.h", "inspector_cache_storage_agent.cc",
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc index 2970003..43aa9b35 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache.cc +++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -30,8 +30,10 @@ #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage.h" +#include "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage_trace_utils.h" +#include "third_party/blink/renderer/modules/cache_storage/cache_utils.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" @@ -41,6 +43,7 @@ #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h" #include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h" +#include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h" #include "third_party/blink/renderer/platform/network/http_names.h" #include "third_party/blink/renderer/platform/network/http_parsers.h" #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h" @@ -316,8 +319,8 @@ continue; } uint64_t side_data_blob_size = - operation->response->side_data_blob - ? operation->response->side_data_blob->size() + operation->response->side_data_blob_for_cache_put + ? operation->response->side_data_blob_for_cache_put->size() : 0; global_scope->CountCacheStorageInstalledScript(blob_data_handle->size(), side_data_blob_size); @@ -430,8 +433,9 @@ side_data_blob_data->AppendBytes(serialized_data.data(), serialized_data.size()); - batch_operation->response->side_data_blob = BlobDataHandle::Create( - std::move(side_data_blob_data), serialized_data.size()); + batch_operation->response->side_data_blob_for_cache_put = + BlobDataHandle::Create(std::move(side_data_blob_data), + serialized_data.size()); } barrier_callback_->OnSuccess(index_, std::move(batch_operation)); @@ -621,12 +625,14 @@ mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> cache_pending_remote, scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : scoped_fetcher_(fetcher) { + : scoped_fetcher_(fetcher), + blob_client_list_(MakeGarbageCollected<CacheStorageBlobClientList>()) { cache_remote_.Bind(std::move(cache_pending_remote), std::move(task_runner)); } void Cache::Trace(blink::Visitor* visitor) { visitor->Trace(scoped_fetcher_); + visitor->Trace(blob_client_list_); ScriptWrappable::Trace(visitor); } @@ -651,14 +657,20 @@ return promise; } + bool in_related_fetch_event = false; + ExecutionContext* context = ExecutionContext::From(script_state); + if (auto* global_scope = DynamicTo<ServiceWorkerGlobalScope>(context)) + in_related_fetch_event = global_scope->HasRelatedFetchEvent(request->url()); + // Make sure to bind the Cache object to keep the mojo remote alive during // the operation. Otherwise GC might prevent the callback from ever being // executed. cache_remote_->Match( - std::move(mojo_request), std::move(mojo_options), trace_id, + std::move(mojo_request), std::move(mojo_options), in_related_fetch_event, + trace_id, WTF::Bind( [](ScriptPromiseResolver* resolver, base::TimeTicks start_time, - const CacheQueryOptions* options, int64_t trace_id, Cache* _, + const CacheQueryOptions* options, int64_t trace_id, Cache* self, mojom::blink::MatchResultPtr result) { base::TimeDelta elapsed = base::TimeTicks::Now() - start_time; UMA_HISTOGRAM_LONG_TIMES("ServiceWorkerCache.Cache.Renderer.Match", @@ -695,8 +707,15 @@ UMA_HISTOGRAM_LONG_TIMES( "ServiceWorkerCache.Cache.Renderer.Match.Hit", elapsed); ScriptState::Scope scope(resolver->GetScriptState()); - resolver->Resolve(Response::Create(resolver->GetScriptState(), - *result->get_response())); + if (result->is_eager_response()) { + resolver->Resolve( + CreateEagerResponse(resolver->GetScriptState(), + std::move(result->get_eager_response()), + self->blob_client_list_)); + } else { + resolver->Resolve(Response::Create(resolver->GetScriptState(), + *result->get_response())); + } } }, WrapPersistent(resolver), base::TimeTicks::Now(),
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.h b/third_party/blink/renderer/modules/cache_storage/cache.h index 1b291d3..b386ecd 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache.h +++ b/third_party/blink/renderer/modules/cache_storage/cache.h
@@ -40,6 +40,7 @@ namespace blink { +class CacheStorageBlobClientList; class ExceptionState; class Response; class Request; @@ -116,6 +117,7 @@ const CacheQueryOptions*); Member<GlobalFetch::ScopedFetcher> scoped_fetcher_; + Member<CacheStorageBlobClientList> blob_client_list_; mojo::AssociatedRemote<mojom::blink::CacheStorageCache> cache_remote_;
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc index c86254e..05536ddb 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc +++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -20,8 +20,10 @@ #include "third_party/blink/renderer/core/fetch/response.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage_trace_utils.h" +#include "third_party/blink/renderer/modules/cache_storage/cache_utils.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/heap.h" @@ -351,6 +353,12 @@ request->CreateFetchAPIRequest(); mojom::blink::MultiCacheQueryOptionsPtr mojo_options = mojom::blink::MultiCacheQueryOptions::From(options); + + ExecutionContext* context = ExecutionContext::From(script_state); + bool in_related_fetch_event = false; + if (auto* global_scope = DynamicTo<ServiceWorkerGlobalScope>(context)) + in_related_fetch_event = global_scope->HasRelatedFetchEvent(request->url()); + TRACE_EVENT_WITH_FLOW2("CacheStorage", "CacheStorage::MatchImpl", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT, "request", CacheStorageTracedValue(mojo_request), @@ -384,11 +392,12 @@ // pointer alive during the operation. Otherwise GC might prevent the // callback from ever being executed. cache_storage_remote_->Match( - std::move(mojo_request), std::move(mojo_options), trace_id, + std::move(mojo_request), std::move(mojo_options), in_related_fetch_event, + trace_id, WTF::Bind( [](ScriptPromiseResolver* resolver, base::TimeTicks start_time, const MultiCacheQueryOptions* options, int64_t trace_id, - mojom::blink::MatchResultPtr result) { + CacheStorage* self, mojom::blink::MatchResultPtr result) { base::TimeDelta elapsed = base::TimeTicks::Now() - start_time; if (!options->hasCacheName() || options->cacheName().IsEmpty()) { UMA_HISTOGRAM_LONG_TIMES( @@ -424,12 +433,19 @@ TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN, "response", CacheStorageTracedValue(result->get_response())); ScriptState::Scope scope(resolver->GetScriptState()); - resolver->Resolve(Response::Create(resolver->GetScriptState(), - *result->get_response())); + if (result->is_eager_response()) { + resolver->Resolve( + CreateEagerResponse(resolver->GetScriptState(), + std::move(result->get_eager_response()), + self->blob_client_list_)); + } else { + resolver->Resolve(Response::Create(resolver->GetScriptState(), + *result->get_response())); + } } }, WrapPersistent(resolver), base::TimeTicks::Now(), - WrapPersistent(options), trace_id)); + WrapPersistent(options), trace_id, WrapPersistent(this))); return promise; } @@ -438,6 +454,7 @@ GlobalFetch::ScopedFetcher* fetcher) : ContextLifecycleObserver(context), scoped_fetcher_(fetcher), + blob_client_list_(MakeGarbageCollected<CacheStorageBlobClientList>()), ever_used_(false) { // See https://bit.ly/2S0zRAS for task types. scoped_refptr<base::SingleThreadTaskRunner> task_runner = @@ -474,6 +491,7 @@ void CacheStorage::Trace(blink::Visitor* visitor) { visitor->Trace(scoped_fetcher_); + visitor->Trace(blob_client_list_); ScriptWrappable::Trace(visitor); ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.h b/third_party/blink/renderer/modules/cache_storage/cache_storage.h index f09b31e0..b545f836 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache_storage.h +++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.h
@@ -23,6 +23,8 @@ namespace blink { +class CacheStorageBlobClientList; + class CacheStorage final : public ScriptWrappable, public ActiveScriptWrappable<CacheStorage>, public ContextLifecycleObserver { @@ -54,6 +56,7 @@ bool IsAllowed(ScriptState*); Member<GlobalFetch::ScopedFetcher> scoped_fetcher_; + Member<CacheStorageBlobClientList> blob_client_list_; mojo::Remote<mojom::blink::CacheStorage> cache_storage_remote_; base::Optional<bool> allowed_;
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc new file mode 100644 index 0000000..b46756aa --- /dev/null +++ b/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc
@@ -0,0 +1,87 @@ +// 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 "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h" + +namespace blink { + +// Class implementing the BlobReaderClient interface. This is used to +// propagate the completion of an eager body blob read to the +// DataPipeBytesConsumer. +class CacheStorageBlobClientList::Client + : public GarbageCollected<CacheStorageBlobClientList::Client>, + public mojom::blink::BlobReaderClient { + // We must prevent any mojo messages from coming in after this object + // starts getting garbage collected. + USING_PRE_FINALIZER(CacheStorageBlobClientList::Client, Dispose); + + public: + Client(CacheStorageBlobClientList* owner, + mojo::PendingReceiver<mojom::blink::BlobReaderClient> + client_pending_receiver, + DataPipeBytesConsumer::CompletionNotifier* completion_notifier) + : owner_(owner), + client_receiver_(this, std::move(client_pending_receiver)), + completion_notifier_(completion_notifier) {} + + void OnCalculatedSize(uint64_t total_size, + uint64_t expected_content_size) override {} + + void OnComplete(int32_t status, uint64_t data_length) override { + client_receiver_.reset(); + + // 0 is net::OK + if (status == 0) + completion_notifier_->SignalComplete(); + else + completion_notifier_->SignalError(BytesConsumer::Error()); + + if (owner_) + owner_->RevokeClient(this); + } + + void Trace(blink::Visitor* visitor) { + visitor->Trace(owner_); + visitor->Trace(completion_notifier_); + } + + private: + void Dispose() { + // Use the existence of the client_receiver_ binding to see if this + // client has already completed. + if (!client_receiver_.is_bound()) + return; + + client_receiver_.reset(); + completion_notifier_->SignalError(BytesConsumer::Error("aborted")); + + // If we are already being garbage collected its not necessary to + // call RevokeClient() on the owner. + } + + WeakMember<CacheStorageBlobClientList> owner_; + mojo::Receiver<mojom::blink::BlobReaderClient> client_receiver_; + Member<DataPipeBytesConsumer::CompletionNotifier> completion_notifier_; + + DISALLOW_COPY_AND_ASSIGN(Client); +}; + +void CacheStorageBlobClientList::AddClient( + mojo::PendingReceiver<mojom::blink::BlobReaderClient> + client_pending_receiver, + DataPipeBytesConsumer::CompletionNotifier* completion_notifier) { + clients.emplace_back(MakeGarbageCollected<Client>( + this, std::move(client_pending_receiver), completion_notifier)); +} + +void CacheStorageBlobClientList::Trace(blink::Visitor* visitor) { + visitor->Trace(clients); +} + +void CacheStorageBlobClientList::RevokeClient(Client* client) { + auto index = clients.Find(client); + clients.EraseAt(index); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h b/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h new file mode 100644 index 0000000..23b0452 --- /dev/null +++ b/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h
@@ -0,0 +1,39 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_STORAGE_BLOB_CLIENT_LIST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_STORAGE_BLOB_CLIENT_LIST_H_ + +#include "mojo/public/cpp/bindings/receiver.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h" + +namespace blink { + +// This class holds a list of BlobReaderClient implementations alive until +// they complete or the entire list is garbage collected. +class CacheStorageBlobClientList + : public GarbageCollected<CacheStorageBlobClientList> { + public: + CacheStorageBlobClientList() = default; + void AddClient( + mojo::PendingReceiver<mojom::blink::BlobReaderClient> + client_pending_receiver, + DataPipeBytesConsumer::CompletionNotifier* completion_notifier); + + void Trace(blink::Visitor* visitor); + + private: + class Client; + + void RevokeClient(Client* client); + + HeapVector<Member<Client>> clients; + DISALLOW_COPY_AND_ASSIGN(CacheStorageBlobClientList); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_STORAGE_BLOB_CLIENT_LIST_H_
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_test.cc b/third_party/blink/renderer/modules/cache_storage/cache_test.cc index 016dbac..707c7592 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache_test.cc +++ b/third_party/blink/renderer/modules/cache_storage/cache_test.cc
@@ -141,6 +141,7 @@ void Match(mojom::blink::FetchAPIRequestPtr fetch_api_request, mojom::blink::CacheQueryOptionsPtr query_options, + bool in_related_fetch_event, int64_t trace_id, MatchCallback callback) override { last_error_web_cache_method_called_ = "dispatchMatch"; @@ -537,6 +538,7 @@ // From WebServiceWorkerCache: void Match(mojom::blink::FetchAPIRequestPtr fetch_api_request, mojom::blink::CacheQueryOptionsPtr query_options, + bool in_related_fetch_event, int64_t trace_id, MatchCallback callback) override { mojom::blink::MatchResultPtr result = mojom::blink::MatchResult::New();
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_utils.cc b/third_party/blink/renderer/modules/cache_storage/cache_utils.cc new file mode 100644 index 0000000..f702022 --- /dev/null +++ b/third_party/blink/renderer/modules/cache_storage/cache_utils.cc
@@ -0,0 +1,47 @@ +// 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 "third_party/blink/renderer/modules/cache_storage/cache_utils.h" + +#include "third_party/blink/renderer/core/fetch/fetch_response_data.h" +#include "third_party/blink/renderer/core/fetch/response.h" +#include "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h" +#include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h" + +namespace blink { + +Response* CreateEagerResponse(ScriptState* script_state, + mojom::blink::EagerResponsePtr eager_response, + CacheStorageBlobClientList* client_list) { + auto& response = eager_response->response; + DCHECK(!response->blob); + + ExecutionContext* context = ExecutionContext::From(script_state); + + FetchResponseData* fetch_data = + Response::CreateUnfilteredFetchResponseDataWithoutBody(script_state, + *response); + + DataPipeBytesConsumer::CompletionNotifier* completion_notifier = nullptr; + fetch_data->ReplaceBodyStreamBuffer(MakeGarbageCollected<BodyStreamBuffer>( + script_state, + MakeGarbageCollected<DataPipeBytesConsumer>( + context->GetTaskRunner(TaskType::kNetworking), + std::move(eager_response->pipe), &completion_notifier), + nullptr /* AbortSignal */)); + + // Create a BlobReaderClient in the provided list. This will track the + // completion of the eagerly read blob and propagate it to the given + // DataPipeBytesConsumer::CompletionNotifier. The list will also hold + // the client alive. + client_list->AddClient(std::move(eager_response->client_receiver), + std::move(completion_notifier)); + + fetch_data = Response::FilterResponseData( + response->response_type, fetch_data, response->cors_exposed_header_names); + + return Response::Create(context, fetch_data); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_utils.h b/third_party/blink/renderer/modules/cache_storage/cache_utils.h new file mode 100644 index 0000000..2c80bed --- /dev/null +++ b/third_party/blink/renderer/modules/cache_storage/cache_utils.h
@@ -0,0 +1,26 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_UTILS_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_UTILS_H_ + +#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h" + +namespace blink { + +class CacheStorageBlobClientList; +class Response; +class ScriptState; + +// A utility function to deserialize an eagerly read cache_storage response +// into a web-exposed fetch Response object. The resulting Response will +// have a DataPipeBytesConsumer body and a side_data_blob which can be used +// to read any code cache. +Response* CreateEagerResponse(ScriptState* script_state, + mojom::blink::EagerResponsePtr eager_response, + CacheStorageBlobClientList* client_list); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CACHE_STORAGE_CACHE_UTILS_H_
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc index cc82723..ccc8cee 100644 --- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc +++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -266,7 +266,8 @@ request->fetch_window_id, request->keepalive, request->is_reload, request->is_history_navigation); cache_remote_->Match( - std::move(request), mojom::blink::CacheQueryOptions::New(), trace_id, + std::move(request), mojom::blink::CacheQueryOptions::New(), + false /* in_related_fetch_event */, trace_id, WTF::Bind( [](scoped_refptr<ResponsesAccumulator> accumulator, mojom::blink::FetchAPIRequestPtr request, @@ -718,7 +719,8 @@ multi_query_options->cache_name = cache_name; cache_storage->Match( - std::move(request), std::move(multi_query_options), trace_id, + std::move(request), std::move(multi_query_options), + false /* in_related_fetch_event */, trace_id, WTF::Bind( [](std::unique_ptr<RequestCachedResponseCallback> callback, mojom::blink::MatchResultPtr result) {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_key_range.idl b/third_party/blink/renderer/modules/indexeddb/idb_key_range.idl index 49dbff0..d922a27 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_key_range.idl +++ b/third_party/blink/renderer/modules/indexeddb/idb_key_range.idl
@@ -41,5 +41,5 @@ optional boolean lowerOpen = false, optional boolean upperOpen = false); - [CallWith=ScriptState, RaisesException] boolean _includes(any key); + [CallWith=ScriptState, RaisesException] boolean includes(any key); };
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 5d0860f..2fb3d77c 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -1014,8 +1014,6 @@ "webdatabase/window_web_database.idl", "webgl/webgl2_rendering_context_base.idl", "webgl/webgl_rendering_context_base.idl", - "webgpu/gpu_programmable_pass_encoder.idl", - "webgpu/gpu_render_encoder_base.idl", "webgpu/navigator_gpu.idl", "webmidi/navigator_web_midi.idl", "webshare/navigator_share.idl",
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc index ca0dd6e..7de6a92c 100644 --- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -216,7 +216,7 @@ response->status_text = ""; response->error = error; To<ServiceWorkerGlobalScope>(GetExecutionContext()) - ->RespondToFetchEvent(event_id_, std::move(response), + ->RespondToFetchEvent(event_id_, request_url_, std::move(response), event_dispatch_time_, base::TimeTicks::Now()); } @@ -323,8 +323,8 @@ // Handle the blob response body. fetch_api_response->blob = blob_data_handle; service_worker_global_scope->RespondToFetchEvent( - event_id_, std::move(fetch_api_response), event_dispatch_time_, - base::TimeTicks::Now()); + event_id_, request_url_, std::move(fetch_api_response), + event_dispatch_time_, base::TimeTicks::Now()); return; } @@ -349,19 +349,20 @@ } service_worker_global_scope->RespondToFetchEventWithResponseStream( - event_id_, std::move(fetch_api_response), std::move(stream_handle), - event_dispatch_time_, base::TimeTicks::Now()); + event_id_, request_url_, std::move(fetch_api_response), + std::move(stream_handle), event_dispatch_time_, base::TimeTicks::Now()); return; } service_worker_global_scope->RespondToFetchEvent( - event_id_, std::move(fetch_api_response), event_dispatch_time_, - base::TimeTicks::Now()); + event_id_, request_url_, std::move(fetch_api_response), + event_dispatch_time_, base::TimeTicks::Now()); } void FetchRespondWithObserver::OnNoResponse() { DCHECK(GetExecutionContext()); To<ServiceWorkerGlobalScope>(GetExecutionContext()) - ->RespondToFetchEventWithNoResponse(event_id_, event_dispatch_time_, + ->RespondToFetchEventWithNoResponse(event_id_, request_url_, + event_dispatch_time_, base::TimeTicks::Now()); }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index c50950453..a5da035 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -762,6 +762,12 @@ WorkerGlobalScope::Trace(visitor); } +bool ServiceWorkerGlobalScope::HasRelatedFetchEvent( + const KURL& request_url) const { + auto it = unresponded_fetch_event_counts_.find(request_url); + return it != unresponded_fetch_event_counts_.end(); +} + void ServiceWorkerGlobalScope::importScripts( const HeapVector<StringOrTrustedScriptURL>& urls, ExceptionState& exception_state) { @@ -932,6 +938,7 @@ void ServiceWorkerGlobalScope::RespondToFetchEventWithNoResponse( int fetch_event_id, + const KURL& request_url, base::TimeTicks event_dispatch_time, base::TimeTicks respond_with_settled_time) { DCHECK(IsContextThread()); @@ -949,11 +956,14 @@ timing->dispatch_event_time = event_dispatch_time; timing->respond_with_settled_time = respond_with_settled_time; + NoteRespondedToFetchEvent(request_url); + response_callback->OnFallback(std::move(timing)); } void ServiceWorkerGlobalScope::RespondToFetchEvent( int fetch_event_id, + const KURL& request_url, mojom::blink::FetchAPIResponsePtr response, base::TimeTicks event_dispatch_time, base::TimeTicks respond_with_settled_time) { @@ -972,11 +982,14 @@ timing->dispatch_event_time = event_dispatch_time; timing->respond_with_settled_time = respond_with_settled_time; + NoteRespondedToFetchEvent(request_url); + response_callback->OnResponse(std::move(response), std::move(timing)); } void ServiceWorkerGlobalScope::RespondToFetchEventWithResponseStream( int fetch_event_id, + const KURL& request_url, mojom::blink::FetchAPIResponsePtr response, mojom::blink::ServiceWorkerStreamHandlePtr body_as_stream, base::TimeTicks event_dispatch_time, @@ -996,6 +1009,8 @@ timing->dispatch_event_time = event_dispatch_time; timing->respond_with_settled_time = respond_with_settled_time; + NoteRespondedToFetchEvent(request_url); + response_callback->OnResponseStream( std::move(response), std::move(body_as_stream), std::move(timing)); } @@ -1391,6 +1406,8 @@ pending_preload_fetch_events_.insert(event_id, fetch_event); } + NoteNewFetchEvent(request->url()); + DispatchExtendableEventWithRespondWith(fetch_event, wait_until_observer, respond_with_observer); } @@ -2014,4 +2031,22 @@ /* column_number= */ 0))); } +void ServiceWorkerGlobalScope::NoteNewFetchEvent(const KURL& request_url) { + auto it = unresponded_fetch_event_counts_.find(request_url); + if (it == unresponded_fetch_event_counts_.end()) { + unresponded_fetch_event_counts_.insert(request_url, 1); + } else { + it->value += 1; + } +} + +void ServiceWorkerGlobalScope::NoteRespondedToFetchEvent( + const KURL& request_url) { + auto it = unresponded_fetch_event_counts_.find(request_url); + DCHECK_GE(it->value, 1); + it->value -= 1; + if (it->value == 0) + unresponded_fetch_event_counts_.erase(it); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h index e17118c..d337037 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -49,6 +49,7 @@ #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" namespace blink { @@ -214,10 +215,12 @@ // native fetch. void RespondToFetchEventWithNoResponse( int fetch_event_id, + const KURL& request_url, base::TimeTicks event_dispatch_time, base::TimeTicks respond_with_settled_time); // Responds to the fetch event with |response|. void RespondToFetchEvent(int fetch_event_id, + const KURL& request_url, mojom::blink::FetchAPIResponsePtr, base::TimeTicks event_dispatch_time, base::TimeTicks respond_with_settled_time); @@ -225,6 +228,7 @@ // |body_as_stream|. void RespondToFetchEventWithResponseStream( int fetch_event_id, + const KURL& request_url, mojom::blink::FetchAPIResponsePtr, mojom::blink::ServiceWorkerStreamHandlePtr, base::TimeTicks event_dispatch_time, @@ -283,6 +287,10 @@ void Trace(blink::Visitor*) override; + // Returns true if a FetchEvent exists with the given request URL and + // is still waiting for a Response. + bool HasRelatedFetchEvent(const KURL& request_url) const; + protected: // EventTarget bool AddEventListenerInternal( @@ -450,6 +458,9 @@ void AddMessageToConsole(mojom::blink::ConsoleMessageLevel, const String& message) override; + void NoteNewFetchEvent(const KURL& request_url); + void NoteRespondedToFetchEvent(const KURL& request_url); + Member<ServiceWorkerClients> clients_; Member<ServiceWorkerRegistration> registration_; Member<::blink::ServiceWorker> service_worker_; @@ -537,6 +548,13 @@ HeapHashMap<int, Member<FetchEvent>> pending_preload_fetch_events_; + // Track outstanding FetchEvent objects still waiting for a response by + // request URL. This information can be used as a hint that cache_storage + // or fetch requests to the same URL is likely to be used to satisfy a + // FetchEvent. This in turn can allow us to use more aggressive + // optimizations in these cases. + HashMap<KURL, int> unresponded_fetch_event_counts_; + // Timer triggered when the service worker considers it should be stopped or // an event should be aborted. std::unique_ptr<ServiceWorkerTimeoutTimer> timeout_timer_;
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_controller.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_controller.cc index 6c87877..d760cfe 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_controller.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_controller.cc
@@ -109,7 +109,9 @@ // abort early. if (type == WakeLockType::kScreen && !(GetPage() && GetPage()->IsPageVisible())) { - ReleaseWakeLock(type, resolver); + resolver->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kNotAllowedError, + "The requesting page is not visible")); return; } // 6.2. Let success be the result of awaiting acquire a wake lock with promise
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl index dd75cea..fc1b92f 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
@@ -7,7 +7,16 @@ [ RuntimeEnabled=WebGPU ] interface GPUComputePassEncoder { + // GPUProgrammablePassEncoder methods + void setBindGroup(unsigned long index, + GPUBindGroup bindGroup, + optional sequence<GPUBufferSize> dynamicOffsets = []); + void pushDebugGroup(DOMString groupLabel); + void popDebugGroup(); + void insertDebugMarker(DOMString markerLabel); + void setPipeline(GPUComputePipeline pipeline); + void dispatch(unsigned long x, optional unsigned long y = 1, optional unsigned long z = 1); @@ -16,4 +25,3 @@ void endPass(); }; -GPUComputePassEncoder includes GPUProgrammablePassEncoder;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl deleted file mode 100644 index 4d57cef..0000000 --- a/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// https://gpuweb.github.io/gpuweb/ - -[ - RuntimeEnabled=WebGPU -] interface mixin GPUProgrammablePassEncoder { - void setBindGroup(unsigned long index, GPUBindGroup bindGroup, - optional sequence<GPUBufferSize> dynamicOffsets = []); - - void pushDebugGroup(DOMString groupLabel); - void popDebugGroup(); - void insertDebugMarker(DOMString markerLabel); -};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl index 43b226a..23f97cd 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
@@ -7,6 +7,32 @@ [ RuntimeEnabled=WebGPU ] interface GPURenderBundleEncoder { + // GPUProgrammablePassEncoder methods + void setBindGroup(unsigned long index, + GPUBindGroup bindGroup, + optional sequence<GPUBufferSize> dynamicOffsets = []); + void pushDebugGroup(DOMString groupLabel); + void popDebugGroup(); + void insertDebugMarker(DOMString markerLabel); + + // GPURenderEncoderBase methods + void setPipeline(GPURenderPipeline pipeline); + void setIndexBuffer(GPUBuffer buffer, optional GPUBufferSize offset = 0); + void setVertexBuffer(unsigned long slot, + GPUBuffer buffer, + optional GPUBufferSize offset = 0); + void draw(unsigned long vertexCount, unsigned long instanceCount, + unsigned long firstVertex, + unsigned long firstInstance); + void drawIndexed(unsigned long indexCount, unsigned long instanceCount, + unsigned long firstIndex, + long baseVertex, + unsigned long firstInstance); + void drawIndirect(GPUBuffer indirectBuffer, + GPUBufferSize indirectOffset); + void drawIndexedIndirect(GPUBuffer indirectBuffer, + GPUBufferSize indirectOffset); + + // GPURenderBundleEncoder methods GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); }; -GPURenderBundleEncoder includes GPURenderEncoderBase;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl index 7061c18c..e61fe3c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
@@ -7,17 +7,39 @@ [ RuntimeEnabled=WebGPU ] interface GPURenderPassEncoder { - void setViewport(float x, float y, - float width, float height, - float minDepth, float maxDepth); + // GPUProgrammablePassEncoder methods + void setBindGroup(unsigned long index, + GPUBindGroup bindGroup, + optional sequence<GPUBufferSize> dynamicOffsets = []); + void pushDebugGroup(DOMString groupLabel); + void popDebugGroup(); + void insertDebugMarker(DOMString markerLabel); - void setScissorRect(unsigned long x, unsigned long y, - unsigned long width, unsigned long height); + void setPipeline(GPURenderPipeline pipeline); [RaisesException] void setBlendColor(GPUColor color); void setStencilReference(unsigned long reference); + void setViewport(float x, float y, + float width, float height, + float minDepth, float maxDepth); + void setScissorRect(unsigned long x, unsigned long y, + unsigned long width, unsigned long height); + void setIndexBuffer(GPUBuffer buffer, optional GPUBufferSize offset = 0); + void setVertexBuffer(unsigned long slot, + GPUBuffer buffer, + optional GPUBufferSize offset = 0); + void draw(unsigned long vertexCount, unsigned long instanceCount, + unsigned long firstVertex, + unsigned long firstInstance); + void drawIndexed(unsigned long indexCount, unsigned long instanceCount, + unsigned long firstIndex, + long baseVertex, + unsigned long firstInstance); + void drawIndirect(GPUBuffer indirectBuffer, + GPUBufferSize indirectOffset); + void drawIndexedIndirect(GPUBuffer indirectBuffer, + GPUBufferSize indirectOffset); void executeBundles(sequence<GPURenderBundle> bundles); void endPass(); }; -GPURenderPassEncoder includes GPURenderEncoderBase;
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index 4b69014c..d904b4b 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -939,6 +939,9 @@ TaskType::kMiscPlatformAPI))); environment_provider_.set_connection_error_handler(WTF::Bind( &XR::OnEnvironmentProviderDisconnect, WrapWeakPersistent(this))); + + session->OnEnvironmentProviderCreated(); + LocalFrame* frame = GetFrame(); DCHECK(frame);
diff --git a/third_party/blink/renderer/modules/xr/xr_hit_test_options.cc b/third_party/blink/renderer/modules/xr/xr_hit_test_options.cc index 907b407..73d366ff 100644 --- a/third_party/blink/renderer/modules/xr/xr_hit_test_options.cc +++ b/third_party/blink/renderer/modules/xr/xr_hit_test_options.cc
@@ -12,7 +12,6 @@ XRHitTestOptions::XRHitTestOptions(XRHitTestOptionsInit* options_init) { DCHECK(options_init); - DCHECK(options_init->hasSpace()); // Is it enforced by generated bindings? space_ = options_init->space();
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl index d1869d2..78ee80c 100644 --- a/third_party/blink/renderer/modules/xr/xr_input_source.idl +++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -23,6 +23,6 @@ readonly attribute XRTargetRayMode targetRayMode; [SameObject] readonly attribute XRSpace targetRaySpace; [SameObject] readonly attribute XRSpace? gripSpace; - [SameObject, Measure] readonly attribute Gamepad? gamepad; + [SameObject, Measure, RuntimeEnabled=WebXrGamepadModule] readonly attribute Gamepad? gamepad; [SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> profiles; };
diff --git a/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc b/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc index 775a4c6..f25edd1 100644 --- a/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc +++ b/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc
@@ -34,11 +34,54 @@ base::Optional<XRNativeOriginInformation> XRNativeOriginInformation::Create( const XRReferenceSpace* reference_space) { DCHECK(reference_space); - // TODO(https://crbug.com/997369): Implement once mojo changes land. - return base::nullopt; + switch (reference_space->GetType()) { + case XRReferenceSpace::Type::kTypeBoundedFloor: + return XRNativeOriginInformation( + Type::ReferenceSpace, + device::mojom::XRReferenceSpaceCategory::BOUNDED_FLOOR); + case XRReferenceSpace::Type::kTypeUnbounded: + return XRNativeOriginInformation( + Type::ReferenceSpace, + device::mojom::XRReferenceSpaceCategory::UNBOUNDED); + case XRReferenceSpace::Type::kTypeLocalFloor: + return XRNativeOriginInformation( + Type::ReferenceSpace, + device::mojom::XRReferenceSpaceCategory::LOCAL_FLOOR); + case XRReferenceSpace::Type::kTypeLocal: + return XRNativeOriginInformation( + Type::ReferenceSpace, device::mojom::XRReferenceSpaceCategory::LOCAL); + case XRReferenceSpace::Type::kTypeViewer: + return XRNativeOriginInformation( + Type::ReferenceSpace, + device::mojom::XRReferenceSpaceCategory::VIEWER); + } } XRNativeOriginInformation::XRNativeOriginInformation(Type type, uint32_t id) - : id_(id) {} + : type_(type), id_(id) {} + +XRNativeOriginInformation::XRNativeOriginInformation( + Type type, + device::mojom::XRReferenceSpaceCategory reference_space_category) + : type_(type), reference_space_category_(reference_space_category) {} + +device::mojom::blink::XRNativeOriginInformationPtr +XRNativeOriginInformation::ToMojo() const { + switch (type_) { + case XRNativeOriginInformation::Type::Anchor: + return device::mojom::blink::XRNativeOriginInformation::NewAnchorId(id_); + + case XRNativeOriginInformation::Type::InputSource: + return device::mojom::blink::XRNativeOriginInformation::NewInputSourceId( + id_); + + case XRNativeOriginInformation::Type::Plane: + return device::mojom::blink::XRNativeOriginInformation::NewPlaneId(id_); + + case XRNativeOriginInformation::Type::ReferenceSpace: + return device::mojom::blink::XRNativeOriginInformation:: + NewReferenceSpaceCategory(reference_space_category_); + } +} } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_native_origin_information.h b/third_party/blink/renderer/modules/xr/xr_native_origin_information.h index 899556e..e517126 100644 --- a/third_party/blink/renderer/modules/xr/xr_native_origin_information.h +++ b/third_party/blink/renderer/modules/xr/xr_native_origin_information.h
@@ -16,10 +16,16 @@ class XRPlane; class XRReferenceSpace; +// XRNativeOriginInformation carries all the information that is required to +// uniquely identify a native origin on the device side. Native origin roughly +// represents anything that is known and tracked by the device, for example +// anchors, planes, input sources, reference spaces. class XRNativeOriginInformation { public: XRNativeOriginInformation(XRNativeOriginInformation&& other) = default; + device::mojom::blink::XRNativeOriginInformationPtr ToMojo() const; + static base::Optional<XRNativeOriginInformation> Create( const XRAnchor* anchor); static base::Optional<XRNativeOriginInformation> Create( @@ -36,10 +42,16 @@ void operator=(const XRNativeOriginInformation& other) = delete; XRNativeOriginInformation(Type type, uint32_t id); + XRNativeOriginInformation( + Type type, + device::mojom::XRReferenceSpaceCategory reference_space_type); - // TODO(https://crbug.com/997369): Add reference space category to the union - // once mojo changes land. - const union { uint32_t id_; }; + const Type type_; + + const union { + uint32_t id_; + device::mojom::XRReferenceSpaceCategory reference_space_category_; + }; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index bdcad2b..ffa613f 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -476,7 +476,6 @@ << ", pose_ptr->position = [" << pose_ptr->position->x << ", " << pose_ptr->position->y << ", " << pose_ptr->position->z << "]"; - EnsureEnvironmentErrorHandler(); if (plane) { xr_->xrEnvironmentProviderPtr()->CreatePlaneAnchor( std::move(pose_ptr), plane->id(), @@ -563,7 +562,6 @@ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); - EnsureEnvironmentErrorHandler(); xr_->xrEnvironmentProviderPtr()->RequestHitTest( std::move(ray_mojo), WTF::Bind(&XRSession::OnHitTestResults, WrapPersistent(this), @@ -625,11 +623,16 @@ auto direction = origin_from_ray.MapPoint({0, 0, -1}); ray_mojo->direction = {direction.X(), direction.Y(), direction.Z()}; - // TODO(https://crbug.com/997369): Actually issue a call to the device once - // mojo interfaces land. - exception_state.ThrowDOMException(DOMExceptionCode::kOperationError, - kHitTestSubscriptionFailed); - return {}; + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + ScriptPromise promise = resolver->Promise(); + + xr_->xrEnvironmentProviderPtr()->SubscribeToHitTest( + maybe_native_origin->ToMojo(), std::move(ray_mojo), + WTF::Bind(&XRSession::OnSubscribeToHitTestResult, WrapPersistent(this), + WrapPersistent(resolver), WrapPersistent(options))); + request_hit_test_source_promises_.insert(resolver); + + return promise; } void XRSession::OnHitTestResults( @@ -652,6 +655,32 @@ resolver->Resolve(hit_results); } +void XRSession::OnSubscribeToHitTestResult( + ScriptPromiseResolver* resolver, + XRHitTestOptions* options, + device::mojom::SubscribeToHitTestResult result, + uint32_t subscription_id) { + DVLOG(2) << __func__ << ": result=" << result + << ", subscription_id=" << subscription_id; + + DCHECK(request_hit_test_source_promises_.Contains(resolver)); + request_hit_test_source_promises_.erase(resolver); + + if (result != device::mojom::SubscribeToHitTestResult::SUCCESS) { + resolver->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kOperationError, kHitTestSubscriptionFailed)); + return; + } + + XRHitTestSource* hit_test_source = + MakeGarbageCollected<XRHitTestSource>(subscription_id, options); + + hit_test_source_ids_to_hit_test_sources_.insert(subscription_id, + hit_test_source); + + resolver->Resolve(hit_test_source); +} + void XRSession::OnCreateAnchorResult(ScriptPromiseResolver* resolver, device::mojom::CreateAnchorResult result, uint32_t id) { @@ -665,6 +694,10 @@ resolver->Resolve(anchor); } +void XRSession::OnEnvironmentProviderCreated() { + EnsureEnvironmentErrorHandler(); +} + void XRSession::EnsureEnvironmentErrorHandler() { // Install error handler on environment provider to ensure that we get // notified so that we can clean up all relevant pending promises. @@ -758,6 +791,55 @@ anchor_ids_to_anchors_.swap(updated_anchors); } +void XRSession::CleanUpUnusedHitTestSources() { + // Gather all IDs of unused hit test sources. + HashSet<uint32_t> unused_hit_test_source_ids; + for (auto& subscription_id_and_hit_test_source : + hit_test_source_ids_to_hit_test_sources_) { + if (!subscription_id_and_hit_test_source.value) { + unused_hit_test_source_ids.insert( + subscription_id_and_hit_test_source.key); + } + } + + // Remove all of the unused hit test sources. + hit_test_source_ids_to_hit_test_sources_.RemoveAll( + unused_hit_test_source_ids); + + DVLOG(3) << __func__ << ": removed unused hit test sources, amount: " + << unused_hit_test_source_ids.size(); +} + +void XRSession::ProcessHitTestData( + const device::mojom::blink::XRHitTestSubscriptionResultsDataPtr& + hit_test_subscriptions_data) { + DVLOG(2) << __func__; + + CleanUpUnusedHitTestSources(); + + if (hit_test_subscriptions_data) { + // We have received hit test results for hit test subscriptions - process + // each result and notify its corresponding hit test source about new + // results for the current frame. + for (auto& hit_test_subscription_data : + hit_test_subscriptions_data->results) { + auto it = hit_test_source_ids_to_hit_test_sources_.find( + hit_test_subscription_data->subscription_id); + if (it != hit_test_source_ids_to_hit_test_sources_.end()) { + it->value->Update(hit_test_subscription_data->hit_test_results); + } + } + } else { + // We have not received hit test results for any of the hit test + // subscriptions in the current frame - clean up the results on all hit test + // source objects. + for (auto& subscription_id_and_hit_test_source : + hit_test_source_ids_to_hit_test_sources_) { + subscription_id_and_hit_test_source.value->Update({}); + } + } +} + ScriptPromise XRSession::end(ScriptState* script_state, ExceptionState& exception_state) { // Don't allow a session to end twice. @@ -1033,15 +1115,11 @@ world_information_->ProcessPlaneInformation( frame_data->detected_planes_data, timestamp); ProcessAnchorsData(frame_data->anchors_data, timestamp); - // TODO(https://crbug.com/997369): Implement processing hit test data once - // mojo change lands. - // ProcessHitTestData(frame_data->hit_test_subscription_results); + ProcessHitTestData(frame_data->hit_test_subscription_results); } else { world_information_->ProcessPlaneInformation(nullptr, timestamp); ProcessAnchorsData(nullptr, timestamp); - // TODO(https://crbug.com/997369): Implement processing hit test data once - // mojo change lands. - // ProcessHitTestData(nullptr); + ProcessHitTestData(nullptr); } }
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index f3af97c..2cab242 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -36,6 +36,7 @@ class XRAnchor; class XRAnchorSet; class XRCanvasInputProvider; +class XRHitTestOptions; class XRHitTestOptionsInit; class XRHitTestSource; class XRPlane; @@ -243,6 +244,12 @@ const device::mojom::blink::XRFrameDataPtr& frame_data, bool emulated_position); + // Notifies immersive session that the environment integration provider has + // been created by the session's XR instance, |xr_|. Gives a session an + // opportunity to register its own error handlers on environment integration + // provider endpoint. + void OnEnvironmentProviderCreated(); + private: class XRSessionResizeObserverDelegate; @@ -272,6 +279,12 @@ base::Optional<WTF::Vector<device::mojom::blink::XRHitResultPtr>> results); + void OnSubscribeToHitTestResult( + ScriptPromiseResolver* resolver, + XRHitTestOptions* options, + device::mojom::SubscribeToHitTestResult result, + uint32_t subscription_id); + void OnCreateAnchorResult(ScriptPromiseResolver* resolver, device::mojom::CreateAnchorResult result, uint32_t id); @@ -283,6 +296,12 @@ const device::mojom::blink::XRAnchorsDataPtr& tracked_anchors_data, double timestamp); + void CleanUpUnusedHitTestSources(); + + void ProcessHitTestData( + const device::mojom::blink::XRHitTestSubscriptionResultsDataPtr& + hit_test_data); + const Member<XR> xr_; const SessionMode mode_; const bool environment_integration_;
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc index b1d8403..c5dac37 100644 --- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc +++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -485,6 +485,10 @@ RuntimeEnabledFeatures::SetWebXRAnchorsEnabled(enable); } +void WebRuntimeFeatures::EnableWebXrGamepadModule(bool enable) { + RuntimeEnabledFeatures::SetWebXrGamepadModuleEnabled(enable); +} + void WebRuntimeFeatures::EnableWebXRHitTest(bool enable) { RuntimeEnabledFeatures::SetWebXRHitTestEnabled(enable); }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index f2f8bdd..c98d8f2 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -976,7 +976,7 @@ const cc::EffectNode& converted_effect1 = *effect_tree.Node(2); EXPECT_EQ(converted_root_effect.id, converted_effect1.parent_id); EXPECT_FLOAT_EQ(0.5, converted_effect1.opacity); - EXPECT_EQ(real_effect1->GetCompositorElementId().GetInternalValue(), + EXPECT_EQ(real_effect1->GetCompositorElementId().GetStableId(), converted_effect1.stable_id); const cc::EffectNode& converted_effect2 = *effect_tree.Node(3);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc index 94e6d59..757e737f 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -290,7 +290,7 @@ static UniqueObjectId unique_id = NewUniqueObjectId(); effect_node.stable_id = - CompositorElementIdFromUniqueObjectId(unique_id).GetInternalValue(); + CompositorElementIdFromUniqueObjectId(unique_id).GetStableId(); effect_node.transform_id = kRealRootNodeId; effect_node.clip_id = kSecondaryRootNodeId; effect_node.render_surface_reason = cc::RenderSurfaceReason::kRoot; @@ -598,14 +598,14 @@ DCHECK_EQ(static_cast<uint64_t>(cc::EffectNode::INVALID_STABLE_ID), mask_isolation.stable_id); - mask_isolation.stable_id = mask_isolation_id.GetInternalValue(); + mask_isolation.stable_id = mask_isolation_id.GetStableId(); if (!needs_layer) return; cc::EffectNode& mask_effect = *GetEffectTree().Node( GetEffectTree().Insert(cc::EffectNode(), current_.effect_id)); - mask_effect.stable_id = mask_effect_id.GetInternalValue(); + mask_effect.stable_id = mask_effect_id.GetStableId(); mask_effect.clip_id = clip_id; mask_effect.blend_mode = SkBlendMode::kDstIn; @@ -906,7 +906,7 @@ } else { synthetic_effect.stable_id = CompositorElementIdFromUniqueObjectId(NewUniqueObjectId()) - .GetInternalValue(); + .GetStableId(); // The clip of the synthetic effect is the parent of the clip, so that // the clip itself will be applied in the render surface. DCHECK(pending_clip.clip->Parent()); @@ -1048,7 +1048,7 @@ const EffectPaintPropertyNode& effect, int output_clip_id, SkBlendMode blend_mode) { - effect_node.stable_id = effect.GetCompositorElementId().GetInternalValue(); + effect_node.stable_id = effect.GetCompositorElementId().GetStableId(); effect_node.clip_id = output_clip_id; // An effect with filters or backdrop filters needs a render surface.
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc index 0ea298e9..86486ca 100644 --- a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc +++ b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
@@ -47,7 +47,7 @@ CompositorElementIdNamespace NamespaceFromCompositorElementId( CompositorElementId element_id) { return static_cast<CompositorElementIdNamespace>( - element_id.GetInternalValue() % + element_id.GetStableId() % static_cast<uint64_t>(CompositorElementIdNamespace::kMaxRepresentable)); }
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc b/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc index 225187d..7247c18 100644 --- a/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc
@@ -11,7 +11,7 @@ class CompositorElementIdTest : public testing::Test {}; uint64_t IdFromCompositorElementId(CompositorElementId element_id) { - return element_id.GetInternalValue() >> kCompositorNamespaceBitCount; + return element_id.GetStableId() >> kCompositorNamespaceBitCount; } TEST_F(CompositorElementIdTest, EncodeDecode) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index dc032029..05960cb 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -207,7 +207,7 @@ }, { name: "Badging", - origin_trial_feature_name: "Badging", + origin_trial_feature_name: "BadgingV2", status: "experimental", }, { @@ -1799,8 +1799,7 @@ }, { name: "WebXR", - origin_trial_feature_name: "WebXRDeviceM76", - status: "experimental", + status: "stable", }, { name: "WebXRAnchors", @@ -1813,6 +1812,11 @@ }, { name: "WebXRARModule", + depends_on: ["WebXR"], + status: "experimental", + }, + { + name: "WebXrGamepadModule", // depends_on: ["WebXR"], // TODO(https://crbug.com/954679): uncomment once bug is fixed status: "experimental", },
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations index afed031..b8844a5 100644 --- a/third_party/blink/web_tests/MSANExpectations +++ b/third_party/blink/web_tests/MSANExpectations
@@ -159,6 +159,7 @@ crbug.com/856601 [ Linux ] virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] crbug.com/856601 [ Linux ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] crbug.com/856601 [ Linux ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Pass Timeout ] +crbug.com/856601 [ Linux ] virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] crbug.com/856601 [ Linux ] virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Pass Failure Timeout ] crbug.com/856601 [ Linux ] external/wpt/fetch/api/idl.any.sharedworker.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/fetch/cors-rfc1918/idlharness.tentative.https.any.serviceworker.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index 164c804..2a320041 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -1925,6 +1925,9 @@ virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ] +virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ] +virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ] +virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-abort-manual.https.html [ WontFix ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-onerror-manual.https.html [ WontFix ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-onresult-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 6018a197..1836362 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1051,8 +1051,8 @@ crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-after-break.html [ Crash Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-with-margin-top-and-line-before-break.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-line-overflow.html [ Failure ] -crbug.com/829028 virtual/layout_ng_experimental/fast/multicol/balance-line-underflow-1.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-line-underflow-2.html [ Failure ] +crbug.com/994172 virtual/layout_ng_experimental/fast/multicol/balance-line-underflow-1.html [ Pass Crash ] +crbug.com/994172 virtual/layout_ng_experimental/fast/multicol/balance-line-underflow-2.html [ Pass Crash ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/basic-rtl.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/break-before-first-line-in-first-child.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/break-in-scrollable.html [ Failure ] @@ -2016,11 +2016,8 @@ # The spec for "Propagation to the Initial Containing Block" was changed. # https://drafts.csswg.org/css-writing-modes-4/#icb crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-001.html [ Failure ] -crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-002.html [ Failure ] -crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-033.html [ Failure ] crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-034.html [ Failure ] crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-035.html [ Failure ] -crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-037.html [ Failure ] crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-038.html [ Failure ] crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-039.html [ Failure ] crbug.com/988585 external/wpt/css/css-writing-modes/wm-propagation-body-042.html [ Failure ] @@ -2555,6 +2552,7 @@ crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] +crbug.com/832071 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] # failures in external/wpt/css/css-animations/ and web-animations/ from Mozilla tests crbug.com/849859 external/wpt/css/css-animations/CSSAnimation-pausing.tentative.html [ Failure ] @@ -2878,10 +2876,6 @@ crbug.com/626703 virtual/audio-service/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Timeout ] crbug.com/626703 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Timeout ] crbug.com/699040 external/wpt/svg/text/reftests/text-xml-space-001.svg [ Failure ] -crbug.com/626703 external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] -crbug.com/626703 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] -crbug.com/626703 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] -crbug.com/626703 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] crbug.com/626703 [ Linux ] external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-auto-and-math-style-002.tentative.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-auto-and-math-style-002.tentative.html [ Failure ] crbug.com/626703 [ Win ] external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-auto-and-math-style-002.tentative.html [ Failure ] @@ -4040,12 +4034,14 @@ crbug.com/691944 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] crbug.com/691944 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] crbug.com/691944 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] +crbug.com/691944 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] # These tests (erroneously) see a platform-specific User-Agent header crbug.com/595993 external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] +crbug.com/595993 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/619427 [ Mac ] fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ] @@ -4306,6 +4302,7 @@ crbug.com/889798 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] +crbug.com/889798 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] # Sheriff failures 2017-07-03 crbug.com/708994 http/tests/security/cross-frame-mouse-source-capabilities.html [ Timeout Pass ] @@ -4873,6 +4870,8 @@ crbug.com/873873 external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] crbug.com/873873 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] crbug.com/873873 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] +crbug.com/873873 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] +crbug.com/873873 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] crbug.com/875884 [ Linux ] lifecycle/background-change-lifecycle-count.html [ Pass Failure ] crbug.com/875884 [ Win ] lifecycle/background-change-lifecycle-count.html [ Pass Failure ] @@ -5192,6 +5191,7 @@ crbug.com/933880 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] +crbug.com/933880 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ] crbug.com/933880 http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ] # This passes in content_shell but not in chrome with network service disabled, @@ -5422,9 +5422,6 @@ crbug.com/963141 [ Linux ] media/video-object-fit.html [ Pass Failure ] crbug.com/963141 [ Linux ] virtual/audio-service/media/video-object-fit.html [ Pass Failure ] -# Workaround for bug; should be removed soon. -crbug.com/959693 external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html [ Timeout ] - # Allow failure until its appearance gets stable. crbug.com/972476 std-switch/switch-appearance.html [ Failure ] crbug.com/972476 std-switch/switch-appearance-customization.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 82ae233..a66c757b 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1090,6 +1090,11 @@ "args": ["--disable-features=CacheStorageSequence"] }, { + "prefix": "cache-storage-eager-reading", + "base": "external/wpt/service-workers", + "args": ["--enable-features=CacheStorageEagerReading"] + }, + { "prefix": "conditional-appcache-delay", "base": "http/tests/loading/appcache-delay", "args": ["--enable-features=VerifyHTMLFetchedFromAppCacheBeforeDelay"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index 5fef2d24..59a52c2 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -461973,7 +461973,7 @@ "support" ], "interfaces/cssom-view.idl": [ - "5d30ede1e40debc56ab71ba58a7ddec0ba5b40cf", + "34036484195e28b3068c9ef09f44acd0bed6bda9", "support" ], "interfaces/cssom.idl": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.html new file mode 100644 index 0000000..a478f9a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.html
@@ -0,0 +1,81 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Layout Test: Intrinsic contribution of an item with flex tracks</title> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-spanning-items" title="11.5.3 Increase sizes to accommodate spanning items crossing content-sized tracks"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-spanning-flex-items" title="11.5.4 Increase sizes to accommodate spanning items crossing flexible tracks"> +<meta name="assert" content="This test checks that the intrinsic contribution of a single grid item is distributed correctly among the tracks it spans when flexible tracks are involved."> +<style> +#grid { + display: grid; + width: 50px; + height: 50px; + border: solid; +} +#item { + width: 100px; + height: 100px; + background: blue; +} +</style> + +<div id="log"></div> + +<div id="grid"> + <div id="item"></div> +</div> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../grid-definition/support/testing-utils.js"></script> +<script> +const item = document.getElementById("item"); +function checkTrackSizes(span, trackList, expected) { + item.style.gridColumn = item.style.gridRow = `span ${span}`; + TestingUtils.testGridTemplateColumnsRows("grid", trackList, trackList, expected, expected); +} + +// Item spanning an intrinsic flexible track +checkTrackSizes(1, "0fr", "100px"); +checkTrackSizes(1, "1fr", "100px"); +checkTrackSizes(1, "2fr", "100px"); + +// Item spanning a fixed flexible track +checkTrackSizes(1, "minmax(0, 0fr)", "0px"); +checkTrackSizes(1, "minmax(0, .5fr)", "25px"); +checkTrackSizes(1, "minmax(0, 1fr)", "50px"); +checkTrackSizes(1, "minmax(0, 2fr)", "50px"); +checkTrackSizes(1, "minmax(75px, 1fr)", "75px"); + +// Item spanning 2 intrinsic flexible tracks +checkTrackSizes(2, "0fr 0fr", "50px 50px"); +checkTrackSizes(2, "0fr 1fr", "0px 100px"); +checkTrackSizes(2, "1fr 0fr", "100px 0px"); +checkTrackSizes(2, "1fr 1fr", "50px 50px"); +checkTrackSizes(2, "1fr 3fr", "25px 75px"); +checkTrackSizes(2, "0fr 0fr 1fr", "50px 50px 0px"); + +// Item spanning 2 fixed flexible tracks +checkTrackSizes(2, "minmax(0, 0fr) minmax(0, 0fr)", "0px 0px"); +checkTrackSizes(2, "minmax(0, 0fr) minmax(0, 1fr)", "0px 50px"); +checkTrackSizes(2, "minmax(15px, 0fr) minmax(0, 1fr)", "15px 35px"); +checkTrackSizes(2, "minmax(20px, 1fr) minmax(0, 1fr)", "25px 25px"); +checkTrackSizes(2, "minmax(30px, 1fr) minmax(0, 1fr)", "30px 20px"); + +// Item spanning an intrinsic flexible track and a fixed flexible track +checkTrackSizes(2, "0fr minmax(0, 0fr)", "100px 0px"); +checkTrackSizes(2, "0fr minmax(0, 1fr)", "100px 0px"); +checkTrackSizes(2, "1fr minmax(0, 1fr)", "100px 0px"); +checkTrackSizes(2, "1fr minmax(25px, 1fr)", "75px 25px"); + +// Item spanning an intrinsic flexible track and an intrinsic non-flexible track +checkTrackSizes(2, "0fr auto", "100px 0px"); +checkTrackSizes(2, "1fr auto", "100px 0px"); +checkTrackSizes(2, "1fr max-content", "100px 0px"); + +// Item spanning a fixed flexible track and an intrinsic non-flexible track +checkTrackSizes(2, "minmax(0, 0fr) auto", "0px 100px"); +checkTrackSizes(2, "minmax(0, 1fr) auto", "0px 100px"); +checkTrackSizes(2, "minmax(25px, 0fr) auto", "25px 75px"); +checkTrackSizes(2, "minmax(25px, 1fr) auto", "25px 75px"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-002.html new file mode 100644 index 0000000..ef5f1ae --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-002.html
@@ -0,0 +1,105 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Layout Test: Intrinsic contributions of 2 items with flex tracks</title> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-spanning-items" title="11.5.3 Increase sizes to accommodate spanning items crossing content-sized tracks"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-spanning-flex-items" title="11.5.4 Increase sizes to accommodate spanning items crossing flexible tracks"> +<meta name="assert" content="This test checks that the intrinsic contributions of 2 items are distributed in the right order when flexible tracks are involved."> +<style> +#grid { + display: grid; + grid-template-areas: ". . . ." + ". a . ." + ". . . ." + ". . . b"; + width: 50px; + height: 50px; + border: solid; +} +#item1 { + grid-column: 1 / a; + grid-row: 1 / a; + width: 60px; + height: 60px; + background: blue; +} +#item2 { + grid-column: a / b; + grid-row: a / b; + width: 150px; + height: 150px; + background: yellow; +} +</style> + +<div id="log"></div> + +<div id="grid"> + <div id="item1"></div> + <div id="item2"></div> +</div> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../grid-definition/support/testing-utils.js"></script> +<script> +function checkTrackSizes(trackList, expected) { + TestingUtils.testGridTemplateColumnsRows("grid", trackList, trackList, expected, expected); +} + +// We have a symmetric grid with 2 items and 4 tracks, as follows: +// ╔═╤═╗─┬─┐ +// ╟─╔═╬═╪═╗ +// ╚═╬═╝─┼─╢ +// ├─╫─┼─┼─╢ +// └─╚═╧═╧═╝ + +// The 1st item has spans less tracks (2) than the 2nd item (3), +// therefore its contribution (60px) is distributed first. +// All the 60px go to the 2nd track, since the 1st track is not intrinsic. +// Then the 2nd item only needs to distribute 150px-60px=90px +// among the 3rd and 4th tracks. +checkTrackSizes("minmax(0, 1fr) auto auto auto", "0px 60px 45px 45px"); + +// The 1st item now spans a flexible track with an intrinsic minimum, +// therefore its contribution (60px) is distributed last. +// The 2nd item distributes its contribution (150px) among the 2nd, 3rd and 4th tracks. +// Then the 1st item only needs to distribute 60px-50px=10px to the 1st track. +checkTrackSizes("1fr auto auto auto", "10px 50px 50px 50px"); + +// Now both items span a flexible track with an intrinsic minimum, +// so their contributions are handled simultaneously, +// even if the 1st item still spans less tracks than the 2nd one. +// Therefore the distribution is as follows: +// - 1st track: 60px/2 = 30px +// - 2nd track: max(60px/2, 150px/3) = 50px +// - 3rd track: 150px/3 = 50px +// - 4th track: 150px/3 = 50px +checkTrackSizes("1fr 1fr 1fr 1fr", "30px 50px 50px 50px"); + +// Like the previous case, but with different flex ratios: +// - 1st track: 60px/2 = 30px +// - 2nd track: max(60px/2, 150px/6) = 30px +// - 3rd track: 150px/6 = 25px +// - 4th track: 150px*4/6 = 100px +checkTrackSizes("1fr 1fr 1fr 4fr", "30px 30px 25px 100px"); + +// Change the grid as follows: +// ╔═╦═╤═╗ +// ╠═╝─┼─╢ +// ╟─┼─┼─╢ +// ╚═╧═╧═╝ +document.getElementById("grid").style.gridTemplateAreas = ` + "a . ." + ". . ." + ". . b"`; + +// Now the 1st item has a span of 1, so usually we would handle its contribution +// at the very beginning, before items that span multiple tracks. +// But not if its track is flexible, then it's still handled at the end, +// simultaneously with other items that span some intrinsic flexible track. +// - 1nd track: max(60px, 150px/3) = 60px +// - 2nd track: 150px/3 = 50px +// - 3rd track: 150px/3 = 50px +checkTrackSizes("1fr 1fr 1fr", "60px 50px 50px"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vlr-005.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vlr-005.xht index 2754e24..a443db4e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vlr-005.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vlr-005.xht
@@ -36,10 +36,6 @@ html { writing-mode: vertical-lr; - } - - body#containing-block - { background-image: url("support/bg-red-3col-2row-320x320.png"); background-position: 198px 8px; /* first value represents the horizontal position and the second represents the vertical position */ @@ -58,9 +54,12 @@ 198px */ background-repeat: no-repeat; + } + + #containing-block + { direction: rtl; height: 320px; - margin: 8px; } p @@ -70,7 +69,7 @@ margin-right: 16px; } - div + #test { background-color: green; margin-top: 160px; @@ -139,16 +138,16 @@ </head> - <body id="containing-block"> + <body> + <div id="containing-block"> + <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p> + <!-- + The image says: + Test passes if there is a filled + green square and <strong>no red</strong>. + --> - <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p> - <!-- - The image says: - Test passes if there is a filled - green square and <strong>no red</strong>. - --> - - <div></div> - + <div id="test"></div> + </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vrl-004.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vrl-004.xht index 472405d..d084c2c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vrl-004.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/normal-flow-overconstrained-vrl-004.xht
@@ -36,10 +36,6 @@ html { writing-mode: vertical-rl; - } - - body#containing-block - { background-image: url("support/bg-red-3col-2row-320x320.png"); background-position: -152px 8px; /* first value represents the horizontal position and the second represents the vertical position */ @@ -54,9 +50,11 @@ -152px */ background-repeat: no-repeat; + } + #containing-block + { direction: rtl; height: 320px; - margin: 8px; } p @@ -66,7 +64,7 @@ margin-right: 16px; } - div + #test { background-color: green; margin-top: 160px; @@ -135,16 +133,16 @@ </head> - <body id="containing-block"> + <body> + <div id="containing-block"> + <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p> + <!-- + The image says: + Test passes if there is a filled + green square and <strong>no red</strong>. + --> - <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p> - <!-- - The image says: - Test passes if there is a filled - green square and <strong>no red</strong>. - --> - - <div></div> - + <div id="test"></div> + </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/cssom-view.idl b/third_party/blink/web_tests/external/wpt/interfaces/cssom-view.idl index 5d30ede..34036484 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/cssom-view.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/cssom-view.idl
@@ -53,8 +53,8 @@ interface MediaQueryList : EventTarget { readonly attribute CSSOMString media; readonly attribute boolean matches; - void addListener(EventListener? listener); - void removeListener(EventListener? listener); + void addListener(EventListener? callback); + void removeListener(EventListener? callback); attribute EventHandler onchange; };
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt index 2b0c2f8..096b59d 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. FAIL Verify matchAll() with window client type assert_array_equals: property 2, expected "https://web-platform.test:8444/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html" but got "https://web-platform.test:8444/service-workers/service-worker/resources/url-modified-via-pushstate.html" -FAIL Verify matchAll() with {window, sharedworker, worker} client types promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker" +FAIL Verify matchAll() with {window, sharedworker, worker} client types assert_array_equals: property 2, expected "https://web-platform.test:8444/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html" but got "https://web-platform.test:8444/service-workers/service-worker/resources/url-modified-via-pushstate.html" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/ready.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/ready.https-expected.txt index d29a2b4e..10f1cc7 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/ready.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/ready.https-expected.txt
@@ -7,6 +7,7 @@ PASS ready on an iframe that installs a new service worker PASS ready after a longer matched registration registered PASS access ready after it has been resolved -FAIL access ready on uninstalling registration that is resurrected assert_not_equals: ready promise should resolve before timeout got disallowed value null +PASS resolve ready after unregistering and reregistering +FAIL resolve ready before unregistering and reregistering assert_equals: Resolves with the first registration expected "https://web-platform.test:8444/service-workers/service-worker/resources/empty-worker.js" but got "https://web-platform.test:8444/service-workers/service-worker/resources/empty-worker.js?2" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register-new-script.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register-new-script.https-expected.txt deleted file mode 100644 index 20a0fa54..0000000 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register-new-script.https-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -FAIL Registering a new script URL while an unregistered registration is in use assert_equals: before activated registration.installing expected null but got object "[object ServiceWorker]" -PASS Registering a new script URL that 404s does not resurrect unregistered registration -FAIL Registering a new script URL that fails to install does not resurrect unregistered registration assert_not_equals: New registration is different got disallowed value object "[object ServiceWorkerRegistration]" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register.https-expected.txt deleted file mode 100644 index 30d5ef1..0000000 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-then-register.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -PASS Unregister then register resolves to a new value -FAIL Unregister then register does not resolve to the original value even if the registration is in use. assert_not_equals: Unregister and register should always create a new registration got disallowed value object "[object ServiceWorkerRegistration]" -PASS Unregister then register does not affect existing controllee -FAIL Unregister then register does not resurrect the registration assert_equals: Registration is new expected null but got object "[object ServiceWorker]" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/Node-multiple-arguments.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/Node-multiple-arguments.tentative.html index 062c26d..e3e4a263 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/Node-multiple-arguments.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/Node-multiple-arguments.tentative.html
@@ -9,7 +9,7 @@ <div id="container"></div> <script> const container = document.querySelector("#container"); - const policy = window.TrustedTypes.createPolicy("policy", { + const policy = window.trustedTypes.createPolicy("policy", { createScript: t => t, }); function stringify(arg) {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-no-name.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-no-name.tentative.html index 2dfec26..18819b20 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-no-name.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-no-name.tentative.html
@@ -9,7 +9,7 @@ // No name given test test(t => { assert_throws(new TypeError(), - () => window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ), + () => window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ), "createPolicy with an empty trusted-types CSP directive"); }, "No name list given - policy creation fails."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-wildcard.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-wildcard.tentative.html index 22b8796..0e97a4a2 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-wildcard.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP-wildcard.tentative.html
@@ -7,7 +7,7 @@ <body> <script> test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); assert_equals(policy.name, 'SomeName'); }, "CSP supports wildcards."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP.tentative.html index 1293493..0b57c3a 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-CSP.tentative.html
@@ -8,20 +8,20 @@ <script> // Whitelisted name test test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); assert_equals(policy.name, 'SomeName'); }, "Whitelisted policy creation works."); // Another whitelisted name test test(t => { - let policy = window.TrustedTypes.createPolicy('JustOneMoreName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('JustOneMoreName', { createHTML: s => s } ); assert_equals(policy.name, 'JustOneMoreName'); }, "Another whitelisted policy creation works."); // Non-whitelisted names test test(t => { assert_throws(new TypeError(), _ => { - window.TrustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); + window.trustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); }); }, "Non-whitelisted policy creation throws."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html index a078af4b..73ed8c7 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html
@@ -7,14 +7,14 @@ <body> <script> test(t => { - const p1 = TrustedTypes.createPolicy("policyHTMLAndScript", { + const p1 = trustedTypes.createPolicy("policyHTMLAndScript", { createHTML: s => s, createScript: s => s }); assert_throws(new TypeError(), _ => { p1.createScriptURL("foo"); }); assert_throws(new TypeError(), _ => { p1.createURL("foo"); }); - const p2 = TrustedTypes.createPolicy("policyURLAndScriptURL", { + const p2 = trustedTypes.createPolicy("policyURLAndScriptURL", { createURL: s => s, createScriptURL: s => s }); @@ -29,7 +29,7 @@ createURL: (s) => s, createScript: (s) => s, }; - policy = TrustedTypes.createPolicy(Math.random(), noopPolicy, true); + policy = trustedTypes.createPolicy(Math.random(), noopPolicy, true); let el = document.createElement("div"); el.title = policy.createHTML(INPUTS.URL); @@ -40,12 +40,12 @@ }, "Attributes without type constraints will work as before."); test(t => { - const policy = TrustedTypes.createPolicy("nullpolicy", null); + const policy = trustedTypes.createPolicy("nullpolicy", null); assert_throws(new TypeError(), _ => { policy.createScriptURL("foo"); }); assert_throws(new TypeError(), _ => { policy.createURL("foo"); }); assert_throws(new TypeError(), _ => { policy.createHTML("foo"); }); assert_throws(new TypeError(), _ => { policy.createScript("foo"); }); - }, "TrustedTypes.createPolicy(.., null) creates empty policy."); + }, "trustedTypes.createPolicy(.., null) creates empty policy."); // testCases contains a list of policy functions and expected results (when @@ -85,7 +85,7 @@ return function(name, fn) { let options = {}; options[trustedMethodName] = fn; - let policy = window.TrustedTypes.createPolicy(name, options); + let policy = window.trustedTypes.createPolicy(name, options); let result = policy[trustedMethodName](defaultArg); assert_true(result instanceof trustedType); return result;
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-name.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-name.tentative.html index c121fe4..4b7c30c 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-name.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-name.tentative.html
@@ -8,7 +8,7 @@ <script> // Policy name test test(t => { - let policy = TrustedTypes.createPolicy('hidden', { createHTML: s => s }, false ); + let policy = trustedTypes.createPolicy('hidden', { createHTML: s => s }, false ); assert_true(policy instanceof TrustedTypePolicy); assert_equals(policy.name, 'hidden'); }, "policy.name = name"); @@ -16,14 +16,14 @@ // Duplicate names test test(t => { assert_throws(new TypeError(), _ => { - TrustedTypes.createPolicy('hidden', { createURL: s => s } ); + trustedTypes.createPolicy('hidden', { createURL: s => s } ); }); }, "duplicate policy name attempt throws"); // Retrieve policy names tests test(t => { - let policy = TrustedTypes.createPolicy('exposed', { createURL: s => s }, true ); - let names = TrustedTypes.getPolicyNames(); + let policy = trustedTypes.createPolicy('exposed', { createURL: s => s }, true ); + let names = trustedTypes.getPolicyNames(); assert_equals(names.length, 2); assert_true(names.includes('hidden')); assert_true(names.includes('exposed'));
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-constants.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-constants.tentative.html index f164e79..001a6ce 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-constants.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-constants.tentative.html
@@ -7,20 +7,20 @@ <body> <script> test(t => { - const empty = TrustedTypes.emptyHTML; - assert_true(TrustedTypes.isHTML(empty)); + const empty = trustedTypes.emptyHTML; + assert_true(trustedTypes.isHTML(empty)); assert_equals(empty.toString(), ""); - }, 'TrustedTypes.emptyHTML returns the intended value.'); + }, 'trustedTypes.emptyHTML returns the intended value.'); test(t => { - try { TrustedTypes.emptyHTML = 'fake'; } catch { } - assert_true(TrustedTypes.isHTML(TrustedTypes.emptyHTML)); - assert_equals(TrustedTypes.emptyHTML.toString(), ""); - }, 'TrustedTypes.emptyHTML cannot be redefined.'); + try { trustedTypes.emptyHTML = 'fake'; } catch { } + assert_true(trustedTypes.isHTML(trustedTypes.emptyHTML)); + assert_equals(trustedTypes.emptyHTML.toString(), ""); + }, 'trustedTypes.emptyHTML cannot be redefined.'); test(t => { try { Object.defineProperty(TrustedTypes, 'emptyHTML', 'fake'); } catch { } - assert_true(TrustedTypes.isHTML(TrustedTypes.emptyHTML)); - assert_equals(TrustedTypes.emptyHTML.toString(), ""); - }, 'TrustedTypes.emptyHTML cannot be redefined via defineProperty.'); + assert_true(trustedTypes.isHTML(trustedTypes.emptyHTML)); + assert_equals(trustedTypes.emptyHTML.toString(), ""); + }, 'trustedTypes.emptyHTML cannot be redefined via defineProperty.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html index 8cdc837..05c7301 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html
@@ -6,10 +6,10 @@ <script> //HTML tests function createHTMLTest(policyName, policy, expectedHTML, t) { - let p = window.TrustedTypes.createPolicy(policyName, policy); + let p = window.trustedTypes.createPolicy(policyName, policy); let html = p.createHTML('whatever'); assert_true(html instanceof TrustedHTML); - assert_true(TrustedTypes.isHTML(html)); + assert_true(trustedTypes.isHTML(html)); assert_equals(html + "", expectedHTML); } @@ -33,7 +33,7 @@ }, "html = identity function, global string changed"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyHTML5', { createHTML: s => { throw new Error(); }}); + let p = window.trustedTypes.createPolicy('TestPolicyHTML5', { createHTML: s => { throw new Error(); }}); assert_throws(new Error(), _ => { p.createHTML('whatever'); }); @@ -57,14 +57,14 @@ }, "html = this without bind"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyHTML8', null); + let p = window.trustedTypes.createPolicy('TestPolicyHTML8', null); assert_throws(new TypeError(), _ => { p.createHTML('whatever'); }); }, "html - calling undefined callback throws"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyHTML9', { createHTML: createHTMLJS }); + let p = window.trustedTypes.createPolicy('TestPolicyHTML9', { createHTML: createHTMLJS }); assert_throws(new TypeError(), _ => { p.createScript(INPUTS.SCRIPT); }); @@ -78,10 +78,10 @@ //Script tests function createScriptTest(policyName, policy, expectedScript, t) { - let p = window.TrustedTypes.createPolicy(policyName, policy); + let p = window.trustedTypes.createPolicy(policyName, policy); let script = p.createScript('whatever'); assert_true(script instanceof TrustedScript); - assert_true(TrustedTypes.isScript(script)); + assert_true(trustedTypes.isScript(script)); assert_equals(script + "", expectedScript); } @@ -105,7 +105,7 @@ }, "script = identity function, global string changed"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScript5', { + let p = window.trustedTypes.createPolicy('TestPolicyScript5', { createScript: s => { throw new Error(); } }); assert_throws(new Error(), _ => { @@ -131,14 +131,14 @@ }, "script = this without bind"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScript8', null); + let p = window.trustedTypes.createPolicy('TestPolicyScript8', null); assert_throws(new TypeError(), _ => { p.createScript('whatever'); }); }, "script - calling undefined callback throws"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScript9', { createScript: createScriptJS }); + let p = window.trustedTypes.createPolicy('TestPolicyScript9', { createScript: createScriptJS }); assert_throws(new TypeError(), _ => { p.createHTML(INPUTS.HTML); }); @@ -153,10 +153,10 @@ //ScriptURL tests function createScriptURLTest(policyName, policy, expectedScriptURL, t) { - let p = window.TrustedTypes.createPolicy(policyName, policy); + let p = window.trustedTypes.createPolicy(policyName, policy); let scriptUrl = p.createScriptURL(INPUTS.SCRIPTURL); assert_true(scriptUrl instanceof TrustedScriptURL); - assert_true(TrustedTypes.isScriptURL(scriptUrl)); + assert_true(trustedTypes.isScriptURL(scriptUrl)); assert_equals(scriptUrl + "", expectedScriptURL); } @@ -180,7 +180,7 @@ }, "script_url = identity function, global string changed"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL5', { + let p = window.trustedTypes.createPolicy('TestPolicyScriptURL5', { createScriptURL: s => { throw new Error(); } }); assert_throws(new Error(), _ => { @@ -206,14 +206,14 @@ }, "script_url = this without bind"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL8', null); + let p = window.trustedTypes.createPolicy('TestPolicyScriptURL8', null); assert_throws(new TypeError(), _ => { p.createScriptURL(INPUTS.SCRIPTURL); }); }, "script_url - calling undefined callback throws"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyScriptURL9', { createScriptURL: createScriptURLJS }); + let p = window.trustedTypes.createPolicy('TestPolicyScriptURL9', { createScriptURL: createScriptURLJS }); assert_throws(new TypeError(), _ => { p.createHTML(INPUTS.HTML); }); @@ -228,10 +228,10 @@ //URL tests function createURLTest(policyName, policy, expectedURL, t) { - let p = window.TrustedTypes.createPolicy(policyName, policy); + let p = window.trustedTypes.createPolicy(policyName, policy); let url = p.createURL(INPUTS.URL); assert_true(url instanceof TrustedURL); - assert_true(TrustedTypes.isURL(url)); + assert_true(trustedTypes.isURL(url)); assert_equals(url + "", expectedURL); } @@ -255,7 +255,7 @@ }, "url = identity function, global string changed"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyURL5', { + let p = window.trustedTypes.createPolicy('TestPolicyURL5', { createURL: s => { throw new Error(); } }); assert_throws(new Error(), _ => { @@ -281,14 +281,14 @@ }, "url = this without bind"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyURL8', null); + let p = window.trustedTypes.createPolicy('TestPolicyURL8', null); assert_throws(new TypeError(), _ => { p.createURL(INPUTS.URL); }); }, "url - calling undefined callback throws"); test(t => { - let p = window.TrustedTypes.createPolicy('TestPolicyURL9', { createURL: createURLJS }); + let p = window.trustedTypes.createPolicy('TestPolicyURL9', { createURL: createURLJS }); assert_throws(new TypeError(), _ => { p.createHTML(INPUTS.HTML); });
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html index 2fc8f01..cec1bfb6 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html
@@ -8,7 +8,7 @@ //No name given test test(t => { assert_throws(new TypeError(), _ => { - window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); }); }, "No name list given - policy creation throws"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html index 7edc64b..f1b5f27 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html
@@ -7,7 +7,7 @@ <script> //No name given test test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); assert_equals(policy.name, 'SomeName'); }, "Wildcard given - policy creation works"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.tentative.html index 1293493..0b57c3a 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.tentative.html
@@ -8,20 +8,20 @@ <script> // Whitelisted name test test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); assert_equals(policy.name, 'SomeName'); }, "Whitelisted policy creation works."); // Another whitelisted name test test(t => { - let policy = window.TrustedTypes.createPolicy('JustOneMoreName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('JustOneMoreName', { createHTML: s => s } ); assert_equals(policy.name, 'JustOneMoreName'); }, "Another whitelisted policy creation works."); // Non-whitelisted names test test(t => { assert_throws(new TypeError(), _ => { - window.TrustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); + window.trustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); }); }, "Non-whitelisted policy creation throws."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html index 6d43e0b..e0aa537 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-nameTests.tentative.html
@@ -6,7 +6,7 @@ <script> //Policy name test test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } ); assert_true(policy instanceof TrustedTypePolicy); assert_equals(policy.name, 'SomeName'); }, "policy.name = name"); @@ -14,14 +14,14 @@ //Duplicate names test test(t => { assert_throws(new TypeError(), _ => { - window.TrustedTypes.createPolicy('SomeName', { createURL: s => s } ); + window.trustedTypes.createPolicy('SomeName', { createURL: s => s } ); }); }, "duplicate policy name attempt throws"); //Retrieve policy names tests test(t => { - let policy = window.TrustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); - let names = window.TrustedTypes.getPolicyNames(); + let policy = window.trustedTypes.createPolicy('SomeOtherName', { createURL: s => s } ); + let names = window.trustedTypes.getPolicyNames(); assert_true(names.includes('SomeName')); assert_true(names.includes('SomeOtherName')); }, "Retrieving policy names");
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-defaultPolicy.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-defaultPolicy.tentative.html index ea00566..7ac09d8b 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-defaultPolicy.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-defaultPolicy.tentative.html
@@ -5,20 +5,20 @@ <body> <script> test(t => { - assert_equals(window.TrustedTypes.defaultPolicy, null); + assert_equals(window.trustedTypes.defaultPolicy, null); }, "defaultPolicy with no default created is not an error"); test(t => { - let policy = window.TrustedTypes.createPolicy('default', { createHTML: s => s } ); + let policy = window.trustedTypes.createPolicy('default', { createHTML: s => s } ); assert_true(policy instanceof TrustedTypePolicy); - assert_equals(policy, window.TrustedTypes.defaultPolicy); + assert_equals(policy, window.trustedTypes.defaultPolicy); }, "defaultPolicy returns the correct default policy"); test(t => { - let foo_policy = window.TrustedTypes.createPolicy('foo', { createHTML: s => s } ); - let default_policy = window.TrustedTypes.defaultPolicy; - window.TrustedTypes.defaultPolicy = foo_policy; - assert_equals(window.TrustedTypes.defaultPolicy, default_policy); - assert_not_equals(window.TrustedTypes.defaultPolicy, foo_policy); + let foo_policy = window.trustedTypes.createPolicy('foo', { createHTML: s => s } ); + let default_policy = window.trustedTypes.defaultPolicy; + window.trustedTypes.defaultPolicy = foo_policy; + assert_equals(window.trustedTypes.defaultPolicy, default_policy); + assert_not_equals(window.trustedTypes.defaultPolicy, foo_policy); }, "defaultPolicy is a read-only property"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html index 90fc7d556..f9ba8f27 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html
@@ -8,77 +8,77 @@ <div id="target"></div> <script> test(t => { - assert_equals(TrustedTypes.getPropertyType("a", "href"), "TrustedURL"); - assert_equals(TrustedTypes.getPropertyType("a", "id"), null); - assert_equals(TrustedTypes.getPropertyType("a", "b"), null); - }, "sanity check TrustedTypes.getPropertyType for the HTML a element."); + assert_equals(trustedTypes.getPropertyType("a", "href"), "TrustedURL"); + assert_equals(trustedTypes.getPropertyType("a", "id"), null); + assert_equals(trustedTypes.getPropertyType("a", "b"), null); + }, "sanity check trustedTypes.getPropertyType for the HTML a element."); test(t => { - assert_equals(TrustedTypes.getAttributeType("img", "onerror"), "TrustedScript"); - assert_equals(TrustedTypes.getAttributeType("img", "width"), null); - assert_equals(TrustedTypes.getAttributeType("img", "madeup"), null); - }, "sanity check TrustedTypes.getAttributeType."); + assert_equals(trustedTypes.getAttributeType("img", "onerror"), "TrustedScript"); + assert_equals(trustedTypes.getAttributeType("img", "width"), null); + assert_equals(trustedTypes.getAttributeType("img", "madeup"), null); + }, "sanity check trustedTypes.getAttributeType."); test(t => { - assert_true(!!TrustedTypes.getTypeMapping()); - }, "sanity check TrustedTypes.getTypeMapping"); + assert_true(!!trustedTypes.getTypeMapping()); + }, "sanity check trustedTypes.getTypeMapping"); // getPropertyType tests adapted from WICG/trusted-types polyfill: test(t => { // returns the proper type for attribute-related properties - assert_equals(TrustedTypes.getPropertyType("script", "src"), "TrustedScriptURL"); - assert_equals(TrustedTypes.getPropertyType("img", "src"), "TrustedURL"); + assert_equals(trustedTypes.getPropertyType("script", "src"), "TrustedScriptURL"); + assert_equals(trustedTypes.getPropertyType("img", "src"), "TrustedURL"); // is case insensitive for tag names - assert_equals(TrustedTypes.getPropertyType("SCRIPT", "src"), "TrustedScriptURL"); - assert_equals(TrustedTypes.getPropertyType("ImG", "src"), "TrustedURL"); + assert_equals(trustedTypes.getPropertyType("SCRIPT", "src"), "TrustedScriptURL"); + assert_equals(trustedTypes.getPropertyType("ImG", "src"), "TrustedURL"); // is case sensitive for property names - assert_equals(TrustedTypes.getPropertyType("script", "sRc"), null); - assert_equals(TrustedTypes.getPropertyType("div", "innerhtml"), null); + assert_equals(trustedTypes.getPropertyType("script", "sRc"), null); + assert_equals(trustedTypes.getPropertyType("div", "innerhtml"), null); // returns the proper type for innerHTML - assert_equals(TrustedTypes.getPropertyType("div", "innerHTML"), "TrustedHTML"); + assert_equals(trustedTypes.getPropertyType("div", "innerHTML"), "TrustedHTML"); // returns the proper type for outerHTML - assert_equals(TrustedTypes.getPropertyType("div", "outerHTML"), "TrustedHTML"); + assert_equals(trustedTypes.getPropertyType("div", "outerHTML"), "TrustedHTML"); // returns the proper type for script.prop ["text", "innerText", "textContent"].forEach((prop) => { - assert_equals(TrustedTypes.getPropertyType("script", prop), "TrustedScript"); + assert_equals(trustedTypes.getPropertyType("script", prop), "TrustedScript"); }); }, "getPropertyType tests adapted from WICG/trusted-types polyfill"); test(t => { // returns the proper type - assert_equals(TrustedTypes.getAttributeType('script', 'src'), 'TrustedScriptURL'); - assert_equals(TrustedTypes.getAttributeType('img', 'src'), 'TrustedURL'); + assert_equals(trustedTypes.getAttributeType('script', 'src'), 'TrustedScriptURL'); + assert_equals(trustedTypes.getAttributeType('img', 'src'), 'TrustedURL'); // ignores attributes from unknown namespaces - assert_equals(TrustedTypes.getAttributeType( + assert_equals(trustedTypes.getAttributeType( 'a', 'href', '', 'http://foo.bar'), null); // is case insensitive for element names - assert_equals(TrustedTypes.getAttributeType('SCRIPT', 'src'), 'TrustedScriptURL'); - assert_equals(TrustedTypes.getAttributeType('imG', 'src'), 'TrustedURL'); + assert_equals(trustedTypes.getAttributeType('SCRIPT', 'src'), 'TrustedScriptURL'); + assert_equals(trustedTypes.getAttributeType('imG', 'src'), 'TrustedURL'); // is case insensitive for the attribute names - assert_equals(TrustedTypes.getAttributeType('script', 'SRC'), 'TrustedScriptURL'); - assert_equals(TrustedTypes.getAttributeType('imG', 'srC'), 'TrustedURL'); + assert_equals(trustedTypes.getAttributeType('script', 'SRC'), 'TrustedScriptURL'); + assert_equals(trustedTypes.getAttributeType('imG', 'srC'), 'TrustedURL'); // supports the inline event handlers - assert_equals(TrustedTypes.getAttributeType('img', 'onerror'), 'TrustedScript'); - assert_equals(TrustedTypes.getAttributeType('unknown', 'onerror'), 'TrustedScript'); + assert_equals(trustedTypes.getAttributeType('img', 'onerror'), 'TrustedScript'); + assert_equals(trustedTypes.getAttributeType('unknown', 'onerror'), 'TrustedScript'); // defaults to undefined - assert_equals(TrustedTypes.getAttributeType('unknown', 'src'), null); - assert_equals(TrustedTypes.getAttributeType('img', 'bar'), null); + assert_equals(trustedTypes.getAttributeType('unknown', 'src'), null); + assert_equals(trustedTypes.getAttributeType('img', 'bar'), null); }, "getAttributeType tests adapted from WICG/trusted-types polyfill"); test(t=> { - const map = TrustedTypes.getTypeMapping(); + const map = trustedTypes.getTypeMapping(); // Spot testing some values. assert_equals(map["script"].attributes.src, "TrustedScriptURL"); @@ -89,10 +89,10 @@ // getTypeMapping returns a 'clean' object, in case the return value has // been modified. map["*"].attributes["foo"] = "bar"; - assert_equals(TrustedTypes.getTypeMapping()["*"].attributes["foo"], undefined); + assert_equals(trustedTypes.getTypeMapping()["*"].attributes["foo"], undefined); ; // Unknown namespaces: - assert_equals(TrustedTypes.getTypeMapping("http://foo/bar"), undefined); + assert_equals(trustedTypes.getTypeMapping("http://foo/bar"), undefined); }, "getTypeMapping tests adapted from WICG/trusted-types polyfill"); // Test case handling for both attributes and properties. @@ -100,12 +100,12 @@ for (let elem of ["object", "OBJECT", "oBjEcT"]) { test(t => { // attributes are case-insensitive, so all variants should be defined. - assert_true(TrustedTypes.getAttributeType(elem, attr) != undefined); + assert_true(trustedTypes.getAttributeType(elem, attr) != undefined); }, `${elem}[${attr}] is defined`); test(t => { // properties are case-sensitive, so only the "correct" spelling // should be defined. - assert_equals(TrustedTypes.getPropertyType(elem, attr) != undefined, + assert_equals(trustedTypes.getPropertyType(elem, attr) != undefined, attr == "codeBase"); }, `${elem}.${attr} is maybe defined`); }
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html index 854f69ed..efaac5d 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html
@@ -16,94 +16,94 @@ // isHTML tests test(t => { - const p = TrustedTypes.createPolicy('html', noopPolicy); + const p = trustedTypes.createPolicy('html', noopPolicy); let html = p.createHTML(INPUTS.HTML); - assert_true(TrustedTypes.isHTML(html)); + assert_true(trustedTypes.isHTML(html)); let html2 = Object.create(html); // instanceof can pass, but we rely on isHTML assert_true(html2 instanceof TrustedHTML); - assert_false(TrustedTypes.isHTML(html2)); + assert_false(trustedTypes.isHTML(html2)); let html3 = Object.assign({}, html, {toString: () => 'fake'}); - assert_false(TrustedTypes.isHTML(html3)); + assert_false(trustedTypes.isHTML(html3)); }, 'TrustedTypePolicyFactory.isHTML requires the object to be created via policy.'); // isScript tests test(t => { - const p = TrustedTypes.createPolicy('script', noopPolicy); + const p = trustedTypes.createPolicy('script', noopPolicy); let script = p.createScript(INPUTS.SCRIPT); - assert_true(TrustedTypes.isScript(script)); + assert_true(trustedTypes.isScript(script)); let script2 = Object.create(script); // instanceof can pass, but we rely on isScript assert_true(script2 instanceof TrustedScript); - assert_false(TrustedTypes.isScript(script2)); + assert_false(trustedTypes.isScript(script2)); let script3 = Object.assign({}, script, {toString: () => 'fake'}); - assert_false(TrustedTypes.isScript(script3)); + assert_false(trustedTypes.isScript(script3)); }, 'TrustedTypePolicyFactory.isScript requires the object to be created via policy.'); // isScriptURL tests test(t => { - const p = TrustedTypes.createPolicy('script_url', noopPolicy); + const p = trustedTypes.createPolicy('script_url', noopPolicy); let script = p.createScriptURL(INPUTS.SCRIPTURL); - assert_true(TrustedTypes.isScriptURL(script)); + assert_true(trustedTypes.isScriptURL(script)); let script2 = Object.create(script); // instanceof can pass, but we rely on isScript assert_true(script2 instanceof TrustedScriptURL); - assert_false(TrustedTypes.isScriptURL(script2)); + assert_false(trustedTypes.isScriptURL(script2)); let script3 = Object.assign({}, script, {toString: () => 'fake'}); - assert_false(TrustedTypes.isScriptURL(script3)); + assert_false(trustedTypes.isScriptURL(script3)); }, 'TrustedTypePolicyFactory.isScriptURL requires the object to be created via policy.'); // isURL tests test(t => { - const p = TrustedTypes.createPolicy('url', noopPolicy); + const p = trustedTypes.createPolicy('url', noopPolicy); let url = p.createURL(INPUTS.URL); - assert_true(TrustedTypes.isURL(url)); + assert_true(trustedTypes.isURL(url)); let url2 = Object.create(url); // instanceof can pass, but we rely on isScript assert_true(url2 instanceof TrustedURL); - assert_false(TrustedTypes.isURL(url2)); + assert_false(trustedTypes.isURL(url2)); let url3 = Object.assign({}, url, {toString: () => 'fake'}); - assert_false(TrustedTypes.isURL(url3)); + assert_false(trustedTypes.isURL(url3)); }, 'TrustedTypePolicyFactory.isURL requires the object to be created via policy.'); // Test non-object parameters. test(t => { - assert_false(TrustedTypes.isHTML(null)); - assert_false(TrustedTypes.isHTML(123)); - assert_false(TrustedTypes.isHTML(0.5)); - assert_false(TrustedTypes.isHTML('test')); - assert_false(TrustedTypes.isHTML({})); - assert_false(TrustedTypes.isScript(null)); - assert_false(TrustedTypes.isScript(123)); - assert_false(TrustedTypes.isScript(0.5)); - assert_false(TrustedTypes.isScript('test')); - assert_false(TrustedTypes.isScript({})); - assert_false(TrustedTypes.isURL(null)); - assert_false(TrustedTypes.isURL(123)); - assert_false(TrustedTypes.isURL(0.5)); - assert_false(TrustedTypes.isURL('test')); - assert_false(TrustedTypes.isURL({})); - assert_false(TrustedTypes.isScriptURL(null)); - assert_false(TrustedTypes.isScriptURL(123)); - assert_false(TrustedTypes.isScriptURL(0.5)); - assert_false(TrustedTypes.isScriptURL('test')); - assert_false(TrustedTypes.isScriptURL({})); + assert_false(trustedTypes.isHTML(null)); + assert_false(trustedTypes.isHTML(123)); + assert_false(trustedTypes.isHTML(0.5)); + assert_false(trustedTypes.isHTML('test')); + assert_false(trustedTypes.isHTML({})); + assert_false(trustedTypes.isScript(null)); + assert_false(trustedTypes.isScript(123)); + assert_false(trustedTypes.isScript(0.5)); + assert_false(trustedTypes.isScript('test')); + assert_false(trustedTypes.isScript({})); + assert_false(trustedTypes.isURL(null)); + assert_false(trustedTypes.isURL(123)); + assert_false(trustedTypes.isURL(0.5)); + assert_false(trustedTypes.isURL('test')); + assert_false(trustedTypes.isURL({})); + assert_false(trustedTypes.isScriptURL(null)); + assert_false(trustedTypes.isScriptURL(123)); + assert_false(trustedTypes.isScriptURL(0.5)); + assert_false(trustedTypes.isScriptURL('test')); + assert_false(trustedTypes.isScriptURL({})); }, 'TrustedTypePolicyFactory.isXXX should accept anything without throwing.'); // Redefinition tests, assign to property. @@ -112,44 +112,44 @@ // what [Unforgeable] does. Hence, the tests use try {..} catch {} to cover // both situationsm rather than expect_throws(...).) test(t => { - try { TrustedTypes.isHTML = () => 'fake'; } catch { } - assert_false(TrustedTypes.isHTML({})); + try { trustedTypes.isHTML = () => 'fake'; } catch { } + assert_false(trustedTypes.isHTML({})); }, 'TrustedTypePolicyFactory.IsHTML cannot be redefined.'); test(t => { - try { TrustedTypes.isScript = () => 'fake'; } catch { } - assert_false(TrustedTypes.isScript({})); + try { trustedTypes.isScript = () => 'fake'; } catch { } + assert_false(trustedTypes.isScript({})); }, 'TrustedTypePolicyFactory.isScript cannot be redefined.'); test(t => { - try { TrustedTypes.isScriptURL = () => 'fake'; } catch { } - assert_false(TrustedTypes.isScriptURL({})); + try { trustedTypes.isScriptURL = () => 'fake'; } catch { } + assert_false(trustedTypes.isScriptURL({})); }, 'TrustedTypePolicyFactory.isScriptURL cannot be redefined.'); test(t => { - try { TrustedTypes.isURL = () => 'fake'; } catch { } - assert_false(TrustedTypes.isURL({})); + try { trustedTypes.isURL = () => 'fake'; } catch { } + assert_false(trustedTypes.isURL({})); }, 'TrustedTypePolicyFactory.isURL cannot be redefined.'); // Redefinition tests, via Object.defineProperty. test(t => { try { Object.defineProperty(TrustedTypes, 'isHTML', () => 'fake'); } catch { } - assert_false(TrustedTypes.isHTML({})); + assert_false(trustedTypes.isHTML({})); }, 'TrustedTypePolicyFactory.IsHTML cannot be redefined via defineProperty.'); test(t => { try { Object.defineProperty(TrustedTypes, 'isScript', () => 'fake'); } catch { } - assert_false(TrustedTypes.isScript({})); + assert_false(trustedTypes.isScript({})); }, 'TrustedTypePolicyFactory.isScript cannot be redefined via definePropert.'); test(t => { try { Object.defineProperty(TrustedTypes, 'isScriptURL', () => 'fake'); } catch { } - assert_false(TrustedTypes.isScriptURL({})); + assert_false(trustedTypes.isScriptURL({})); }, 'TrustedTypePolicyFactory.isScriptURL cannot be redefined via definePropert.'); test(t => { try { Object.defineProperty(TrustedTypes, 'isURL', () => 'fake'); } catch { } - assert_false(TrustedTypes.isURL({})); + assert_false(trustedTypes.isURL({})); }, 'TrustedTypePolicyFactory.isURL cannot be redefined via definePropert.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html index 694e4d2..70f77b1b 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html
@@ -9,7 +9,7 @@ <div id="target"></div> <script> - const policy = TrustedTypes.createPolicy("anythinggoes", { + const policy = trustedTypes.createPolicy("anythinggoes", { "createHTML": x => x, "createScript": x => x, "createURL": x => x, @@ -41,7 +41,7 @@ // so we'll get decent error messages when it might fail. test(t => { // Collect all element and property names from getTypeMapping(). - const map = TrustedTypes.getTypeMapping(); + const map = trustedTypes.getTypeMapping(); for (let elem in map) { elements.push(elem); properties = properties.concat(Object.keys(map[elem].properties)); @@ -91,7 +91,7 @@ test(t => { const element = target.appendChild(document.createElement(elem)); t.add_cleanup(_ => element.remove()); - const expected_type = TrustedTypes.getPropertyType(elem, property); + const expected_type = trustedTypes.getPropertyType(elem, property); const value = create_value[type]; const test_fn = _ => { element[property] = value; }; if (type == expected_type || !expected_type) { @@ -129,7 +129,7 @@ test(t => { const element = target.appendChild(document.createElement(elem)); t.add_cleanup(_ => element.remove()); - const expected_type = TrustedTypes.getAttributeType(elem, property); + const expected_type = trustedTypes.getAttributeType(elem, property); const value = create_value[type]; const test_fn = _ => { element.setAttribute(property, value); }; if (type == expected_type || !expected_type) {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/Window-TrustedTypes.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/Window-TrustedTypes.tentative.html index 5bbb435..c61d9207 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/Window-TrustedTypes.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/Window-TrustedTypes.tentative.html
@@ -5,9 +5,9 @@ <body> <script> test(t => { - let factory = window.TrustedTypes; + let factory = window.trustedTypes; assert_true(factory instanceof TrustedTypePolicyFactory); - }, "factory = window.TrustedTypes"); + }, "factory = window.trustedTypes"); test(t => { assert_throws(new TypeError(), _ => {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html index 6ae5263..9dbfd7b 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html
@@ -18,7 +18,7 @@ // For the same reason we cannot use the otherwise preferred 'META: workers' // tag, since that test setup would be blocked as soon as trusted types // enforcement is enabled. -const test_setup_policy = TrustedTypes.createPolicy("hurrayanythinggoes", { +const test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", { createScriptURL: x => x}); const test_url = test_setup_policy.createScriptURL("support/WorkerGlobalScope-importScripts.https.js");
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-Node-multiple-arguments.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-Node-multiple-arguments.tentative.html index f84998d4..5552e13 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-Node-multiple-arguments.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-Node-multiple-arguments.tentative.html
@@ -10,7 +10,7 @@ <div id="container"></div> <script> const container = document.querySelector("#container"); - const policy = window.TrustedTypes.createPolicy("policy", { + const policy = window.trustedTypes.createPolicy("policy", { createScript: t => t, }); function stringify(arg) {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html index 4446a58..82e3120 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html
@@ -33,7 +33,7 @@ // After default policy creation string assignment implicitly calls createHTML. test(t => { - let p = window.TrustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); let parser = new DOMParser(); let doc = parser.parseFromString(INPUTS.HTML, "text/html"); assert_equals(doc.body.innerText, RESULTS.HTML);
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html index 2554ce6..468ed7b 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html
@@ -56,7 +56,7 @@ // After default policy creation string assignment implicitly calls createScript. test(t => { - let policy = window.TrustedTypes.createPolicy("default", { createScript: createScriptJS }, true); + let policy = window.trustedTypes.createPolicy("default", { createScript: createScriptJS }, true); setTimeout(INPUTS.SCRIPT); setInterval(INPUTS.SCRIPT); }, "`setTimeout(string)`, `setInterval(string)` via default policy (successful Script transformation).");
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html index 845df47..4defb56 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html
@@ -62,7 +62,7 @@ assert_equals(document.body.innerText, old); }, "`document.writeln(null)` throws"); - let default_policy = TrustedTypes.createPolicy('default', + let default_policy = trustedTypes.createPolicy('default', { createHTML: createHTMLJS }, true ); // Default policy works.
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html index ae1ace69..37a73f08 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html
@@ -93,7 +93,7 @@ // After default policy creation string assignment implicitly calls createHTML. test(t => { - let p = window.TrustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); var d = document.createElement('div'); container.appendChild(d);
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html index 945e3dd..8f314a26 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html
@@ -52,7 +52,7 @@ // After default policy creation string assignment implicitly calls createHTML. test(t => { - let p = window.TrustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); var d = document.createElement('div'); document.querySelector('#container').appendChild(d);
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html index d77d9da..3cae5d29 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
@@ -9,7 +9,7 @@ </head> <body> <script> - const nullPolicy = TrustedTypes.createPolicy('NullPolicy', {createScript: s => s}); + const nullPolicy = trustedTypes.createPolicy('NullPolicy', {createScript: s => s}); // TrustedURL Assignments const URLTestCases = [ @@ -93,7 +93,7 @@ }, "`Element.prototype.setAttribute.SrC = string` throws."); // After default policy creation string and null assignments implicitly call createXYZ - let p = window.TrustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS, createScript: createScriptJS }, true); + let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS, createScript: createScriptJS }, true); URLTestCases.forEach(c => { test(t => { assert_element_accepts_trusted_type(c[0], c[1], INPUTS.URL, RESULTS.URL);
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html index fe27d45..89d1216 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
@@ -69,7 +69,7 @@ }); // After default policy creation string and null assignments implicitly call createHTML - let p = window.TrustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS }, true); URLTestCases.forEach(c => { test(t => {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html index 4c295ff..8e89d0d 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html
@@ -36,7 +36,7 @@ }, "`location.assign = null` throws"); // Create default policy. Applies to all subsequent tests. - let p = window.TrustedTypes.createPolicy("default", + let p = window.trustedTypes.createPolicy("default", { createURL: createLocationURLJS }, true); // After default policy creation string assignment implicitly calls createURL.
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html index 86bce799..998ee21 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html
@@ -36,7 +36,7 @@ }, "`location.href = null` throws"); // Create default policy. Applies to all subsequent tests. - let p = window.TrustedTypes.createPolicy("default", + let p = window.trustedTypes.createPolicy("default", { createURL: createLocationURLJS }, true); // After default policy creation string assignment implicitly calls createURL.
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html index aa3af64..e85bb646 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html
@@ -36,7 +36,7 @@ }, "`location.replace = null` throws"); // Create default policy. Applies to all subsequent tests. - let p = window.TrustedTypes.createPolicy("default", + let p = window.trustedTypes.createPolicy("default", { createURL: createLocationURLJS }, true); // After default policy creation string assignment implicitly calls createURL.
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html index 4919b7f..61553eb 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html
@@ -36,7 +36,7 @@ // After default policy creation string assignment implicitly calls createHTML test(t => { - let p = window.TrustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true); var range = document.createRange(); range.selectNodeContents(document.documentElement); var result = range.createContextualFragment(INPUTS.HTML);
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html index c66a16d..e9c1c79 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html
@@ -64,7 +64,7 @@ }, "`document.open(null)` throws."); // After default policy creation string assignment implicitly calls createURL. - let p = window.TrustedTypes.createPolicy("default", { createURL: createURLJS }, true); + let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS }, true); test(t => { testWindowDoesntThrow(t, INPUTS.URL, RESULTS.URL, window); }, "'window.open(string)' assigned via default policy (successful URL transformation).");
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/default-policy-report-only.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/default-policy-report-only.tentative.html index 1170655..1a54fd6 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/default-policy-report-only.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/default-policy-report-only.tentative.html
@@ -70,7 +70,7 @@ return "sanitized: " + str; } -TrustedTypes.createPolicy("default", { +trustedTypes.createPolicy("default", { createURL: policy, createScriptURL: policy, createHTML: policy,
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/default-policy.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/default-policy.tentative.html index 68e05c130..672eccf 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/default-policy.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/default-policy.tentative.html
@@ -70,7 +70,7 @@ return "sanitized: " + str; } -TrustedTypes.createPolicy("default", { +trustedTypes.createPolicy("default", { createURL: policy, createScriptURL: policy, createHTML: policy,
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/eval-with-permissive-csp.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/eval-with-permissive-csp.tentative.html index 25b4948c..074fe79d 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/eval-with-permissive-csp.tentative.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/eval-with-permissive-csp.tentative.html
@@ -25,7 +25,7 @@ assert_equals("" + s, "Hello a cat string"); }, "eval with TrustedScript and permissive CSP works."); - TrustedTypes.createPolicy("default", { createScript: createScriptJS }, true); + trustedTypes.createPolicy("default", { createScript: createScriptJS }, true); test(t => { let s = eval('"Hello transformed untrusted string"'); assert_equals(s, "Hello a cat untrusted string");
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/idlharness.window.js b/third_party/blink/web_tests/external/wpt/trusted-types/idlharness.window.js index de136977..4c1ee6e0 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/idlharness.window.js +++ b/third_party/blink/web_tests/external/wpt/trusted-types/idlharness.window.js
@@ -6,12 +6,12 @@ ['dom', 'html'], idl_array => { idl_array.add_objects({ - TrustedTypePolicyFactory: ['window.TrustedTypes'], - TrustedTypePolicy: ['window.TrustedTypes.createPolicy("SomeName", { createHTML: s => s })'], - TrustedHTML: ['window.TrustedTypes.createPolicy("SomeName1", { createHTML: s => s }).createHTML("A string")'], - TrustedScript: ['window.TrustedTypes.createPolicy("SomeName2", { createScript: s => s }).createScript("A string")'], - TrustedScriptURL: ['window.TrustedTypes.createPolicy("SomeName3", { createScriptURL: s => s }).createScriptURL("A string")'], - TrustedURL: ['window.TrustedTypes.createPolicy("SomeName4", { createURL: s => s }).createURL("A string")'] + TrustedTypePolicyFactory: ['window.trustedTypes'], + TrustedTypePolicy: ['window.trustedTypes.createPolicy("SomeName", { createHTML: s => s })'], + TrustedHTML: ['window.trustedTypes.createPolicy("SomeName1", { createHTML: s => s }).createHTML("A string")'], + TrustedScript: ['window.trustedTypes.createPolicy("SomeName2", { createScript: s => s }).createScript("A string")'], + TrustedScriptURL: ['window.trustedTypes.createPolicy("SomeName3", { createScriptURL: s => s }).createScriptURL("A string")'], + TrustedURL: ['window.trustedTypes.createPolicy("SomeName4", { createURL: s => s }).createURL("A string")'] }); }, 'Trusted Types'
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-importScripts.https.js b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-importScripts.https.js index 8665c69..fa63c8ba 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-importScripts.https.js +++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-importScripts.https.js
@@ -1,4 +1,4 @@ -let test_setup_policy = TrustedTypes.createPolicy("hurrayanythinggoes", { +let test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", { createScriptURL: x => x }); importScripts(test_setup_policy.createScriptURL("/resources/testharness.js")); @@ -13,14 +13,14 @@ worker_type = "service worker"; } -let test_policy = TrustedTypes.createPolicy("xxx", { +let test_policy = trustedTypes.createPolicy("xxx", { createScriptURL: url => url.replace("play", "work") }); test(t => { self.result = "Fail"; let trusted_url = test_policy.createScriptURL("player.js"); - assert_true(this.TrustedTypes.isScriptURL(trusted_url)); + assert_true(this.trustedTypes.isScriptURL(trusted_url)); importScripts(trusted_url); // worker.js modifies self.result. assert_equals(self.result, "Pass"); }, "importScripts with TrustedScriptURL works in " + worker_type); @@ -63,7 +63,7 @@ }, "importScripts with two URLs, one trusted, in " + worker_type); // Test default policy application: -TrustedTypes.createPolicy("default", { +trustedTypes.createPolicy("default", { createScriptURL: url => url.replace("play", "work") }, true); test(t => {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/helper.sub.js b/third_party/blink/web_tests/external/wpt/trusted-types/support/helper.sub.js index 36ee240..d63ff54 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/support/helper.sub.js +++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/helper.sub.js
@@ -40,19 +40,19 @@ } function createHTML_policy(win, c) { - return win.TrustedTypes.createPolicy('SomeHTMLPolicyName' + c, { createHTML: createHTMLJS }); + return win.trustedTypes.createPolicy('SomeHTMLPolicyName' + c, { createHTML: createHTMLJS }); } function createScript_policy(win, c) { - return win.TrustedTypes.createPolicy('SomeScriptPolicyName' + c, { createScript: createScriptJS }); + return win.trustedTypes.createPolicy('SomeScriptPolicyName' + c, { createScript: createScriptJS }); } function createScriptURL_policy(win, c) { - return win.TrustedTypes.createPolicy('SomeScriptURLPolicyName' + c, { createScriptURL: createScriptURLJS }); + return win.trustedTypes.createPolicy('SomeScriptURLPolicyName' + c, { createScriptURL: createScriptURLJS }); } function createURL_policy(win, c) { - return win.TrustedTypes.createPolicy('SomeURLPolicyName' + c, { createURL: createURLJS }); + return win.trustedTypes.createPolicy('SomeURLPolicyName' + c, { createURL: createURLJS }); } function assert_element_accepts_trusted_html(win, c, t, tag, attribute, expected) {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.tentative.https.html index dc86536..e15ecfa 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.tentative.https.html
@@ -48,7 +48,7 @@ try { fn(); assert_unreached(); } catch (err) { /* ignore */ } } - // A sample policy we use to test TrustedTypes.createPolicy behaviour. + // A sample policy we use to test trustedTypes.createPolicy behaviour. const id = x => x; const a_policy = { createHTML: id, @@ -57,7 +57,7 @@ createScript: id, }; - const scriptyPolicy = TrustedTypes.createPolicy('allowEval', a_policy); + const scriptyPolicy = trustedTypes.createPolicy('allowEval', a_policy); // Provoke/wait for a CSP violation, in order to be sure that all previous // CSP violations have been delivered. @@ -96,7 +96,7 @@ }, "Trusted Type violation report: evaluating a Trusted Script violates script-src."); promise_test(t => { - TrustedTypes.createPolicy('default', { + trustedTypes.createPolicy('default', { createScript: s => s.replace('payload', 'default policy'), }, true); let p = Promise.resolve()
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-report-only.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-report-only.tentative.https.html index 1fb65459..bd8933a4 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-report-only.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting-report-only.tentative.https.html
@@ -48,7 +48,7 @@ try { fn(); assert_unreached(); } catch (err) { /* ignore */ } } - // A sample policy we use to test TrustedTypes.createPolicy behaviour. + // A sample policy we use to test trustedTypes.createPolicy behaviour. const id = x => x; const a_policy = { createHTML: id, @@ -57,7 +57,7 @@ createScript: id, }; - const scriptyPolicy = TrustedTypes.createPolicy('allowEval', a_policy); + const scriptyPolicy = trustedTypes.createPolicy('allowEval', a_policy); // Provoke/wait for a CSP violation, in order to be sure that all previous // CSP violations have been delivered. @@ -93,7 +93,7 @@ }, "Trusted Type violation report: evaluating a Trusted Script."); promise_test(t => { - TrustedTypes.createPolicy('default', { + trustedTypes.createPolicy('default', { createScript: s => s.replace('payload', 'default policy'), }, true); let p = promise_flush()();
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting.tentative.https.html index 4ec5db1..c751ae1 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-eval-reporting.tentative.https.html
@@ -42,7 +42,7 @@ try { fn(); assert_unreached(); } catch (err) { /* ignore */ } } - // A sample policy we use to test TrustedTypes.createPolicy behaviour. + // A sample policy we use to test trustedTypes.createPolicy behaviour. const id = x => x; const a_policy = { createHTML: id, @@ -50,7 +50,7 @@ createURL: id, createScript: id, }; - const scriptyPolicy = TrustedTypes.createPolicy('allowEval', a_policy); + const scriptyPolicy = trustedTypes.createPolicy('allowEval', a_policy); // Provoke/wait for a CSP violation, in order to be sure that all previous // CSP violations have been delivered. @@ -88,7 +88,7 @@ promise_test(t => { let beacon = 'never_overwritten'; - TrustedTypes.createPolicy('default', { + trustedTypes.createPolicy('default', { createScript: s => s.replace('payload', 'default policy'), }, true); let p = promise_flush()();
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-report-only.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-report-only.tentative.https.html index f33183b..1a17d529 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-report-only.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-report-only.tentative.https.html
@@ -34,9 +34,9 @@ }); } - // A sample policy we use to test TrustedTypes.createPolicy behaviour. + // A sample policy we use to test trustedTypes.createPolicy behaviour. const id = x => x; - const policy = TrustedTypes.createPolicy("two", { + const policy = trustedTypes.createPolicy("two", { createHTML: id, createScriptURL: id, createURL: id,
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting-check-report.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting-check-report.https.html index 1119077..fc98f5c 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting-check-report.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting-check-report.https.html
@@ -15,7 +15,7 @@ </head> <body> <script> - TrustedTypes.createPolicy("three", {}); + trustedTypes.createPolicy("three", {}); </script> <script async defer src='../content-security-policy/support/checkReport.sub.js?reportField=violated-directive&reportValue=trusted-types'></script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html index 0104ba3..6a79fec 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html
@@ -72,7 +72,7 @@ return e; } } - // A sample policy we use to test TrustedTypes.createPolicy behaviour. + // A sample policy we use to test trustedTypes.createPolicy behaviour. const id = x => x; const a_policy = { createHTML: id, @@ -101,14 +101,14 @@ .then(expect_sample("three")) .then(expect_blocked_uri("trusted-types-policy")) .then(promise_flush()); - expect_throws(_ => TrustedTypes.createPolicy("three", a_policy)); + expect_throws(_ => trustedTypes.createPolicy("three", a_policy)); flush(); return p; }, "Trusted Type violation report: creating a forbidden policy."); promise_test(t => { let p = promise_flush()(); - expect_throws(_ => TrustedTypes.createPolicy("two", a_policy)); + expect_throws(_ => trustedTypes.createPolicy("two", a_policy)); flush(); return p; }, "Trusted Type violation report: creating a report-only-forbidden policy."); @@ -120,7 +120,7 @@ let p = Promise.resolve() .then(promise_violation("trusted-types two")) .then(promise_flush()); - policy_one = TrustedTypes.createPolicy("one", a_policy); + policy_one = trustedTypes.createPolicy("one", a_policy); flush(); return p; }, "Trusted Type violation report: creating a forbidden-but-not-reported policy.");
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns-expected.txt b/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns-expected.txt index 0074a83..c60be850 100644 --- a/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns-expected.txt +++ b/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns-expected.txt
@@ -1,10 +1,10 @@ PASS window.getComputedStyle(gridFixedAndMinContentAndFlex, '').getPropertyValue('grid-template-columns') is "20px 30px 50px" PASS window.getComputedStyle(gridFixedAndMinContentAndFlexMultipleOverlap, '').getPropertyValue('grid-template-columns') is "20px 10px 70px" -PASS window.getComputedStyle(gridMinMaxFixedFlexAndMaxContentAndAuto, '').getPropertyValue('grid-template-columns') is "60px 20px 20px" -PASS window.getComputedStyle(gridMinMaxFixedFlexAndMaxContentAndAutoNoFlexSpanningItems, '').getPropertyValue('grid-template-columns') is "100px 0px 0px" +PASS window.getComputedStyle(gridMinMaxFixedFlexAndMaxContentAndAuto, '').getPropertyValue('grid-template-columns') is "30px 50px 20px" +PASS window.getComputedStyle(gridMinMaxFixedFlexAndMaxContentAndAutoNoFlexSpanningItems, '').getPropertyValue('grid-template-columns') is "30px 70px 0px" PASS window.getComputedStyle(gridMinMaxAutoFixedAndMinContentAndFixed, '').getPropertyValue('grid-template-columns') is "35px 20px 25px" PASS window.getComputedStyle(gridMinContentAndMinMaxFixedMinContentAndFlex, '').getPropertyValue('grid-template-columns') is "20px 20px 60px" -PASS window.getComputedStyle(gridMaxContentAndMinMaxFixedMaxContentAndFlex, '').getPropertyValue('grid-template-columns') is "70px 20px 10px" +PASS window.getComputedStyle(gridMaxContentAndMinMaxFixedMaxContentAndFlex, '').getPropertyValue('grid-template-columns') is "70px 20px 30px" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns.html b/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns.html index 113a142..0b68649 100644 --- a/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns.html +++ b/third_party/blink/web_tests/fast/css-grid-layout/flex-and-content-sized-resolution-columns.html
@@ -98,11 +98,11 @@ checkColumns("gridFixedAndMinContentAndFlex", "20px 30px 50px"); checkColumns("gridFixedAndMinContentAndFlexMultipleOverlap", "20px 10px 70px"); -checkColumns("gridMinMaxFixedFlexAndMaxContentAndAuto", "60px 20px 20px"); -checkColumns("gridMinMaxFixedFlexAndMaxContentAndAutoNoFlexSpanningItems", "100px 0px 0px"); +checkColumns("gridMinMaxFixedFlexAndMaxContentAndAuto", "30px 50px 20px"); +checkColumns("gridMinMaxFixedFlexAndMaxContentAndAutoNoFlexSpanningItems", "30px 70px 0px"); checkColumns("gridMinMaxAutoFixedAndMinContentAndFixed", "35px 20px 25px"); checkColumns("gridMinContentAndMinMaxFixedMinContentAndFlex", "20px 20px 60px"); -checkColumns("gridMaxContentAndMinMaxFixedMaxContentAndFlex", "70px 20px 10px"); +checkColumns("gridMaxContentAndMinMaxFixedMaxContentAndFlex", "70px 20px 30px"); </script> </html>
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index dcb6f0e..ef68b1d 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS window.cached_TrustedTypes.defaultPolicy is null PASS window.cached_applicationCache.oncached is null PASS window.cached_applicationCache.onchecking is null PASS window.cached_applicationCache.ondownloading is null @@ -108,6 +107,7 @@ PASS window.cached_statusbar.visible is false PASS window.cached_styleMedia.type is '' PASS window.cached_toolbar.visible is false +PASS window.cached_trustedTypes.defaultPolicy is null PASS window.cached_visualViewport.height is 0 PASS window.cached_visualViewport.offsetLeft is 0 PASS window.cached_visualViewport.offsetTop is 0
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index ed75ee3..40852a9 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS window.cached_TrustedTypes.defaultPolicy is null PASS window.cached_applicationCache.oncached is null PASS window.cached_applicationCache.onchecking is null PASS window.cached_applicationCache.ondownloading is null @@ -108,6 +107,7 @@ PASS window.cached_statusbar.visible is false PASS window.cached_styleMedia.type is '' PASS window.cached_toolbar.visible is false +PASS window.cached_trustedTypes.defaultPolicy is null PASS window.cached_visualViewport.height is 0 PASS window.cached_visualViewport.offsetLeft is 0 PASS window.cached_visualViewport.offsetTop is 0
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index e54c2b0..eedea18a 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS window.cached_TrustedTypes.defaultPolicy is null PASS window.cached_applicationCache.oncached is null PASS window.cached_applicationCache.onchecking is null PASS window.cached_applicationCache.ondownloading is null @@ -108,6 +107,7 @@ PASS window.cached_statusbar.visible is false PASS window.cached_styleMedia.type is '' PASS window.cached_toolbar.visible is false +PASS window.cached_trustedTypes.defaultPolicy is null PASS window.cached_visualViewport.height is 0 PASS window.cached_visualViewport.offsetLeft is 0 PASS window.cached_visualViewport.offsetTop is 0
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index 26a3eae2..e6bd51193 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS oldChildWindow.TrustedTypes.defaultPolicy is newChildWindow.TrustedTypes.defaultPolicy PASS oldChildWindow.applicationCache.oncached is newChildWindow.applicationCache.oncached PASS oldChildWindow.applicationCache.onchecking is newChildWindow.applicationCache.onchecking PASS oldChildWindow.applicationCache.ondownloading is newChildWindow.applicationCache.ondownloading @@ -244,6 +243,7 @@ PASS oldChildWindow.statusbar.visible is newChildWindow.statusbar.visible PASS oldChildWindow.styleMedia.type is newChildWindow.styleMedia.type PASS oldChildWindow.toolbar.visible is newChildWindow.toolbar.visible +PASS oldChildWindow.trustedTypes.defaultPolicy is newChildWindow.trustedTypes.defaultPolicy PASS oldChildWindow.visualViewport.height is newChildWindow.visualViewport.height PASS oldChildWindow.visualViewport.offsetLeft is newChildWindow.visualViewport.offsetLeft PASS oldChildWindow.visualViewport.offsetTop is newChildWindow.visualViewport.offsetTop
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index 0780dd8..c94a582 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS childWindow.TrustedTypes.defaultPolicy is null PASS childWindow.closed is true PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' @@ -179,6 +178,7 @@ PASS childWindow.statusbar.visible is false PASS childWindow.styleMedia.type is '' PASS childWindow.toolbar.visible is false +PASS childWindow.trustedTypes.defaultPolicy is null PASS childWindow.visualViewport.height is 0 PASS childWindow.visualViewport.offsetLeft is 0 PASS childWindow.visualViewport.offsetTop is 0
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index aa0c57a..636dcaca 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -3,7 +3,6 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS childWindow.TrustedTypes.defaultPolicy is null PASS childWindow.closed is true PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' @@ -179,6 +178,7 @@ PASS childWindow.statusbar.visible is false PASS childWindow.styleMedia.type is '' PASS childWindow.toolbar.visible is false +PASS childWindow.trustedTypes.defaultPolicy is null PASS childWindow.visualViewport.height is 0 PASS childWindow.visualViewport.offsetLeft is 0 PASS childWindow.visualViewport.offsetTop is 0
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-display-locked.js b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-display-locked.js index b33e6365..40ec9369 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-display-locked.js +++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-display-locked.js
@@ -8,16 +8,10 @@ await TestRunner.loadModule('console_test_runner'); await TestRunner.showPanel('elements'); await TestRunner.loadHTML(` - <div id="container" renderSubtree="invisible" style="content-size: 10px;"> + <div id="container" renderSubtree="invisible skip-activation" style="content-size: 10px;"> <div id="child" style="width: 50px; height: 50px;"></div> </div> `); - //await TestRunner.evaluateInPagePromise(` - // container.renderSubtree = "invisible"; - // await requestAnimationFrame(() => {}); - // //// force layout so that acquire finishes. - // //container.offsetTop; - //`); function dumpChild() { ElementsTestRunner.dumpInspectorHighlightJSON('child', TestRunner.completeTest.bind(TestRunner));
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/badging-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/badging-origin-trial-interfaces.html index c0ac874..be17e92 100644 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/badging-origin-trial-interfaces.html +++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/badging-origin-trial-interfaces.html
@@ -1,10 +1,10 @@ <!DOCTYPE html> <meta charset="utf-8"> <!-- Generate token with the command: -generate_token.py http://127.0.0.1:8000 Badging --expire-timestamp=2000000000 +generate_token.py http://127.0.0.1:8000 BadgingV2 --expire-timestamp=2000000000 --> -<meta http-equiv="origin-trial" content="AjMyKQIep8aE/3H2rfLKB0UEt0aGtfdVGult8LN5tjpYZnkhbaGEm8KirzODRym/5KnVfv33DaXex0tUZoDQFQ0AAABPeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQmFkZ2luZyIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==" /> +<meta http-equiv="origin-trial" content="AqzH1yAjqt/6grJkR3r1584FLOYa+kkfoenZBdnmBOShEN/eGrOF7OoxdPXg5e2b+KeB+ysH8qp/F9eyimHZygIAAABReyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQmFkZ2luZ1YyIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9" /> <title>Badging API - interfaces exposed by origin trial</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -19,4 +19,4 @@ assert_function_on(navigator, 'setExperimentalAppBadge', 'setExperimentalAppBadge is not defined on navigator'); assert_function_on(navigator, 'clearExperimentalAppBadge', 'clearExperimentalAppBadge is not defined on navigator'); }, 'Badge API interfaces and properties in Origin-Trial enabled document.'); -</script> \ No newline at end of file +</script>
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-origin-trial-interfaces.html deleted file mode 100644 index 4aab4c44..0000000 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-origin-trial-interfaces.html +++ /dev/null
@@ -1,156 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>WebXR - interfaces exposed by origin trial</title> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -<script src="../../../resources/origin-trials-helper.js"></script> -<script> -let properties_to_check = { - 'Navigator': ['xr'] -}; - -// The WebXR APIs should not be present without the token. -test(t => { - OriginTrialsHelper.check_properties_missing_unless_runtime_flag( - this, properties_to_check, 'webXREnabled'); -}, "WebXR's entrypoint properties are not available without a token."); - -test(() => { - if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { - assert_in_array('xr-spatial-tracking', document.featurePolicy.features()); - } else { - assert_equals(document.featurePolicy.features().indexOf("xr-spatial-tracking"), -1); - } -}, 'document.featurePolicy.features does not advertise xr-spatial-tracking without a token or flag.'); - -// Add the token, which was generated with the following command: -// tools/origin_trials/generate_token.py http://127.0.0.1:8000 WebXRDeviceM76 --expire-timestamp=2000000000 -let token = "AkyVxpb70lHShWfDAoWZVaVN2iZ9BxVFtnErcD8gysTmnF+SNXlduVTCLBpcr1V2q/MFrjeqPb2BlFALolT1bAwAAABWeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiV2ViWFJEZXZpY2VNNzYiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0="; -OriginTrialsHelper.add_token(token); - -// The WebXR APIs should be available now. -test(t => { - OriginTrialsHelper.check_properties_exist(this, properties_to_check); -}, "WebXR's entrypoint properties are available with origin trial token."); - -test(() => { - assert_in_array('xr-spatial-tracking', document.featurePolicy.features()); -}, 'document.featurePolicy.features advertises xr-spatial-tracking after token added.'); - -// Ensure Gamepad Extensions are NOT enabled by the WebXR origin trial token. -test(t => { - webvr_gamepad_properties = { - 'Gamepad': ['pose', 'hand', 'displayId'], - }; - OriginTrialsHelper.check_properties_missing_unless_runtime_flag( - this, webvr_gamepad_properties, 'webVREnabled'); -}, "WebVR-specific Gamepad properties are not available with a WebXR token."); -test(t => { - webvr_gamepad_interfaces = [ - 'GamepadPose' - ]; - OriginTrialsHelper.check_interfaces_missing_unless_runtime_flag( - this, webvr_gamepad_interfaces, 'webVREnabled'); -}, "WebVR-specific Gamepad interfaces are not available with a WebXR token."); - - -// Ensure that APIs that are not part of the core WebXR set are NOT enabled by -// the WebXR origin trial token. - -test(t => { - let ar_properties = { - 'XRSession': ['environmentBlendMode'] - }; - // TODO: Update AR support to use it's own runtime flag - OriginTrialsHelper.check_properties_missing_unless_runtime_flag( - this, ar_properties, 'webXRARModuleEnabled'); -}, "AR properties are not available with a WebXR token."); - -test(t => { - let hittest_properties = { - 'XRSession': ['requestHitTest'] - }; - OriginTrialsHelper.check_properties_missing_unless_runtime_flag( - this, hittest_properties, 'webXRHitTestEnabled'); -}, "Hit-test properties are not available with a WebXR token."); -test(t => { - let hittest_interfaces = [ - 'XRHitResult', - 'XRRay' - ]; - OriginTrialsHelper.check_interfaces_missing_unless_runtime_flag( - this, hittest_interfaces, 'webXRHitTestEnabled'); -}, "Hit-test interfaces are not available with a WebXR token."); - -test(t => { - let planes_properties = { - 'XRFrame': ['worldInformation'], - 'XRSession': ['worldTrackingState', 'updateWorldTrackingState'] - }; - OriginTrialsHelper.check_properties_missing_unless_runtime_flag( - this, planes_properties, 'webXRPlaneDetectionEnabled'); -}, "Plane properties are not available with a WebXR token."); -test(t => { - let planes_interfaces = [ - 'XRPlane', - 'XRPlaneDetectionState', - 'XRWorldInformation', - 'XRWorldTrackingState' - ]; - OriginTrialsHelper.check_interfaces_missing_unless_runtime_flag( - this, planes_interfaces, 'webXRPlaneDetectionEnabled'); -}, "Plane interfaces are not available with a WebXR token."); - - -// Ensure that AR sessions are not exposed as part of the WebXR origin trial. -// The webXREnabled check is effectively checking whether experimental features -// are enabled. This works as long as at least one AR feature is experimental. -promise_test(t => { - let promise = navigator.xr.supportsSession('immersive-ar'); - if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { - return promise_rejects(t, "NotSupportedError", promise); - } else { - return promise_rejects(t, new TypeError(), promise); - } -}, "immersive-ar is not recognized by supportsSession() with a WebXR token."); -promise_test(t => { - let promise = navigator.xr.requestSession('immersive-ar'); - if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { - return promise_rejects(t, "SecurityError", promise); - } else { - return promise_rejects(t, new TypeError(), promise); - } -}, "immersive-ar is not recognized by requestSession() with a WebXR token."); -// Verify the rejection reason matches that for other invalid enum values. -// It only makes sense to run these when the failure occurs. -if (!OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { - promise_test(t => { - return navigator.xr.supportsSession('invalid').then(function() { - assert_unreached("Promise should be rejected.") - }).catch(function(invalidReason) { - return navigator.xr.supportsSession('immersive-ar').then(function() { - assert_unreached("Promise should be rejected.") - }).catch(function(arReason) { - // Replace the enum value in the expected message. That is the only - // thing that should be different. - invalidReason.message = invalidReason.message.replace('invalid', 'immersive-ar'); - assert_object_equals(invalidReason, arReason); - }); - }); - }, "supportsSession('immersive-ar') result matches result for other invalid values."); - promise_test(t => { - return navigator.xr.requestSession('invalid').then(function() { - assert_unreached("Promise should be rejected.") - }).catch(function(invalidReason) { - return navigator.xr.requestSession('immersive-ar').then(function() { - assert_unreached("Promise should be rejected.") - }).catch(function(arReason) { - // Replace the enum value in the expected message. That is the only - // thing that should be different. - invalidReason.message = invalidReason.message.replace('invalid', 'immersive-ar'); - assert_object_equals(invalidReason, arReason); - }); - }); - }, "requestSession('immersive-ar') result matches result for other invalid values."); -} -</script>
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 82d14229..93fd88d 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -3765,7 +3765,6 @@ attribute console attribute globalThis attribute internals - getter TrustedTypesWorkers getter clients getter cookieStore getter onabortpayment @@ -3789,6 +3788,7 @@ getter onsync getter registration getter serviceWorker + getter trustedTypes method gc method skipWaiting setter cookieStore
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-get-platform-fonts-display-locked.js b/third_party/blink/web_tests/inspector-protocol/css/css-get-platform-fonts-display-locked.js index 3773117..03d1a520 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-get-platform-fonts-display-locked.js +++ b/third_party/blink/web_tests/inspector-protocol/css/css-get-platform-fonts-display-locked.js
@@ -29,7 +29,7 @@ `, 'Test css.getPlatformFontsForNode method with display locking.'); await session.evaluateAsync(async () => { - await requestAnimationFrame(() => { document.getElementById("parent").renderSubtree = "invisible"; }); + await requestAnimationFrame(() => { document.getElementById("parent").renderSubtree = "invisible skip-activation"; }); }); var CSSHelper = await testRunner.loadScript('../resources/css-helper.js');
diff --git a/third_party/blink/web_tests/virtual/cache-storage-eager-reading/external/wpt/service-workers/README.txt b/third_party/blink/web_tests/virtual/cache-storage-eager-reading/external/wpt/service-workers/README.txt new file mode 100644 index 0000000..5f43f63 --- /dev/null +++ b/third_party/blink/web_tests/virtual/cache-storage-eager-reading/external/wpt/service-workers/README.txt
@@ -0,0 +1,4 @@ +This suite runs the ServiceWorker and CacheStorage tests with the +CacheStorageEagerReading feature enabled. This makes CacheStorage immediately +read response bodies when cache.match() called within a FetchEvent handler. +See crbug.com/1010624.
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index e0ec92c9..e9c65a5a 100644 --- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1951,6 +1951,7 @@ method isVertexArray method lineWidth method linkProgram + method makeXRCompatible method pauseTransformFeedback method pixelStorei method polygonOffset @@ -2443,6 +2444,7 @@ method isTexture method lineWidth method linkProgram + method makeXRCompatible method pixelStorei method polygonOffset method readPixels
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt index aee6621..324728f0 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
@@ -18,4 +18,5 @@ sync-xhr usb vr +xr-spatial-tracking
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 5af578b..c2efd05 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1973,6 +1973,7 @@ [Worker] method isVertexArray [Worker] method lineWidth [Worker] method linkProgram +[Worker] method makeXRCompatible [Worker] method pauseTransformFeedback [Worker] method pixelStorei [Worker] method polygonOffset @@ -2465,6 +2466,7 @@ [Worker] method isTexture [Worker] method lineWidth [Worker] method linkProgram +[Worker] method makeXRCompatible [Worker] method pixelStorei [Worker] method polygonOffset [Worker] method readPixels
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 2aae6d3..5f8b634a 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
@@ -4324,6 +4324,7 @@ getter vendorSub getter webkitPersistentStorage getter webkitTemporaryStorage + getter xr method constructor method getBattery method getGamepads @@ -7953,6 +7954,7 @@ method isVertexArray method lineWidth method linkProgram + method makeXRCompatible method pauseTransformFeedback method pixelStorei method polygonOffset @@ -8449,6 +8451,7 @@ method isTexture method lineWidth method linkProgram + method makeXRCompatible method pixelStorei method polygonOffset method readPixels @@ -8750,6 +8753,139 @@ method constructor method iterateNext method snapshotItem +interface XR : EventTarget + attribute @@toStringTag + getter ondevicechange + method constructor + method isSessionSupported + method requestSession + method supportsSession + setter ondevicechange +interface XRBoundedReferenceSpace : XRReferenceSpace + attribute @@toStringTag + getter boundsGeometry + method constructor +interface XRFrame + attribute @@toStringTag + getter session + method constructor + method getPose + method getViewerPose +interface XRInputSource + attribute @@toStringTag + getter gripSpace + getter handedness + getter profiles + getter targetRayMode + getter targetRaySpace + method constructor +interface XRInputSourceArray + attribute @@toStringTag + getter length + method @@iterator + method constructor + method entries + method forEach + method keys + method values +interface XRInputSourceEvent : Event + attribute @@toStringTag + getter frame + getter inputSource + method constructor +interface XRInputSourcesChangeEvent : Event + attribute @@toStringTag + getter added + getter removed + getter session + method constructor +interface XRPose + attribute @@toStringTag + getter emulatedPosition + getter transform + method constructor +interface XRReferenceSpace : XRSpace + attribute @@toStringTag + getter onreset + method constructor + method getOffsetReferenceSpace + setter onreset +interface XRReferenceSpaceEvent : Event + attribute @@toStringTag + getter referenceSpace + getter transform + method constructor +interface XRRenderState + attribute @@toStringTag + getter baseLayer + getter depthFar + getter depthNear + getter inlineVerticalFieldOfView + method constructor +interface XRRigidTransform + attribute @@toStringTag + getter inverse + getter matrix + getter orientation + getter position + method constructor +interface XRSession : EventTarget + attribute @@toStringTag + getter inputSources + getter onend + getter oninputsourceschange + getter onselect + getter onselectend + getter onselectstart + getter onvisibilitychange + getter renderState + getter visibilityState + method cancelAnimationFrame + method constructor + method end + method requestAnimationFrame + method requestReferenceSpace + method updateRenderState + setter onend + setter oninputsourceschange + setter onselect + setter onselectend + setter onselectstart + setter onvisibilitychange +interface XRSessionEvent : Event + attribute @@toStringTag + getter session + method constructor +interface XRSpace : EventTarget + attribute @@toStringTag + method constructor +interface XRView + attribute @@toStringTag + getter eye + getter projectionMatrix + getter transform + method constructor +interface XRViewerPose : XRPose + attribute @@toStringTag + getter views + method constructor +interface XRViewport + attribute @@toStringTag + getter height + getter width + getter x + getter y + method constructor +interface XRWebGLLayer + static method getNativeFramebufferScaleFactor + attribute @@toStringTag + getter antialias + getter framebuffer + getter framebufferHeight + getter framebufferWidth + getter ignoreDepthValues + method constructor + method getViewport interface XSLTProcessor attribute @@toStringTag method clearParameters
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index 9a25a1e2..84ada2d 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1869,6 +1869,7 @@ [Worker] method isVertexArray [Worker] method lineWidth [Worker] method linkProgram +[Worker] method makeXRCompatible [Worker] method pauseTransformFeedback [Worker] method pixelStorei [Worker] method polygonOffset @@ -2361,6 +2362,7 @@ [Worker] method isTexture [Worker] method lineWidth [Worker] method linkProgram +[Worker] method makeXRCompatible [Worker] method pixelStorei [Worker] method polygonOffset [Worker] method readPixels
diff --git a/third_party/blink/web_tests/wake-lock/wakelock-document-hidden.https.html b/third_party/blink/web_tests/wake-lock/wakelock-document-hidden.https.html index 10cdcad..e0fc6b3 100644 --- a/third_party/blink/web_tests/wake-lock/wakelock-document-hidden.https.html +++ b/third_party/blink/web_tests/wake-lock/wakelock-document-hidden.https.html
@@ -20,7 +20,7 @@ const screenLock = WakeLock.request('screen'); window.testRunner.setPageVisibility('hidden'); assert_true(document.hidden); - return promise_rejects(t, "AbortError", screenLock); + return promise_rejects(t, "NotAllowedError", screenLock); }, "WakeLock.request('screen') aborts when the page is hidden"); promise_test(async t => { @@ -30,7 +30,7 @@ const screenLock = WakeLock.request('screen', { signal: controller.signal }); window.testRunner.setPageVisibility('hidden'); assert_true(document.hidden); - await promise_rejects(t, "AbortError", screenLock); + await promise_rejects(t, "NotAllowedError", screenLock); controller.abort(); }, "Aborting a rejected wake lock does not crash"); </script>
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 5e5121a..e6fff60 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -3866,10 +3866,10 @@ [Worker] attribute console [Worker] attribute globalThis [Worker] attribute internals -[Worker] getter TrustedTypesWorkers [Worker] getter name [Worker] getter onmessage [Worker] getter onmessageerror +[Worker] getter trustedTypes [Worker] method cancelAnimationFrame [Worker] method close [Worker] method gc
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index ac21954..94d36cd 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -11267,7 +11267,6 @@ attribute textInputController attribute top attribute window - getter TrustedTypes getter applicationCache getter caches getter clientInformation @@ -11428,6 +11427,7 @@ getter statusbar getter styleMedia getter toolbar + getter trustedTypes getter visualViewport getter webkitStorageInfo method NodeFilter
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index ccf0496..1b87eaa 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -3715,9 +3715,9 @@ [Worker] attribute console [Worker] attribute globalThis [Worker] attribute internals -[Worker] getter TrustedTypesWorkers [Worker] getter name [Worker] getter onconnect +[Worker] getter trustedTypes [Worker] method close [Worker] method gc [Worker] method webkitRequestFileSystem
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html index 30118b7..3dc49994d 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html
@@ -8,7 +8,7 @@ <body> <div id="container"> - <div id="locked" rendersubtree="invisible"> + <div id="locked" rendersubtree="invisible skip-activation"> locked <div id="child"> child
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html index df7de7a..c1c9ee1 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-on-display-contents.html
@@ -18,7 +18,7 @@ slot.style = "display: block;"; document.body.appendChild(slot); await setInvisible(slot).then(() => { - t.step(() => assert_equals(slot.renderSubtree, "invisible")); + t.step(() => assert_equals(slot.renderSubtree, INVISIBLE_NOT_ACTIVATABLE)); t.done(); }); }, "<slot> with changed display type can be locked");
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-focus.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-focus.html index bde2f4a..1f10a76 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-focus.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-focus.html
@@ -3,10 +3,11 @@ <head> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="../resources/utils.js"></script> </head> <body> -<div id="locked" rendersubtree="invisible activatable"> +<div id="locked" rendersubtree="invisible"> foo <div id="child" tabindex="0"> bar @@ -20,7 +21,7 @@ async_test(async(t) => { const lockedEl = document.getElementById("locked"); - t.step(() => { assert_equals(lockedEl.renderSubtree, "invisible activatable") }); + t.step(() => { assert_equals(lockedEl.renderSubtree, INVISIBLE_ACTIVATABLE) }); let axLocked = axElementById("locked"); t.step(() => { assert_equals(axLocked.childrenCount, 3, "Child count after acquire"); }); axElementById("child").takeFocus();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-press.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-press.html index 0ae0de2f..2fb80a7 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-press.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-press.html
@@ -3,10 +3,11 @@ <head> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="../resources/utils.js"></script> </head> <body> -<div id="locked" rendersubtree="invisible activatable"> +<div id="locked" rendersubtree="invisible"> foo <div id="child" tabindex="0"> bar @@ -20,7 +21,7 @@ async_test(async(t) => { const lockedEl = document.getElementById("locked"); - t.step(() => { assert_equals(lockedEl.renderSubtree, "invisible activatable") }); + t.step(() => { assert_equals(lockedEl.renderSubtree, INVISIBLE_ACTIVATABLE) }); let axLocked = axElementById("locked"); t.step(() => { assert_equals(axLocked.childrenCount, 3, "Child count after acquire"); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-scroll.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-scroll.html index bee65918..0cedebf 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-scroll.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/accessibility-activatable-scroll.html
@@ -3,10 +3,11 @@ <head> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="../resources/utils.js"></script> </head> <body> -<div id="locked" rendersubtree="invisible activatable"> +<div id="locked" rendersubtree="invisible"> foo <div id="child" tabindex="0"> bar @@ -20,7 +21,7 @@ async_test(async(t) => { const lockedEl = document.getElementById("locked"); - t.step(() => { assert_equals(lockedEl.renderSubtree, "invisible activatable") }); + t.step(() => { assert_equals(lockedEl.renderSubtree, INVISIBLE_ACTIVATABLE) }); let axLocked = axElementById("locked"); t.step(() => { assert_equals(axLocked.childrenCount, 3, "Child count after acquire"); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html index 169016e4..bc9ffb2 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links-ancestor.html
@@ -35,8 +35,8 @@ return new Promise((resolve, reject) => { prepareTest().then(() => { assert_equals(outermost.renderSubtree, ""); - assert_equals(outer.renderSubtree, "invisible activatable"); - assert_equals(inner.renderSubtree, "invisible activatable"); + assert_equals(outer.renderSubtree, INVISIBLE_ACTIVATABLE); + assert_equals(inner.renderSubtree, INVISIBLE_ACTIVATABLE); assert_equals(innermost.renderSubtree, ""); let innerPromise = new Promise((resolve, reject) => {
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html index b6d40ac1..4e6852d 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/anchor-links.html
@@ -31,7 +31,7 @@ promise_test(() => { return new Promise((resolve, reject) => { prepareTest().then(() => { - assert_equals(inner.renderSubtree, "invisible activatable"); + assert_equals(inner.renderSubtree, INVISIBLE_ACTIVATABLE); inner.onbeforeactivate = (e) => { assert_equals(e.activatedElement, inner); resolve();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html index cd282fa..9e71dfe 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/commit-in-beforeactivate.html
@@ -24,7 +24,7 @@ async function runTest() { const target = document.getElementById("target"); await setInvisibleActivatable(target); - t.step(() => assert_equals(target.renderSubtree, "invisible activatable")); + t.step(() => assert_equals(target.renderSubtree, INVISIBLE_ACTIVATABLE)); target.addEventListener("beforeactivate", () => commit(target)); target.scrollIntoView();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html index 5655cdb5..35cf768 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll-into-view-beforeactivate.html
@@ -34,8 +34,8 @@ return new Promise((resolve, reject) => { prepareTest().then(() => { assert_equals(outermost.renderSubtree, ""); - assert_equals(outer.renderSubtree, "invisible activatable"); - assert_equals(inner.renderSubtree, "invisible activatable"); + assert_equals(outer.renderSubtree, INVISIBLE_ACTIVATABLE); + assert_equals(inner.renderSubtree, INVISIBLE_ACTIVATABLE); assert_equals(innermost.renderSubtree, ""); let innerPromise = new Promise((resolve, reject) => {
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll.html index 9108983b..0170d33 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/scroll.html
@@ -8,9 +8,9 @@ <script src="/resources/testharnessreport.js"></script> <script src="../resources/utils.js"></script> -<div id=visible rendersubtree="invisible activatable">text</div> +<div id=visible rendersubtree="invisible">text</div> <div id=spacer style="height: 3000px">text</div> -<div id=target rendersubtree="invisible activatable">text</div> +<div id=target rendersubtree="invisible">text</div> <script> promise_test(() => {
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html index 8e823944..5336162 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html
@@ -30,7 +30,7 @@ window.getSelection().selectAllChildren(container); assert_equals(window.getSelection().toString(), "foo\nbar"); assert_equals(container.renderSubtree, ""); - assert_equals(nonActivatable.renderSubtree, "invisible"); + assert_equals(nonActivatable.renderSubtree, INVISIBLE_NOT_ACTIVATABLE); assert_equals(nested.renderSubtree, ""); resolve(); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/attribute/values.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/attribute/values.html index a22bd69e..559c926 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/attribute/values.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/attribute/values.html
@@ -3,18 +3,19 @@ <title>Tests rendersubtree attribute values</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="../resources/utils.js"></script> <script> test(() => { const element = document.createElement("div"); - element.setAttribute("rendersubtree", "invisible"); - assert_equals(element.getAttribute("rendersubtree"), "invisible"); - assert_equals(element.renderSubtree, "invisible"); + element.setAttribute("rendersubtree", INVISIBLE_ACTIVATABLE); + assert_equals(element.getAttribute("rendersubtree"), INVISIBLE_ACTIVATABLE); + assert_equals(element.renderSubtree, INVISIBLE_ACTIVATABLE); - element.setAttribute("rendersubtree", "invisible activatable"); - assert_equals(element.getAttribute("rendersubtree"), "invisible activatable"); - assert_equals(element.renderSubtree, "invisible activatable"); + element.setAttribute("rendersubtree", INVISIBLE_NOT_ACTIVATABLE); + assert_equals(element.getAttribute("rendersubtree"), INVISIBLE_NOT_ACTIVATABLE); + assert_equals(element.renderSubtree, INVISIBLE_NOT_ACTIVATABLE); element.setAttribute("rendersubtree", "not-visible"); assert_equals(element.getAttribute("rendersubtree"), "not-visible");
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html index 2bae9bf1..e2f09e4 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/containment/rendersubtree-adds-containment.html
@@ -9,7 +9,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/utils.js"></script> +<script src="../resources/utils.js"></script> <script> function setUp() { @@ -20,15 +20,15 @@ test(() => { setUp(); - container.setAttribute("rendersubtree", "invisible"); + container.setAttribute("rendersubtree", INVISIBLE_NOT_ACTIVATABLE); assert_equals(getComputedStyle(container).contain, "size layout style"); -}, "rendersubtree=invisible adds contain: size layout style;"); +}, "rendersubtree='invisible skip-activation' adds contain: size layout style;"); test(() => { setUp(); - container.setAttribute("rendersubtree", "invisible activatable"); + container.setAttribute("rendersubtree", INVISIBLE_ACTIVATABLE); assert_equals(getComputedStyle(container).contain, "size layout style"); -}, "rendersubtree='invisible activatable' adds contain: size layout style;"); +}, "rendersubtree='invisible' adds contain: size layout style;"); test(() => { setUp(); @@ -48,7 +48,7 @@ test(() => { setUp(); - container.setAttribute("rendersubtree", "invisible"); + container.setAttribute("rendersubtree", INVISIBLE_ACTIVATABLE); container.style = "contain: style;"; assert_equals(getComputedStyle(container).contain, "size layout style"); container.style = "contain: style layout;"; @@ -59,7 +59,7 @@ test(() => { setUp(); - container.setAttribute("rendersubtree", "invisible"); + container.setAttribute("rendersubtree", INVISIBLE_ACTIVATABLE); container.style = "contain: paint;"; assert_equals(getComputedStyle(container).contain, "size layout style paint"); container.style = "contain: strict;";
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/element-in-template.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/element-in-template.html index 879e1d3d..e6cad57 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/element-in-template.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/element-in-template.html
@@ -21,20 +21,20 @@ const acquirePromise = setInvisible(templateChild); await acquirePromise; - t.step(() => assert_equals(templateChild.renderSubtree, "invisible", "Can lock element in template")); + t.step(() => assert_equals(templateChild.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "Can lock element in template")); const adoptedNode = document.adoptNode(templateChild); - t.step(() => assert_equals(adoptedNode.renderSubtree, "invisible", "Adopted element is still locked")); + t.step(() => assert_equals(adoptedNode.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "Adopted element is still locked")); container.appendChild(adoptedNode); - t.step(() => assert_equals(adoptedNode.renderSubtree, "invisible", "Still locked after appended")); + t.step(() => assert_equals(adoptedNode.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "Still locked after appended")); await setVisible(adoptedNode); t.step(() => assert_equals(adoptedNode.renderSubtree, "", "Can commit")); await setInvisible(adoptedNode); - t.step(() => assert_equals(adoptedNode.renderSubtree, "invisible", "Can re-lock element")); + t.step(() => assert_equals(adoptedNode.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "Can re-lock element")); await setVisible(adoptedNode); t.step(() => assert_equals(adoptedNode.renderSubtree, "", "Can re-commit element"));
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html index d521599..4cc9acc 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
@@ -16,16 +16,16 @@ async function runTest() { const container = document.getElementById("container"); const acquire_promise = setInvisible(container); - t.step(() => assert_equals(container.renderSubtree, "invisible", "context before acquire finishes is locked")); + t.step(() => assert_equals(container.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "context before acquire finishes is locked")); await acquire_promise; - t.step(() => assert_equals(container.renderSubtree, "invisible", "context after acquire finishes is locked")); + t.step(() => assert_equals(container.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "context after acquire finishes is locked")); const update_promise = container.updateRendering(); - t.step(() => assert_equals(container.renderSubtree, "invisible", "context during update is locked")); + t.step(() => assert_equals(container.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "context during update is locked")); await update_promise; - t.step(() => assert_equals(container.renderSubtree, "invisible", "context after update is locked")); + t.step(() => assert_equals(container.renderSubtree, INVISIBLE_NOT_ACTIVATABLE, "context after update is locked")); const commit_promise = setVisible(container); t.step(() => assert_equals(container.renderSubtree, "", "context during commit is unlocked"));
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/resources/utils.js b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/resources/utils.js index 3e6d56e..aa3ac0f 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/resources/utils.js +++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/resources/utils.js
@@ -1,10 +1,12 @@ +const INVISIBLE_ACTIVATABLE = "invisible"; +const INVISIBLE_NOT_ACTIVATABLE = "invisible skip-activation"; function setInvisible(element) { - return setRenderSubtree(element, "invisible"); + return setRenderSubtree(element, INVISIBLE_NOT_ACTIVATABLE); } function setInvisibleActivatable(element) { - return setRenderSubtree(element, "invisible activatable"); + return setRenderSubtree(element, INVISIBLE_ACTIVATABLE); } function setVisible(element) {
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium index 39092bf..a73a85c 100644 --- a/third_party/inspector_protocol/README.chromium +++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@ Short Name: inspector_protocol URL: https://chromium.googlesource.com/deps/inspector_protocol/ Version: 0 -Revision: ed2845d5409a04d3c87655f0b55e87a66e806de2 +Revision: a14dad30f0e5b0fc05911856d5a20b1ffe89fd9b License: BSD License File: LICENSE Security Critical: yes
diff --git a/third_party/inspector_protocol/bindings/bindings.h b/third_party/inspector_protocol/bindings/bindings.h index 6ae15ac5..50c83f0 100644 --- a/third_party/inspector_protocol/bindings/bindings.h +++ b/third_party/inspector_protocol/bindings/bindings.h
@@ -58,10 +58,9 @@ return is_just_ ? value_ : default_value; } bool isJust() const { return is_just_; } - // TODO(johannes): |is_just_| isn't reset by this operation - - // introduce && to ensure avoiding continued usage of |this|? T takeJust() { assert(is_just_); + is_just_ = false; return std::move(value_); }
diff --git a/third_party/inspector_protocol/code_generator.py b/third_party/inspector_protocol/code_generator.py index 7c72cc7..5cf5a308 100755 --- a/third_party/inspector_protocol/code_generator.py +++ b/third_party/inspector_protocol/code_generator.py
@@ -43,6 +43,9 @@ items = [(k, os.path.join(output_base, v) if k == "output" else v) for (k, v) in items] keys, values = list(zip(*items)) + # 'async' is a keyword since Python 3.7. + # Avoid namedtuple(rename=True) for compatibility with Python 2.X. + keys = tuple('async_' if k == 'async' else k for k in keys) return collections.namedtuple('X', keys)(*values) return json.loads(data, object_hook=json_object_hook) @@ -555,7 +558,7 @@ if not self.config.protocol.options: return False return self.check_options(self.config.protocol.options, domain, command, - "async", None, False) + "async_", None, False) def is_exported(self, domain, name): if not self.config.protocol.options:
diff --git a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template index 982e2c61..b1c3ab7 100644 --- a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template +++ b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
@@ -385,7 +385,6 @@ {% endif %} return; {% else %} - std::unique_ptr<DispatcherBase::WeakPtr> weak = weakPtr(); std::unique_ptr<{{command_name_title}}CallbackImpl> callback(new {{command.name | to_title_case}}CallbackImpl(weakPtr(), callId, method, message)); m_backend->{{command.name | to_method_case}}( {%- for property in command.parameters -%}
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html index e32cb9d..ae5646a 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html
@@ -62,6 +62,7 @@ import {QueryArgs} from '../js/cottontail/src/util/query-args.js'; import {FallbackHelper} from '../js/cottontail/src/util/fallback-helper.js'; import {Node} from '../js/cottontail/src/core/node.js'; + import {RayNode} from '../js/cottontail/src/nodes/ray-node.js'; import {DropShadowNode} from '../js/cottontail/src/nodes/drop-shadow.js'; import {vec3} from '../js/cottontail/src/math/gl-matrix.js'; @@ -75,6 +76,10 @@ // XR globals. let xrButton = null; let xrRefSpace = null; + let xrLocalFloor = null; + let xrViewerSpace = null; + let xrOffsetSpace = null; + let xrViewerSpaceHitTestSource = null; // WebGL scene globals. let gl = null; @@ -82,6 +87,35 @@ let scene = new Scene(); scene.enableStats(false); + // Visualise the origin. + { + let xRay = new RayNode({direction : [5, 0, 0], baseColor : [1, 0, 0, 1]}); + let yRay = new RayNode({direction : [0, 5, 0], baseColor : [0, 1, 0, 1]}); + let zRay = new RayNode({direction : [0, 0, 5], baseColor : [0, 0, 1, 1]}); + + scene.addNode(xRay); + scene.addNode(yRay); + scene.addNode(zRay); + } + + // Visualise the offset space. + let offsetSpaceNode = new Node(); + offsetSpaceNode.visible = false; + + { + let xRay = new RayNode({direction : [5, 0, 0], baseColor : [1, 0, 0, 1]}); + let yRay = new RayNode({direction : [0, 5, 0], baseColor : [0, 1, 0, 1]}); + let zRay = new RayNode({direction : [0, 0, 5], baseColor : [0, 0, 1, 1]}); + + offsetSpaceNode.addNode(xRay); + offsetSpaceNode.addNode(yRay); + offsetSpaceNode.addNode(zRay); + } + + scene.addNode(offsetSpaceNode); + + // ----------------------------------------------------------------------- + let arObject = new Node(); arObject.visible = false; scene.addNode(arObject); @@ -114,7 +148,10 @@ } function onRequestSession() { - navigator.xr.requestSession('immersive-ar').then((session) => { + let options = { + requiredFeatures: ['local-floor'], + }; + navigator.xr.requestSession('immersive-ar', options).then((session) => { session.mode = 'immersive-ar'; xrButton.setSession(session); onSessionStarted(session); @@ -124,6 +161,7 @@ function onSessionStarted(session) { session.addEventListener('end', onSessionEnded); session.addEventListener('select', onSelect); + session.addEventListener('inputsourceschange', onInputSourcesChange); if (!gl) { gl = createWebGLContext({ @@ -139,7 +177,36 @@ session.requestReferenceSpace('local').then((refSpace) => { xrRefSpace = refSpace; - session.requestAnimationFrame(onXRFrame); + + session.requestReferenceSpace('local-floor').then((localFloor) => { + xrLocalFloor = localFloor; + + session.requestReferenceSpace('viewer').then((viewerSpace) => { + xrViewerSpace = viewerSpace; + + xrOffsetSpace = xrViewerSpace.getOffsetReferenceSpace( + new XRRigidTransform(new DOMPointReadOnly(0.1, 0, 0.5)) + ); + + if (useReticle.checked) { + console.debug("Requesting hit test source."); + session.requestHitTestSource({ + space : xrViewerSpace, + //space : xrLocalFloor, // WIP: change back to viewer + //space : xrOffsetSpace, // WIP: change back to viewer + offsetRay : new XRRay() + //offsetRay : new XRRay(new DOMPointReadOnly(0,.5,-.5), new DOMPointReadOnly(0, -0.5, -1)) // WIP: change back to default + }).then((hitTestSource) => { + console.debug("Hit test source created."); + xrViewerSpaceHitTestSource = hitTestSource; + }).catch(error => { + console.error("Error when requesting hit test source", error); + }); + } + + session.requestAnimationFrame(onXRFrame); + }); + }); }); } @@ -176,10 +243,11 @@ let rayOrigin = vec3.create(); let rayDirection = vec3.create(); + function onSelect(event) { if (useReticle.checked && arObject.visible) { // If we're using the reticle then we've already got a mesh positioned - // at the latest hit point and we should just use it's matrix to save + // at the latest hit point and we should just use its matrix to save // an unnecessary requestHitTest call. addARObjectAt(arObject.matrix); } else { @@ -207,34 +275,36 @@ } } + function onInputSourcesChange(inputSourcesChangeEvent) { + console.debug("Input sources changed!", inputSourcesChangeEvent); + } + // Called every time a XRSession requests that a new frame be drawn. function onXRFrame(t, frame) { let session = frame.session; let pose = frame.getViewerPose(xrRefSpace); + let viewerSpacePose = frame.getPose(xrViewerSpace, xrRefSpace); + let offsetSpacePose = frame.getPose(xrOffsetSpace, xrRefSpace); - // If requested, use the pose to cast a reticle into the scene using a - // continuous hit test. For the moment we're just using the flower - // as the "reticle". - if (useReticle.checked && pose && pose.transform.matrix) { - vec3.set(rayOrigin, 0, 0, 0); - vec3.transformMat4(rayOrigin, rayOrigin, pose.transform.matrix); + if(offsetSpacePose) { + offsetSpaceNode.matrix = offsetSpacePose.transform.matrix; + offsetSpaceNode.visible = true; + } else { + offsetSpaceNode.visible = false; + } - vec3.set(rayDirection, 0, 0, -1); - vec3.transformMat4(rayDirection, rayDirection, pose.transform.matrix); - vec3.sub(rayDirection, rayDirection, rayOrigin); - vec3.normalize(rayDirection, rayDirection); + if (useReticle.checked && xrViewerSpaceHitTestSource) { + let results = frame.getHitTestResults(xrViewerSpaceHitTestSource); - let ray = new XRRay(DOMPointFromVec3(rayOrigin), DOMPointFromVec3(rayDirection)); - session.requestHitTest(ray, xrRefSpace).then((results) => { - // When the hit test returns use it to place our proxy object. - if (results.length) { - let hitResult = results[0]; - arObject.visible = true; - arObject.matrix = hitResult.hitMatrix; - } else { - arObject.visible = false; - } - }); + // Use the results to place our proxy object. + if (results.length) { + let hitResult = results[0]; + arObject.visible = true; + arObject.matrix = hitResult.getPose(xrRefSpace).transform.matrix; + } else { + arObject.visible = false; + } + } else { arObject.visible = false; }
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py index ceedb91..e6c76497 100755 --- a/tools/idl_parser/idl_parser.py +++ b/tools/idl_parser/idl_parser.py
@@ -274,14 +274,20 @@ | ATTRIBUTE | CALLBACK | CONST + | CONSTRUCTOR | DELETER | DICTIONARY | ENUM | GETTER | INCLUDES | INHERIT + | INTERFACE + | ITERABLE + | MAPLIKE | NAMESPACE | PARTIAL + | REQUIRED + | SETLIKE | SETTER | STATIC | STRINGIFIER @@ -555,13 +561,22 @@ p[0] = self.BuildNamed('Operation', p, 1, arguments) def p_OptionalOperationName(self, p): - """OptionalOperationName : identifier + """OptionalOperationName : OperationName |""" if len(p) > 1: p[0] = p[1] else: p[0] = '' + def p_OperationName(self, p): + """OperationName : OperationNameKeyword + | identifier""" + p[0] = p[1] + + def p_OperationNameKeyword(self, p): + """OperationNameKeyword : INCLUDES""" + p[0] = p[1] + def p_ArgumentList(self, p): """ArgumentList : Argument Arguments |"""
diff --git a/tools/idl_parser/test_parser/interface_web.idl b/tools/idl_parser/test_parser/interface_web.idl index 10ac458..97dc116 100644 --- a/tools/idl_parser/test_parser/interface_web.idl +++ b/tools/idl_parser/test_parser/interface_web.idl
@@ -152,6 +152,33 @@ }; /** TREE + *Interface(IFaceAllowedKeywords) + * Attribute(async) + * Type() + * PrimitiveType(long) + * Operation(includes) + * Arguments() + * Argument(async) + * Type() + * PrimitiveType(long) + * Argument(constructor) + * Type() + * PrimitiveType(long) + * Type() + * PrimitiveType(void) + * Attribute(constructor) + * Type() + * PrimitiveType(long) + * Error(Unexpected constructor.) + */ +interface IFaceAllowedKeywords { + attribute long async; + void includes(long async, long constructor); + attribute long _constructor; + attribute long constructor; +}; + +/** TREE *Interface(MyIfaceDefalutValue) * Operation(foo) * Arguments() @@ -667,19 +694,3 @@ * REFERENCE: Bar */ Foo includes Bar; - -/** TREE - *Interface(IFaceWithKeyword) - * Operation(includes) - * Arguments() - * Argument(val) - * Type() - * StringType(DOMString) - * Type() - * PrimitiveType(void) - */ -interface IFaceWithKeyword { - // '_' prefix needs to be removed in tokenization. - // https://heycam.github.io/webidl/#idl-names - void _includes(DOMString val); -};
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 4ab8cc8..4f55d66 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -1863,6 +1863,9 @@ </action> <action name="Android.DownloadManager.List.Selection.Menu.Images.Action"> + <obsolete> + Deprecated October 2019. Feature dropped during implementation review. + </obsolete> <owner>dtrainor@chromium.org</owner> <description> User triggered a menu action on the images section header of download home.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index fd88c0e..9a236d8e 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1241,6 +1241,10 @@ </enum> <enum name="Android.DownloadManager.List.Section.Menu.Actions"> + <obsolete> + Deprecated 10/2019. Section menu button was removed during Download Home V2 + implementation review. + </obsolete> <int value="0" label="START_SELECTING"/> <int value="1" label="SHARE_ALL"/> <int value="2" label="DELETE_ALL"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a76bc737..84399ac 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -2346,6 +2346,10 @@ <histogram name="Android.DownloadManager.List.Section.Menu.Images.Action" enum="Android.DownloadManager.List.Section.Menu.Actions"> + <obsolete> + Deprecated October 2019. The feature was dropped during implementation + review. + </obsolete> <owner>dtrainor@chromium.org</owner> <owner>shaktisahu@chromium.org</owner> <owner>clank-downloads@google.com</owner> @@ -144395,6 +144399,9 @@ </histogram> <histogram name="Sync.Preferences.SyncingUnknownPrefs" units="prefs"> + <obsolete> + Deprecated in M79 because support for lazy pref registration was removed. + </obsolete> <owner>tschumann@chromium.org</owner> <owner>treib@chromium.org</owner> <summary>
diff --git a/tools/perf/core/results_processor/processor.py b/tools/perf/core/results_processor/processor.py index 4e22cd5f..d16a0c7 100644 --- a/tools/perf/core/results_processor/processor.py +++ b/tools/perf/core/results_processor/processor.py
@@ -20,7 +20,6 @@ from core.results_processor import formatters from core.results_processor import util -from tracing.trace_data import trace_data from tracing.value.diagnostics import generic_set from tracing.value.diagnostics import reserved_infos from tracing.value import histogram_set @@ -47,7 +46,7 @@ intermediate_results = _LoadIntermediateResults( os.path.join(options.intermediate_dir, TELEMETRY_RESULTS)) - AggregateTraces(intermediate_results) + _AggregateTraces(intermediate_results) UploadArtifacts( intermediate_results, options.upload_bucket, options.results_label) @@ -100,7 +99,7 @@ return results -def AggregateTraces(intermediate_results): +def _AggregateTraces(intermediate_results): """Replace individual traces with an aggregate one for each test result. For each test run with traces, generates an aggregate HTML trace. Removes @@ -110,16 +109,10 @@ artifacts = result.get('outputArtifacts', {}) traces = [name for name in artifacts if name.startswith('trace/')] if len(traces) > 0: - if compute_metrics.HTML_TRACE_NAME not in artifacts: - trace_files = [artifacts[name]['filePath'] for name in traces] - html_path = os.path.join( - os.path.dirname(os.path.commonprefix(trace_files)), - compute_metrics.HTML_TRACE_NAME) - trace_data.SerializeAsHtml(trace_files, html_path) - artifacts[compute_metrics.HTML_TRACE_NAME] = { - 'filePath': html_path, - 'contentType': 'text/html', - } + # For now, the html trace is generated by Telemetry, so it should be there + # already. All we need to do is remove individual traces from the dict. + # TODO(crbug.com/981349): replace this with actual aggregation code. + assert compute_metrics.HTML_TRACE_NAME in artifacts for trace in traces: del artifacts[trace]
diff --git a/tools/perf/core/results_processor/processor_test.py b/tools/perf/core/results_processor/processor_test.py index b25893d4..a755845 100644 --- a/tools/perf/core/results_processor/processor_test.py +++ b/tools/perf/core/results_processor/processor_test.py
@@ -24,7 +24,6 @@ from core.results_processor import processor from core.results_processor import testing -from tracing.value.diagnostics import generic_set from tracing.value import histogram from tracing.value import histogram_set from tracing_build import render_histograms_viewer @@ -269,45 +268,12 @@ out_histograms = histogram_set.HistogramSet() out_histograms.ImportDicts(results) + self.assertEqual(len(out_histograms), 4) + self.assertIsNotNone(out_histograms.GetHistogramNamed('foo')) - # sampleMetric records a histogram with the name 'foo'. - hist = out_histograms.GetHistogramNamed('foo') - self.assertIsNotNone(hist) - self.assertEqual(hist.diagnostics['traceUrls'], - generic_set.GenericSet(['gs://trace.html'])) - - def testHistogramsOutputNoAggregatedTrace(self): - json_trace = os.path.join(self.output_dir, 'trace.json') - with open(json_trace, 'w') as f: - json.dump({'traceEvents': []}, f) - - self.SerializeIntermediateResults( - test_results=[ - testing.TestResult( - 'benchmark/story', - output_artifacts={'trace/json': testing.Artifact(json_trace)}, - tags=['tbmv2:sampleMetric'], - ), - ], - ) - - processor.main([ - '--output-format', 'histograms', - '--output-dir', self.output_dir, - '--intermediate-dir', self.intermediate_dir, - ]) - - with open(os.path.join( - self.output_dir, histograms_output.OUTPUT_FILENAME)) as f: - results = json.load(f) - - out_histograms = histogram_set.HistogramSet() - out_histograms.ImportDicts(results) - - # sampleMetric records a histogram with the name 'foo'. - hist = out_histograms.GetHistogramNamed('foo') - self.assertIsNotNone(hist) - self.assertIn('traceUrls', hist.diagnostics) + diag_values = [list(v) for v in out_histograms.shared_diagnostics] + self.assertEqual(len(diag_values), 1) + self.assertIn(['gs://trace.html'], diag_values) def testHtmlOutput(self): hist_file = os.path.join(self.output_dir,
diff --git a/tools/perf/core/results_processor/processor_unittest.py b/tools/perf/core/results_processor/processor_unittest.py index d2de1e5..192f37e 100644 --- a/tools/perf/core/results_processor/processor_unittest.py +++ b/tools/perf/core/results_processor/processor_unittest.py
@@ -94,55 +94,3 @@ 'src_abc_123_20191001T120000_54321/benchmark/story/trace.html', '/trace.html' ) - - def testAggregateTraces(self): - in_results = testing.IntermediateResults( - test_results=[ - testing.TestResult( - 'benchmark/story1', - output_artifacts={ - 'trace/1.json': testing.Artifact( - '/artifacts/test_run/story1/trace/1.json'), - }, - ), - testing.TestResult( - 'benchmark/story2', - output_artifacts={ - 'trace/1.json': testing.Artifact( - '/artifacts/test_run/story2/trace/1.json'), - 'trace/2.json': testing.Artifact( - '/artifacts/test_run/story2/trace/2.json'), - }, - ), - ], - ) - - with mock.patch('tracing.trace_data.trace_data.SerializeAsHtml') as patch: - processor.AggregateTraces(in_results) - - call_list = [list(call[0]) for call in patch.call_args_list] - self.assertEqual(len(call_list), 2) - for call in call_list: - call[0] = set(call[0]) - self.assertIn( - [ - set(['/artifacts/test_run/story1/trace/1.json']), - '/artifacts/test_run/story1/trace/trace.html', - ], - call_list - ) - self.assertIn( - [ - set([ - '/artifacts/test_run/story2/trace/1.json', - '/artifacts/test_run/story2/trace/2.json', - ]), - '/artifacts/test_run/story2/trace/trace.html', - ], - call_list - ) - - for result in in_results['testResults']: - artifacts = result['outputArtifacts'] - self.assertEqual(len(artifacts), 1) - self.assertEqual(artifacts.keys()[0], 'trace.html')
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 6ba2b78..4490ef1 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -58,6 +58,8 @@ crbug.com/978159 [ android-nexus-5x android-webview ] blink_perf.canvas/* [ Skip ] crbug.com/994912 [ android-webview ] blink_perf.canvas/transferFromImageBitmap_RAF.html?RAF [ Skip ] crbug.com/994912 [ android-webview ] blink_perf.canvas/transferFromImageBitmap.html [ Skip ] +crbug.com/1013618 [ android-webview ] blink_perf.canvas/putImageData.html [ Skip ] +crbug.com/1013618 [ android-webview ] blink_perf.canvas/putImageData_RAF.html?RAF [ Skip ] # Benchmark: blink_perf.css crbug.com/891878 [ android-nexus-5x android-webview ] blink_perf.css/CustomPropertiesVarAlias.html [ Skip ]
diff --git a/tools/perf/page_sets/rendering/maps.py b/tools/perf/page_sets/rendering/maps.py index 4e04c09..932e538 100644 --- a/tools/perf/page_sets/rendering/maps.py +++ b/tools/perf/page_sets/rendering/maps.py
@@ -25,8 +25,7 @@ """ BASE_NAME = 'maps_perf_test' URL = 'file://performance.html' - TAGS = [story_tags.REQUIRED_WEBGL, story_tags.MAPS, - story_tags.REPRESENTATIVE_MOBILE] + TAGS = [story_tags.REQUIRED_WEBGL, story_tags.MAPS] def __init__(self, page_set,
diff --git a/tools/perf/page_sets/rendering/motionmark.py b/tools/perf/page_sets/rendering/motionmark.py index 3af6dcf..ac39b626 100644 --- a/tools/perf/page_sets/rendering/motionmark.py +++ b/tools/perf/page_sets/rendering/motionmark.py
@@ -122,7 +122,6 @@ class MotionmarkHTMLCSSBouncingBlendCircles25(MotionMarkPage): BASE_NAME = 'motionmark_html_css_bouncing_blend_circles_25' URL = MotionMarkPage.GetUrl('HTML suite', 'CSS bouncing blend circles', 25) - TAGS = MotionMarkPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] # Why: MotionMark HTML case """
diff --git a/tools/perf/page_sets/rendering/top_real_world_desktop.py b/tools/perf/page_sets/rendering/top_real_world_desktop.py index 0667a276..a6909a55 100644 --- a/tools/perf/page_sets/rendering/top_real_world_desktop.py +++ b/tools/perf/page_sets/rendering/top_real_world_desktop.py
@@ -40,8 +40,6 @@ BASE_NAME = 'google_web_search' YEAR = '2018' URL = 'https://www.google.com/#hl=en&q=barack+obama' - TAGS = TopRealWorldDesktopPage.TAGS + [ - story_tags.REPRESENTATIVE_WIN_DESKTOP] def __init__(self, page_set, @@ -153,7 +151,6 @@ YEAR = '2018' # pylint: disable=line-too-long URL = 'http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/' - TAGS = TopRealWorldDesktopPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] def __init__(self, page_set, @@ -264,7 +261,6 @@ BASE_NAME = 'pinterest' YEAR = '2018' URL = 'https://www.pinterest.com/search/pins/?q=flowers&rs=typed' - TAGS = TopRealWorldDesktopPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] def __init__(self, page_set, @@ -301,6 +297,10 @@ BASE_NAME = 'twitch' YEAR = '2018' URL = 'https://www.twitch.tv' + TAGS = TopRealWorldDesktopPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] def __init__(self, page_set, @@ -428,7 +428,6 @@ BASE_NAME = 'yahoo_news' YEAR = '2018' URL = 'http://news.yahoo.com' - TAGS = TopRealWorldDesktopPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class CNNNews2018Page(TopRealWorldDesktopPage): @@ -472,7 +471,6 @@ BASE_NAME = 'yahoo_sports' YEAR = '2018' URL = 'http://sports.yahoo.com/' - TAGS = TopRealWorldDesktopPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class TechCrunch2018Page(TopRealWorldDesktopPage):
diff --git a/tools/perf/page_sets/rendering/tough_animation_cases.py b/tools/perf/page_sets/rendering/tough_animation_cases.py index ad66356..abade9f 100644 --- a/tools/perf/page_sets/rendering/tough_animation_cases.py +++ b/tools/perf/page_sets/rendering/tough_animation_cases.py
@@ -44,6 +44,10 @@ """Why: Tests the balls animation implemented with Javascript and canvas.""" BASE_NAME = 'balls_javascript_canvas' URL = 'file://../tough_animation_cases/balls_javascript_canvas.html' + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class BallsJavascriptCssPage(ToughAnimationPage): @@ -73,6 +77,7 @@ """ BASE_NAME = 'balls_css_transition_2_properties' URL = 'file://../tough_animation_cases/balls_css_transition_2_properties.html' + TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class BallsCssTransition40PropertiesPage(ToughAnimationPage): @@ -133,6 +138,7 @@ BASE_NAME = 'css_transitions_inline_style' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_transitions_simultaneous_by_updating_inline_style.html?N=0316' + TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CssTransitionsStaggeredNewElementPage(ToughAnimationPage): @@ -250,6 +256,7 @@ BASE_NAME = 'css_animations_simultaneous_inline_style' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_animations_simultaneous_by_updating_inline_style.html?N=0316' + TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CssAnimationsStaggeredNewElementPage(ToughAnimationPage): @@ -304,7 +311,6 @@ BASE_NAME = 'css_animations_staggered_infinite_iterations' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_animations_staggered_infinite_iterations.html?N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CssAnimationsTriggeredStyleElementPage(ToughAnimationPage): @@ -341,7 +347,6 @@ BASE_NAME = 'web_animations_many_keyframes' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/web_animations_many_keyframes.html?N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class WebAnimationsSetCurrentTimePage(ToughAnimationPage): @@ -376,6 +381,10 @@ BASE_NAME = 'web_animations_staggered_infinite_iterations' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/web_animations_staggered_infinite_iterations.html?N=0316' + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class WebAnimationsStaggeredTriggeringPage(ToughAnimationPage): @@ -383,6 +392,7 @@ BASE_NAME = 'web_animations_staggered_triggering_page' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/web_animations_staggered_triggering.html?N=0316' + TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CssValueTypeColorPage(ToughAnimationPage): @@ -397,6 +407,10 @@ BASE_NAME = 'css_value_type_filter' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_filter.html?api=css_animations&N=0316' + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class CssValueTypeLengthPage(ToughAnimationPage): @@ -411,7 +425,6 @@ BASE_NAME = 'css_value_type_length_complex' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_length_complex.html?api=css_animations&N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CssValueTypeLengthSimplePage(ToughAnimationPage): @@ -434,8 +447,9 @@ # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_shadow.html?api=css_animations&N=0316' TAGS = ToughAnimationPage.TAGS + [ - story_tags.REPRESENTATIVE_WIN_DESKTOP, - story_tags.REPRESENTATIVE_MAC_DESKTOP, + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_WIN_DESKTOP, + story_tags.REPRESENTATIVE_MAC_DESKTOP ] @@ -465,7 +479,6 @@ BASE_NAME = 'web_animation_value_type_length_3d' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_length_3d.html?api=web_animations&N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class WebAnimationValueTypeLengthComplexPage(ToughAnimationPage): @@ -473,7 +486,6 @@ BASE_NAME = 'web_animation_value_type_length_complex' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_length_complex.html?api=web_animations&N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class WebAnimationValueTypeLengthSimplePage(ToughAnimationPage): @@ -488,7 +500,6 @@ BASE_NAME = 'web_animation_value_type_path' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_path.html?api=web_animations&N=0316' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class WebAnimationValueTypeShadowPage(ToughAnimationPage): @@ -503,6 +514,7 @@ BASE_NAME = 'web_animation_value_type_transform_complex' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_transform_complex.html?api=web_animations&N=0316' + TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class WebAnimationValueTypeTransformSimplePage(ToughAnimationPage): @@ -510,6 +522,10 @@ BASE_NAME = 'web_animation_value_type_transform_simple' # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/css_value_type_transform_simple.html?api=web_animations&N=0316' + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class CompositorHeavyAnimationPage(ToughAnimationPage): @@ -518,7 +534,6 @@ """ BASE_NAME = 'compositor_heavy_animation' URL = 'file://../tough_animation_cases/compositor_heavy_animation.html?N=0200' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class KeyframedAnimationsPage(ToughAnimationPage): @@ -540,6 +555,10 @@ BASE_NAME = 'transform_transitions_js_block' URL = 'file://../tough_animation_cases/transform_transition_js_block.html' NEED_MEASUREMENT_READY = False + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class MixBlendModeAnimationDifferencePage(ToughAnimationPage): @@ -568,6 +587,10 @@ # pylint: disable=line-too-long URL = 'file://../tough_animation_cases/mix_blend_mode_animation_screen.html' NEED_MEASUREMENT_READY = False + TAGS = ToughAnimationPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class MixAnimationPropagatingIsolationPage(ToughAnimationPage): @@ -584,7 +607,6 @@ """Why: Login page is slow because of ineffecient transform operations.""" BASE_NAME = 'microsoft_performance' URL = 'http://ie.microsoft.com/testdrive/performance/robohornetpro/' - TAGS = ToughAnimationPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] NEED_MEASUREMENT_READY = False
diff --git a/tools/perf/page_sets/rendering/tough_canvas_cases.py b/tools/perf/page_sets/rendering/tough_canvas_cases.py index 19e8cd0..edc5867 100644 --- a/tools/perf/page_sets/rendering/tough_canvas_cases.py +++ b/tools/perf/page_sets/rendering/tough_canvas_cases.py
@@ -41,19 +41,18 @@ class GeoAPIsPage(ToughCanvasPage): BASE_NAME = 'geo_apis' URL = 'http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class RunwayPage(ToughCanvasPage): BASE_NAME = 'runway' URL = 'http://runway.countlessprojects.com/prototype/performance_test.html' + TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class MicrosoftFishIETankPage(ToughCanvasPage): BASE_NAME = 'microsoft_fish_ie_tank' # pylint: disable=line-too-long URL = 'http://ie.microsoft.com/testdrive/Performance/FishIETank/Default.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class MicrosoftSpeedReadingPage(ToughCanvasPage): @@ -65,13 +64,11 @@ class Kevs3DPage(ToughCanvasPage): BASE_NAME = 'kevs_3d' URL = 'http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class MegiDishPage(ToughCanvasPage): BASE_NAME = 'megi_dish' URL = 'http://www.megidish.net/awjs/' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class ManInBluePage(ToughCanvasPage): @@ -82,7 +79,6 @@ class Mix10KPage(ToughCanvasPage): BASE_NAME = 'mix_10k' URL = 'http://mix10k.visitmix.com/Entry/Details/169' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class CraftyMindPage(ToughCanvasPage): @@ -93,6 +89,7 @@ class ChipTunePage(ToughCanvasPage): BASE_NAME = 'chip_tune' URL = 'http://www.chiptune.com/starfield/starfield.html' + TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class JarroDoversonPage(ToughCanvasPage): @@ -134,7 +131,6 @@ class MicrosoftVideoCityPage(ToughCanvasPage): BASE_NAME = 'microsoft_video_city' URL = 'http://ie.microsoft.com/testdrive/Graphics/VideoCity/Default.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class MicrosoftAsteroidBeltPage(ToughCanvasPage): @@ -146,15 +142,12 @@ class SmashCatPage(ToughCanvasPage): BASE_NAME = 'smash_cat' URL = 'http://www.smashcat.org/av/canvas_test/' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP, - story_tags.REPRESENTATIVE_MOBILE] class BouncingBallsShadowPage(ToughCanvasPage): BASE_NAME = 'bouncing_balls_shadow' # pylint: disable=line-too-long URL = 'file://../tough_canvas_cases/canvas2d_balls_common/bouncing_balls.html?ball=image_with_shadow&back=image' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class BouncingBalls15Page(ToughCanvasPage): @@ -171,12 +164,12 @@ class CanvasAnimationNoClearPage(ToughCanvasPage): BASE_NAME = 'canvas_animation_no_clear' URL = 'file://../tough_canvas_cases/canvas-animation-no-clear.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class CanvasToBlobPage(ToughCanvasPage): BASE_NAME = 'canvas_to_blob' URL = 'file://../tough_canvas_cases/canvas_toBlob.html' + TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class ManyImagesPage(ToughCanvasPage): @@ -192,7 +185,6 @@ class CanvasLinesPage(ToughCanvasPage): BASE_NAME = 'canvas_lines' URL = 'file://../tough_canvas_cases/rendering_throughput/canvas_lines.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class PutGetImageDataPage(ToughCanvasPage): @@ -209,13 +201,16 @@ class StrokeShapesPage(ToughCanvasPage): BASE_NAME = 'stroke_shapes' URL = 'file://../tough_canvas_cases/rendering_throughput/stroke_shapes.html' - TAGS = ToughCanvasPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class BouncingClippedRectanglesPage(ToughCanvasPage): BASE_NAME = 'bouncing_clipped_rectangles' # pylint: disable=line-too-long URL = 'file://../tough_canvas_cases/rendering_throughput/bouncing_clipped_rectangles.html' + TAGS = ToughCanvasPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class BouncingGradientCirclesPage(ToughCanvasPage):
diff --git a/tools/perf/page_sets/rendering/tough_compositor_cases.py b/tools/perf/page_sets/rendering/tough_compositor_cases.py index 964588b..31bbcb4 100644 --- a/tools/perf/page_sets/rendering/tough_compositor_cases.py +++ b/tools/perf/page_sets/rendering/tough_compositor_cases.py
@@ -63,13 +63,14 @@ class CCPosterCirclePage(ToughCompositorWaitPage): BASE_NAME = 'cc_poster_circle' URL = 'http://jsbin.com/falefice/1/quiet?CC_POSTER_CIRCLE' - TAGS = ToughCompositorWaitPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] + TAGS = ToughCompositorWaitPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] # Why: JS poster circle animates/commits many layers """ class JSPosterCirclePage(ToughCompositorWaitPage): BASE_NAME = 'js_poster_circle' URL = 'http://jsbin.com/giqafofe/1/quiet?JS_POSTER_CIRCLE' + TAGS = ToughCompositorWaitPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] # Why: JS invalidation does lots of uploads """ @@ -82,6 +83,10 @@ class NewTilingsPage(ToughCompositorWaitPage): BASE_NAME = 'new_tilings' URL = 'http://jsbin.com/covoqi/1/quiet?NEW_TILINGS' + TAGS = ToughCompositorWaitPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] # Why: CSS property update baseline """ @@ -121,7 +126,6 @@ SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS URL = ('file://../../../../chrome/test/data/perf/tough_compositor_cases/' 'css_opacity_plus_n_layers.html?layer_count=306&visible_layers=46') - TAGS = ToughCompositorWaitPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] # Why: JS driven CSS property change on 1 layer baseline """ @@ -162,7 +166,6 @@ SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS URL = ('file://../../../../chrome/test/data/perf/tough_compositor_cases/' 'js_opacity_plus_n_layers.html?layer_count=306&visible_layers=46') - TAGS = ToughCompositorWaitPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] # Why: Painting 1 layer baseline """ @@ -339,7 +342,3 @@ SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS URL = ('file://../../../../chrome/test/data/perf/tough_compositor_cases/' 'infinite_scroll_root_fixed_n_layers.html?layer_count=306') - TAGS = InfiniteScrollRootNLayersPage.TAGS + [ - story_tags.REPRESENTATIVE_WIN_DESKTOP, - story_tags.REPRESENTATIVE_MAC_DESKTOP, - ]
diff --git a/tools/perf/page_sets/rendering/tough_filters_cases.py b/tools/perf/page_sets/rendering/tough_filters_cases.py index be33a82..a6a73457 100644 --- a/tools/perf/page_sets/rendering/tough_filters_cases.py +++ b/tools/perf/page_sets/rendering/tough_filters_cases.py
@@ -30,6 +30,7 @@ class FilterTerrainSVGPage(ToughFiltersCasesPage): BASE_NAME = 'filter_terrain_svg' URL = 'http://letmespellitoutforyou.com/samples/svg/filter_terrain.svg' + TAGS = ToughFiltersCasesPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class AnalogClockSVGPage(ToughFiltersCasesPage): @@ -42,8 +43,6 @@ URL = ('http://web.archive.org/web/20150502135732/' 'http://ie.microsoft.com/testdrive/Performance/' 'Pirates/Default.html') - TAGS = rendering_story.RenderingStory.TAGS + [ - story_tags.REPRESENTATIVE_MOBILE] def __init__(self, page_set,
diff --git a/tools/perf/page_sets/rendering/tough_path_rendering_cases.py b/tools/perf/page_sets/rendering/tough_path_rendering_cases.py index cb6790d..d4f1516 100644 --- a/tools/perf/page_sets/rendering/tough_path_rendering_cases.py +++ b/tools/perf/page_sets/rendering/tough_path_rendering_cases.py
@@ -24,7 +24,7 @@ BASE_NAME = 'motion_mark_canvas_fill_shapes' # pylint: disable=line-too-long URL = 'http://rawgit.com/WebKit/webkit/master/PerformanceTests/MotionMark/developer.html?test-name=Fillshapes&test-interval=20&display=minimal&tiles=big&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Canvassuite&complexity=1000' - TAGS = ToughPathRenderingPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] + TAGS = ToughPathRenderingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class MotionMarkCanvasStrokeShapesPage(ToughPathRenderingPage): @@ -36,7 +36,11 @@ class ChalkboardPage(rendering_story.RenderingStory): BASE_NAME = 'ie_chalkboard' URL = 'https://testdrive-archive.azurewebsites.net/performance/chalkboard/' - TAGS = [story_tags.TOUGH_PATH_RENDERING] + TAGS = [ + story_tags.TOUGH_PATH_RENDERING, + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] def RunPageInteractions(self, action_runner): with action_runner.CreateInteraction('ClickStart'):
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py index 5de2bed..4beeeb9 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -113,7 +113,6 @@ BASE_NAME = 'youtube_pinch' YEAR = '2018' URL = 'http://www.youtube.com' - TAGS = ToughPinchZoomPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] def RunNavigateSteps(self, action_runner): super(YoutubePinchZoom2018Page, self).RunNavigateSteps(action_runner) @@ -170,7 +169,6 @@ BASE_NAME = 'twitter_pinch' YEAR = '2018' URL = 'https://twitter.com/katyperry' - TAGS = ToughPinchZoomPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] def RunNavigateSteps(self, action_runner): @@ -229,7 +227,6 @@ BASE_NAME = 'amazon_pinch' YEAR = '2018' URL = 'http://www.amazon.com' - TAGS = ToughPinchZoomPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class EBayPinchZoom2018Page(ToughPinchZoomPage):
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py index ea4c8a8e..c9056f4e 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py
@@ -58,7 +58,6 @@ BASE_NAME = 'linkedin_mobile_pinch' YEAR = '2018' URL = 'http://www.linkedin.com/in/linustorvalds' - TAGS = ToughPinchZoomMobilePage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] # Linkedin has expensive shader compilation so it can benefit from shader # cache from reload.
diff --git a/tools/perf/page_sets/rendering/tough_scheduling_cases.py b/tools/perf/page_sets/rendering/tough_scheduling_cases.py index f5f39ac8..37307c3 100644 --- a/tools/perf/page_sets/rendering/tough_scheduling_cases.py +++ b/tools/perf/page_sets/rendering/tough_scheduling_cases.py
@@ -66,7 +66,6 @@ BASE_NAME = 'raf' URL = 'file://../tough_scheduling_cases/raf.html' - TAGS = ToughSchedulingPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class RafCanvasScrollingPage(ToughSchedulingPage): @@ -133,7 +132,6 @@ class SecondBatchLightJsPage(SecondBatchJsPage): BASE_NAME = 'second_batch_js_light' URL = 'file://../tough_scheduling_cases/second_batch_js.html?light' - TAGS = SecondBatchJsPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class SecondBatchJsMediumPage(SecondBatchJsPage):
diff --git a/tools/perf/page_sets/rendering/tough_scrolling_cases.py b/tools/perf/page_sets/rendering/tough_scrolling_cases.py index 451f743..95b2c7a 100644 --- a/tools/perf/page_sets/rendering/tough_scrolling_cases.py +++ b/tools/perf/page_sets/rendering/tough_scrolling_cases.py
@@ -43,6 +43,7 @@ BASE_NAME = 'text_10000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text.html' SPEED_IN_PIXELS_PER_SECOND = 10000 + TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingText20000Page(ToughFastScrollingPage): @@ -134,7 +135,6 @@ BASE_NAME = 'text_constant_full_page_raster_10000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' SPEED_IN_PIXELS_PER_SECOND = 10000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingTextRaster20000Page(ToughFastScrollingPage): @@ -171,27 +171,28 @@ BASE_NAME = 'canvas_05000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 5000 + TAGS = ToughFastScrollingPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class ScrollingCanvas10000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_10000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 10000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingCanvas20000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_20000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 20000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingCanvas40000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_40000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 40000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingCanvas60000Page(ToughFastScrollingPage): @@ -204,11 +205,9 @@ BASE_NAME = 'canvas_75000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 75000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_MOBILE] class ScrollingCanvas90000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_90000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 90000 - TAGS = ToughFastScrollingPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP]
diff --git a/tools/perf/page_sets/rendering/tough_texture_upload_cases.py b/tools/perf/page_sets/rendering/tough_texture_upload_cases.py index 2b350b2..eedea04 100644 --- a/tools/perf/page_sets/rendering/tough_texture_upload_cases.py +++ b/tools/perf/page_sets/rendering/tough_texture_upload_cases.py
@@ -36,7 +36,6 @@ BASE_NAME = 'background_color_animation_with_gradient' # pylint: disable=line-too-long URL = 'file://../tough_texture_upload_cases/background_color_animation_with_gradient.html' - TAGS = ToughTextureUploadPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class SmallTextureUploadsPage(ToughTextureUploadPage): @@ -57,3 +56,7 @@ class ExtraLargeTextureUploadsPage(ToughTextureUploadPage): BASE_NAME = 'extra_large_texture_uploads' URL = 'file://../tough_texture_upload_cases/extra_large_texture_uploads.html' + TAGS = ToughTextureUploadPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ]
diff --git a/tools/perf/page_sets/rendering/tough_webgl_cases.py b/tools/perf/page_sets/rendering/tough_webgl_cases.py index 567cf86..844b2593 100644 --- a/tools/perf/page_sets/rendering/tough_webgl_cases.py +++ b/tools/perf/page_sets/rendering/tough_webgl_cases.py
@@ -45,6 +45,7 @@ BASE_NAME = 'nvidia_vertex_buffer_object' # pylint: disable=line-too-long URL = 'http://www.khronos.org/registry/webgl/sdk/demos/google/nvidia-vertex-buffer-object/index.html' + TAGS = ToughWebglPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class SansAngelesPage(ToughWebglPage): @@ -57,19 +58,18 @@ BASE_NAME = 'particles' # pylint: disable=line-too-long URL = 'http://www.khronos.org/registry/webgl/sdk/demos/google/particles/index.html' - TAGS = ToughWebglPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class EarthPage(ToughWebglPage): BASE_NAME = 'earth' URL = 'http://www.khronos.org/registry/webgl/sdk/demos/webkit/Earth.html' - TAGS = ToughWebglPage.TAGS + [story_tags.REPRESENTATIVE_MAC_DESKTOP] class ManyPlanetsDeepPage(ToughWebglPage): BASE_NAME = 'many_planets_deep' # pylint: disable=line-too-long URL = 'http://www.khronos.org/registry/webgl/sdk/demos/webkit/ManyPlanetsDeep.html' + TAGS = ToughWebglPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class AquariumPage(ToughWebglPage): @@ -81,6 +81,7 @@ class Aquarium20KFishPage(ToughWebglPage): BASE_NAME = 'aquarium_20k' URL = 'http://webglsamples.org/aquarium/aquarium.html?numFish=20000' + TAGS = ToughWebglPage.TAGS + [story_tags.REPRESENTATIVE_WIN_DESKTOP] class BlobPage(ToughWebglPage): @@ -107,6 +108,10 @@ BASE_NAME = 'animometer_webgl_attrib_arrays' # pylint: disable=line-too-long URL = 'http://kenrussell.github.io/webgl-animometer/Animometer/tests/3d/webgl.html?use_attributes=1' + TAGS = ToughWebglPage.TAGS + [ + story_tags.REPRESENTATIVE_MOBILE, + story_tags.REPRESENTATIVE_MAC_DESKTOP + ] class CameraToWebGLPage(ToughWebglPage): TAGS = ToughWebglPage.TAGS + [story_tags.USE_FAKE_CAMERA_DEVICE]
diff --git a/ui/accessibility/ax_table_info.cc b/ui/accessibility/ax_table_info.cc index 05a1325..89453af 100644 --- a/ui/accessibility/ax_table_info.cc +++ b/ui/accessibility/ax_table_info.cc
@@ -342,23 +342,18 @@ // The table header container is just a node with all of the headers in the // table as indirect children. - // One node for each column, and one more for the table header container. - size_t extra_node_count = col_count + 1; + // Delete old extra nodes. + ClearExtraMacNodes(); - if (extra_mac_nodes.size() != extra_node_count) { - // Delete old extra nodes. - ClearExtraMacNodes(); + // Resize. + extra_mac_nodes.resize(col_count + 1); - // Resize. - extra_mac_nodes.resize(col_count + 1); + // Create column nodes. + for (size_t i = 0; i < col_count; i++) + extra_mac_nodes[i] = CreateExtraMacColumnNode(i); - // Create column nodes. - for (size_t i = 0; i < col_count; i++) - extra_mac_nodes[i] = CreateExtraMacColumnNode(i); - - // Create table header container node. - extra_mac_nodes[col_count] = CreateExtraMacTableHeaderNode(); - } + // Create table header container node. + extra_mac_nodes[col_count] = CreateExtraMacTableHeaderNode(); // Update the columns to reflect current state of the table. for (size_t i = 0; i < col_count; i++)
diff --git a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc index 87f2774..7c0447a 100644 --- a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc +++ b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
@@ -52,12 +52,25 @@ element2_data.relative_bounds.bounds = gfx::RectF(0, 50, 30, 30); root_data.child_ids.push_back(element2_data.id); - Init(root_data, element1_data, element2_data); + AXNodeData element3_data; + element3_data.id = 4; + element3_data.relative_bounds.bounds = gfx::RectF(50, 0, 20, 20); + root_data.child_ids.push_back(element3_data.id); + + // Overlapping child view. + AXNodeData element4_data; + element4_data.id = 5; + element4_data.relative_bounds.bounds = gfx::RectF(50, 0, 10, 10); + element3_data.child_ids.push_back(element4_data.id); + + Init(root_data, element1_data, element2_data, element3_data, element4_data); InitFragmentRoot(); AXNode* root_node = GetRootNode(); AXNode* element1_node = root_node->children()[0]; AXNode* element2_node = root_node->children()[1]; + AXNode* element3_node = root_node->children()[2]; + AXNode* element4_node = root_node->children()[2]->children()[0]; ComPtr<IRawElementProviderFragmentRoot> fragment_root_prov(GetFragmentRoot()); ComPtr<IRawElementProviderFragment> root_provider( @@ -66,6 +79,10 @@ QueryInterfaceFromNode<IRawElementProviderFragment>(element1_node); ComPtr<IRawElementProviderFragment> element2_provider = QueryInterfaceFromNode<IRawElementProviderFragment>(element2_node); + ComPtr<IRawElementProviderFragment> element3_provider = + QueryInterfaceFromNode<IRawElementProviderFragment>(element3_node); + ComPtr<IRawElementProviderFragment> element4_provider = + QueryInterfaceFromNode<IRawElementProviderFragment>(element4_node); ComPtr<IRawElementProviderFragment> provider_from_point; EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint( @@ -80,6 +97,11 @@ 47, 67, &provider_from_point)); EXPECT_EQ(root_provider.Get(), provider_from_point.Get()); + // This is on node 3 and 4. + EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint( + 55, 5, &provider_from_point)); + EXPECT_EQ(element4_provider.Get(), provider_from_point.Get()); + // This is on node 1 with scale factor of 1.5. std::unique_ptr<base::AutoReset<float>> scale_factor_reset = TestAXNodeWrapper::SetScaleFactor(1.5);
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index bcfd818..1c3cac2 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -3361,6 +3361,14 @@ } void AXPlatformNodeAuraLinux::OnValueChanged() { + // If this is a non-web-content text entry, then we need to trigger text + // change signals when the value changes. This is handled by browser + // accessibility for web content. + if (IsPlainTextField() || !GetDelegate()->IsWebContent()) { + UpdateHypertext(); + return; + } + if (!IsRangeValueSupported(GetData())) return;
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index d607880..92a7e4bf 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -460,7 +460,20 @@ node2.SetName("Name2"); root.child_ids.push_back(node2.id); - Init(root, node1, node2); + AXNodeData node3; + node3.id = 4; + node3.relative_bounds.bounds = gfx::RectF(10, 10, 10, 10); + node3.SetName("Name3"); + root.child_ids.push_back(node3.id); + + // Overlapping child view. + AXNodeData node4; + node4.id = 5; + node4.relative_bounds.bounds = gfx::RectF(10, 10, 5, 5); + node4.SetName("Name4"); + node3.child_ids.push_back(node4.id); + + Init(root, node1, node2, node3, node4); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -474,13 +487,19 @@ ASSERT_NE(nullptr, obj_1.ptr()); CheckVariantHasName(obj_1, L"Name1"); - // This is directly on node 2 with a scale factor of 1.5. + // This is directly on node 3 and 4. ScopedVariant obj_2; + EXPECT_EQ(S_OK, root_obj->accHitTest(12, 12, obj_2.Receive())); + ASSERT_NE(nullptr, obj_2.ptr()); + CheckVariantHasName(obj_2, L"Name4"); + + // This is directly on node 2 with a scale factor of 1.5. + ScopedVariant obj_3; std::unique_ptr<base::AutoReset<float>> scale_factor_reset = TestAXNodeWrapper::SetScaleFactor(1.5); - EXPECT_EQ(S_OK, root_obj->accHitTest(38, 38, obj_2.Receive())); - ASSERT_NE(nullptr, obj_2.ptr()); - CheckVariantHasName(obj_2, L"Name2"); + EXPECT_EQ(S_OK, root_obj->accHitTest(38, 38, obj_3.Receive())); + ASSERT_NE(nullptr, obj_3.ptr()); + CheckVariantHasName(obj_3, L"Name2"); } TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) {
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index 5f260ead..c4a0a8e 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -396,7 +396,7 @@ // provided element_id. if (type == WebInputEvent::Type::kGestureScrollBegin) synthetic_gesture_event->data.scroll_begin.scrollable_area_element_id = - pointer_result.target_scroller.GetInternalValue(); + pointer_result.target_scroller.GetStableId(); WebScopedInputEvent web_scoped_gesture_event( synthetic_gesture_event.release());
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn index 2d6d7ee5..9ca2f4b 100644 --- a/ui/message_center/BUILD.gn +++ b/ui/message_center/BUILD.gn
@@ -119,8 +119,6 @@ "views/proportional_image_view.h", "views/relative_time_formatter.cc", "views/relative_time_formatter.h", - "views/slide_out_controller.cc", - "views/slide_out_controller.h", ] deps += [ "//ui/compositor", @@ -207,7 +205,6 @@ "views/notification_header_view_unittest.cc", "views/notification_view_md_unittest.cc", "views/relative_time_formatter_unittest.cc", - "views/slide_out_controller_unittest.cc", ] deps += [ "//ui/display",
diff --git a/ui/message_center/public/cpp/message_center_constants.h b/ui/message_center/public/cpp/message_center_constants.h index c87bb97..f4939b4 100644 --- a/ui/message_center/public/cpp/message_center_constants.h +++ b/ui/message_center/public/cpp/message_center_constants.h
@@ -141,10 +141,6 @@ // The corners are only rounded in Chrome OS. constexpr int kNotificationCornerRadius = 2; -// Close if notification is slided more than this amount in addition to the -// width of the buttons and their margins. -constexpr int kSwipeCloseMargin = 64; - } // namespace message_center #endif // UI_MESSAGE_CENTER_PUBLIC_CPP_MESSAGE_CENTER_CONSTANTS_H_
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc index 468a330..8e33233 100644 --- a/ui/message_center/views/message_view.cc +++ b/ui/message_center/views/message_view.cc
@@ -359,21 +359,21 @@ } } -SlideOutController::SlideMode MessageView::CalculateSlideMode() const { +views::SlideOutController::SlideMode MessageView::CalculateSlideMode() const { if (disable_slide_) - return SlideOutController::SlideMode::NO_SLIDE; + return views::SlideOutController::SlideMode::kNone; switch (GetMode()) { case Mode::SETTING: - return SlideOutController::SlideMode::NO_SLIDE; + return views::SlideOutController::SlideMode::kNone; case Mode::PINNED: - return SlideOutController::SlideMode::PARTIALLY; + return views::SlideOutController::SlideMode::kPartial; case Mode::NORMAL: - return SlideOutController::SlideMode::FULL; + return views::SlideOutController::SlideMode::kFull; } NOTREACHED(); - return SlideOutController::SlideMode::FULL; + return views::SlideOutController::SlideMode::kFull; } MessageView::Mode MessageView::GetMode() const {
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h index 59a20ec9..e3c3181 100644 --- a/ui/message_center/views/message_view.h +++ b/ui/message_center/views/message_view.h
@@ -18,8 +18,9 @@ #include "ui/message_center/message_center_export.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" -#include "ui/message_center/views/slide_out_controller.h" #include "ui/views/animation/ink_drop_host_view.h" +#include "ui/views/animation/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller_delegate.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/view.h" @@ -43,9 +44,10 @@ // NotificationViewMD subclass needs ink drop functionality. Rework ink drops // to not need to be the base class of views which use them, and move the // functionality to the subclass that uses these. -class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView, - public SlideOutController::Delegate, - public views::FocusChangeListener { +class MESSAGE_CENTER_EXPORT MessageView + : public views::InkDropHostView, + public views::SlideOutControllerDelegate, + public views::FocusChangeListener { public: static const char kViewClassName[]; @@ -126,7 +128,7 @@ void AddedToWidget() override; const char* GetClassName() const final; - // message_center::SlideOutController::Delegate: + // views::SlideOutControllerDelegate: ui::Layer* GetSlideOutLayer() override; void OnSlideStarted() override; void OnSlideChanged(bool in_progress) override; @@ -179,7 +181,7 @@ friend class test::MessagePopupCollectionTest; // Returns the ideal slide mode by calculating the current status. - SlideOutController::SlideMode CalculateSlideMode() const; + views::SlideOutController::SlideMode CalculateSlideMode() const; // Returns if the control buttons should be shown. bool ShouldShowControlButtons() const; @@ -196,7 +198,7 @@ // "fixed" mode flag. See the comment in MessageView::Mode for detail. bool setting_mode_ = false; - SlideOutController slide_out_controller_; + views::SlideOutController slide_out_controller_; base::ObserverList<SlideObserver>::Unchecked slide_observers_; // True if |this| is embedded in another view. Equivalent to |!top_level| in
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 1ade466..4e5403b 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -88,6 +88,8 @@ "animation/installable_ink_drop_config.h", "animation/installable_ink_drop_painter.h", "animation/scroll_animator.h", + "animation/slide_out_controller.h", + "animation/slide_out_controller_delegate.h", "animation/square_ink_drop_ripple.h", "background.h", "border.h", @@ -311,6 +313,7 @@ "animation/installable_ink_drop_animator.cc", "animation/installable_ink_drop_painter.cc", "animation/scroll_animator.cc", + "animation/slide_out_controller.cc", "animation/square_ink_drop_ripple.cc", "background.cc", "border.cc", @@ -994,6 +997,7 @@ "animation/ink_drop_unittest.cc", "animation/installable_ink_drop_animator_unittest.cc", "animation/installable_ink_drop_unittest.cc", + "animation/slide_out_controller_unittest.cc", "animation/square_ink_drop_ripple_unittest.cc", "border_unittest.cc", "bubble/bubble_border_unittest.cc", @@ -1244,6 +1248,12 @@ data_deps += [ "//testing/buildbot/filters:linux_ozone_views_unittests_filters" ] } + + if (use_atk) { + sources += + [ "accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc" ] + configs += [ "//build/config/linux/atk" ] + } } # This target is added as a dependency of browser interactive_ui_tests. It must
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc index ffd1d2a..82b7498 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -349,10 +349,15 @@ if (!view()->HitTestPoint(point)) return nullptr; + // GetEventHandlerForPoint correctly handles overlapping views but it + // only returns views that handle events. For accessibility, we want to + // return the deepest child view. This is why we need to continue + // searching from here. + View* v = view()->GetEventHandlerForPoint(point); + // Check if the point is within any of the immediate children of this // view. We don't have to search further because AXPlatformNode will // do a recursive hit test if we return anything other than |this| or NULL. - View* v = view(); const auto is_point_in_child = [point, v](View* child) { if (!child->GetVisible()) return false; @@ -363,7 +368,7 @@ const auto i = std::find_if(v->children().rbegin(), v->children().rend(), is_point_in_child); // If it's not inside any of our children, it's inside this view. - return (i == v->children().rend()) ? GetNativeObject() + return (i == v->children().rend()) ? v->GetNativeViewAccessible() : (*i)->GetNativeViewAccessible(); }
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc new file mode 100644 index 0000000..22f38a6 --- /dev/null +++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc
@@ -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. + +#include "ui/views/accessibility/view_ax_platform_node_delegate.h" + +#include <atk/atk.h> + +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/test/views_test_base.h" + +namespace views { +namespace test { + +class ViewAXPlatformNodeDelegateAuraLinuxTest : public ViewsTestBase { + public: + ViewAXPlatformNodeDelegateAuraLinuxTest() = default; + ~ViewAXPlatformNodeDelegateAuraLinuxTest() override = default; +}; + +TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, TextfieldAccessibility) { + Widget widget; + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); + + View* content = new View; + widget.SetContentsView(content); + + Textfield* textfield = new Textfield; + textfield->SetAccessibleName(base::UTF8ToUTF16("Name")); + textfield->SetText(base::UTF8ToUTF16("Value")); + content->AddChildView(textfield); + + AtkText* atk_text = ATK_TEXT(textfield->GetNativeViewAccessible()); + ASSERT_NE(nullptr, atk_text); + + struct TextChangeData { + int position; + int length; + std::string text; + }; + + std::vector<TextChangeData> text_remove_events; + std::vector<TextChangeData> text_insert_events; + GCallback callback = G_CALLBACK( + +[](AtkText*, int position, int length, char* text, gpointer data) { + auto* events = static_cast<std::vector<TextChangeData>*>(data); + events->push_back(TextChangeData{position, length, text}); + }); + g_signal_connect(atk_text, "text-insert", callback, &text_insert_events); + g_signal_connect(atk_text, "text-remove", callback, &text_remove_events); + + textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); + ASSERT_EQ(text_remove_events.size(), 0ul); + ASSERT_EQ(text_insert_events.size(), 1ul); + ASSERT_EQ(text_insert_events[0].position, 0); + ASSERT_EQ(text_insert_events[0].length, 5); + ASSERT_EQ(text_insert_events[0].text, "Value"); + text_insert_events.clear(); + + textfield->SetText(base::UTF8ToUTF16("Value A")); + textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); + + ASSERT_EQ(text_remove_events.size(), 0ul); + ASSERT_EQ(text_insert_events.size(), 1ul); + ASSERT_EQ(text_insert_events[0].position, 5); + ASSERT_EQ(text_insert_events[0].length, 2); + ASSERT_EQ(text_insert_events[0].text, " A"); + text_insert_events.clear(); + + textfield->SetText(base::UTF8ToUTF16("Value")); + textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); + ASSERT_EQ(text_remove_events.size(), 1ul); + ASSERT_EQ(text_insert_events.size(), 0ul); + ASSERT_EQ(text_remove_events[0].position, 5); + ASSERT_EQ(text_remove_events[0].length, 2); + ASSERT_EQ(text_remove_events[0].text, " A"); + text_remove_events.clear(); + + textfield->SetText(base::UTF8ToUTF16("Prefix Value")); + textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); + ASSERT_EQ(text_remove_events.size(), 0ul); + ASSERT_EQ(text_insert_events.size(), 1ul); + ASSERT_EQ(text_insert_events[0].position, 0); + ASSERT_EQ(text_insert_events[0].length, 7); + ASSERT_EQ(text_insert_events[0].text, "Prefix "); + text_insert_events.clear(); + + textfield->SetText(base::UTF8ToUTF16("Value")); + textfield->NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); + ASSERT_EQ(text_remove_events.size(), 1ul); + ASSERT_EQ(text_insert_events.size(), 0ul); + ASSERT_EQ(text_remove_events[0].position, 0); + ASSERT_EQ(text_remove_events[0].length, 7); + ASSERT_EQ(text_remove_events[0].text, "Prefix "); + text_insert_events.clear(); +} + +} // namespace test +} // namespace views
diff --git a/ui/message_center/views/slide_out_controller.cc b/ui/views/animation/slide_out_controller.cc similarity index 83% rename from ui/message_center/views/slide_out_controller.cc rename to ui/views/animation/slide_out_controller.cc index fad2063..8e63abc 100644 --- a/ui/message_center/views/slide_out_controller.cc +++ b/ui/views/animation/slide_out_controller.cc
@@ -2,25 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/views/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller.h" #include "base/bind.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/transform.h" -#include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/views/animation/slide_out_controller_delegate.h" -namespace message_center { +namespace views { namespace { -constexpr int kSwipeRestoreDurationMs = 150; + +constexpr base::TimeDelta kSwipeRestoreDuration = + base::TimeDelta::FromMilliseconds(150); constexpr int kSwipeOutTotalDurationMs = 150; gfx::Tween::Type kSwipeTweenType = gfx::Tween::EASE_IN; + +// When we have a swipe control, we will close the target if it is slid more +// than this amount plus the width of the swipe control. +constexpr int kSwipeCloseMargin = 64; + } // anonymous namespace SlideOutController::SlideOutController(ui::EventTarget* target, - Delegate* delegate) + SlideOutControllerDelegate* delegate) : target_handling_(target, this), delegate_(delegate) {} SlideOutController::~SlideOutController() {} @@ -28,13 +35,13 @@ void SlideOutController::CaptureControlOpenState() { if (!has_swipe_control_) return; - if (mode_ == SlideMode::FULL && + if (mode_ == SlideMode::kFull && fabs(gesture_amount_) >= swipe_control_width_) { control_open_state_ = gesture_amount_ < 0 - ? SwipeControlOpenState::OPEN_ON_RIGHT - : SwipeControlOpenState::OPEN_ON_LEFT; + ? SwipeControlOpenState::kOpenOnRight + : SwipeControlOpenState::kOpenOnLeft; } else { - control_open_state_ = SwipeControlOpenState::CLOSED; + control_open_state_ = SwipeControlOpenState::kClosed; } } @@ -49,7 +56,7 @@ // The threshold for the fling velocity is computed empirically. // The unit is in pixels/second. const float kFlingThresholdForClose = 800.f; - if (mode_ == SlideMode::FULL && + if (mode_ == SlideMode::kFull && fabsf(event->details().velocity_x()) > kFlingThresholdForClose) { SlideOutAndClose(event->details().velocity_x()); event->StopPropagation(); @@ -65,13 +72,13 @@ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) { switch (control_open_state_) { - case SwipeControlOpenState::CLOSED: + case SwipeControlOpenState::kClosed: gesture_amount_ = 0.f; break; - case SwipeControlOpenState::OPEN_ON_RIGHT: + case SwipeControlOpenState::kOpenOnRight: gesture_amount_ = -swipe_control_width_; break; - case SwipeControlOpenState::OPEN_ON_LEFT: + case SwipeControlOpenState::kOpenOnLeft: gesture_amount_ = swipe_control_width_; break; default: @@ -85,15 +92,15 @@ float scroll_amount; float opacity; switch (mode_) { - case SlideMode::FULL: + case SlideMode::kFull: scroll_amount = gesture_amount_; opacity = 1.f - std::min(fabsf(scroll_amount) / width, 1.f); break; - case SlideMode::NO_SLIDE: + case SlideMode::kNone: scroll_amount = 0.f; opacity = 1.f; break; - case SlideMode::PARTIALLY: + case SlideMode::kPartial: if (gesture_amount_ >= 0) { scroll_amount = std::min(0.5f * gesture_amount_, scroll_amount_for_closing_notification); @@ -113,7 +120,7 @@ delegate_->OnSlideChanged(true); } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { float scrolled_ratio = fabsf(gesture_amount_) / width; - if (mode_ == SlideMode::FULL && + if (mode_ == SlideMode::kFull && scrolled_ratio >= scroll_amount_for_closing_notification / width) { SlideOutAndClose(gesture_amount_); event->StopPropagation(); @@ -130,22 +137,21 @@ // Restore the layer state. gfx::Transform transform; switch (control_open_state_) { - case SwipeControlOpenState::CLOSED: + case SwipeControlOpenState::kClosed: gesture_amount_ = 0.f; break; - case SwipeControlOpenState::OPEN_ON_RIGHT: + case SwipeControlOpenState::kOpenOnRight: gesture_amount_ = -swipe_control_width_; transform.Translate(-swipe_control_width_, 0); break; - case SwipeControlOpenState::OPEN_ON_LEFT: + case SwipeControlOpenState::kOpenOnLeft: gesture_amount_ = swipe_control_width_; transform.Translate(swipe_control_width_, 0); break; } SetOpacityIfNecessary(1.f); - SetTransformWithAnimationIfNecessary( - transform, base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMs)); + SetTransformWithAnimationIfNecessary(transform, kSwipeRestoreDuration); } void SlideOutController::SlideOutAndClose(int direction) { @@ -210,7 +216,8 @@ if (!is_completely_slid_out) return; - // Call Delegate::OnSlideOut() if this animation came from SlideOutAndClose(). + // Call SlideOutControllerDelegate::OnSlideOut() if this animation came from + // SlideOutAndClose(). // OnImplicitAnimationsCompleted is called from BeginMainFrame, so we should // delay operation that might result in deletion of LayerTreeHost. @@ -237,4 +244,4 @@ RestoreVisualState(); } -} // namespace message_center +} // namespace views
diff --git a/ui/message_center/views/slide_out_controller.h b/ui/views/animation/slide_out_controller.h similarity index 71% rename from ui/message_center/views/slide_out_controller.h rename to ui/views/animation/slide_out_controller.h index 2c750e9..61be0f2 100644 --- a/ui/message_center/views/slide_out_controller.h +++ b/ui/views/animation/slide_out_controller.h
@@ -2,47 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_MESSAGE_CENTER_VIEWS_SLIDE_OUT_CONTROLLER_H_ -#define UI_MESSAGE_CENTER_VIEWS_SLIDE_OUT_CONTROLLER_H_ +#ifndef UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_H_ +#define UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_H_ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/events/scoped_target_handler.h" -#include "ui/message_center/message_center_export.h" #include "ui/views/view.h" +#include "ui/views/views_export.h" -namespace message_center { +namespace views { + +class SlideOutControllerDelegate; // This class contains logic to control sliding out of a layer in response to // swipes, i.e. gesture scroll events. -class MESSAGE_CENTER_EXPORT SlideOutController - : public ui::EventHandler, - public ui::ImplicitAnimationObserver { +class VIEWS_EXPORT SlideOutController : public ui::EventHandler, + public ui::ImplicitAnimationObserver { public: + // Indicates how much the target layer is allowed to slide. enum class SlideMode { - FULL, - PARTIALLY, - NO_SLIDE, + kFull, + kPartial, + kNone, }; - class Delegate { - public: - // Returns the layer for slide operations. - virtual ui::Layer* GetSlideOutLayer() = 0; - - // Called when a manual slide starts. - virtual void OnSlideStarted() {} - - // Called when a manual slide updates or ends. The argument is true if the - // slide starts or in progress, false if it ends. - virtual void OnSlideChanged(bool in_progress) = 0; - - // Called when user intends to close the View by sliding it out. - virtual void OnSlideOut() = 0; - }; - - SlideOutController(ui::EventTarget* target, Delegate* delegate); + SlideOutController(ui::EventTarget* target, + SlideOutControllerDelegate* delegate); ~SlideOutController() override; void set_update_opacity(bool update_opacity) { @@ -68,7 +55,7 @@ float GetGestureAmount() const { return gesture_amount_; } // Moves slide back to the center position to closes the swipe control. - // Effective only when swipe control is enabled by EnableSwipeControl(). + // Effective only when swipe control is enabled by |SetSwipeControlWidth()|. void CloseSwipeControl(); // Slides the view out and closes it after the animation. The sign of @@ -77,7 +64,7 @@ private: // Positions where the slided view stays after the touch released. - enum class SwipeControlOpenState { CLOSED, OPEN_ON_LEFT, OPEN_ON_RIGHT }; + enum class SwipeControlOpenState { kClosed, kOpenOnLeft, kOpenOnRight }; // Restores the transform and opacity of the view. void RestoreVisualState(); @@ -99,26 +86,26 @@ ui::ScopedTargetHandler target_handling_; // Unowned and outlives this object. - Delegate* delegate_; + SlideOutControllerDelegate* delegate_; // Cumulative scroll amount since the beginning of current slide gesture. // Includes the initial shift when swipe control was open at gesture start. float gesture_amount_ = 0.f; // Whether or not this view can be slided and/or swiped out. - SlideMode mode_ = SlideMode::FULL; + SlideMode mode_ = SlideMode::kFull; - // Whether the swipe control is enabled. See EnableSwipeControl(). + // Whether the swipe control is enabled. See |SetSwipeControlWidth()|. // Effective only when |mode_| is FULL. bool has_swipe_control_ = false; // The horizontal position offset to for swipe control. - // See |EnableSwipeControl|. + // See |SetSwipeControlWidth()|. int swipe_control_width_ = 0; // The position where the slided view stays after the touch released. // Changed only when |mode_| is FULL and |has_swipe_control_| is true. - SwipeControlOpenState control_open_state_ = SwipeControlOpenState::CLOSED; + SwipeControlOpenState control_open_state_ = SwipeControlOpenState::kClosed; // If false, it doesn't update the opacity. bool update_opacity_ = true; @@ -131,6 +118,6 @@ DISALLOW_COPY_AND_ASSIGN(SlideOutController); }; -} // namespace message_center +} // namespace views -#endif // UI_MESSAGE_CENTER_VIEWS_SLIDE_OUT_CONTROLLER_H_ +#endif // UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_H_
diff --git a/ui/views/animation/slide_out_controller_delegate.h b/ui/views/animation/slide_out_controller_delegate.h new file mode 100644 index 0000000..99c5bff8 --- /dev/null +++ b/ui/views/animation/slide_out_controller_delegate.h
@@ -0,0 +1,37 @@ +// 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 UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_DELEGATE_H_ +#define UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_DELEGATE_H_ + +#include "ui/views/views_export.h" + +namespace ui { +class Layer; +} // namespace ui + +namespace views { + +class VIEWS_EXPORT SlideOutControllerDelegate { + public: + // Returns the layer for slide operations. + virtual ui::Layer* GetSlideOutLayer() = 0; + + // Called when a manual slide starts. + virtual void OnSlideStarted() {} + + // Called when a manual slide updates or ends. The argument is true if the + // slide starts or in progress, false if it ends. + virtual void OnSlideChanged(bool in_progress) = 0; + + // Called when user intends to close the View by sliding it out. + virtual void OnSlideOut() = 0; + + protected: + virtual ~SlideOutControllerDelegate() = default; +}; + +} // namespace views + +#endif // UI_VIEWS_ANIMATION_SLIDE_OUT_CONTROLLER_DELEGATE_H_
diff --git a/ui/message_center/views/slide_out_controller_unittest.cc b/ui/views/animation/slide_out_controller_unittest.cc similarity index 93% rename from ui/message_center/views/slide_out_controller_unittest.cc rename to ui/views/animation/slide_out_controller_unittest.cc index 16ea607..5abfefb 100644 --- a/ui/message_center/views/slide_out_controller_unittest.cc +++ b/ui/views/animation/slide_out_controller_unittest.cc
@@ -2,22 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/views/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller.h" +#include "ui/views/animation/slide_out_controller_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" -namespace message_center { +namespace views { namespace { constexpr int kSwipeControlWidth = 30; // px constexpr int kTargetWidth = 200; // px } // namespace -class SlideOutControllerDelegate : public SlideOutController::Delegate { +class TestSlideOutControllerDelegate : public SlideOutControllerDelegate { public: - explicit SlideOutControllerDelegate(views::View* target) : target_(target) {} - virtual ~SlideOutControllerDelegate() = default; + explicit TestSlideOutControllerDelegate(View* target) : target_(target) {} + ~TestSlideOutControllerDelegate() override = default; ui::Layer* GetSlideOutLayer() override { return target_->layer(); } @@ -45,34 +46,33 @@ int slide_out_count_ = 0; private: - views::View* const target_; + View* const target_; }; -class SlideOutControllerTest : public views::ViewsTestBase { +class SlideOutControllerTest : public ViewsTestBase { public: SlideOutControllerTest() = default; ~SlideOutControllerTest() override = default; void SetUp() override { - views::ViewsTestBase::SetUp(); + ViewsTestBase::SetUp(); - widget_ = std::make_unique<views::Widget>(); + widget_ = std::make_unique<Widget>(); - views::Widget::InitParams params = - CreateParams(views::Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); widget_->Init(std::move(params)); - views::View* root = widget_->GetRootView(); + View* root = widget_->GetRootView(); - views::View* target_ = new views::View(); + View* target_ = new View(); target_->SetPaintToLayer(ui::LAYER_TEXTURED); target_->SetSize(gfx::Size(kTargetWidth, 50)); root->AddChildView(target_); widget_->Show(); - delegate_ = std::make_unique<SlideOutControllerDelegate>(target_); + delegate_ = std::make_unique<TestSlideOutControllerDelegate>(target_); slide_out_controller_ = std::make_unique<SlideOutController>(target_, delegate_.get()); } @@ -82,7 +82,7 @@ delegate_.reset(); widget_.reset(); - views::ViewsTestBase::TearDown(); + ViewsTestBase::TearDown(); } protected: @@ -90,7 +90,7 @@ return slide_out_controller_.get(); } - SlideOutControllerDelegate* delegate() { return delegate_.get(); } + TestSlideOutControllerDelegate* delegate() { return delegate_.get(); } void PostSequentialGestureEvent(const ui::GestureEventDetails& details) { // Set the timestamp ahead one microsecond. @@ -112,9 +112,9 @@ } private: - std::unique_ptr<views::Widget> widget_; + std::unique_ptr<Widget> widget_; std::unique_ptr<SlideOutController> slide_out_controller_; - std::unique_ptr<SlideOutControllerDelegate> delegate_; + std::unique_ptr<TestSlideOutControllerDelegate> delegate_; base::TimeDelta sequential_event_timestamp_; }; @@ -507,4 +507,4 @@ EXPECT_EQ(0, delegate()->slide_out_count_); } -} // namespace message_center +} // namespace views