diff --git a/DEPS b/DEPS index 90c20c7..ac72a5c 100644 --- a/DEPS +++ b/DEPS
@@ -142,11 +142,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': '4d03689edb5dfdce22f11414d2351ce2b221a410', + 'skia_revision': '38ae3f42fec129839767e96b05ada677c2f9b22d', # 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': 'da069071ec861916b268f20bcc21d2d440299a74', + 'v8_revision': '7a88817255bf8557ebdcff2dacaf4cf6f1ff8ecd', # 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. @@ -154,7 +154,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': 'da904484bfc696193c15d89c9c6e847afeb978cc', + 'angle_revision': '6b5830333673c370d9ee086af3e14a9c5e46b928', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -205,7 +205,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '63f7fcc05ac1011f52d81e926f8638e7aea91133', + 'catapult_revision': 'e9399f9f929fbb6cc36a9f8fcae866e75512d487', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -261,7 +261,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': 'e6e3e2ccc6a2a9bf43730d8edccf0b1a212d660a', + 'spv_tools_revision': '9702d47c6fe4cefbc55f905b0e9966452124b6c2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -277,7 +277,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '4886403b610c39e2fa92463503b5b6d872b82736', + 'dawn_revision': '72508d6d0634bdb28353c2ec26bbe79307ab916a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -806,7 +806,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '104b067af6a2eea63e010a4d2a3038c59f178436', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5e4b1bc773108632898be413caa4f9dbf8592f89', 'condition': 'checkout_linux', }, @@ -831,7 +831,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dc37feb99d46bdf499715ceb467d341d24524e0b', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ffd96e6df09708e09e5e3e467a2ffd322e8cb143', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -900,7 +900,7 @@ }, 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '22683b409e6df419da940df561b24b4b5d8ab90a', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '4b4b41a63499d34c527ee4f714dde8072f60c900', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1356,7 +1356,7 @@ Var('chromium_git') + '/external/github.com/SeleniumHQ/selenium/py.git' + '@' + 'd0045ec570c1a77612db35d1e92f05e1d27b4d53', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '91350f8ecf9ab2922ee062c114e4a759f24bd8d0', 'src/third_party/webrtc': Var('webrtc_git') + '/src.git' + '@' + '02d7d353a90bccc6fdd0e517af31fab50944d31c', @@ -1400,7 +1400,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@dbcafbd04544f460eadeccb3a7f8f5b6149937cc', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@097e6a0deb3091ac1c592c18ab61b4e2162467cd', 'condition': 'checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 5ac749f..e03180a 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -431,6 +431,8 @@ "login/ui/login_user_menu_view.h", "login/ui/login_user_view.cc", "login/ui/login_user_view.h", + "login/ui/media_controls_header_view.cc", + "login/ui/media_controls_header_view.h", "login/ui/non_accessible_view.cc", "login/ui/non_accessible_view.h", "login/ui/note_action_launch_button.cc", @@ -1658,6 +1660,7 @@ "login/ui/fake_login_detachable_base_model.cc", "login/ui/fake_login_detachable_base_model.h", "login/ui/lock_contents_view_unittest.cc", + "login/ui/lock_screen_media_controls_view_unittest.cc", "login/ui/lock_screen_sanity_unittest.cc", "login/ui/lock_window_unittest.cc", "login/ui/login_auth_user_view_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 6a9c319c..07c5f7f3 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1970,6 +1970,11 @@ <message name="IDS_ASH_MEDIA_NOTIFICATION_ACCESSIBLE_NAME" desc="The accessible name for the media notification to control playback"> Media Controls </message> + + <!-- Lock Screen Media Controls --> + <message name="IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_ACCESSIBLE_NAME" desc="The accessible name for the lock screen media controls view."> + Media Controls + </message> </messages> </release> </grit>
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc index cee939e..e502ea8a 100644 --- a/ash/login/ui/lock_screen_media_controls_view.cc +++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -3,22 +3,44 @@ // found in the LICENSE file. #include "ash/login/ui/lock_screen_media_controls_view.h" + #include "ash/login/ui/lock_contents_view.h" +#include "ash/login/ui/media_controls_header_view.h" #include "ash/media/media_controller_impl.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "components/media_message_center/media_notification_util.h" #include "services/media_session/public/mojom/constants.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h" #include "services/service_manager/public/cpp/connector.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/vector_icons.h" #include "ui/views/background.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/layout/box_layout.h" namespace ash { namespace { -// Total width of the media controls view. -const int kMediaControlsTotalWidthDp = 320; -// Total height of the media controls view. -const int kMediaControlsTotalHeightDp = 400; +constexpr SkColor kMediaControlsBackground = SkColorSetA(SK_ColorDKGRAY, 100); + +// Dimensions. +constexpr int kMediaControlsTotalWidthDp = 320; +constexpr int kMediaControlsTotalHeightDp = 400; +constexpr int kMediaControlsCornerRadius = 8; +constexpr gfx::Insets kMediaControlsInsets = gfx::Insets(25, 25, 50, 25); +constexpr int kMediaControlsChildSpacing = 50; +constexpr int kMinimumIconSize = 16; +constexpr int kDesiredIconSize = 20; +constexpr int kIconSize = 20; +constexpr int kMinimumArtworkSize = 200; +constexpr int kDesiredArtworkSize = 300; +constexpr int kArtworkViewWidth = 270; +constexpr int kArtworkViewHeight = 200; // How long to wait (in milliseconds) for a new media session to begin. constexpr base::TimeDelta kNextMediaDelay = @@ -26,6 +48,25 @@ constexpr const char kLockScreenMediaControlsViewName[] = "LockScreenMediaControlsView"; + +// Scales |size| to fit |view_size| while preserving proportions. +gfx::Size ScaleSizeToFitView(const gfx::Size& size, + const gfx::Size& view_size) { + // If |size| is too big in either dimension or two small in both + // dimensions, scale it appropriately. + if ((size.width() > view_size.width() || + size.height() > view_size.height()) || + (size.width() < view_size.width() && + size.height() < view_size.height())) { + const float scale = + std::min(view_size.width() / static_cast<float>(size.width()), + view_size.height() / static_cast<float>(size.height())); + return gfx::ScaleToFlooredSize(size, scale); + } + + return size; +} + } // namespace LockScreenMediaControlsView::LockScreenMediaControlsView( @@ -34,13 +75,32 @@ : view_(view), connector_(connector), hide_controls_timer_(new base::OneShotTimer()) { - SetBackground(views::CreateSolidBackground(SK_ColorBLACK)); + SetBackground(views::CreateRoundedRectBackground(kMediaControlsBackground, + kMediaControlsCornerRadius)); middle_spacing_ = std::make_unique<NonAccessibleView>(); middle_spacing_->set_owned_by_client(); // Media controls have not been dismissed initially. Shell::Get()->media_controller()->SetMediaControlsDismissed(false); + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, kMediaControlsInsets, + kMediaControlsChildSpacing)); + + header_row_ = AddChildView(std::make_unique<MediaControlsHeaderView>()); + + auto session_artwork = std::make_unique<views::ImageView>(); + session_artwork->SetPreferredSize( + gfx::Size(kArtworkViewWidth, kArtworkViewHeight)); + session_artwork_ = AddChildView(std::move(session_artwork)); + + // Set child view data to default values initially, until the media controller + // observers are triggered by a change in media session state.. + MediaSessionMetadataChanged(base::nullopt); + MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kSourceIcon, SkBitmap()); + SetArtwork(base::nullopt); + // |connector_| can be null in tests. if (!connector_) return; @@ -57,17 +117,40 @@ media_session::mojom::MediaControllerObserverPtr media_controller_observer; observer_binding_.Bind(mojo::MakeRequest(&media_controller_observer)); media_controller_ptr_->AddObserver(std::move(media_controller_observer)); + + media_session::mojom::MediaControllerImageObserverPtr artwork_observer; + artwork_observer_binding_.Bind(mojo::MakeRequest(&artwork_observer)); + media_controller_ptr_->ObserveImages( + media_session::mojom::MediaSessionImageType::kArtwork, + kMinimumArtworkSize, kDesiredArtworkSize, std::move(artwork_observer)); + + media_session::mojom::MediaControllerImageObserverPtr icon_observer; + icon_observer_binding_.Bind(mojo::MakeRequest(&icon_observer)); + media_controller_ptr_->ObserveImages( + media_session::mojom::MediaSessionImageType::kSourceIcon, + kMinimumIconSize, kDesiredIconSize, std::move(icon_observer)); } LockScreenMediaControlsView::~LockScreenMediaControlsView() = default; -// views::View: +const char* LockScreenMediaControlsView::GetClassName() const { + return kLockScreenMediaControlsViewName; +} + gfx::Size LockScreenMediaControlsView::CalculatePreferredSize() const { return gfx::Size(kMediaControlsTotalWidthDp, kMediaControlsTotalHeightDp); } -const char* LockScreenMediaControlsView::GetClassName() const { - return kLockScreenMediaControlsViewName; +void LockScreenMediaControlsView::GetAccessibleNodeData( + ui::AXNodeData* node_data) { + node_data->role = ax::mojom::Role::kListItem; + node_data->AddStringAttribute( + ax::mojom::StringAttribute::kRoleDescription, + l10n_util::GetStringUTF8( + IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_ACCESSIBLE_NAME)); + + if (!accessible_name_.empty()) + node_data->SetName(accessible_name_); } views::View* LockScreenMediaControlsView::GetMiddleSpacingView() { @@ -103,4 +186,51 @@ media_session_info_ = std::move(session_info); } +void LockScreenMediaControlsView::MediaSessionMetadataChanged( + const base::Optional<media_session::MediaMetadata>& metadata) { + media_session::MediaMetadata session_metadata = + metadata.value_or(media_session::MediaMetadata()); + base::string16 source_title = + session_metadata.source_title.empty() + ? message_center::MessageCenter::Get()->GetSystemNotificationAppName() + : session_metadata.source_title; + header_row_->SetAppName(source_title); + + accessible_name_ = + media_message_center::GetAccessibleNameFromMetadata(session_metadata); +} + +void LockScreenMediaControlsView::MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType type, + const SkBitmap& bitmap) { + switch (type) { + case media_session::mojom::MediaSessionImageType::kArtwork: { + base::Optional<gfx::ImageSkia> session_artwork = + gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + SetArtwork(session_artwork); + break; + } + case media_session::mojom::MediaSessionImageType::kSourceIcon: { + gfx::ImageSkia session_icon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + if (session_icon.isNull()) { + session_icon = gfx::CreateVectorIcon(message_center::kProductIcon, + kIconSize, gfx::kChromeIconGrey); + } + header_row_->SetAppIcon(session_icon); + } + } +} + +void LockScreenMediaControlsView::SetArtwork( + base::Optional<gfx::ImageSkia> img) { + if (!img.has_value()) { + session_artwork_->SetImage(nullptr); + return; + } + + session_artwork_->SetImageSize(ScaleSizeToFitView( + img->size(), gfx::Size(kArtworkViewWidth, kArtworkViewHeight))); + session_artwork_->SetImage(*img); +} + } // namespace ash
diff --git a/ash/login/ui/lock_screen_media_controls_view.h b/ash/login/ui/lock_screen_media_controls_view.h index 2f971bf..78498fd7 100644 --- a/ash/login/ui/lock_screen_media_controls_view.h +++ b/ash/login/ui/lock_screen_media_controls_view.h
@@ -13,23 +13,30 @@ namespace service_manager { class Connector; -} // namespace service_manager +} + +namespace views { +class ImageView; +} namespace ash { class LockContentsView; +class MediaControlsHeaderView; -class LockScreenMediaControlsView +class ASH_EXPORT LockScreenMediaControlsView : public views::View, - public media_session::mojom::MediaControllerObserver { + public media_session::mojom::MediaControllerObserver, + public media_session::mojom::MediaControllerImageObserver { public: LockScreenMediaControlsView(service_manager::Connector* connector, LockContentsView* view); ~LockScreenMediaControlsView() override; // views::View: - gfx::Size CalculatePreferredSize() const override; const char* GetClassName() const override; + gfx::Size CalculatePreferredSize() const override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; views::View* GetMiddleSpacingView(); @@ -37,18 +44,29 @@ void MediaSessionInfoChanged( media_session::mojom::MediaSessionInfoPtr session_info) override; void MediaSessionMetadataChanged( - const base::Optional<media_session::MediaMetadata>& metadata) override {} + const base::Optional<media_session::MediaMetadata>& metadata) override; void MediaSessionActionsChanged( const std::vector<media_session::mojom::MediaSessionAction>& actions) override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + // media_session::mojom::MediaControllerImageObserver: + void MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType type, + const SkBitmap& bitmap) override; + void set_timer_for_testing(std::unique_ptr<base::OneShotTimer> test_timer) { hide_controls_timer_ = std::move(test_timer); } private: + friend class LockScreenMediaControlsViewTest; + + // Sets the media artwork to |img|. If |img| is nullopt, the default artwork + // is set instead. + void SetArtwork(base::Optional<gfx::ImageSkia> img); + // Lock screen view which this view belongs to. LockContentsView* const view_; @@ -62,6 +80,14 @@ mojo::Binding<media_session::mojom::MediaControllerObserver> observer_binding_{this}; + // Used to receive updates to the active media's icon. + mojo::Binding<media_session::mojom::MediaControllerImageObserver> + icon_observer_binding_{this}; + + // Used to receive updates to the active media's artwork. + mojo::Binding<media_session::mojom::MediaControllerImageObserver> + artwork_observer_binding_{this}; + // The info about the current media session. It will be null if there is not // a current session. media_session::mojom::MediaSessionInfoPtr media_session_info_; @@ -72,6 +98,14 @@ // Automatically hides the controls a few seconds if no media playing. std::unique_ptr<base::OneShotTimer> hide_controls_timer_; + // Caches the text to be read by screen readers describing the media controls + // view. + base::string16 accessible_name_; + + // Container views directly attached to this view. + MediaControlsHeaderView* header_row_ = nullptr; + views::ImageView* session_artwork_ = nullptr; + DISALLOW_COPY_AND_ASSIGN(LockScreenMediaControlsView); };
diff --git a/ash/login/ui/lock_screen_media_controls_view_unittest.cc b/ash/login/ui/lock_screen_media_controls_view_unittest.cc new file mode 100644 index 0000000..4381981a --- /dev/null +++ b/ash/login/ui/lock_screen_media_controls_view_unittest.cc
@@ -0,0 +1,186 @@ +// 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 "ash/login/ui/lock_screen_media_controls_view.h" + +#include "ash/login/ui/fake_login_detachable_base_model.h" +#include "ash/login/ui/lock_contents_view.h" +#include "ash/login/ui/login_test_base.h" +#include "ash/login/ui/media_controls_header_view.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/vector_icons.h" +#include "ui/views/controls/image_view.h" + +namespace ash { + +namespace { + +const int kAppIconSize = 20; +constexpr int kArtworkViewWidth = 270; +constexpr int kArtworkViewHeight = 200; +const base::string16 kTestAppName = base::ASCIIToUTF16("Test app"); + +} // namespace + +class LockScreenMediaControlsViewTest : public LoginTestBase { + public: + LockScreenMediaControlsViewTest() = default; + ~LockScreenMediaControlsViewTest() override = default; + + void SetUp() override { + LoginTestBase::SetUp(); + + lock_contents_view_ = new LockContentsView( + mojom::TrayActionState::kAvailable, LockScreen::ScreenType::kLock, + DataDispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + LockContentsView::TestApi lock_contents(lock_contents_view_); + + std::unique_ptr<views::Widget> widget = + CreateWidgetWithContent(lock_contents_view_); + SetWidget(std::move(widget)); + + SetUserCount(1); + + media_controls_view_ = lock_contents.media_controls_view(); + } + + MediaControlsHeaderView* header_row() const { + return media_controls_view_->header_row_; + } + + views::ImageView* artwork_view() const { + return media_controls_view_->session_artwork_; + } + + const gfx::ImageSkia& GetAppIcon() const { + return header_row()->app_icon_for_testing(); + } + + const base::string16& GetAppName() const { + return header_row()->app_name_for_testing(); + } + + LockScreenMediaControlsView* media_controls_view_ = nullptr; + + private: + LockContentsView* lock_contents_view_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(LockScreenMediaControlsViewTest); +}; + +TEST_F(LockScreenMediaControlsViewTest, UpdateAppIcon) { + gfx::ImageSkia default_icon = gfx::CreateVectorIcon( + message_center::kProductIcon, kAppIconSize, gfx::kChromeIconGrey); + + // Verify that the icon is initialized to the default. + EXPECT_TRUE(GetAppIcon().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, GetAppIcon().width()); + EXPECT_EQ(kAppIconSize, GetAppIcon().height()); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kSourceIcon, SkBitmap()); + + // Verify that the default icon is used if no icon is provided. + EXPECT_TRUE(GetAppIcon().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, GetAppIcon().width()); + EXPECT_EQ(kAppIconSize, GetAppIcon().height()); + + SkBitmap bitmap; + bitmap.allocN32Pixels(kAppIconSize, kAppIconSize); + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kSourceIcon, bitmap); + + // Verify that the provided icon is used. + EXPECT_FALSE(GetAppIcon().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, GetAppIcon().width()); + EXPECT_EQ(kAppIconSize, GetAppIcon().height()); +} + +TEST_F(LockScreenMediaControlsViewTest, UpdateAppName) { + // Verify that the app name is initialized to the default. + EXPECT_EQ( + message_center::MessageCenter::Get()->GetSystemNotificationAppName(), + GetAppName()); + + media_session::MediaMetadata metadata; + media_controls_view_->MediaSessionMetadataChanged(metadata); + + // Verify that default name is used if no name is provided. + EXPECT_EQ( + message_center::MessageCenter::Get()->GetSystemNotificationAppName(), + GetAppName()); + + metadata.source_title = kTestAppName; + media_controls_view_->MediaSessionMetadataChanged(metadata); + + // Verify that the provided app name is used. + EXPECT_EQ(kTestAppName, GetAppName()); +} + +TEST_F(LockScreenMediaControlsViewTest, UpdateArtwork) { + // Verify that the artwork is initially empty. + EXPECT_TRUE(artwork_view()->GetImage().isNull()); + + // Create artwork that must be scaled down to fit the view. + SkBitmap artwork; + artwork.allocN32Pixels(540, 300); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kArtwork, artwork); + + gfx::Rect artwork_bounds = artwork_view()->GetImageBounds(); + + // Verify that the provided artwork is correctly scaled down. + EXPECT_EQ(kArtworkViewWidth, artwork_bounds.width()); + EXPECT_EQ(150, artwork_bounds.height()); + + // Create artwork that must be scaled up to fit the view. + artwork.allocN32Pixels(200, 190); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kArtwork, artwork); + + artwork_bounds = artwork_view()->GetImageBounds(); + + // Verify that the provided artwork is correctly scaled up. + EXPECT_EQ(210, artwork_bounds.width()); + EXPECT_EQ(kArtworkViewHeight, artwork_bounds.height()); + + // Create artwork that already fits the view size. + artwork.allocN32Pixels(250, kArtworkViewHeight); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kArtwork, artwork); + + artwork_bounds = artwork_view()->GetImageBounds(); + + // Verify that the provided artwork size doesn't change. + EXPECT_EQ(250, artwork_bounds.width()); + EXPECT_EQ(kArtworkViewHeight, artwork_bounds.height()); +} + +TEST_F(LockScreenMediaControlsViewTest, AccessibleNodeData) { + ui::AXNodeData data; + media_controls_view_->GetAccessibleNodeData(&data); + + // Verify that the accessible name is initially empty. + EXPECT_FALSE(data.HasStringAttribute(ax::mojom::StringAttribute::kName)); + + // Update the metadata. + media_session::MediaMetadata metadata; + metadata.title = base::ASCIIToUTF16("title"); + metadata.artist = base::ASCIIToUTF16("artist"); + media_controls_view_->MediaSessionMetadataChanged(metadata); + media_controls_view_->GetAccessibleNodeData(&data); + + // Verify that the accessible name updates with the metadata. + EXPECT_TRUE( + data.HasStringAttribute(ax::mojom::StringAttribute::kRoleDescription)); + EXPECT_EQ(base::ASCIIToUTF16("title - artist"), + data.GetString16Attribute(ax::mojom::StringAttribute::kName)); +} + +} // namespace ash \ No newline at end of file
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc new file mode 100644 index 0000000..103dd42738 --- /dev/null +++ b/ash/login/ui/media_controls_header_view.cc
@@ -0,0 +1,78 @@ +// 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 "ash/login/ui/media_controls_header_view.h" + +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/font_list.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { + +namespace { + +constexpr int kIconSize = 20; +constexpr int kHeaderTextFontSize = 14; +constexpr int kMediaControlsHeaderChildSpacing = 10; +constexpr gfx::Insets kIconPadding = gfx::Insets(1, 1, 1, 1); +constexpr int kIconCornerRadius = 2; + +} // namespace + +MediaControlsHeaderView::MediaControlsHeaderView() { + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), + kMediaControlsHeaderChildSpacing)); + + auto app_icon_view = std::make_unique<views::ImageView>(); + app_icon_view->SetImageSize(gfx::Size(kIconSize, kIconSize)); + app_icon_view->SetVerticalAlignment(views::ImageView::Alignment::kLeading); + app_icon_view->SetHorizontalAlignment(views::ImageView::Alignment::kLeading); + app_icon_view->SetBorder(views::CreateEmptyBorder(kIconPadding)); + app_icon_view->SetBackground( + views::CreateRoundedRectBackground(SK_ColorWHITE, kIconCornerRadius)); + app_icon_view_ = AddChildView(std::move(app_icon_view)); + + // Font list for text views. + gfx::Font default_font; + int font_size_delta = kHeaderTextFontSize - default_font.GetFontSize(); + gfx::Font font = default_font.Derive(font_size_delta, gfx::Font::NORMAL, + gfx::Font::Weight::NORMAL); + gfx::FontList font_list(font); + + auto app_name_view = std::make_unique<views::Label>(); + app_name_view->SetFontList(font_list); + app_name_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); + app_name_view->SetEnabledColor(SK_ColorWHITE); + app_name_view->SetAutoColorReadabilityEnabled(false); + app_name_view_ = AddChildView(std::move(app_name_view)); +} + +MediaControlsHeaderView::~MediaControlsHeaderView() = default; + +void MediaControlsHeaderView::SetAppIcon(const gfx::ImageSkia& img) { + app_icon_view_->SetImage(img); +} + +void MediaControlsHeaderView::SetAppName(const base::string16& name) { + app_name_view_->SetText(name); +} + +void MediaControlsHeaderView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->SetName(app_name_view_->GetText()); +} + +const base::string16& MediaControlsHeaderView::app_name_for_testing() const { + return app_name_view_->GetText(); +} + +const gfx::ImageSkia& MediaControlsHeaderView::app_icon_for_testing() const { + return app_icon_view_->GetImage(); +} + +} // namespace ash \ No newline at end of file
diff --git a/ash/login/ui/media_controls_header_view.h b/ash/login/ui/media_controls_header_view.h new file mode 100644 index 0000000..3d6154b --- /dev/null +++ b/ash/login/ui/media_controls_header_view.h
@@ -0,0 +1,41 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_LOGIN_UI_MEDIA_CONTROLS_HEADER_VIEW_H_ +#define ASH_LOGIN_UI_MEDIA_CONTROLS_HEADER_VIEW_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace views { +class ImageView; +class Label; +} // namespace views + +namespace ash { + +class ASH_EXPORT MediaControlsHeaderView : public views::View { + public: + MediaControlsHeaderView(); + ~MediaControlsHeaderView() override; + + void SetAppIcon(const gfx::ImageSkia& img); + void SetAppName(const base::string16& name); + + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + const base::string16& app_name_for_testing() const; + const gfx::ImageSkia& app_icon_for_testing() const; + + private: + views::ImageView* app_icon_view_; + views::Label* app_name_view_; + + DISALLOW_COPY_AND_ASSIGN(MediaControlsHeaderView); +}; + +} // namespace ash + +#endif // ASH_LOGIN_UI_MEDIA_CONTROLS_HEADER_VIEW_H_ \ No newline at end of file
diff --git a/ash/system/audio/unified_volume_view.cc b/ash/system/audio/unified_volume_view.cc index 90196b74a..62b30c3 100644 --- a/ash/system/audio/unified_volume_view.cc +++ b/ash/system/audio/unified_volume_view.cc
@@ -9,6 +9,7 @@ #include "ash/system/audio/unified_volume_slider_controller.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_popup_utils.h" +#include "base/i18n/rtl.h" #include "base/stl_util.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" @@ -73,9 +74,12 @@ auto* more = new views::ImageView(); more->set_can_process_events_within_subtree(false); + auto icon_rotation = base::i18n::IsRTL() + ? SkBitmapOperations::ROTATION_270_CW + : SkBitmapOperations::ROTATION_90_CW; more->SetImage(gfx::ImageSkiaOperations::CreateRotatedImage( CreateVectorIcon(kUnifiedMenuExpandIcon, kUnifiedMenuIconColor), - SkBitmapOperations::ROTATION_90_CW)); + icon_rotation)); AddChildView(more); SetTooltipText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO));
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index 31965c33..8f8c992 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -379,6 +379,8 @@ overview_bounds_.reset(); } +// TODO(sammiequon): Investigate if waiting till the end of the animation to set +// these properties is still required. void ScopedOverviewTransformWindow::UpdateMask(bool show) { // Minimized windows have their corners rounded in CaptionContainerView. if (IsMinimized()) @@ -392,11 +394,13 @@ : 0.0f); layer->SetRoundedCornerRadius(radii); layer->SetIsFastRoundedCorner(true); - int top_inset = GetTopInset(); - if (top_inset > 0) { - gfx::Rect clip_rect(window_->bounds().size()); - clip_rect.Inset(0, top_inset, 0, 0); - layer->SetClipRect(clip_rect); + if (!layer->GetAnimator()->is_animating()) { + int top_inset = GetTopInset(); + if (top_inset > 0) { + gfx::Rect clip_rect(window_->bounds().size()); + clip_rect.Inset(0, top_inset, 0, 0); + layer->SetClipRect(clip_rect); + } } }
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py index 0d7b4473..6a51396 100644 --- a/build/fuchsia/device_target.py +++ b/build/fuchsia/device_target.py
@@ -160,7 +160,7 @@ if self._node_name: # Handle the result of "dev_finder resolve". - self._host = output[0].strip() + self._host = output.pop().strip() else: name_host_pairs = [x.strip().split(' ') for x in output]
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index db96dbf..a0e1d62 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8909016706543512784 \ No newline at end of file +8908988868010627552 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index d5d8184..0145f776 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8909064474621102512 \ No newline at end of file +8908988579903450896 \ No newline at end of file
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc index 5168e82..f2d85b5 100644 --- a/cc/animation/animation_host.cc +++ b/cc/animation/animation_host.cc
@@ -653,10 +653,12 @@ ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, - float autoscroll_velocity) { + float autoscroll_velocity, + base::TimeDelta animation_start_offset) { DCHECK(scroll_offset_animations_impl_); scroll_offset_animations_impl_->AutoScrollAnimationCreate( - element_id, target_offset, current_offset, autoscroll_velocity); + element_id, target_offset, current_offset, autoscroll_velocity, + animation_start_offset); } void AnimationHost::ImplOnlyScrollAnimationCreate(
diff --git a/cc/animation/animation_host.h b/cc/animation/animation_host.h index 84cba1b..0e770e06 100644 --- a/cc/animation/animation_host.h +++ b/cc/animation/animation_host.h
@@ -168,7 +168,8 @@ ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, - float autoscroll_velocity) override; + float autoscroll_velocity, + base::TimeDelta animation_start_offset) override; void ImplOnlyScrollAnimationCreate( ElementId element_id,
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc index d713fa375..0bc523f 100644 --- a/cc/animation/scroll_offset_animation_curve.cc +++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -103,7 +103,8 @@ kInverseDeltaMaxDuration); break; case DurationBehavior::CONSTANT_VELOCITY: - duration = MaximumDimension(delta) / velocity * kDurationDivisor; + duration = + std::abs(MaximumDimension(delta) / velocity * kDurationDivisor); break; default: NOTREACHED();
diff --git a/cc/animation/scroll_offset_animations_impl.cc b/cc/animation/scroll_offset_animations_impl.cc index a54fa300..5c7ff936 100644 --- a/cc/animation/scroll_offset_animations_impl.cc +++ b/cc/animation/scroll_offset_animations_impl.cc
@@ -38,7 +38,8 @@ ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, - float autoscroll_velocity) { + float autoscroll_velocity, + base::TimeDelta animation_start_offset) { std::unique_ptr<ScrollOffsetAnimationCurve> curve = ScrollOffsetAnimationCurve::Create( target_offset, LinearTimingFunction::Create(), @@ -46,7 +47,7 @@ curve->SetInitialValue(current_offset, base::TimeDelta(), autoscroll_velocity); ScrollAnimationCreateInternal(element_id, std::move(curve), - base::TimeDelta()); + animation_start_offset); } void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
diff --git a/cc/animation/scroll_offset_animations_impl.h b/cc/animation/scroll_offset_animations_impl.h index 3f959faa..4371deed 100644 --- a/cc/animation/scroll_offset_animations_impl.h +++ b/cc/animation/scroll_offset_animations_impl.h
@@ -35,7 +35,8 @@ void AutoScrollAnimationCreate(ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, - float autoscroll_velocity); + float autoscroll_velocity, + base::TimeDelta animation_start_offset); // |delayed_by| shrinks the duration of the // animation. |animation_start_offset| causes us to start the animation
diff --git a/cc/input/scrollbar.h b/cc/input/scrollbar.h index ec23fef..c63c800 100644 --- a/cc/input/scrollbar.h +++ b/cc/input/scrollbar.h
@@ -10,8 +10,15 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" -static const int kPixelsPerLineStep = 40; -static const float kMinFractionToStepWhenPaging = 0.875f; +static constexpr int kPixelsPerLineStep = 40; +static constexpr float kMinFractionToStepWhenPaging = 0.875f; + +// Autoscrolling (on the main thread) happens by applying a delta every 50ms. +// Hence, pixels per second for a autoscroll cc animation can be calculated as: +// autoscroll velocity = delta / 0.05 sec = delta x 20 +static constexpr float kAutoscrollMultiplier = 20.f; +static constexpr base::TimeDelta kInitialAutoscrollTimerDelay = + base::TimeDelta::FromMilliseconds(250); namespace cc {
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc index d29a257..d95235f 100644 --- a/cc/input/scrollbar_controller.cc +++ b/cc/input/scrollbar_controller.cc
@@ -6,19 +6,30 @@ #include <algorithm> +#include "base/cancelable_callback.h" #include "cc/base/math_util.h" #include "cc/input/scrollbar.h" #include "cc/input/scrollbar_controller.h" #include "cc/trees/layer_tree_impl.h" +#include "cc/trees/scroll_node.h" namespace cc { +ScrollbarController::~ScrollbarController() { + if (cancelable_autoscroll_task_) { + cancelable_autoscroll_task_->Cancel(); + cancelable_autoscroll_task_.reset(); + } +} + ScrollbarController::ScrollbarController( LayerTreeHostImpl* layer_tree_host_impl) : layer_tree_host_impl_(layer_tree_host_impl), scrollbar_scroll_is_active_(false), thumb_drag_in_progress_(false), + autoscroll_in_progress_(false), currently_captured_scrollbar_(nullptr), - previous_pointer_position_(gfx::PointF(0, 0)) {} + previous_pointer_position_(gfx::PointF(0, 0)), + cancelable_autoscroll_task_(nullptr) {} // Performs hit test and prepares scroll deltas that will be used by GSB and // GSU. @@ -49,6 +60,19 @@ ui::input_types::ScrollGranularity::kScrollByPixel; } + // Thumb drag is the only scrollbar manipulation that cannot produce an + // autoscroll. All other interactions like clicking on arrows/trackparts have + // the potential of initiating an autoscroll (if held down long enough). + if (!scroll_result.scroll_offset.IsZero() && !thumb_drag_in_progress_) { + cancelable_autoscroll_task_ = std::make_unique<base::CancelableClosure>( + base::Bind(&ScrollbarController::StartAutoScrollAnimation, + base::Unretained(this), scroll_result.scroll_offset, + currently_captured_scrollbar_->scroll_element_id())); + layer_tree_host_impl_->task_runner_provider() + ->ImplThreadTaskRunner() + ->PostDelayedTask(FROM_HERE, cancelable_autoscroll_task_->callback(), + kInitialAutoscrollTimerDelay); + } return scroll_result; } @@ -138,6 +162,52 @@ return scroll_result; } +void ScrollbarController::StartAutoScrollAnimation( + gfx::ScrollOffset scroll_offset, + ElementId element_id) { + // scroll_node is set up while handling GSB. If there's no node to scroll, we + // don't need to create any animation for it. + ScrollTree& scroll_tree = + layer_tree_host_impl_->active_tree()->property_trees()->scroll_tree; + ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id); + + if (!(scroll_node && scrollbar_scroll_is_active_)) + return; + + layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); + ScrollbarOrientation orientation = + currently_captured_scrollbar_->orientation(); + // TODO(arakeri): The animation needs to be readjusted if the scroller length + // changes. Tracked here: crbug.com/972485 + float scroll_layer_length = + currently_captured_scrollbar_->scroll_layer_length(); + + gfx::ScrollOffset current_offset = + scroll_tree.current_scroll_offset(scroll_node->element_id); + gfx::Vector2dF target_offset; + + // Determine the max offset for the scroll based on the scrolling direction. + // Negative scroll_delta indicates backwards scrolling whereas a positive + // scroll_delta indicates forwards scrolling. + float scroll_delta = 0; + if (orientation == ScrollbarOrientation::VERTICAL) { + DCHECK_NE(scroll_offset.y(), 0); + scroll_delta = scroll_offset.y(); + float final_offset = scroll_delta < 0 ? 0 : scroll_layer_length; + target_offset = gfx::Vector2dF(current_offset.x(), final_offset); + } else { + DCHECK_NE(scroll_offset.x(), 0); + scroll_delta = scroll_offset.x(); + float final_offset = scroll_delta < 0 ? 0 : scroll_layer_length; + target_offset = gfx::Vector2dF(final_offset, current_offset.y()); + } + + float autoscroll_velocity = std::abs(scroll_delta) * kAutoscrollMultiplier; + autoscroll_in_progress_ = true; + layer_tree_host_impl_->AutoScrollAnimationCreate(scroll_node, target_offset, + autoscroll_velocity); +} + // Performs hit test and prepares scroll deltas that will be used by GSE. InputHandlerPointerResult ScrollbarController::HandleMouseUp( const gfx::PointF position_in_widget) { @@ -146,7 +216,20 @@ scrollbar_scroll_is_active_ = false; scroll_result.type = PointerResultType::kScrollbarScroll; } + + // TODO(arakeri): This needs to be moved to ScrollOffsetAnimationsImpl as it + // has knowledge about what type of animation is running. crbug.com/976353 + // Only abort the animation if it is an "autoscroll" animation. + if (autoscroll_in_progress_) + layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); + + if (cancelable_autoscroll_task_) { + cancelable_autoscroll_task_->Cancel(); + cancelable_autoscroll_task_.reset(); + } + thumb_drag_in_progress_ = false; + autoscroll_in_progress_ = false; return scroll_result; }
diff --git a/cc/input/scrollbar_controller.h b/cc/input/scrollbar_controller.h index 3ce46246..517fa9f51 100644 --- a/cc/input/scrollbar_controller.h +++ b/cc/input/scrollbar_controller.h
@@ -18,7 +18,7 @@ class CC_EXPORT ScrollbarController { public: explicit ScrollbarController(LayerTreeHostImpl*); - virtual ~ScrollbarController() = default; + virtual ~ScrollbarController(); InputHandlerPointerResult HandleMouseDown( const gfx::PointF position_in_widget); @@ -26,6 +26,16 @@ const gfx::PointF position_in_widget); InputHandlerPointerResult HandleMouseUp(const gfx::PointF position_in_widget); + // scroll_offset is the delta from the initial click. This is needed to + // determine whether we should set up the autoscrolling in the forwards or the + // backwards direction and the speed of the animation. + void StartAutoScrollAnimation(gfx::ScrollOffset scroll_offset, + ElementId element_id); + bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; } + ScrollbarOrientation orientation() { + return currently_captured_scrollbar_->orientation(); + } + private: // Returns a gfx::ScrollOffset object which contains scroll deltas for the // synthetic Gesture events. @@ -43,10 +53,17 @@ // Used to tell if the scrollbar thumb is getting dragged. bool thumb_drag_in_progress_; + + // "Autoscroll" here means the continuous scrolling that occurs when the + // pointer is held down on a hit-testable area of the scrollbar such as an + // arrows of the track itself. + bool autoscroll_in_progress_; const ScrollbarLayerImplBase* currently_captured_scrollbar_; // This is relative to the RenderWidget's origin. gfx::PointF previous_pointer_position_; + + std::unique_ptr<base::CancelableClosure> cancelable_autoscroll_task_; }; } // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 9465fb7..d645e1d2 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -38,6 +38,7 @@ #include "cc/input/page_scale_animation.h" #include "cc/input/scroll_elasticity_helper.h" #include "cc/input/scroll_state.h" +#include "cc/input/scrollbar.h" #include "cc/input/scrollbar_animation_controller.h" #include "cc/input/scroller_size_metrics.h" #include "cc/input/snap_selection_strategy.h" @@ -3939,14 +3940,31 @@ return gfx::Vector2dF(scrolled.x(), scrolled.y()); } +bool LayerTreeHostImpl::AutoScrollAnimationCreate(ScrollNode* scroll_node, + const gfx::Vector2dF& delta, + float autoscroll_velocity) { + return ScrollAnimationCreateInternal(scroll_node, delta, base::TimeDelta(), + autoscroll_velocity); +} + bool LayerTreeHostImpl::ScrollAnimationCreate(ScrollNode* scroll_node, const gfx::Vector2dF& delta, base::TimeDelta delayed_by) { + return ScrollAnimationCreateInternal(scroll_node, delta, delayed_by, + base::nullopt); +} + +bool LayerTreeHostImpl::ScrollAnimationCreateInternal( + ScrollNode* scroll_node, + const gfx::Vector2dF& delta, + base::TimeDelta delayed_by, + base::Optional<float> autoscroll_velocity) { ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; const float kEpsilon = 0.1f; bool scroll_animated = - (std::abs(delta.x()) > kEpsilon || std::abs(delta.y()) > kEpsilon); + (std::abs(delta.x()) > kEpsilon || std::abs(delta.y()) > kEpsilon) || + autoscroll_velocity; if (!scroll_animated) { scroll_tree.ScrollBy(scroll_node, delta, active_tree()); TRACE_EVENT_INSTANT0("cc", "no scroll animation due to small delta", @@ -3966,9 +3984,15 @@ // input latency tracking architecture from working. base::TimeDelta animation_start_offset = CurrentBeginFrameArgs().interval; - mutator_host_->ImplOnlyScrollAnimationCreate( - scroll_node->element_id, target_offset, current_offset, delayed_by, - animation_start_offset); + if (autoscroll_velocity) { + mutator_host_->ImplOnlyAutoScrollAnimationCreate( + scroll_node->element_id, gfx::ScrollOffset(delta), current_offset, + autoscroll_velocity.value(), animation_start_offset); + } else { + mutator_host_->ImplOnlyScrollAnimationCreate( + scroll_node->element_id, target_offset, current_offset, delayed_by, + animation_start_offset); + } SetNeedsOneBeginImplFrame();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index a348b86..4115da9 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -726,6 +726,9 @@ bool ScrollAnimationCreate(ScrollNode* scroll_node, const gfx::Vector2dF& scroll_amount, base::TimeDelta delayed_by); + bool AutoScrollAnimationCreate(ScrollNode* scroll_node, + const gfx::Vector2dF& scroll_amount, + float autoscroll_velocity); void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator); void SetPaintWorkletLayerPainter( @@ -817,6 +820,10 @@ const gfx::PointF& viewport_point, const gfx::Vector2dF& viewport_delta, ScrollTree* scroll_tree); + bool ScrollAnimationCreateInternal(ScrollNode* scroll_node, + const gfx::Vector2dF& delta, + base::TimeDelta delayed_by, + base::Optional<float> autoscroll_velocity); void CleanUpTileManagerResources(); void CreateTileManagerResources();
diff --git a/cc/trees/mutator_host.h b/cc/trees/mutator_host.h index 5496c42..49673bd6 100644 --- a/cc/trees/mutator_host.h +++ b/cc/trees/mutator_host.h
@@ -135,7 +135,8 @@ ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, - float autoscroll_velocity) = 0; + float autoscroll_velocity, + base::TimeDelta animation_start_offset) = 0; virtual void ImplOnlyScrollAnimationCreate( ElementId element_id,
diff --git a/chrome/VERSION b/chrome/VERSION index f358afb7..4fa6b80 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=77 MINOR=0 -BUILD=3842 +BUILD=3843 PATCH=0
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java index e061d311..739d1a180 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -255,7 +255,7 @@ } void showWhenKeyboardIsVisible() { - if (!isInitialized() || mKeyboardAccessory.empty()) return; + if (!isInitialized()) return; mModel.set(SHOW_WHEN_VISIBLE, true); if (is(HIDDEN)) mModel.set(KEYBOARD_EXTENSION_STATE, FLOATING_BAR); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index eacc712..1d997d3a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -256,6 +256,7 @@ public static final String SEARCH_ENGINE_PROMO_EXISTING_DEVICE = "SearchEnginePromo.ExistingDevice"; public static final String SEARCH_ENGINE_PROMO_NEW_DEVICE = "SearchEnginePromo.NewDevice"; + // TODO(crbug.com/980849) Remove ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY public static final String MOBILE_IDENTITY_CONSISTENCY = "MobileIdentityConsistency"; public static final String MODAL_PERMISSION_PROMPTS = "ModalPermissionPrompts"; public static final String MODAL_PERMISSION_DIALOG_VIEW = "ModalPermissionDialogView";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java index 53c0bdf4..d2f2c2c2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -27,7 +27,6 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.task.PostTask; -import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.components.signin.AccountIdProvider; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.AccountTrackerService; @@ -308,7 +307,7 @@ public boolean isSigninSupported() { return !ApiCompatibilityUtils.isDemoUser(mContext) && mDelegate.isGooglePlayServicesPresent(mContext) - && !ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY); + && !SigninManagerJni.get().isMobileIdentityConsistencyEnabled(); } /** @@ -732,5 +731,7 @@ boolean isSignedInOnNative(@JCaller SigninManager self, long nativeSigninManagerAndroid); String extractDomainName(String email); + + boolean isMobileIdentityConsistencyEnabled(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java index 3ad643d0..3ee437d4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java
@@ -19,7 +19,7 @@ /** * Perform destruction of the object, including destructing the associated native object. */ - public void destroy(); + void destroy(); /** * If there is no Google Play Services available, ask the user to fix by showing either a @@ -27,17 +27,17 @@ * @param activity The activity used to open the dialog, or null to use notifications * @param cancelable Whether the dialog can be canceled */ - public void handleGooglePlayServicesUnavailability(Activity activity, boolean cancelable); + void handleGooglePlayServicesUnavailability(Activity activity, boolean cancelable); /** * @return the management domain if the signed in account is managed, otherwise null. */ - public String getManagementDomain(); + String getManagementDomain(); /** * @return Whether the device has Google Play Services. */ - public boolean isGooglePlayServicesPresent(Context context); + boolean isGooglePlayServicesPresent(Context context); /** * Verifies if the account is managed. Callback may be called either synchronously or @@ -46,25 +46,25 @@ * @param callback The callback that will receive true if the account is managed, false * otherwise. */ - public void isAccountManaged(String email, final Callback<Boolean> callback); + void isAccountManaged(String email, final Callback<Boolean> callback); /** * Interact with the UserPolicySigninService to retrieve the user policy. * @param username (email) of the user signing in. * @param callback The callback called once the policy is retrieved and applied */ - public void fetchAndApplyCloudPolicy(String username, Runnable callback); + void fetchAndApplyCloudPolicy(String username, Runnable callback); /** * Perform the required cloud policy cleanup when a signin is aborted. */ - public void stopApplyingCloudPolicy(); + void stopApplyingCloudPolicy(); /** * Called AFTER native sign-in is complete, enabling Sync. * @param account to be used by sync */ - public void enableSync(Account account); + void enableSync(Account account); /** * Called AFTER native sign-out is complete, this method clears various @@ -73,5 +73,5 @@ * different cleanup flow * @param wipeDataCallback to be called once profile data cleanup is complete */ - public void disableSyncAndWipeData(boolean isManagedOrForceWipe, Runnable wipeDataCallback); + void disableSyncAndWipeData(boolean isManagedOrForceWipe, Runnable wipeDataCallback); }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 7fc3f33..b8a80341 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-77.0.3841.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-77.0.3842.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 0984de9..15ca8c9 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3632,12 +3632,6 @@ flag_descriptions::kEnableGpuServiceLoggingDescription, kOsAll, SINGLE_VALUE_TYPE(switches::kEnableGPUServiceLogging)}, -#if defined(OS_CHROMEOS) - {"crostini-app-search", flag_descriptions::kCrostiniAppSearchName, - flag_descriptions::kCrostiniAppSearchDescription, kOsCrOS, - FEATURE_VALUE_TYPE(features::kCrostiniAppSearch)}, -#endif // OS_CHROMEOS - #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) {"autofill-settings-split-by-card-type", flag_descriptions::kAutofillSettingsSplitByCardTypeName,
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc index 4db70d6..d573bd5f 100644 --- a/chrome/browser/android/signin/signin_manager_android.cc +++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -9,12 +9,14 @@ #include "base/android/jni_string.h" #include "base/bind.h" +#include "base/feature_list.h" #include "chrome/android/chrome_jni_headers/SigninManager_jni.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/signin/core/browser/account_consistency_method.h" #include "components/signin/core/browser/primary_account_manager.h" #include "components/signin/core/browser/signin_pref_names.h" #include "google_apis/gaia/gaia_auth_util.h" @@ -142,3 +144,7 @@ std::string domain = gaia::ExtractDomainName(email); return base::android::ConvertUTF8ToJavaString(env, domain); } + +jboolean JNI_SigninManager_IsMobileIdentityConsistencyEnabled(JNIEnv* env) { + return base::FeatureList::IsEnabled(signin::kMiceFeature); +}
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc index 9446e6a2..dca38b7 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -1205,23 +1205,6 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void CrostiniManager::GetLinuxPackageInfoFromApt( - const std::string& vm_name, - const std::string& container_name, - const std::string& package_name, - GetLinuxPackageInfoCallback callback) { - vm_tools::cicerone::LinuxPackageInfoRequest request; - request.set_owner_id(owner_id_); - request.set_vm_name(vm_name); - request.set_container_name(container_name); - request.set_package_name(package_name); - - GetCiceroneClient()->GetLinuxPackageInfo( - std::move(request), - base::BindOnce(&CrostiniManager::OnGetLinuxPackageInfo, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); -} - void CrostiniManager::InstallLinuxPackage( std::string vm_name, std::string container_name, @@ -1456,23 +1439,6 @@ std::move(callback).Run(/*success=*/true, std::move(mount_points)); } -void CrostiniManager::SearchApp(const std::string& vm_name, - const std::string& container_name, - const std::string& query, - SearchAppCallback callback) { - vm_tools::cicerone::AppSearchRequest request; - - request.set_owner_id(owner_id_); - request.set_vm_name(std::move(vm_name)); - request.set_container_name(std::move(container_name)); - request.set_query(query); - - GetCiceroneClient()->SearchApp( - std::move(request), - base::BindOnce(&CrostiniManager::OnSearchApp, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); -} - CrostiniManager::RestartId CrostiniManager::RestartCrostini( std::string vm_name, std::string container_name, @@ -2334,20 +2300,6 @@ } } -void CrostiniManager::OnSearchApp( - SearchAppCallback callback, - base::Optional<vm_tools::cicerone::AppSearchResponse> response) { - std::vector<std::string> package_names; - if (!response) { - LOG(ERROR) << "Failed to SearchApp. Empty response."; - std::move(callback).Run(package_names); - return; - } - for (auto& package : response->packages()) - package_names.push_back(package.package_name()); - std::move(callback).Run(package_names); -} - void CrostiniManager::OnExportLxdContainer( std::string vm_name, std::string container_name,
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h index 7d2f1d65..83711de 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.h +++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -400,13 +400,6 @@ std::string package_path, GetLinuxPackageInfoCallback callback); - // Asynchronously retrieve information about a Linux Package in the APT - // repository. This uses a package_name to identify a package. - void GetLinuxPackageInfoFromApt(const std::string& vm_name, - const std::string& container_name, - const std::string& package_name, - GetLinuxPackageInfoCallback callback); - // Begin installation of a Linux Package inside the container. If the // installation is successfully started, further updates will be sent to // added LinuxPackageOperationProgressObservers. @@ -472,15 +465,6 @@ void ListUsbDevices(const std::string& vm_name, ListUsbDevicesCallback callback); - // Searches for not installed packages that have names matching the passed - // plaintext search query and returns a vector containing their names. - using SearchAppCallback = - base::OnceCallback<void(const std::vector<std::string>& package_names)>; - void SearchApp(const std::string& vm_name, - const std::string& container_name, - const std::string& query, - SearchAppCallback callback); - using RestartId = int; static const RestartId kUninitializedRestartId = -1; // Runs all the steps required to restart the given crostini vm and container. @@ -718,8 +702,7 @@ GetContainerAppIconsCallback callback, base::Optional<vm_tools::cicerone::ContainerAppIconResponse> response); - // Callback for CrostiniManager::GetLinuxPackageInfo and - // CrostiniManager::GetLinuxPackageInfoFromApt. + // Callback for CrostiniManager::GetLinuxPackageInfo. void OnGetLinuxPackageInfo( GetLinuxPackageInfoCallback callback, base::Optional<vm_tools::cicerone::LinuxPackageInfoResponse> response); @@ -762,11 +745,6 @@ ListUsbDevicesCallback callback, base::Optional<vm_tools::concierge::ListUsbDeviceResponse> response); - // Callback for CrostiniManager::SearchApp. - void OnSearchApp( - SearchAppCallback callback, - base::Optional<vm_tools::cicerone::AppSearchResponse> response); - // Helper for CrostiniManager::MaybeUpgradeCrostini. Makes blocking calls to // check for file paths and registered components. static void CheckPathsAndComponents();
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc index 9cb7eee..50329b89 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -124,13 +124,6 @@ std::move(closure).Run(); } - void SearchAppCallback(base::OnceClosure closure, - const std::vector<std::string>& expected_result, - const std::vector<std::string>& result) { - EXPECT_THAT(result, testing::ContainerEq(expected_result)); - std::move(closure).Run(); - } - void GetLinuxPackageInfoFromAptCallback( base::OnceClosure closure, const LinuxPackageInfo& expected_result, @@ -1200,92 +1193,6 @@ run_loop()->Run(); } -TEST_F(CrostiniManagerTest, SearchAppSuccess) { - vm_tools::cicerone::AppSearchResponse response; - vm_tools::cicerone::AppSearchResponse::AppSearchResult* app = - response.add_packages(); - app->set_package_name("fake app"); - app = response.add_packages(); - app->set_package_name("fake app1"); - app = response.add_packages(); - app->set_package_name("fake app2"); - fake_cicerone_client_->set_search_app_response(response); - std::vector<std::string> expected = {"fake app", "fake app1", "fake app2"}; - crostini_manager()->SearchApp( - kVmName, kContainerName, "fake ap", - base::BindOnce(&CrostiniManagerTest::SearchAppCallback, - base::Unretained(this), run_loop()->QuitClosure(), - expected)); - run_loop()->Run(); -} - -TEST_F(CrostiniManagerTest, SearchAppNoResults) { - vm_tools::cicerone::AppSearchResponse response; - fake_cicerone_client_->set_search_app_response(response); - std::vector<std::string> expected = {}; - crostini_manager()->SearchApp( - kVmName, kContainerName, "fake ap", - base::BindOnce(&CrostiniManagerTest::SearchAppCallback, - base::Unretained(this), run_loop()->QuitClosure(), - expected)); - run_loop()->Run(); -} - -TEST_F(CrostiniManagerTest, GetLinuxPackageInfoFromAptFailedToGetInfo) { - const char kFailMessage[] = "Failed to get package info."; - vm_tools::cicerone::LinuxPackageInfoResponse response; - response.set_success(false); - response.set_failure_reason(kFailMessage); - fake_cicerone_client_->set_linux_package_info_response(response); - LinuxPackageInfo expected; - expected.success = false; - expected.failure_reason = kFailMessage; - crostini_manager()->GetLinuxPackageInfoFromApt( - kVmName, kContainerName, "fake app", - base::BindOnce(&CrostiniManagerTest::GetLinuxPackageInfoFromAptCallback, - base::Unretained(this), run_loop()->QuitClosure(), - expected)); - run_loop()->Run(); -} - -TEST_F(CrostiniManagerTest, GetLinuxPackageInfoFromAptInvalidID) { - vm_tools::cicerone::LinuxPackageInfoResponse response; - response.set_success(true); - response.set_package_id("Bad;;id;"); - fake_cicerone_client_->set_linux_package_info_response(response); - LinuxPackageInfo expected; - expected.success = false; - expected.failure_reason = "Linux package info contained invalid package id."; - crostini_manager()->GetLinuxPackageInfoFromApt( - kVmName, kContainerName, "fake app", - base::BindOnce(&CrostiniManagerTest::GetLinuxPackageInfoFromAptCallback, - base::Unretained(this), run_loop()->QuitClosure(), - expected)); - run_loop()->Run(); -} - -TEST_F(CrostiniManagerTest, GetLinuxPackageInfoFromAptSuccess) { - vm_tools::cicerone::LinuxPackageInfoResponse response; - response.set_success(true); - response.set_package_id("good;1.1;id;"); - response.set_summary("A summary"); - response.set_description("A description"); - fake_cicerone_client_->set_linux_package_info_response(response); - LinuxPackageInfo expected; - expected.success = true; - expected.package_id = "good;1.1;id;"; - expected.name = "good"; - expected.version = "1.1"; - expected.summary = "A summary"; - expected.description = "A description"; - crostini_manager()->GetLinuxPackageInfoFromApt( - kVmName, kContainerName, "fake app", - base::BindOnce(&CrostiniManagerTest::GetLinuxPackageInfoFromAptCallback, - base::Unretained(this), run_loop()->QuitClosure(), - expected)); - run_loop()->Run(); -} - TEST_F(CrostiniManagerTest, InstallLinuxPackageFromAptSignalNotConnectedError) { fake_cicerone_client_->set_install_linux_package_progress_signal_connected( false);
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.cc b/chrome/browser/chromeos/crostini/crostini_package_service.cc index e3833c9..de126ac 100644 --- a/chrome/browser/chromeos/crostini/crostini_package_service.cc +++ b/chrome/browser/chromeos/crostini/crostini_package_service.cc
@@ -173,18 +173,6 @@ std::move(callback))); } -void CrostiniPackageService::InstallLinuxPackageFromApt( - const std::string& vm_name, - const std::string& container_name, - const std::string& package_id, - CrostiniManager::InstallLinuxPackageCallback callback) { - CrostiniManager::GetForProfile(profile_)->InstallLinuxPackageFromApt( - vm_name, container_name, package_id, - base::BindOnce(&CrostiniPackageService::OnInstallLinuxPackage, - weak_ptr_factory_.GetWeakPtr(), vm_name, container_name, - std::move(callback))); -} - void CrostiniPackageService::OnInstallLinuxPackageProgress( const std::string& vm_name, const std::string& container_name,
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.h b/chrome/browser/chromeos/crostini/crostini_package_service.h index ad13ee9..a82cb14 100644 --- a/chrome/browser/chromeos/crostini/crostini_package_service.h +++ b/chrome/browser/chromeos/crostini/crostini_package_service.h
@@ -64,14 +64,6 @@ const std::string& package_path, CrostiniManager::InstallLinuxPackageCallback callback); - // Install a Linux package via a package_id. If successfully started, a - // system notification will be used to display further updates. - void InstallLinuxPackageFromApt( - const std::string& vm_name, - const std::string& container_name, - const std::string& package_id, - CrostiniManager::InstallLinuxPackageCallback callback); - // LinuxPackageOperationProgressObserver: void OnInstallLinuxPackageProgress(const std::string& vm_name, const std::string& container_name,
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index ce0772a6..661c64d9 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -744,91 +744,6 @@ DISALLOW_COPY_AND_ASSIGN(LocalTestVolume); }; -// Removable TestVolume: local test volume for external media devices. -class RemovableTestVolume : public LocalTestVolume { - public: - RemovableTestVolume(const std::string& name, - VolumeType volume_type, - chromeos::DeviceType device_type, - const base::FilePath& device_path, - const std::string& drive_label) - : LocalTestVolume(name), - volume_type_(volume_type), - device_type_(device_type), - device_path_(device_path), - drive_label_(drive_label) {} - ~RemovableTestVolume() override = default; - - bool PreparePartitionTestEntries(Profile* profile) { - if (!CreateRootDirectory(profile)) - return false; - - // Create fake file on the removable volume. - CreateEntry(AddEntriesMessage::TestEntryInfo(AddEntriesMessage::FILE, - "text.txt", "hello.txt") - .SetMimeType("text/plain")); - - CreateEntry(AddEntriesMessage::TestEntryInfo(AddEntriesMessage::DIRECTORY, - "", "Folder")); - base::RunLoop().RunUntilIdle(); - return true; - } - - bool PrepareUsbTestEntries(Profile* profile) { - if (!CreateRootDirectory(profile)) - return false; - - // Create fake file on the removable volume. - CreateEntry(AddEntriesMessage::TestEntryInfo(AddEntriesMessage::FILE, - "text.txt", "hello.txt") - .SetMimeType("text/plain")); - CreateEntry(AddEntriesMessage::TestEntryInfo(AddEntriesMessage::DIRECTORY, - "", "Folder")); - - base::RunLoop().RunUntilIdle(); - return true; - } - - bool Mount(Profile* profile) override { - if (!CreateRootDirectory(profile)) - return false; - - // Revoke name() mount point first, then re-add its mount point. - GetMountPoints()->RevokeFileSystem(name()); - const bool added = GetMountPoints()->RegisterFileSystem( - name(), storage::kFileSystemTypeNativeLocal, - storage::FileSystemMountOption(), root_path()); - if (!added) - return false; - - // Expose the mount point with the given volume and device type. - VolumeManager::Get(profile)->AddVolumeForTesting( - root_path(), volume_type_, device_type_, read_only_, device_path_, - drive_label_); - base::RunLoop().RunUntilIdle(); - return true; - } - - void Unmount(Profile* profile) { - VolumeManager::Get(profile)->RemoveVolumeForTesting( - root_path(), volume_type_, device_type_, read_only_, device_path_, - drive_label_); - } - - private: - storage::ExternalMountPoints* GetMountPoints() { - return storage::ExternalMountPoints::GetSystemInstance(); - } - - const VolumeType volume_type_; - const chromeos::DeviceType device_type_; - const base::FilePath device_path_; - const bool read_only_ = false; - const std::string drive_label_; - - DISALLOW_COPY_AND_ASSIGN(RemovableTestVolume); -}; - // DownloadsTestVolume: local test volume for the "Downloads" directory. class DownloadsTestVolume : public LocalTestVolume { public: @@ -973,15 +888,7 @@ } bool Mount(Profile* profile) override { - if (!CreateRootDirectory(profile)) - return false; - - // Revoke name() mount point first, then re-add its mount point. - GetMountPoints()->RevokeFileSystem(name()); - const bool added = GetMountPoints()->RegisterFileSystem( - name(), storage::kFileSystemTypeNativeLocal, - storage::FileSystemMountOption(), root_path()); - if (!added) + if (!MountSetup(profile)) return false; // Expose the mount point with the given volume and device type. @@ -996,18 +903,75 @@ root_path(), volume_type_, device_type_, read_only_); } - private: + protected: storage::ExternalMountPoints* GetMountPoints() { return storage::ExternalMountPoints::GetSystemInstance(); } + bool MountSetup(Profile* profile) { + if (!CreateRootDirectory(profile)) + return false; + + // Revoke name() mount point first, then re-add its mount point. + GetMountPoints()->RevokeFileSystem(name()); + const bool added = GetMountPoints()->RegisterFileSystem( + name(), storage::kFileSystemTypeNativeLocal, + storage::FileSystemMountOption(), root_path()); + if (!added) + return false; + + return true; + } + const VolumeType volume_type_; const chromeos::DeviceType device_type_; const bool read_only_ = false; + private: DISALLOW_COPY_AND_ASSIGN(FakeTestVolume); }; +// Removable TestVolume: local test volume for external media devices. +class RemovableTestVolume : public FakeTestVolume { + public: + RemovableTestVolume(const std::string& name, + VolumeType volume_type, + chromeos::DeviceType device_type, + const base::FilePath& device_path, + const std::string& drive_label, + const std::string& file_system_type) + : FakeTestVolume(name, volume_type, device_type), + device_path_(device_path), + drive_label_(drive_label), + file_system_type_(file_system_type) {} + ~RemovableTestVolume() override = default; + + bool Mount(Profile* profile) override { + if (!MountSetup(profile)) + return false; + + // Expose the mount point with the given volume and device type. + VolumeManager::Get(profile)->AddVolumeForTesting( + root_path(), volume_type_, device_type_, read_only_, device_path_, + drive_label_, file_system_type_); + base::RunLoop().RunUntilIdle(); + return true; + } + + void Unmount(Profile* profile) { + VolumeManager::Get(profile)->RemoveVolumeForTesting( + root_path(), volume_type_, device_type_, read_only_, device_path_, + drive_label_, file_system_type_); + } + + private: + const base::FilePath device_path_; + const std::string drive_label_; + const std::string file_system_type_; + + DISALLOW_COPY_AND_ASSIGN(RemovableTestVolume); +}; + // DriveTestVolume: test volume for Google Drive. class DriveTestVolume : public TestVolume { public: @@ -2000,9 +1964,14 @@ if (name == "mountFakeUsb" || name == "mountFakeUsbEmpty" || name == "mountFakeUsbDcim") { - usb_volume_ = std::make_unique<FakeTestVolume>( + std::string file_system = "ext4"; + const std::string* file_system_param = value.FindStringKey("filesystem"); + if (file_system_param) { + file_system = *file_system_param; + } + usb_volume_ = std::make_unique<RemovableTestVolume>( "fake-usb", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB); + chromeos::DEVICE_TYPE_USB, base::FilePath(), "FAKEUSB", file_system); if (name == "mountFakeUsb") ASSERT_TRUE(usb_volume_->PrepareTestEntries(profile())); @@ -2016,6 +1985,7 @@ if (name == "unmountUsb") { DCHECK(usb_volume_); usb_volume_->Unmount(profile()); + return; } if (name == "mountUsbWithPartitions") { @@ -2028,14 +1998,14 @@ // Create partition volumes with the same device path and drive label. partition_1_ = std::make_unique<RemovableTestVolume>( "partition-1", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB, device_path, "Drive Label"); + chromeos::DEVICE_TYPE_USB, device_path, "Drive Label", "ext4"); partition_2_ = std::make_unique<RemovableTestVolume>( "partition-2", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB, device_path, "Drive Label"); + chromeos::DEVICE_TYPE_USB, device_path, "Drive Label", "ext4"); // Create fake entries on partitions. - ASSERT_TRUE(partition_1_->PreparePartitionTestEntries(profile())); - ASSERT_TRUE(partition_2_->PreparePartitionTestEntries(profile())); + ASSERT_TRUE(partition_1_->PrepareTestEntries(profile())); + ASSERT_TRUE(partition_2_->PrepareTestEntries(profile())); ASSERT_TRUE(partition_1_->Mount(profile())); ASSERT_TRUE(partition_2_->Mount(profile()));
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc index 98fe917..0da12c4d 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -442,7 +442,8 @@ chromeos::DeviceType device_type, bool read_only, const base::FilePath& device_path, - const std::string& drive_label) { + const std::string& drive_label, + const std::string& file_system_type) { std::unique_ptr<Volume> volume(new Volume()); volume->type_ = volume_type; volume->device_type_ = device_type; @@ -455,7 +456,7 @@ volume->volume_id_ = GenerateVolumeId(*volume); volume->drive_label_ = drive_label; if (volume_type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) { - volume->file_system_type_ = "ext4"; + volume->file_system_type_ = file_system_type; } return volume; } @@ -750,11 +751,13 @@ chromeos::DeviceType device_type, bool read_only, const base::FilePath& device_path, - const std::string& drive_label) { + const std::string& drive_label, + const std::string& file_system_type) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DoMountEvent(chromeos::MOUNT_ERROR_NONE, - Volume::CreateForTesting(path, volume_type, device_type, - read_only, device_path, drive_label)); + DoMountEvent( + chromeos::MOUNT_ERROR_NONE, + Volume::CreateForTesting(path, volume_type, device_type, read_only, + device_path, drive_label, file_system_type)); } void VolumeManager::AddVolumeForTesting(std::unique_ptr<Volume> volume) { @@ -762,17 +765,19 @@ DoMountEvent(chromeos::MOUNT_ERROR_NONE, std::move(volume)); } -void VolumeManager::RemoveVolumeForTesting(const base::FilePath& path, - VolumeType volume_type, - chromeos::DeviceType device_type, - bool read_only, - const base::FilePath& device_path, - const std::string& drive_label) { +void VolumeManager::RemoveVolumeForTesting( + const base::FilePath& path, + VolumeType volume_type, + chromeos::DeviceType device_type, + bool read_only, + const base::FilePath& device_path, + const std::string& drive_label, + const std::string& file_system_type) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DoUnmountEvent( chromeos::MOUNT_ERROR_NONE, *Volume::CreateForTesting(path, volume_type, device_type, read_only, - device_path, drive_label)); + device_path, drive_label, file_system_type)); } void VolumeManager::OnFileSystemMounted() {
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h index 3588c1a5..6ce0775 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.h +++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -127,7 +127,8 @@ chromeos::DeviceType device_type, bool read_only, const base::FilePath& device_path, - const std::string& drive_label); + const std::string& drive_label, + const std::string& file_system_type = ""); static std::unique_ptr<Volume> CreateForTesting( const base::FilePath& device_path, const base::FilePath& mount_path); @@ -348,7 +349,8 @@ chromeos::DeviceType device_type, bool read_only, const base::FilePath& device_path = base::FilePath(), - const std::string& drive_label = ""); + const std::string& drive_label = "", + const std::string& file_system_type = ""); // For testing purposes, adds the volume info to the volume manager. void AddVolumeForTesting(std::unique_ptr<Volume> volume); @@ -359,7 +361,8 @@ chromeos::DeviceType device_type, bool read_only, const base::FilePath& device_path = base::FilePath(), - const std::string& drive_label = ""); + const std::string& drive_label = "", + const std::string& file_system_type = ""); // drive::DriveIntegrationServiceObserver overrides. void OnFileSystemMounted() override;
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc index 21671708..3f23bc5 100644 --- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc +++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -848,7 +848,14 @@ } #if defined(OS_ANDROID) -TEST_F(ChromeDownloadManagerDelegateTest, InterceptDownloadByOfflinePages) { +#if defined(DISABLE_OFFLINE_PAGES_TOUCHLESS) +#define MAYBE_InterceptDownloadByOfflinePages \ + DISABLED_InterceptDownloadByOfflinePages +#else +#define MAYBE_InterceptDownloadByOfflinePages InterceptDownloadByOfflinePages +#endif +TEST_F(ChromeDownloadManagerDelegateTest, + MAYBE_InterceptDownloadByOfflinePages) { const GURL kUrl("http://example.com/foo"); std::string mime_type = "text/html"; bool should_intercept = delegate()->InterceptDownloadIfApplicable(
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 67e2cb7..16c40758 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -1017,6 +1017,8 @@ "api/image_writer_private/removable_storage_provider_linux.cc", "api/messaging/native_message_process_host.cc", "api/messaging/native_message_process_host.h", + "api/messaging/native_messaging_launch_from_native.cc", + "api/messaging/native_messaging_launch_from_native.h", "api/messaging/native_process_launcher.cc", "api/messaging/native_process_launcher.h", "api/messaging/native_process_launcher_win.cc",
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc index 94b83a3e..c7dfc4d 100644 --- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc +++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -16,6 +16,7 @@ #include "base/task/post_task.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h" +#include "chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h" #include "chrome/browser/extensions/api/messaging/native_process_launcher.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/browser_context.h" @@ -44,9 +45,10 @@ base::FilePath GetProfilePathIfEnabled(Profile* profile, const std::string& extension_id, const std::string& host_id) { - // TODO(crbug.com/967262): Return an empty path if the extension would not - // accept an inbound native messaging connection. - return profile->GetPath(); + return extensions::ExtensionSupportsConnectionFromNativeApp( + extension_id, host_id, profile, /* log_errors = */ false) + ? profile->GetPath() + : base::FilePath(); } } // namespace @@ -104,7 +106,8 @@ NativeProcessLauncher::CreateDefault( allow_user_level, native_view, GetProfilePathIfEnabled(Profile::FromBrowserContext(browser_context), - source_extension_id, native_host_name))); + source_extension_id, native_host_name), + /* require_native_initiated_connections = */ false)); } // static
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc index 702ac7c..ddab3fb 100644 --- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc +++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -31,6 +31,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "build/build_config.h" +#include "chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h" #include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h" #include "chrome/browser/extensions/api/messaging/native_process_launcher.h" #include "chrome/browser/profiles/profile.h" @@ -321,6 +322,7 @@ TEST_F(NativeMessagingTest, ReconnectArgs) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kOnConnectNative); + ScopedAllowNativeAppConnectionForTest allow_native_app_connection(true); ScopedTestNativeMessagingHost test_host; ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(false)); std::string error_message; @@ -397,6 +399,34 @@ EXPECT_TRUE(args->is_none()); } +// Test that reconnect args are not sent if the extension is not permitted to +// receive natively-established connections. +TEST_F(NativeMessagingTest, ReconnectArgsIfNativeConnectionDisallowed) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kOnConnectNative); + ScopedAllowNativeAppConnectionForTest disallow_native_app_connection(false); + ScopedTestNativeMessagingHost test_host; + ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(false)); + std::string error_message; + native_message_host_ = NativeMessageProcessHost::Create( + &profile_, NULL, ScopedTestNativeMessagingHost::kExtensionId, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + false, &error_message); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_); + + native_message_host_->OnMessage("{\"text\": \"Hello.\"}"); + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + ASSERT_FALSE(last_message_.empty()); + ASSERT_TRUE(last_message_parsed_); + + const base::Value* args_value = nullptr; + ASSERT_TRUE(last_message_parsed_->Get("args", &args_value)); + EXPECT_TRUE(args_value->is_none()); +} + TEST_F(NativeMessagingTest, UserLevel) { ScopedTestNativeMessagingHost test_host; ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(true));
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc index 0983cc2..d577d53 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc +++ b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -2,10 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/feature_list.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/startup/startup_browser_creator.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/chrome_switches.h" +#include "extensions/browser/process_manager.h" +#include "extensions/test/result_catcher.h" namespace extensions { +namespace { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, NativeMessagingBasic) { extensions::ScopedTestNativeMessagingHost test_host; @@ -19,4 +29,118 @@ ASSERT_TRUE(RunExtensionTest("native_messaging")) << message_; } +#if !defined(OS_CHROMEOS) + +class TestProcessManagerObserver : public ProcessManagerObserver { + public: + TestProcessManagerObserver() : observer_(this) {} + + void WaitForProcessShutdown(ProcessManager* process_manager, + const std::string& extension_id) { + DCHECK(!quit_); + extension_id_ = extension_id; + base::RunLoop run_loop; + quit_ = run_loop.QuitClosure(); + + observer_.Add(process_manager); + run_loop.Run(); + } + + private: + void OnBackgroundHostClose(const std::string& extension_id) override { + if (extension_id != extension_id_) { + return; + } + observer_.RemoveAll(); + extension_id_.clear(); + std::move(quit_).Run(); + } + + std::string extension_id_; + ScopedObserver<ProcessManager, TestProcessManagerObserver> observer_; + base::OnceClosure quit_; + + DISALLOW_COPY_AND_ASSIGN(TestProcessManagerObserver); +}; + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, NativeMessagingLaunch) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(features::kOnConnectNative); + ProcessManager::SetEventPageIdleTimeForTesting(1); + ProcessManager::SetEventPageSuspendingTimeForTesting(1); + extensions::ScopedTestNativeMessagingHost test_host; + ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(false)); + + auto* extension = + LoadExtension(test_data_dir_.AppendASCII("native_messaging_launch")); + TestProcessManagerObserver observer; + observer.WaitForProcessShutdown(ProcessManager::Get(profile()), + extension->id()); + + ResultCatcher catcher; + + base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); + command_line.AppendSwitchASCII(switches::kNativeMessagingConnectExtension, + extension->id()); + command_line.AppendSwitchASCII( + switches::kNativeMessagingConnectHost, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName); + + StartupBrowserCreator::ProcessCommandLineAlreadyRunning(command_line, {}, + profile()->GetPath()); + + if (!catcher.GetNextResult()) { + FAIL() << catcher.message(); + } + size_t tabs = 0; + for (auto* browser : *BrowserList::GetInstance()) { + tabs += browser->tab_strip_model()->count(); + } + EXPECT_EQ(1u, tabs); +} + +// Test that a natively-initiated connection from a host not supporting +// 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, + NativeMessagingLaunch_LaunchFromNativeUnsupportedByNativeHost) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(features::kOnConnectNative); + ProcessManager::SetEventPageIdleTimeForTesting(1); + ProcessManager::SetEventPageSuspendingTimeForTesting(1); + extensions::ScopedTestNativeMessagingHost test_host; + ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(false)); + + auto* extension = LoadExtension( + test_data_dir_.AppendASCII("native_messaging_launch_unsupported")); + TestProcessManagerObserver observer; + observer.WaitForProcessShutdown(ProcessManager::Get(profile()), + extension->id()); + + ResultCatcher catcher; + + base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); + command_line.AppendSwitchASCII(switches::kNativeMessagingConnectExtension, + extension->id()); + command_line.AppendSwitchASCII(switches::kNativeMessagingConnectHost, + ScopedTestNativeMessagingHost::kHostName); + + StartupBrowserCreator::ProcessCommandLineAlreadyRunning(command_line, {}, + profile()->GetPath()); + + if (!catcher.GetNextResult()) { + FAIL() << catcher.message(); + } + size_t tabs = 0; + for (auto* browser : *BrowserList::GetInstance()) { + tabs += browser->tab_strip_model()->count(); + } + EXPECT_EQ(1u, tabs); +} + +#endif // !defined(OS_CHROMEOS) + +} // namespace } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc new file mode 100644 index 0000000..eabfae99 --- /dev/null +++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
@@ -0,0 +1,126 @@ +// 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/extensions/api/messaging/native_messaging_launch_from_native.h" + +#include <memory> +#include <utility> + +#include "chrome/browser/extensions/api/messaging/native_message_port.h" +#include "chrome/browser/extensions/api/messaging/native_message_process_host.h" +#include "chrome/browser/extensions/api/messaging/native_process_launcher.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/manifest_handlers/natively_connectable_handler.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" +#include "extensions/browser/api/messaging/message_service.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/api/messaging/messaging_endpoint.h" +#include "extensions/common/permissions/permission_set.h" +#include "extensions/common/permissions/permissions_data.h" + +namespace extensions { +namespace { + +ScopedAllowNativeAppConnectionForTest* g_allow_native_app_connection_for_test = + nullptr; + +} // namespace + +bool ExtensionSupportsConnectionFromNativeApp(const std::string& extension_id, + const std::string& host_id, + Profile* profile, + bool log_errors) { + if (g_allow_native_app_connection_for_test) { + return g_allow_native_app_connection_for_test->allow(); + } + if (profile->IsOffTheRecord()) { + return false; + } + auto* extension = + ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( + extension_id); + if (!extension) { + LOG_IF(ERROR, log_errors) + << "Failed to launch native messaging connection: Unknown extension ID " + << extension_id; + return false; + } + const auto* natively_connectable_hosts = + NativelyConnectableHosts::GetConnectableNativeMessageHosts(*extension); + if (!natively_connectable_hosts || + !natively_connectable_hosts->count(host_id)) { + LOG_IF(ERROR, log_errors) + << "Extension \"" << extension_id << "\" does not list \"" << host_id + << "\" in its natively_connectable manifest field"; + return false; + } + if (!extension->permissions_data()->active_permissions().HasAPIPermission( + "nativeMessaging")) { + LOG_IF(ERROR, log_errors) + << "Extension \"" << extension_id + << "\" does not have the \"nativeMessaging\" permission"; + return false; + } + if (!extension->permissions_data()->active_permissions().HasAPIPermission( + "transientBackground")) { + LOG_IF(ERROR, log_errors) + << "Extension \"" << extension_id + << "\" does not have the \"transientBackground\" permission"; + return false; + } + if (!EventRouter::Get(profile)->ExtensionHasEventListener( + extension_id, "runtime.onConnectNative")) { + LOG_IF(ERROR, log_errors) + << "Failed to launch native messaging connection: Extension \"" + << extension_id << "\" is not listening for runtime.onConnectNative"; + return false; + } + + return true; +} + +ScopedAllowNativeAppConnectionForTest::ScopedAllowNativeAppConnectionForTest( + bool allow) + : allow_(allow) { + DCHECK(!g_allow_native_app_connection_for_test); + g_allow_native_app_connection_for_test = this; +} + +ScopedAllowNativeAppConnectionForTest:: + ~ScopedAllowNativeAppConnectionForTest() { + DCHECK_EQ(this, g_allow_native_app_connection_for_test); + g_allow_native_app_connection_for_test = nullptr; +} + +void LaunchNativeMessageHostFromNativeApp(const std::string& extension_id, + const std::string& host_id, + Profile* profile) { + if (!ExtensionSupportsConnectionFromNativeApp(extension_id, host_id, profile, + /* log_errors = */ true)) { + // TODO(crbug.com/967262): Report errors to the native messaging host. + return; + } + const extensions::PortId port_id(base::UnguessableToken::Create(), + 1 /* port_number */, true /* is_opener */); + extensions::MessageService* const message_service = + extensions::MessageService::Get(profile); + // TODO(crbug.com/967262): Apply policy for allow_user_level. + auto native_message_host = NativeMessageProcessHost::CreateWithLauncher( + extension_id, host_id, + NativeProcessLauncher::CreateDefault( + /* allow_user_level = */ true, /* native_view = */ nullptr, + profile->GetPath(), + /* require_native_initiated_connections = */ true)); + auto native_message_port = std::make_unique<extensions::NativeMessagePort>( + message_service->GetChannelDelegate(), port_id, + std::move(native_message_host)); + message_service->OpenChannelToExtension( + extensions::ChannelEndpoint(profile), port_id, + extensions::MessagingEndpoint::ForNativeApp(host_id), + std::move(native_message_port), extension_id, GURL(), + std::string() /* channel_name */); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h new file mode 100644 index 0000000..d730422c --- /dev/null +++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h
@@ -0,0 +1,44 @@ +// 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_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGING_LAUNCH_FROM_NATIVE_H_ +#define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGING_LAUNCH_FROM_NATIVE_H_ + +#include <string> +#include "base/macros.h" + +class Profile; + +namespace extensions { + +// Returns whether |extension_id| running in |profile| is allowed to accept +// connections from native host named |host_id|. +bool ExtensionSupportsConnectionFromNativeApp(const std::string& extension_id, + const std::string& host_id, + Profile* profile, + bool log_errors); + +// Creates a native messaging connection between the extension with ID +// |extension_id| with |profile| and the native messaging host with name +// |host_id|. +void LaunchNativeMessageHostFromNativeApp(const std::string& extension_id, + const std::string& host_id, + Profile* profile); + +class ScopedAllowNativeAppConnectionForTest { + public: + explicit ScopedAllowNativeAppConnectionForTest(bool allow); + ~ScopedAllowNativeAppConnectionForTest(); + + bool allow() const { return allow_; } + + private: + const bool allow_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAllowNativeAppConnectionForTest); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGING_LAUNCH_FROM_NATIVE_H_
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc new file mode 100644 index 0000000..c80afec --- /dev/null +++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
@@ -0,0 +1,230 @@ +// 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/extensions/api/messaging/native_messaging_launch_from_native.h" + +#include <memory> +#include <utility> + +#include "base/path_service.h" +#include "base/test/values_test_util.h" +#include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/event_router_factory.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_paths.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/value_builder.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { +namespace { + +class MockEventRouter : public EventRouter { + public: + MockEventRouter(content::BrowserContext* browser_context, + ExtensionPrefs* extension_prefs, + const bool* has_listener_result) + : EventRouter(browser_context, extension_prefs), + has_listener_result_(has_listener_result) { + DCHECK(has_listener_result_); + } + + bool ExtensionHasEventListener(const std::string& extension_id, + const std::string& event_name) const override { + return *has_listener_result_; + } + + private: + const bool* has_listener_result_; +}; + +std::unique_ptr<KeyedService> BuildMockEventRouter( + const bool* has_listener_result, + content::BrowserContext* context) { + return std::make_unique<MockEventRouter>( + context, ExtensionPrefs::Get(context), has_listener_result); +} + +class ExtensionSupportsConnectionFromNativeAppTest : public ::testing::Test { + public: + void SetUp() override { + EventRouterFactory::GetInstance()->SetTestingFactory( + &profile_, + base::BindRepeating(&BuildMockEventRouter, &has_listener_result_)); + } + + protected: + void RegisterExtension(bool natively_connectable, + bool transient_background_permission, + bool native_messaging_permission) { + DictionaryBuilder manifest_builder( + static_cast<base::DictionaryValue&&>(base::test::ParseJson(R"( + { + "version": "1.0.0.0", + "manifest_version": 2, + "name": "native messaging test", + "description": "native messaging test", + "background": { + "scripts": ["test.js"], + "persistent": false + } + } + )"))); + + if (natively_connectable) { + ListBuilder natively_connectable_hosts; + natively_connectable_hosts.Append( + ScopedTestNativeMessagingHost::kHostName); + + natively_connectable_hosts.Append( + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName); + manifest_builder.Set(manifest_keys::kNativelyConnectable, + natively_connectable_hosts.Build()); + } + + ListBuilder permissions; + if (transient_background_permission) { + permissions.Append("transientBackground"); + } + if (native_messaging_permission) { + permissions.Append("nativeMessaging"); + } + manifest_builder.Set(manifest_keys::kPermissions, permissions.Build()); + + base::FilePath path; + EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path)); + + std::string error; + scoped_refptr<Extension> extension( + Extension::Create(path, Manifest::INTERNAL, *manifest_builder.Build(), + Extension::NO_FLAGS, &error)); + ASSERT_TRUE(extension.get()) << error; + ExtensionRegistry::Get(&profile_)->AddEnabled(extension); + extension_id_ = extension->id(); + } + + content::TestBrowserThreadBundle thread_bundle_; + bool has_listener_result_ = true; + TestingProfile profile_; + std::string extension_id_; +}; + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, Success) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, true, true)); + + EXPECT_TRUE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NoOnConnectNative) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, true, true)); + has_listener_result_ = false; + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, OffTheRecordProfile) { + auto* off_the_record_profile = profile_.GetOffTheRecordProfile(); + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, true, true)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + off_the_record_profile, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NotNativelyConnectable) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(false, true, true)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NotTransientBackground) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, false, true)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NotNativeMessaging) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, true, false)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NativeMessagingOnly) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(false, false, true)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, TransientBackgroundOnly) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(false, true, false)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NativelyConnectableOnly) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(true, false, false)); + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, NoPermissions) { + ASSERT_NO_FATAL_FAILURE(RegisterExtension(false, false, false)); + has_listener_result_ = false; + + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + extension_id_, + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +TEST_F(ExtensionSupportsConnectionFromNativeAppTest, UnknownExtension) { + EXPECT_FALSE(ExtensionSupportsConnectionFromNativeApp( + "fake extension id", + ScopedTestNativeMessagingHost:: + kSupportsNativeInitiatedConnectionsHostName, + &profile_, false)); +} + +} // namespace +} // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_process_launcher.cc b/chrome/browser/extensions/api/messaging/native_process_launcher.cc index a00f9a8..fc731d68 100644 --- a/chrome/browser/extensions/api/messaging/native_process_launcher.cc +++ b/chrome/browser/extensions/api/messaging/native_process_launcher.cc
@@ -46,7 +46,8 @@ public: NativeProcessLauncherImpl(bool allow_user_level_hosts, intptr_t native_window, - const base::FilePath& profile_directory); + const base::FilePath& profile_directory, + bool require_native_initiated_connections); ~NativeProcessLauncherImpl() override; void Launch(const GURL& origin, @@ -58,7 +59,8 @@ public: Core(bool allow_user_level_hosts, intptr_t native_window, - const base::FilePath& profile_directory); + const base::FilePath& profile_directory, + bool require_native_initiated_connections); void Launch(const GURL& origin, const std::string& native_host_name, const LaunchedCallback& callback); @@ -84,10 +86,11 @@ bool detached_; - bool allow_user_level_hosts_; + const bool allow_user_level_hosts_; - base::FilePath profile_directory_; + const base::FilePath profile_directory_; + const bool require_native_initiated_connections_; #if defined(OS_WIN) // Handle of the native window corresponding to the extension. intptr_t window_handle_; @@ -103,10 +106,13 @@ NativeProcessLauncherImpl::Core::Core(bool allow_user_level_hosts, intptr_t window_handle, - const base::FilePath& profile_directory) + const base::FilePath& profile_directory, + bool require_native_initiated_connections) : detached_(false), allow_user_level_hosts_(allow_user_level_hosts), - profile_directory_(profile_directory) + profile_directory_(profile_directory), + require_native_initiated_connections_( + require_native_initiated_connections) #if defined(OS_WIN) , window_handle_(window_handle) @@ -176,6 +182,12 @@ return; } + if (require_native_initiated_connections_ && + !manifest->supports_native_initiated_connections()) { + PostErrorResult(callback, RESULT_FORBIDDEN); + return; + } + base::FilePath host_path = manifest->path(); if (!host_path.IsAbsolute()) { // On Windows host path is allowed to be relative to the location of the @@ -300,9 +312,12 @@ NativeProcessLauncherImpl::NativeProcessLauncherImpl( bool allow_user_level_hosts, intptr_t window_handle, - const base::FilePath& profile_directory) - : core_( - new Core(allow_user_level_hosts, window_handle, profile_directory)) {} + const base::FilePath& profile_directory, + bool require_native_initiated_connections) + : core_(new Core(allow_user_level_hosts, + window_handle, + profile_directory, + require_native_initiated_connections)) {} NativeProcessLauncherImpl::~NativeProcessLauncherImpl() { core_->Detach(); @@ -320,14 +335,16 @@ std::unique_ptr<NativeProcessLauncher> NativeProcessLauncher::CreateDefault( bool allow_user_level_hosts, gfx::NativeView native_view, - const base::FilePath& profile_directory) { + const base::FilePath& profile_directory, + bool require_native_initiated_connections) { intptr_t window_handle = 0; #if defined(OS_WIN) window_handle = reinterpret_cast<intptr_t>( views::HWNDForNativeView(native_view)); #endif return std::make_unique<NativeProcessLauncherImpl>( - allow_user_level_hosts, window_handle, profile_directory); + allow_user_level_hosts, window_handle, profile_directory, + require_native_initiated_connections); } } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_process_launcher.h b/chrome/browser/extensions/api/messaging/native_process_launcher.h index 68032648..51102bc 100644 --- a/chrome/browser/extensions/api/messaging/native_process_launcher.h +++ b/chrome/browser/extensions/api/messaging/native_process_launcher.h
@@ -44,11 +44,14 @@ // window that contains calling page. Can be nullptr, e.g. for background // pages. If |profile_directory| is non-empty and the host supports // native-initiated connections, additional reconnect args will be passed to - // the host. + // the host. If |require_native_initiated_connections| is true, the connection + // will be allowed only if the native messaging host sets + // "supports_native_initiated_connections" to true in its manifest. static std::unique_ptr<NativeProcessLauncher> CreateDefault( bool allow_user_level_hosts, gfx::NativeView native_view, - const base::FilePath& profile_directory); + const base::FilePath& profile_directory, + bool require_native_initiated_connections); NativeProcessLauncher() {} virtual ~NativeProcessLauncher() {}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 414c88d..94481067 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -501,11 +501,6 @@ "expiry_milestone": 80 }, { - "name": "crostini-app-search", - "owners": [ "crostini-ui" ], - "expiry_milestone": 76 - }, - { "name": "crostini-backup", "owners": [ "joelhockey", "nverne", "benwells" ], "expiry_milestone": 77
diff --git a/chrome/browser/net/proxy_browsertest.cc b/chrome/browser/net/proxy_browsertest.cc index f3e2f3ba8..944a4fc 100644 --- a/chrome/browser/net/proxy_browsertest.cc +++ b/chrome/browser/net/proxy_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/test/bind_test_util.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/net/proxy_test_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/login/login_handler.h" @@ -86,53 +87,6 @@ DISALLOW_COPY_AND_ASSIGN(LoginPromptObserver); }; -class ProxyBrowserTest : public InProcessBrowserTest { - public: - ProxyBrowserTest() - : proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, - base::FilePath()) { - } - - void SetUp() override { - ASSERT_TRUE(proxy_server_.Start()); - // Block the GaiaAuthFetcher related requests, they somehow interfere with - // the test when the network service is running. - url_loader_interceptor_ = std::make_unique<content::URLLoaderInterceptor>( - base::BindLambdaForTesting( - [&](content::URLLoaderInterceptor::RequestParams* params) -> bool { - if (params->url_request.url.host() == - GaiaUrls::GetInstance()->gaia_url().host()) { - return true; - } - return false; - })); - InProcessBrowserTest::SetUp(); - } - - void PostRunTestOnMainThread() override { - url_loader_interceptor_.reset(); - InProcessBrowserTest::PostRunTestOnMainThread(); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII(switches::kProxyServer, - proxy_server_.host_port_pair().ToString()); - - // TODO(https://crbug.com/901896): Don't rely on proxying localhost (Relied - // on by BasicAuthWSConnect) - command_line->AppendSwitchASCII( - switches::kProxyBypassList, - net::ProxyBypassRules::GetRulesToSubtractImplicit()); - } - - protected: - net::SpawnedTestServer proxy_server_; - - private: - std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_; - DISALLOW_COPY_AND_ASSIGN(ProxyBrowserTest); -}; - // Test that the browser can establish a WebSocket connection via a proxy // that requires basic authentication. This test also checks the headers // arrive at WebSocket server.
diff --git a/chrome/browser/net/proxy_test_utils.cc b/chrome/browser/net/proxy_test_utils.cc new file mode 100644 index 0000000..e26cec4 --- /dev/null +++ b/chrome/browser/net/proxy_test_utils.cc
@@ -0,0 +1,49 @@ +// 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/net/proxy_test_utils.h" + +#include "base/test/bind_test_util.h" +#include "chrome/common/chrome_switches.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/url_loader_interceptor.h" +#include "google_apis/gaia/gaia_urls.h" + +ProxyBrowserTest::ProxyBrowserTest() + : proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, + base::FilePath()) {} + +ProxyBrowserTest::~ProxyBrowserTest() {} + +void ProxyBrowserTest::SetUp() { + ASSERT_TRUE(proxy_server_.Start()); + // Block the GaiaAuthFetcher related requests, they somehow interfere with + // the test when the network service is running. + url_loader_interceptor_ = std::make_unique<content::URLLoaderInterceptor>( + base::BindLambdaForTesting( + [&](content::URLLoaderInterceptor::RequestParams* params) -> bool { + if (params->url_request.url.host() == + GaiaUrls::GetInstance()->gaia_url().host()) { + return true; + } + return false; + })); + InProcessBrowserTest::SetUp(); +} + +void ProxyBrowserTest::PostRunTestOnMainThread() { + url_loader_interceptor_.reset(); + InProcessBrowserTest::PostRunTestOnMainThread(); +} + +void ProxyBrowserTest::SetUpCommandLine(base::CommandLine* command_line) { + command_line->AppendSwitchASCII(switches::kProxyServer, + proxy_server_.host_port_pair().ToString()); + + // TODO(https://crbug.com/901896): Don't rely on proxying localhost (Relied + // on by BasicAuthWSConnect) + command_line->AppendSwitchASCII( + switches::kProxyBypassList, + net::ProxyBypassRules::GetRulesToSubtractImplicit()); +}
diff --git a/chrome/browser/net/proxy_test_utils.h b/chrome/browser/net/proxy_test_utils.h new file mode 100644 index 0000000..22ac7754 --- /dev/null +++ b/chrome/browser/net/proxy_test_utils.h
@@ -0,0 +1,33 @@ +// 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_NET_PROXY_TEST_UTILS_H_ +#define CHROME_BROWSER_NET_PROXY_TEST_UTILS_H_ + +#include "chrome/test/base/in_process_browser_test.h" +#include "net/test/spawned_test_server/spawned_test_server.h" + +namespace content { +class URLLoaderInterceptor; +} + +class ProxyBrowserTest : public InProcessBrowserTest { + public: + ProxyBrowserTest(); + ~ProxyBrowserTest() override; + + // InProcessBrowserTest:: + void SetUp() override; + void PostRunTestOnMainThread() override; + void SetUpCommandLine(base::CommandLine* command_line) override; + + protected: + net::SpawnedTestServer proxy_server_; + + private: + std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_; + DISALLOW_COPY_AND_ASSIGN(ProxyBrowserTest); +}; + +#endif // CHROME_BROWSER_NET_PROXY_TEST_UTILS_H_
diff --git a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc index 95bfa6c..3011246 100644 --- a/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc +++ b/chrome/browser/notifications/scheduler/internal/background_task_coordinator.cc
@@ -40,7 +40,7 @@ int shown_total = 0; SchedulerClientType last_shown_type = SchedulerClientType::kUnknown; NotificationsShownToday(client_states, &shown_per_type, &shown_total, - &last_shown_type); + &last_shown_type, clock_); bool reach_max_today_all_type = shown_total >= config_->max_daily_shown_all_type; base::Time next_morning = NextMorning();
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc b/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc index 6cf4b82..2731948 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc +++ b/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc
@@ -10,6 +10,32 @@ #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h" namespace notifications { +namespace { +using FirstAndLastIters = std::pair<std::deque<Impression>::const_iterator, + std::deque<Impression>::const_iterator>; + +base::Optional<FirstAndLastIters> FindFirstAndLastNotificationShownToday( + const std::deque<Impression>& impressions, + const base::Time& now, + const base::Time& beginning_of_today) { + if (impressions.empty() || impressions.cbegin()->create_time > now || + impressions.crbegin()->create_time < beginning_of_today) + return base::nullopt; + + auto last = + std::upper_bound(impressions.cbegin(), impressions.cend(), now, + [](const base::Time& lhs, const Impression& rhs) { + return lhs < rhs.create_time; + }); + + auto first = + std::lower_bound(impressions.cbegin(), last, beginning_of_today, + [](const Impression& lhs, const base::Time& rhs) { + return lhs.create_time < rhs; + }); + return base::make_optional<FirstAndLastIters>(first, last - 1); +} +} // namespace bool ToLocalHour(int hour, const base::Time& today, @@ -32,62 +58,50 @@ return base::Time::FromLocalExploded(another_day_exploded, out); } +int NotificationsShownToday(const ClientState* state, base::Clock* clock) { + std::map<SchedulerClientType, const ClientState*> client_states; + std::map<SchedulerClientType, int> shown_per_type; + client_states.emplace(state->type, state); + int shown_total = 0; + SchedulerClientType last_shown_type = SchedulerClientType::kUnknown; + NotificationsShownToday(client_states, &shown_per_type, &shown_total, + &last_shown_type, clock); + return shown_per_type[state->type]; +} + void NotificationsShownToday( const std::map<SchedulerClientType, const ClientState*>& client_states, std::map<SchedulerClientType, int>* shown_per_type, int* shown_total, - SchedulerClientType* last_shown_type) { + SchedulerClientType* last_shown_type, + base::Clock* clock) { base::Time last_shown_time; - base::Time now(base::Time::Now()); + base::Time now = clock->Now(); base::Time beginning_of_today; bool success = ToLocalHour(0, now, 0, &beginning_of_today); DCHECK(success); - for (const auto& state : client_states) { - const auto* client_state = state.second; - for (const auto& impression : client_state->impressions) { - // Tracks last notification shown to the user. - if (impression.create_time > last_shown_time) { - last_shown_time = impression.create_time; - *last_shown_type = client_state->type; - } + auto* client_state = state.second; - // Count notification shown today. - if (impression.create_time >= beginning_of_today) { - (*shown_per_type)[client_state->type]++; - ++(*shown_total); - } + auto iter_pair = FindFirstAndLastNotificationShownToday( + client_state->impressions, now, beginning_of_today); + + if (!iter_pair) + continue; + + if (iter_pair->second != client_state->impressions.cend()) + DLOG(ERROR) << "Wrong format: time stamped to the future! " + << iter_pair->second->create_time; + + if (iter_pair->second->create_time > last_shown_time) { + last_shown_time = iter_pair->second->create_time; + *last_shown_type = client_state->type; } - } -} -int NotificationsShownToday(ClientState* state) { - int count = 0; - auto impressions = state->impressions; - base::Time now(base::Time::Now()); - base::Time beginning_of_today, beginning_of_tomorrow; - bool success = ToLocalHour(0, now, 0, &beginning_of_today); - beginning_of_tomorrow += base::TimeDelta::FromDays(1); - DCHECK(success); - if (impressions.rbegin()->create_time < beginning_of_today) { - count = 0; - } else if (impressions.begin()->create_time > beginning_of_tomorrow) { - count = impressions.size(); - } else { - auto right = lower_bound(impressions.rbegin(), impressions.rend(), - beginning_of_today, - [](const Impression& lhs, const base::Time& rhs) { - return lhs.create_time < rhs; - }); - auto left = upper_bound(impressions.rbegin(), impressions.rend(), - beginning_of_tomorrow, - [](const base::Time& lhs, const Impression& rhs) { - return lhs < rhs.create_time; - }); - count = right - left + 1; + int count = std::distance(iter_pair->first, iter_pair->second) + 1; + (*shown_per_type)[client_state->type] = count; + (*shown_total) += count; } - DCHECK_LE(count, state->current_max_daily_show); - return count; } std::unique_ptr<ClientState> CreateNewClientState(
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_utils.h b/chrome/browser/notifications/scheduler/internal/scheduler_utils.h index 05e944d..28733ac 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduler_utils.h +++ b/chrome/browser/notifications/scheduler/internal/scheduler_utils.h
@@ -5,9 +5,12 @@ #ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_INTERNAL_SCHEDULER_UTILS_H_ #define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_INTERNAL_SCHEDULER_UTILS_H_ +#include <deque> #include <map> #include <memory> +#include "base/time/clock.h" +#include "base/time/default_clock.h" #include "base/time/time.h" #include "chrome/browser/notifications/scheduler/public/notification_scheduler_types.h" @@ -32,10 +35,13 @@ const std::map<SchedulerClientType, const ClientState*>& client_states, std::map<SchedulerClientType, int>* shown_per_type, int* shown_total, - SchedulerClientType* last_shown_type); + SchedulerClientType* last_shown_type, + base::Clock* clock = base::DefaultClock::GetInstance()); // Counts the number of notifications shown today of a given |state|. -int NotificationsShownToday(ClientState* state); +int NotificationsShownToday( + const ClientState* state, + base::Clock* clock = base::DefaultClock::GetInstance()); // Creates client state data for new registered client. std::unique_ptr<ClientState> CreateNewClientState(
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_utils_unittest.cc b/chrome/browser/notifications/scheduler/internal/scheduler_utils_unittest.cc index 3c28e3a..c476d787 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduler_utils_unittest.cc +++ b/chrome/browser/notifications/scheduler/internal/scheduler_utils_unittest.cc
@@ -4,14 +4,60 @@ #include "chrome/browser/notifications/scheduler/internal/scheduler_utils.h" -#include "base/time/time.h" +#include <algorithm> + +#include "base/guid.h" +#include "base/test/scoped_task_environment.h" +#include "chrome/browser/notifications/scheduler/internal/impression_types.h" +#include "chrome/browser/notifications/scheduler/test/fake_clock.h" +#include "chrome/browser/notifications/scheduler/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace notifications { namespace { +const char kFakeNow[] = "01/01/18 01:23:45 AM"; + +class SchedulerUtilsTest : public testing::Test { + public: + SchedulerUtilsTest() {} + ~SchedulerUtilsTest() override = default; + + void SetUp() override { config_.initial_daily_shown_per_type = 100; } + + void InitFakeDay() { + clock_.SetNow(kFakeNow); + ToLocalHour(0, clock_.Now(), 0, &beginning_of_today_); + } + + void CreateFakeImpressions(std::vector<base::Time> times, + std::deque<Impression>& impressions) { + impressions.clear(); + for (auto time : times) { + impressions.emplace_back(SchedulerClientType::kTest1, + base::GenerateGUID(), time); + } + std::sort(impressions.begin(), impressions.end(), + [](const Impression& lhs, const Impression& rhs) { + return lhs.create_time < rhs.create_time; + }); + } + + protected: + SchedulerConfig& config() { return config_; } + test::FakeClock* clock() { return &clock_; } + base::Time& beginning_of_today() { return beginning_of_today_; } + + private: + base::test::ScopedTaskEnvironment scoped_task_environment_; + test::FakeClock clock_; + SchedulerConfig config_; + base::Time beginning_of_today_; + DISALLOW_COPY_AND_ASSIGN(SchedulerUtilsTest); +}; + // Verifies we can get the correct time stamp at certain hour in yesterday. -TEST(SchedulerUtilsTest, ToLocalHour) { +TEST_F(SchedulerUtilsTest, ToLocalHour) { base::Time today, another_day, expected; // Timestamp of another day in the past. @@ -38,5 +84,44 @@ EXPECT_EQ(expected, another_day); } +TEST_F(SchedulerUtilsTest, NotificationsShownToday) { + // Create fake client. + auto new_client = CreateNewClientState(SchedulerClientType::kTest1, config()); + InitFakeDay(); + base::Time now = clock()->Now(); + // Test case 1: + int count = NotificationsShownToday(new_client.get(), clock()); + EXPECT_EQ(count, 0); + + // Test case 2: + std::vector<base::Time> create_times = { + now /*today*/, + beginning_of_today() + base::TimeDelta::FromDays(1) /*tomorrow*/, + beginning_of_today() - base::TimeDelta::FromSeconds(1) /*yesterday*/, + beginning_of_today() + base::TimeDelta::FromSeconds(1) /*today*/, + beginning_of_today() /*today*/}; + + CreateFakeImpressions(create_times, new_client->impressions); + count = NotificationsShownToday(new_client.get(), clock()); + EXPECT_EQ(count, 3); + + // Test case 3: + create_times = { + beginning_of_today() - base::TimeDelta::FromSeconds(2), /*yesterday*/ + beginning_of_today() - base::TimeDelta::FromDays(2), /*tomorrow*/ + }; + CreateFakeImpressions(create_times, new_client->impressions); + count = NotificationsShownToday(new_client.get(), clock()); + EXPECT_EQ(count, 0); + + // Test case 4: + create_times = { + now /*today*/, now - base::TimeDelta::FromSeconds(1) /*today*/, + beginning_of_today() - base::TimeDelta::FromSeconds(1) /*yesterday*/, + beginning_of_today() + base::TimeDelta::FromDays(1) /*tomorrow*/}; + CreateFakeImpressions(create_times, new_client->impressions); + count = NotificationsShownToday(new_client.get(), clock()); + EXPECT_EQ(count, 2); +} } // namespace } // namespace notifications
diff --git a/chrome/browser/offline_pages/offline_page_utils_unittest.cc b/chrome/browser/offline_pages/offline_page_utils_unittest.cc index fdc4165..2bd76419 100644 --- a/chrome/browser/offline_pages/offline_page_utils_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_utils_unittest.cc
@@ -394,7 +394,14 @@ } #endif -TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeBetween) { +#if defined(DISABLE_OFFLINE_PAGES_TOUCHLESS) +#define MAYBE_TestGetCachedOfflinePageSizeBetween \ + DISABLED_TestGetCachedOfflinePageSizeBetween +#else +#define MAYBE_TestGetCachedOfflinePageSizeBetween \ + TestGetCachedOfflinePageSizeBetween +#endif +TEST_F(OfflinePageUtilsTest, MAYBE_TestGetCachedOfflinePageSizeBetween) { // The clock will be at 03:00:00 after adding pages. CreateCachedOfflinePages();
diff --git a/chrome/browser/resources/app_management/browser_proxy.js b/chrome/browser/resources/app_management/browser_proxy.js index cb6dc812..a82975b 100644 --- a/chrome/browser/resources/app_management/browser_proxy.js +++ b/chrome/browser/resources/app_management/browser_proxy.js
@@ -16,7 +16,7 @@ if (useFake) { this.handler = new app_management.FakePageHandler( - this.callbackRouter.createProxy()); + this.callbackRouter.$.createProxy()); const permissionOptions = {}; permissionOptions[PwaPermissionType.CONTENT_SETTINGS_TYPE_GEOLOCATION] = @@ -98,7 +98,8 @@ this.handler = new appManagement.mojom.PageHandlerProxy(); const factory = appManagement.mojom.PageHandlerFactory.getProxy(); factory.createPageHandler( - this.callbackRouter.createProxy(), this.handler.$.createRequest()); + this.callbackRouter.$.createProxy(), + this.handler.$.createRequest()); } } }
diff --git a/chrome/browser/resources/bluetooth_internals/adapter_broker.js b/chrome/browser/resources/bluetooth_internals/adapter_broker.js index 0167d09..918c700 100644 --- a/chrome/browser/resources/bluetooth_internals/adapter_broker.js +++ b/chrome/browser/resources/bluetooth_internals/adapter_broker.js
@@ -40,7 +40,7 @@ super(); this.adapterClient_ = new bluetooth.mojom.AdapterClient(this); this.adapter_ = adapter; - this.adapter_.setClient(this.adapterClient_.createProxy()); + this.adapter_.setClient(this.adapterClient_.$.createProxy()); } presentChanged(present) {
diff --git a/chrome/browser/resources/chromeos/camera/.eslintrc.js b/chrome/browser/resources/chromeos/camera/.eslintrc.js index be7e5f6..875b7ac6 100644 --- a/chrome/browser/resources/chromeos/camera/.eslintrc.js +++ b/chrome/browser/resources/chromeos/camera/.eslintrc.js
@@ -147,6 +147,9 @@ }, 'extends': 'eslint:recommended', 'globals': { + // Adds BigInt64Array here since current version of eslint does not treat + // BigInt64Array as a defined type. + 'BigInt64Array': 'readable', 'cros': 'readable', 'ImageCapture': 'readable', 'webkitRequestFileSystem': 'readable',
diff --git a/chrome/browser/resources/chromeos/camera/BUILD.gn b/chrome/browser/resources/chromeos/camera/BUILD.gn index 09e7daa..daaf9c4d 100644 --- a/chrome/browser/resources/chromeos/camera/BUILD.gn +++ b/chrome/browser/resources/chromeos/camera/BUILD.gn
@@ -55,6 +55,8 @@ "src/images/browser_button_print.svg", "src/images/camera_app_icons_128.png", "src/images/camera_app_icons_48.png", + "src/images/camera_button_fps_30.svg", + "src/images/camera_button_fps_60.svg", "src/images/camera_button_grid_off.svg", "src/images/camera_button_grid_on.svg", "src/images/camera_button_mic_off.svg", @@ -161,12 +163,12 @@ copy("chrome_camera_app_js_views_camera") { sources = [ + "src/js/views/camera/constraints_preferrer.js", "src/js/views/camera/layout.js", "src/js/views/camera/modes.js", "src/js/views/camera/options.js", "src/js/views/camera/preview.js", "src/js/views/camera/recordtime.js", - "src/js/views/camera/resolution_preference.js", "src/js/views/camera/timertick.js", ]
diff --git a/chrome/browser/resources/chromeos/camera/Makefile b/chrome/browser/resources/chromeos/camera/Makefile index 1770fc8..0dcb67a 100644 --- a/chrome/browser/resources/chromeos/camera/Makefile +++ b/chrome/browser/resources/chromeos/camera/Makefile
@@ -77,6 +77,8 @@ src/images/browser_button_delete.svg \ src/images/browser_button_export.svg \ src/images/browser_button_print.svg \ + src/images/camera_button_fps_30.svg \ + src/images/camera_button_fps_60.svg \ src/images/camera_button_grid_off.svg \ src/images/camera_button_grid_on.svg \ src/images/camera_button_mic_off.svg \ @@ -133,12 +135,12 @@ src/js/util.js \ src/js/views/browser.js \ src/js/views/camera.js \ + src/js/views/camera/constraints_preferrer.js \ src/js/views/camera/layout.js \ src/js/views/camera/modes.js \ src/js/views/camera/options.js \ src/js/views/camera/preview.js \ src/js/views/camera/recordtime.js \ - src/js/views/camera/resolution_preference.js \ src/js/views/camera/timertick.js \ src/js/views/dialog.js \ src/js/views/gallery_base.js \
diff --git a/chrome/browser/resources/chromeos/camera/src/_locales/en/messages.json b/chrome/browser/resources/chromeos/camera/src/_locales/en/messages.json index e4bf00c5..5a9f048 100644 --- a/chrome/browser/resources/chromeos/camera/src/_locales/en/messages.json +++ b/chrome/browser/resources/chromeos/camera/src/_locales/en/messages.json
@@ -91,6 +91,10 @@ "message": "Grid type", "description": "Label for the button of grid-type options." }, + "TOGGLE_60FPS_BUTTON": { + "message": "60 FPS", + "description": "Label for the checkbox to toggle 60 FPS recording." + }, "TIMER_DURATION_BUTTON": { "message": "Timer duration", "description": "Label for the button of timer-duration options."
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css index 90a274e..894695b 100644 --- a/chrome/browser/resources/chromeos/camera/src/css/main.css +++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -167,7 +167,7 @@ } .bottom-stripe { - bottom: 56px; + bottom: var(--bottom-line); position: absolute; transform: translateY(50%); } @@ -405,16 +405,17 @@ } #options-group { - bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 30px); + --option-item-vpadding: 12px; + bottom: calc(var(--bottom-line) + (var(--big-icon) / 2) + 32px - var(--option-item-vpadding)); flex-direction: column-reverse; } body:not(.multi-camera) #options-group { - bottom: calc((var(--bottom-line) - 18px) - (var(--small-icon) / 2)); + bottom: calc(var(--bottom-line) - var(--option-item-vpadding) - (var(--small-icon) / 2)); } #options-group input { - margin: 18px 0; + margin: var(--option-item-vpadding) 0; } body._3sec #toggle-timer:checked { @@ -453,6 +454,19 @@ background-image: url(../images/camera_button_mic_off.svg); } +body:not(.multi-fps) #toggle-fps, +body:not(.video-mode) #toggle-fps { + display: none; +} + +body._30fps #toggle-fps { + background-image: url(../images/camera_button_fps_30.svg); +} + +body._60fps #toggle-fps { + background-image: url(../images/camera_button_fps_60.svg); +} + #open-settings { background-image: url(../images/camera_button_settings.svg); } @@ -528,7 +542,7 @@ #camera { --big-icon: 48px; - --bottom-line: 56px; + --bottom-line: 40px; --mode-item-height: 48px; --modes-bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 24px); --modes-gradient-padding: 16px;
diff --git a/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_30.svg b/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_30.svg new file mode 100644 index 0000000..6f859d39 --- /dev/null +++ b/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_30.svg
@@ -0,0 +1 @@ +<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-80.8%" y="-80.8%" width="261.5%" height="261.5%" filterUnits="objectBoundingBox" id="a"><feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.125490196 0 0 0 0 0.129411765 0 0 0 0 0.141176471 0 0 0 0.3 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" transform="translate(5.5 5.5)" fill="#FFF" fill-rule="nonzero"><path d="M.722 0v1.444h3.611V2.89H1.444v1.444h2.89v1.445H.721v1.444h3.611c.795 0 1.445-.65 1.445-1.444V4.694c0-.599-.123-1.083-.722-1.083.599 0 .722-.484.722-1.083V1.444C5.778.65 5.128 0 4.333 0H.723zm10.111 0c.795 0 1.445.65 1.445 1.444v4.334c0 .794-.65 1.444-1.445 1.444H8.667c-.795 0-1.445-.65-1.445-1.444V1.444C7.222.65 7.872 0 8.667 0h2.166zm0 1.444H8.667v4.334h2.166V1.444zM1.444 13H0V9.389h1.444V13zm2.89 0H2.888V9.389h1.444V13zm2.888 0H5.778V9.389h1.444V13zM13 13H8.667V9.389H13V13z"/></g></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_60.svg b/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_60.svg new file mode 100644 index 0000000..087c5d6 --- /dev/null +++ b/chrome/browser/resources/chromeos/camera/src/images/camera_button_fps_60.svg
@@ -0,0 +1 @@ +<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="a"><feOffset in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.125490196 0 0 0 0 0.129411765 0 0 0 0 0.141176471 0 0 0 0.3 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" transform="translate(5.5 5.5)" fill="#FFF" fill-rule="nonzero"><path d="M10.833 1.444v4.334H8.667V1.444h2.166zm0-1.444H8.667c-.795 0-1.445.65-1.445 1.444v4.334c0 .794.65 1.444 1.445 1.444h2.166c.795 0 1.445-.65 1.445-1.444V1.444C12.278.65 11.628 0 10.833 0zM5.778 1.444V0H2.167C1.372 0 .722.65.722 1.444v4.334c0 .794.65 1.444 1.445 1.444h2.166c.795 0 1.445-.65 1.445-1.444V4.333c0-.794-.65-1.444-1.445-1.444H2.167V1.444h3.61zm-1.445 2.89v1.444H2.167V4.333h2.166zM1.444 13H0V9.389h1.444V13zm2.89 0H2.888V9.389h1.444V13zm2.888 0H5.778V9.389h1.444V13zM13 13H8.667V9.389H13V13z"/></g></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/camera/src/js/metrics.js b/chrome/browser/resources/chromeos/camera/src/js/metrics.js index 4f956f2..40dab84 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/metrics.js +++ b/chrome/browser/resources/chromeos/camera/src/js/metrics.js
@@ -124,6 +124,7 @@ .dimen(8, condState(['max-wnd'])) .dimen(9, condState(['tall'])) .dimen(10, `${width}x${height}`) + .dimen(11, condState(['_30fps', '_60fps'], 'video-mode', true)) .value(length || 0); };
diff --git a/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js b/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js index 2fad22c..03a23395 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js +++ b/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js
@@ -85,50 +85,33 @@ * @private */ cca.mojo.getMetadataData_ = function(metadata, tag) { - const size4Bytes = 4; - const size8Bytes = 8; - for (let i = 0; i < metadata.entryCount; i++) { let entry = metadata.entries[i]; if (entry.tag !== tag) { continue; } - let uint8Array = Uint8Array.from(entry.data); - let dataView = new DataView(uint8Array.buffer); - let results = []; - let mostSignificantInt32; - let leastSignificantInt32; - for (let j = 0; j < entry.count; j++) { - switch (entry.type) { - case cros.mojom.EntryType.TYPE_BYTE: - results.push(dataView.getUint8(j, true)); - break; - case cros.mojom.EntryType.TYPE_INT32: - results.push(dataView.getInt32(j * size4Bytes, true)); - break; - case cros.mojom.EntryType.TYPE_FLOAT: - results.push(dataView.getFloat32(j * size4Bytes, true)); - break; - case cros.mojom.EntryType.TYPE_DOUBLE: - results.push(dataView.getFloat64(j * size8Bytes, true)); - break; - case cros.mojom.EntryType.TYPE_INT64: - // TODO(wtlee): Currently int64 value will fallback to int32 by - // picking only the least significant 32 bits. Need to find a way - // to better handle int64 values. - leastSignificantInt32 = dataView.getInt32(j * size8Bytes, true); - mostSignificantInt32 = dataView.getInt32(j * size8Bytes + 4, true); - if (mostSignificantInt32 !== 0) { - console.warn('Truncate non-zero most significant bytes'); + const {buffer} = Uint8Array.from(entry.data); + switch (entry.type) { + case cros.mojom.EntryType.TYPE_BYTE: + return Array.from(new Uint8Array(buffer)); + case cros.mojom.EntryType.TYPE_INT32: + return Array.from(new Int32Array(buffer)); + case cros.mojom.EntryType.TYPE_FLOAT: + return Array.from(new Float32Array(buffer)); + case cros.mojom.EntryType.TYPE_DOUBLE: + return Array.from(new Float64Array(buffer)); + case cros.mojom.EntryType.TYPE_INT64: + return Array.from(new BigInt64Array(buffer), (bigIntVal) => { + let numVal = Number(bigIntVal); + if (!Number.isSafeInteger(numVal)) { + console.warn('The int64 value is not a safe integer'); } - results.push(leastSignificantInt32); - break; - default: - // TODO(wtlee): Supports rational type. - throw new Error('Unsupported type: ' + entry.type); - } + return numVal; + }); + default: + // TODO(wtlee): Supports rational type. + throw new Error('Unsupported type: ' + entry.type); } - return results; } return []; }; @@ -296,8 +279,8 @@ * Gets supported fps ranges for specific camera. * @param {string} deviceId The renderer-facing device Id of the target camera * which could be retrieved from MediaDeviceInfo.deviceId. - * @return {Promise<Array<Object>>} Promise of supported fps ranges. Each range - * is represented as [min, max]. + * @return {Promise<Array<[number, number]>>} Promise of supported fps ranges. + * Each range is represented as [min, max]. */ cca.mojo.getSupportedFpsRanges = function(deviceId) { const numElementPerEntry = 2;
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js index d3a9f96..921699fdb 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -38,10 +38,10 @@ resolBroker, this.stop_.bind(this)); /** - * @type {cca.views.camera.VideoResolPreferrer} + * @type {cca.views.camera.VideoConstraintsPreferrer} * @private */ - this.videoResolPreferrer_ = new cca.views.camera.VideoResolPreferrer( + this.videoPreferrer_ = new cca.views.camera.VideoConstraintsPreferrer( resolBroker, this.stop_.bind(this)); /** @@ -64,8 +64,7 @@ * @private */ this.options_ = new cca.views.camera.Options( - this.photoResolPreferrer_, this.videoResolPreferrer_, - this.stop_.bind(this)); + this.photoResolPreferrer_, this.videoPreferrer_, this.stop_.bind(this)); /** * @type {HTMLElement} @@ -83,8 +82,8 @@ * @private */ this.modes_ = new cca.views.camera.Modes( - this.photoResolPreferrer_, this.videoResolPreferrer_, - this.stop_.bind(this), async (blob, isMotionPicture, filename) => { + this.photoResolPreferrer_, this.videoPreferrer_, this.stop_.bind(this), + async (blob, isMotionPicture, filename) => { if (blob) { cca.metrics.log( cca.metrics.Type.CAPTURE, this.facingMode_, blob.mins, @@ -273,7 +272,7 @@ try { if (!deviceId) { // Null for requesting default camera on HALv1. - throw new Error; + throw new Error('HALv1-api'); } const previewRs = (await this.options_.getDeviceResolutions(deviceId))[1]; var resolCandidates = @@ -281,7 +280,11 @@ } catch (e) { // Assume the exception here is thrown from error of HALv1 not support // resolution query, fallback to use v1 constraints-candidates. - resolCandidates = this.modes_.getResolutionCandidatesV1(mode, deviceId); + if (e.message == 'HALv1-api') { + resolCandidates = this.modes_.getResolutionCandidatesV1(mode, deviceId); + } else { + throw e; + } } for (const [captureResolution, previewCandidates] of resolCandidates) { if (supportedModes && !supportedModes.includes(mode)) { @@ -289,7 +292,7 @@ } for (const constraints of previewCandidates) { try { - const stream = await navigator.mediaDevices.getUserMedia(constraints); + const stream = await cca.mojo.getUserMedia(deviceId, constraints); if (!supportedModes) { supportedModes = await this.modes_.getSupportedModes(stream); if (!supportedModes.includes(mode)) {
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/constraints_preferrer.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/constraints_preferrer.js new file mode 100644 index 0000000..0d22ee0e --- /dev/null +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/constraints_preferrer.js
@@ -0,0 +1,525 @@ +// 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. + +'use strict'; + +/** + * Namespace for the Camera app. + */ +var cca = cca || {}; + +/** + * Namespace for views. + */ +cca.views = cca.views || {}; + +/** + * Namespace for Camera view. + */ +cca.views.camera = cca.views.camera || {}; + +/** + * Controller for managing preference of capture settings and generating a list + * of stream constraints-candidates sorted by user preference. + * @param {cca.ResolutionEventBroker} resolBroker + * @param {function()} doReconfigureStream Trigger stream reconfiguration to + * reflect changes in user preferred settings. + * @constructor + */ +cca.views.camera.ConstraintsPreferrer = function( + resolBroker, doReconfigureStream) { + /** + * @type {cca.ResolutionEventBroker} + * @protected + */ + this.resolBroker_ = resolBroker; + + /** + * @type {function()} + * @protected + */ + this.doReconfigureStream_ = doReconfigureStream; + + /** + * Object saving resolution preference that each of its key as device id and + * value to be preferred width, height of resolution of that video device. + * @type {?Object<string, {width: number, height: number}>} + * @protected + */ + this.prefResolution_ = null; + + /** + * Device id of currently working video device. + * @type {?string} + * @protected + */ + this.deviceId_ = null; + + /** + * Object of device id as its key and all of available capture resolutions + * supported by that video device as its value. + * @type {Object<string, ResolList>} + * @protected + */ + this.deviceResolutions_ = null; +}; + +/** + * Updates resolution preference based on newly updated available resolutions. + * @param {?[string, ResolList]} frontResolutions Device id and available + * resolutions of front camera. + * @param {?[string, ResolList]} backResolutions Device id and available + * resolutions of back camera. + * @param {Array<[string, ResolList]>} externalResolutions Device ids and + * available resolutions of all external cameras. + * @public + */ +cca.views.camera.ConstraintsPreferrer.prototype.updateResolutions = function( + frontResolutions, backResolutions, externalResolutions) {}; + +/** + * Updates values according to currently working video device and capture + * settings. + * @param {string} deviceId Device id of video device to be updated. + * @param {MediaStream} stream Currently active preview stream. + * @param {number} width Width of resolution to be updated to. + * @param {number} height Height of resolution to be updated to. + * @public + */ +cca.views.camera.ConstraintsPreferrer.prototype.updateValues = function( + deviceId, stream, width, height) {}; + +/** + * Gets all available candidates for capturing under this controller and its + * corresponding preview constraints for the specified video device. Returned + * resolutions and constraints candidates are both sorted in desired trying + * order. + * @param {string} deviceId Device id of video device. + * @param {ResolList} previewResolutions Available preview resolutions for the + * video device. + * @return {Array<[[number, number], Array<Object>]>} Result capture resolution + * width, height and constraints-candidates for its preview. + * @public + */ +cca.views.camera.ConstraintsPreferrer.prototype.getSortedCandidates = function( + deviceId, previewResolutions) { + return null; +}; + +/** + * Controller for handling video resolution preference. + * @param {cca.ResolutionEventBroker} resolBroker + * @param {function()} doReconfigureStream + * @constructor + */ +cca.views.camera.VideoConstraintsPreferrer = function( + resolBroker, doReconfigureStream) { + cca.views.camera.ConstraintsPreferrer.call( + this, resolBroker, doReconfigureStream); + + /** + * Object saving information of supported constant fps. Each of its key as + * device id and value as an object mapping from resolution to all constant + * fps options supported by that resolution. + * @type {Object<string, Object<[number, number], Array<number>>>} + * @private + */ + this.constFpsInfo_ = {}; + + /** + * Object saving fps preference that each of its key as device id and value as + * an object mapping from resolution to preferred constant fps for that + * resolution. + * @type {Object<string, Object<[number, number], number>>} + */ + this.prefFpses_ = {}; + + /** + * @type {HTMLButtonElement} + */ + this.toggleFps_ = document.querySelector('#toggle-fps'); + + /** + * Currently in used recording resolution. + * @type {?[number, number]} + * @protected + */ + this.resolution_ = null; + + // End of properties, seal the object. + Object.seal(this); + + // Restore saved preferred recording fps per video device per resolution. + chrome.storage.local.get( + {deviceVideoFps: {}}, + (values) => this.prefFpses_ = values.deviceVideoFps); + + // Restore saved preferred video resolution per video device. + chrome.storage.local.get( + {deviceVideoResolution: {}}, + (values) => this.prefResolution_ = values.deviceVideoResolution); + + this.resolBroker_.registerChangeVideoPrefResolHandler( + (deviceId, width, height) => { + this.prefResolution_[deviceId] = {width, height}; + chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); + if (cca.state.get('video-mode') && deviceId == this.deviceId_) { + this.doReconfigureStream_(); + } else { + this.resolBroker_.notifyVideoPrefResolChange(deviceId, width, height); + } + }); + + this.toggleFps_.addEventListener('click', (event) => { + if (!cca.state.get('streaming') || cca.state.get('taking')) { + event.preventDefault(); + } + }); + this.toggleFps_.addEventListener('change', (event) => { + this.setPreferredConstFps_( + this.deviceId_, ...this.resolution_, this.toggleFps_.checked ? 60 : 30); + this.doReconfigureStream_(); + }); +}; + +cca.views.camera.VideoConstraintsPreferrer.prototype = { + __proto__: cca.views.camera.ConstraintsPreferrer.prototype, +}; + +/** + * All supported constant fps options of video recording. + * @type {Array<number>} + * @const + */ +cca.views.camera.SUPPORTED_CONSTANT_FPS = [30, 60]; + +/** + * Sets the preferred fps used in video recording for particular video device + * and particular resolution. + * @param {string} deviceId Device id of video device to be set with. + * @param {number} width Resolution width to be set with. + * @param {number} height Resolution height to be set with. + * @param {number} prefFps Preferred fps to be set with. + * @private + */ +cca.views.camera.VideoConstraintsPreferrer.prototype.setPreferredConstFps_ = + function(deviceId, width, height, prefFps) { + if (!cca.views.camera.SUPPORTED_CONSTANT_FPS.includes(prefFps)) { + return; + } + this.toggleFps_.checked = prefFps === 60; + cca.views.camera.SUPPORTED_CONSTANT_FPS.forEach( + (fps) => cca.state.set(`_${fps}fps`, fps == prefFps)); + this.prefFpses_[deviceId] = this.prefFpses_[deviceId] || {}; + this.prefFpses_[deviceId][[width, height]] = prefFps; + chrome.storage.local.set({deviceVideoFps: this.prefFpses_}); +}; + +/** + * @param {?[string, ResolList]} frontResolutions + * @param {?[string, ResolList]} backResolutions + * @param {Array<[string, ResolList]>} externalResolutions + * @override + * @public + */ +cca.views.camera.VideoConstraintsPreferrer.prototype.updateResolutions = + function(frontResolutions, backResolutions, externalResolutions) { + this.deviceResolutions_ = {}; + + const toDeviceIdResols = (deviceId, resolutions) => { + this.deviceResolutions_[deviceId] = resolutions; + let {width = -1, height = -1} = this.prefResolution_[deviceId] || {}; + if (!resolutions.find(([w, h]) => w == width && h == height)) { + [width, height] = resolutions.reduce( + (maxR, R) => (maxR[0] * maxR[1] < R[0] * R[1] ? R : maxR), [0, 0]); + } + this.prefResolution_[deviceId] = {width, height}; + return [deviceId, width, height, resolutions]; + }; + + this.resolBroker_.notifyVideoResolChange( + frontResolutions && toDeviceIdResols(...frontResolutions), + backResolutions && toDeviceIdResols(...backResolutions), + externalResolutions.map((ext) => toDeviceIdResols(...ext))); + chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); +}; + +/** + * Updates information of supported fps for all video devices. + * @param {Array<[string, MaxFpsInfo, FpsRangeInfo]>} deviceFpsInfo Video device + * id and max fps for all of its supported video resolutions and supported + * fps ranges of that device. + * @public + */ +cca.views.camera.VideoConstraintsPreferrer.prototype.updateFpses = function( + deviceFpsInfo) { + this.constFpsInfo_ = {}; + for (const [deviceId, maxFpses, fpsRanges] of deviceFpsInfo) { + const constFpses = cca.views.camera.SUPPORTED_CONSTANT_FPS.filter((fps) => { + return fpsRanges.find( + ([minFps, maxFps]) => minFps === fps && maxFps === fps) !== + undefined; + }); + const fpsInfo = {}; + for (const r of Object.keys(maxFpses)) { + fpsInfo[r] = constFpses.filter((fps) => fps <= maxFpses[r]); + } + this.constFpsInfo_[deviceId] = fpsInfo; + } +}; + +/** + * @param {string} deviceId + * @param {MediaStream} stream + * @param {number} width + * @param {number} height + * @public + * @override + */ +cca.views.camera.VideoConstraintsPreferrer.prototype.updateValues = function( + deviceId, stream, width, height) { + this.deviceId_ = deviceId; + this.resolution_ = [width, height]; + this.prefResolution_[deviceId] = {width, height}; + chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); + this.resolBroker_.notifyVideoPrefResolChange(deviceId, width, height); + + const fps = stream.getVideoTracks()[0].getSettings().frameRate; + const availableFpses = this.constFpsInfo_[deviceId][[width, height]]; + if (availableFpses.includes(fps)) { + this.setPreferredConstFps_(deviceId, width, height, fps); + } + cca.state.set('multi-fps', availableFpses.length > 1); +}; + +/** + * @param {string} deviceId + * @param {ResolList} previewResolutions + * @return {Array<[[number, number], Array<Object>]>} + * @public + * @override + */ +cca.views.camera.VideoConstraintsPreferrer.prototype.getSortedCandidates = + function(deviceId, previewResolutions) { + // Due to the limitation of MediaStream API, preview stream is used directly + // to do video recording. + const prefR = this.prefResolution_[deviceId] || {width: 0, height: -1}; + const sortPrefResol = ([w, h], [w2, h2]) => { + if (w == w2 && h == h2) { + return 0; + } + // Exactly the preferred resolution. + if (w == prefR.width && h == prefR.height) { + return -1; + } + if (w2 == prefR.width && h2 == prefR.height) { + return 1; + } + // Aspect ratio same as preferred resolution. + if (w * h2 != w2 * h) { + if (w * prefR.height == prefR.width * h) { + return -1; + } + if (w2 * prefR.height == prefR.width * h2) { + return 1; + } + } + return w2 * h2 - w * h; + }; + + // Maps specified video resolution width, height to tuple of width, height and + // all supported constant fps under that resolution or null fps for not + // support multiple constant fps options. The resolution-fps tuple are sorted + // by user preference of constant fps. + const getFpses = (r) => { + let constFpses = [null]; + if (this.constFpsInfo_[deviceId][r].includes(30) && + this.constFpsInfo_[deviceId][r].includes(60)) { + const prefFps = + this.prefFpses_[deviceId] && this.prefFpses_[deviceId][r] || 30; + constFpses = prefFps == 30 ? [30, 60] : [60, 30]; + } + return constFpses.map((fps) => [...r, fps]); + }; + + const toConstraints = (width, height, fps) => ({ + audio: true, + video: { + deviceId: {exact: deviceId}, + frameRate: fps ? {exact: fps} : {min: 24}, + width, + height, + }, + }); + + return this.deviceResolutions_[deviceId] + .sort(sortPrefResol) + .flatMap(getFpses) + .map(([width, height, fps]) => ([ + [width, height], + [toConstraints(width, height, fps)], + ])); +}; + +/** + * Controller for handling photo resolution preference. + * @param {cca.ResolutionEventBroker} resolBroker + * @param {function()} doReconfigureStream + * @constructor + */ +cca.views.camera.PhotoResolPreferrer = function( + resolBroker, doReconfigureStream) { + cca.views.camera.ConstraintsPreferrer.call( + this, resolBroker, doReconfigureStream); + + // End of properties, seal the object. + Object.seal(this); + + // Restore saved preferred photo resolution per video device. + chrome.storage.local.get( + {devicePhotoResolution: {}}, + (values) => this.prefResolution_ = values.devicePhotoResolution); + + this.resolBroker_.registerChangePhotoPrefResolHandler( + (deviceId, width, height) => { + this.prefResolution_[deviceId] = {width, height}; + chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); + if (!cca.state.get('video-mode') && deviceId == this.deviceId_) { + this.doReconfigureStream_(); + } else { + this.resolBroker_.notifyPhotoPrefResolChange(deviceId, width, height); + } + }); +}; + +cca.views.camera.PhotoResolPreferrer.prototype = { + __proto__: cca.views.camera.ConstraintsPreferrer.prototype, +}; + +/** + * @param {?[string, ResolList]} frontResolutions + * @param {?[string, ResolList]} backResolutions + * @param {Array<[string, ResolList]>} externalResolutions + * @public + * @override + */ +cca.views.camera.PhotoResolPreferrer.prototype.updateResolutions = function( + frontResolutions, backResolutions, externalResolutions) { + this.deviceResolutions_ = {}; + + const toDeviceIdResols = (deviceId, resolutions) => { + this.deviceResolutions_[deviceId] = resolutions; + let {width = -1, height = -1} = this.prefResolution_[deviceId] || {}; + if (!resolutions.find(([w, h]) => w == width && h == height)) { + [width, height] = resolutions.reduce( + (maxR, R) => (maxR[0] * maxR[1] < R[0] * R[1] ? R : maxR), [0, 0]); + } + this.prefResolution_[deviceId] = {width, height}; + return [deviceId, width, height, resolutions]; + }; + + this.resolBroker_.notifyPhotoResolChange( + frontResolutions && toDeviceIdResols(...frontResolutions), + backResolutions && toDeviceIdResols(...backResolutions), + externalResolutions.map((ext) => toDeviceIdResols(...ext))); + chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); +}; + +/** + * @param {string} deviceId + * @param {MediaStream} stream + * @param {number} width + * @param {number} height + * @public + * @override + */ +cca.views.camera.PhotoResolPreferrer.prototype.updateValues = function( + deviceId, stream, width, height) { + this.deviceId_ = deviceId; + this.prefResolution_[deviceId] = {width, height}; + chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); + this.resolBroker_.notifyPhotoPrefResolChange(deviceId, width, height); +}; + +/** + * Finds and pairs photo resolutions and preview resolutions with the same + * aspect ratio. + * @param {ResolList} captureResolutions Available photo capturing resolutions. + * @param {ResolList} previewResolutions Available preview resolutions. + * @return {Array<[ResolList, ResolList]>} Each item of returned array is a pair + * of capture and preview resolutions of same aspect ratio. + */ +cca.views.camera.PhotoResolPreferrer.prototype.pairCapturePreviewResolutions_ = + function(captureResolutions, previewResolutions) { + const toAspectRatio = (w, h) => (w / h).toFixed(4); + const previewRatios = previewResolutions.reduce((rs, [w, h]) => { + const key = toAspectRatio(w, h); + rs[key] = rs[key] || []; + rs[key].push([w, h]); + return rs; + }, {}); + const captureRatios = captureResolutions.reduce((rs, [w, h]) => { + const key = toAspectRatio(w, h); + if (key in previewRatios) { + rs[key] = rs[key] || []; + rs[key].push([w, h]); + } + return rs; + }, {}); + return Object.entries(captureRatios) + .map(([aspectRatio, + captureRs]) => [captureRs, previewRatios[aspectRatio]]); +}; + +/** + * @param {string} deviceId + * @param {ResolList} previewResolutions + * @return {Array<[[number, number], Array<Object>]>} + * @public + * @override + */ +cca.views.camera.PhotoResolPreferrer.prototype.getSortedCandidates = function( + deviceId, previewResolutions) { + const photoResolutions = this.deviceResolutions_[deviceId]; + const prefR = this.prefResolution_[deviceId] || {width: 0, height: -1}; + return this + .pairCapturePreviewResolutions_(photoResolutions, previewResolutions) + .map(([captureRs, previewRs]) => { + if (captureRs.some(([w, h]) => w == prefR.width && h == prefR.height)) { + var captureR = [prefR.width, prefR.height]; + } else { + var captureR = captureRs.reduce( + (captureR, r) => (r[0] > captureR[0] ? r : captureR), [0, -1]); + } + + const candidates = previewRs.sort(([w, h], [w2, h2]) => w2 - w) + .map(([width, height]) => ({ + audio: false, + video: { + deviceId: {exact: deviceId}, + frameRate: {min: 24}, + width, + height, + }, + })); + // Format of map result: + // [ + // [[CaptureW 1, CaptureH 1], [CaptureW 2, CaptureH 2], ...], + // [PreviewConstraint 1, PreviewConstraint 2, ...] + // ] + return [captureR, candidates]; + }) + .sort(([[w, h]], [[w2, h2]]) => { + if (w == w2 && h == h2) { + return 0; + } + if (w == prefR.width && h == prefR.height) { + return -1; + } + if (w2 == prefR.width && h2 == prefR.height) { + return 1; + } + return w2 * h2 - w * h; + }); +};
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js index 86601d38..5d922ef9 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -22,14 +22,14 @@ /** * Mode controller managing capture sequence of different camera mode. * @param {cca.views.camera.PhotoResolPreferrer} photoResolPreferrer - * @param {cca.views.camera.VideoResolPreferrer} videoResolPreferrer + * @param {cca.views.camera.VideoConstraintsPreferrer} videoPreferrer * @param {function()} doSwitchMode Callback to trigger mode switching. * @param {function(?Blob, boolean, string): Promise} doSavePicture Callback for * saving picture. * @constructor */ cca.views.camera.Modes = function( - photoResolPreferrer, videoResolPreferrer, doSwitchMode, doSavePicture) { + photoResolPreferrer, videoPreferrer, doSwitchMode, doSavePicture) { /** * @type {function()} * @private @@ -78,7 +78,7 @@ captureFactory: () => new cca.views.camera.Video(this.stream_, this.doSavePicture_), isSupported: async () => true, - resolutionConfig: videoResolPreferrer, + resolutionConfig: videoPreferrer, v1Config: cca.views.camera.Modes.getV1Constraints.bind(this, true), nextMode: 'photo-mode', }, @@ -227,7 +227,7 @@ * @param {string} mode * @param {string} deviceId * @param {ResolList} previewResolutions - * @return {Array<[?[number, number], Array<Object>]>} Result capture resolution + * @return {Array<[[number, number], Array<Object>]>} Result capture resolution * width, height and constraints-candidates for its preview. */ cca.views.camera.Modes.prototype.getResolutionCandidates = function( @@ -298,8 +298,8 @@ this.captureResolution_ = captureResolution; this.current = this.allModes_[mode].captureFactory(); if (deviceId && this.captureResolution_) { - this.allModes_[mode].resolutionConfig.updateCurrentResolution( - deviceId, ...this.captureResolution_); + this.allModes_[mode].resolutionConfig.updateValues( + deviceId, stream, ...this.captureResolution_); } };
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js index 144c2a9..d5d45826 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js
@@ -20,14 +20,81 @@ cca.views.camera = cca.views.camera || {}; /** + * Map of all available resolution to its maximal supported capture fps. + * @typedef {Object<[number, number], number>} MaxFpsInfo + */ + +/** + * List of supported capture fps ranges. + * @typedef {Array<[number, number]>} FpsRangeInfo + */ + +/** + * Video device information queried from HALv3 mojo private API. + * @param {MediaDeviceInfo} deviceInfo Information of the video device. + * @param {cros.mojom.CameraFacing} facing Camera facing of the video device. + * @param {ResolList} photoResols Supported available photo resolutions of the + * video device. + * @param {Array<[number, number, number]>} videoResolFpses Supported available + * video resolutions and maximal capture fps of the video device. + * @param {FpsRangeInfo} fpsRanges Supported fps ranges of the video device. + */ +cca.views.camera.Camera3DeviceInfo = function( + deviceInfo, facing, photoResols, videoResolFpses, fpsRanges) { + /** + * @type {string} + * @public + */ + this.deviceId = deviceInfo.deviceId; + + /** + * @type {cros.mojom.CameraFacing} + * @public + */ + this.facing = facing; + + /** + * @type {ResolList} + * @public + */ + this.photoResols = photoResols; + + /** + * @type {ResolList} + * @public + */ + this.videoResols = []; + + /** + * @type {MaxFpsInfo} + * @public + */ + this.videoMaxFps = {}; + + /** + * @type {FpsRangeInfo} + * @public + */ + this.fpsRanges = fpsRanges; + + // End of properties, seal the object. + Object.seal(this); + + videoResolFpses.filter(([, , fps]) => fps >= 24).forEach(([w, h, fps]) => { + this.videoResols.push([w, h]); + this.videoMaxFps[[w, h]] = fps; + }); +}; + +/** * Creates a controller for the options of Camera view. * @param {cca.views.camera.PhotoResolPreferrer} photoResolPreferrer - * @param {cca.views.camera.VideoResolPreferrer} videoResolPreferrer + * @param {cca.views.camera.VideoConstraintsPreferrer} videoPreferrer * @param {function()} doSwitchDevice Callback to trigger device switching. * @constructor */ cca.views.camera.Options = function( - photoResolPreferrer, videoResolPreferrer, doSwitchDevice) { + photoResolPreferrer, videoPreferrer, doSwitchDevice) { /** * @type {cca.views.camera.PhotoResolPreferrer} * @private @@ -35,10 +102,10 @@ this.photoResolPreferrer_ = photoResolPreferrer; /** - * @type {cca.views.camera.VideoResolPreferrer} + * @type {cca.views.camera.VideoConstraintsPreferrer} * @private */ - this.videoResolPreferrer_ = videoResolPreferrer; + this.videoPreferrer_ = videoPreferrer; /** * @type {function()} @@ -80,16 +147,12 @@ this.videoDevices_ = null; /** - * MediaDeviceInfo and additional information queried from private mojo api of - * all available video device. The additional fields in the array entry - * represent camera facing, supported photo resolutions, supported video - * resolutions. On HALv1 device, the promise will throw exception for its - * incapability of building mojo api connection. - * @type {Promise<!Array<[MediaDeviceInfo, cros.mojom.CameraFacing, ResolList, - * ResolList]>>} + * Promise for querying Camera3DeviceInfo of all available video devices from + * mojo private API. + * @type {Promise<!Array<Camera3DeviceInfo>>} * @private */ - this.devicePrivateInfo_ = null; + this.devicesPrivateInfo_ = null; /** * Whether the current device is HALv1 and lacks facing configuration. @@ -287,36 +350,39 @@ this.refreshingVideoDeviceIds_ = false; }); - this.devicePrivateInfo_ = - this.videoDevices_ - .then((devices) => { - return Promise.all(devices.map((d) => Promise.all([ - d, - cca.mojo.getCameraFacing(d.deviceId), - cca.mojo.getPhotoResolutions(d.deviceId), - cca.mojo.getVideoConfigs(d.deviceId) - .then( - (v) => v.filter(([, , fps]) => fps >= 24) - .map(([w, h]) => [w, h])), - ]))); - }) - .catch((e) => { - cca.state.set('no-resolution-settings', true); - throw e; - }); + this.devicesPrivateInfo_ = (async () => { + const devices = await this.videoDevices_; + try { + var privateInfos = await Promise.all(devices.map((d) => Promise.all([ + d, + cca.mojo.getCameraFacing(d.deviceId), + cca.mojo.getPhotoResolutions(d.deviceId), + cca.mojo.getVideoConfigs(d.deviceId), + cca.mojo.getSupportedFpsRanges(d.deviceId), + ]))); + } catch (e) { + cca.state.set('no-resolution-settings', true); + throw new Error('HALv1-api'); + } + return privateInfos.map( + (info) => new cca.views.camera.Camera3DeviceInfo(...info)); + })(); (async () => { try { - var devicePrivateInfo = await this.devicePrivateInfo_; + var devicesPrivateInfo = await this.devicesPrivateInfo_; } catch (e) { - return; + if (e.message == 'HALv1-api') { + return; + } + throw e; } let frontSetting = null; let backSetting = null; let externalSettings = []; - devicePrivateInfo.forEach(([{deviceId}, facing, photoRs, videoRs]) => { - const setting = [deviceId, photoRs, videoRs]; - switch (facing) { + devicesPrivateInfo.forEach((info) => { + const setting = [info.deviceId, info.photoResols, info.videoResols]; + switch (info.facing) { case cros.mojom.CameraFacing.CAMERA_FACING_FRONT: frontSetting = setting; break; @@ -327,17 +393,20 @@ externalSettings.push(setting); break; default: - console.error(`Ignore device of unknown facing: ${facing}`); + console.error(`Ignore device of unknown facing: ${info.facing}`); } }); this.photoResolPreferrer_.updateResolutions( frontSetting && [frontSetting[0], frontSetting[1]], backSetting && [backSetting[0], backSetting[1]], externalSettings.map(([deviceId, photoRs]) => [deviceId, photoRs])); - this.videoResolPreferrer_.updateResolutions( + this.videoPreferrer_.updateResolutions( frontSetting && [frontSetting[0], frontSetting[2]], backSetting && [backSetting[0], backSetting[2]], externalSettings.map(([deviceId, , videoRs]) => [deviceId, videoRs])); + + this.videoPreferrer_.updateFpses(devicesPrivateInfo.map( + (info) => [info.deviceId, info.videoMaxFps, info.fpsRanges])); })(); }; @@ -354,14 +423,18 @@ throw new Error('Device list empty.'); } try { - var facings = (await this.devicePrivateInfo_) + var facings = (await this.devicesPrivateInfo_) .reduce( - (facings, [d, facing]) => - Object.assign(facings, {[d.deviceId]: facing}), + (facings, info) => Object.assign( + facings, {[info.deviceId]: info.facing}), {}); this.isV1NoFacingConfig_ = false; } catch (e) { - facings = null; + if (e.message == 'HALv1-api') { + facings = null; + } else { + throw e; + } } // Put the selected video device id first. var sorted = devices.map((device) => device.deviceId).sort((a, b) => { @@ -395,8 +468,7 @@ cca.views.camera.Options.prototype.getDeviceResolutions = async function(deviceId) { // HALv1 device will thrown from here. - const devicePrivateInfo = await this.devicePrivateInfo_; - const [, , photoRs, videoRs] = - devicePrivateInfo.find(([d]) => d.deviceId === deviceId); - return [photoRs, videoRs]; + const info = (await this.devicesPrivateInfo_) + .find((info) => info.deviceId === deviceId); + return [info.photoResols, info.videoResols]; };
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/resolution_preference.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/resolution_preference.js deleted file mode 100644 index 50283ed..0000000 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/resolution_preference.js +++ /dev/null
@@ -1,382 +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. - -'use strict'; - -/** - * Namespace for the Camera app. - */ -var cca = cca || {}; - -/** - * Namespace for views. - */ -cca.views = cca.views || {}; - -/** - * Namespace for Camera view. - */ -cca.views.camera = cca.views.camera || {}; - -/** - * Controller for handling resolution preference. - * @param {cca.ResolutionEventBroker} resolBroker - * @param {function()} doSwitchResolution - * @constructor - */ -cca.views.camera.ResolutionPreferrer = function( - resolBroker, doSwitchResolution) { - /** - * @type {cca.ResolutionEventBroker} - * @protected - */ - this.resolBroker_ = resolBroker; - - /** - * @type {function()} - * @protected - */ - this.doSwitchResolution_ = doSwitchResolution; - - /** - * Object saving resolution preference that each of its key as device id and - * value to be preferred width, height of resolution of that video device. - * @type {?Object<string, {width: number, height: number}>} - * @protected - */ - this.prefResolution_ = null; - - /** - * Device id of currently working video device. - * @type {?string} - * @protected - */ - this.deviceId_ = null; - - /** - * Object of device id as its key and all of available capture resolutions - * supported by that video device as its value. - * @type {Object<string, ResolList>} - * @protected - */ - this.deviceResolutions_ = null; - - // End of properties, seal the object. - Object.seal(this); -}; - -/** - * Updates resolution preference based on newly updated available resolutions. - * @param {?[string, ResolList]} frontResolutions Device id and available - * resolutions of front camera. - * @param {?[string, ResolList]} backResolutions Device id and available - * resolutions of back camera. - * @param {Array<[string, ResolList]>} externalResolutions Device ids and - * available resolutions of all external cameras. - */ -cca.views.camera.ResolutionPreferrer.prototype.updateResolutions = function( - frontResolutions, backResolutions, externalResolutions) {}; - -/** - * Updates preferred resolution of currently working video device. - * @param {string} deviceId Device id of video device to be updated. - * @param {number} width Width of resolution to be updated to. - * @param {number} height Height of resolution to be updated to. - */ -cca.views.camera.ResolutionPreferrer.prototype.updateCurrentResolution = - function(deviceId, width, height) {}; - -/** - * Gets all available resolutions candidates for capturing under this controller - * and its corresponding preview constraints for the specified video device. - * Returned resolutions and constraints candidates are both sorted in desired - * trying order. - * @param {string} deviceId Device id of video device. - * @param {ResolList} previewResolutions Available preview resolutions for the - * video device. - * @return {Array<[number, number, Array<Object>]>} Result capture resolution - * width, height and constraints-candidates for its preview. - */ -cca.views.camera.ResolutionPreferrer.prototype.getSortedCandidates = function( - deviceId, previewResolutions) { - return null; -}; - -/** - * Controller for handling video resolution preference. - * @param {cca.ResolutionEventBroker} resolBroker - * @param {function()} doSwitchResolution - * @constructor - */ -cca.views.camera.VideoResolPreferrer = function( - resolBroker, doSwitchResolution) { - cca.views.camera.ResolutionPreferrer.call( - this, resolBroker, doSwitchResolution); - - // Restore saved preferred video resolution per video device. - chrome.storage.local.get( - {deviceVideoResolution: {}}, - (values) => this.prefResolution_ = values.deviceVideoResolution); - - this.resolBroker_.registerChangeVideoPrefResolHandler( - (deviceId, width, height) => { - this.prefResolution_[deviceId] = {width, height}; - chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); - if (cca.state.get('video-mode') && deviceId == this.deviceId_) { - this.doSwitchResolution_(); - } else { - this.resolBroker_.notifyVideoPrefResolChange(deviceId, width, height); - } - }); -}; - -cca.views.camera.VideoResolPreferrer.prototype = { - __proto__: cca.views.camera.ResolutionPreferrer.prototype, -}; - -/** - * @param {?[string, ResolList]} frontResolutions - * @param {?[string, ResolList]} backResolutions - * @param {Array<[string, ResolList]>} externalResolutions - * @override - */ -cca.views.camera.VideoResolPreferrer.prototype.updateResolutions = function( - frontResolutions, backResolutions, externalResolutions) { - this.deviceResolutions_ = {}; - - const toDeviceIdResols = (deviceId, resolutions) => { - this.deviceResolutions_[deviceId] = resolutions; - let {width = -1, height = -1} = this.prefResolution_[deviceId] || {}; - if (!resolutions.find(([w, h]) => w == width && h == height)) { - [width, height] = resolutions.reduce( - (maxR, R) => (maxR[0] * maxR[1] < R[0] * R[1] ? R : maxR), [0, 0]); - } - this.prefResolution_[deviceId] = {width, height}; - return [deviceId, width, height, resolutions]; - }; - - this.resolBroker_.notifyVideoResolChange( - frontResolutions && toDeviceIdResols(...frontResolutions), - backResolutions && toDeviceIdResols(...backResolutions), - externalResolutions.map((ext) => toDeviceIdResols(...ext))); - chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); -}; - -/** - * @param {string} deviceId - * @param {number} width - * @param {number} height - * @override - */ -cca.views.camera.VideoResolPreferrer.prototype.updateCurrentResolution = - function(deviceId, width, height) { - this.deviceId_ = deviceId; - this.prefResolution_[deviceId] = {width, height}; - chrome.storage.local.set({deviceVideoResolution: this.prefResolution_}); - this.resolBroker_.notifyVideoPrefResolChange(deviceId, width, height); -}; - -/** - * @param {string} deviceId - * @return {Array<[number, number, Array<Object>]>} - * @override - */ -cca.views.camera.VideoResolPreferrer.prototype.getSortedCandidates = function( - deviceId, previewResolutions) { - // Due to the limitation of MediaStream API, preview stream is used directly - // to do video recording. - const prefR = this.prefResolution_[deviceId] || {width: 0, height: -1}; - const preferredOrder = ([w, h], [w2, h2]) => { - if (w == w2 && h == h2) { - return 0; - } - // Exactly the preferred resolution. - if (w == prefR.width && h == prefR.height) { - return -1; - } - if (w2 == prefR.width && h2 == prefR.height) { - return 1; - } - // Aspect ratio same as preferred resolution. - if (w * h2 != w2 * h) { - if (w * prefR.height == prefR.width * h) { - return -1; - } - if (w2 * prefR.height == prefR.width * h2) { - return 1; - } - } - return w2 * h2 - w * h; - }; - const toConstraints = (width, height) => ({ - audio: true, - video: { - deviceId: {exact: deviceId}, - frameRate: {min: 24}, - width, - height, - }, - }); - const videoResolutions = this.deviceResolutions_[deviceId]; - return videoResolutions.sort(preferredOrder).map(([width, height]) => ([ - [width, height], - [toConstraints( - width, height)], - ])); -}; - -/** - * Controller for handling photo resolution preference. - * @param {cca.ResolutionEventBroker} resolBroker - * @param {function()} doSwitchResolution - * @constructor - */ -cca.views.camera.PhotoResolPreferrer = function( - resolBroker, doSwitchResolution) { - cca.views.camera.ResolutionPreferrer.call( - this, resolBroker, doSwitchResolution); - - // Restore saved preferred photo resolution per video device. - chrome.storage.local.get( - {devicePhotoResolution: {}}, - (values) => this.prefResolution_ = values.devicePhotoResolution); - - this.resolBroker_.registerChangePhotoPrefResolHandler( - (deviceId, width, height) => { - this.prefResolution_[deviceId] = {width, height}; - chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); - if (!cca.state.get('video-mode') && deviceId == this.deviceId_) { - this.doSwitchResolution_(); - } else { - this.resolBroker_.notifyPhotoPrefResolChange(deviceId, width, height); - } - }); -}; - -cca.views.camera.PhotoResolPreferrer.prototype = { - __proto__: cca.views.camera.ResolutionPreferrer.prototype, -}; - -/** - * @param {?[string, ResolList]} frontResolutions - * @param {?[string, ResolList]} backResolutions - * @param {Array<[string, ResolList]>} externalResolutions - * @override - */ -cca.views.camera.PhotoResolPreferrer.prototype.updateResolutions = function( - frontResolutions, backResolutions, externalResolutions) { - this.deviceResolutions_ = {}; - - const toDeviceIdResols = (deviceId, resolutions) => { - this.deviceResolutions_[deviceId] = resolutions; - let {width = -1, height = -1} = this.prefResolution_[deviceId] || {}; - if (!resolutions.find(([w, h]) => w == width && h == height)) { - [width, height] = resolutions.reduce( - (maxR, R) => (maxR[0] * maxR[1] < R[0] * R[1] ? R : maxR), [0, 0]); - } - this.prefResolution_[deviceId] = {width, height}; - return [deviceId, width, height, resolutions]; - }; - - this.resolBroker_.notifyPhotoResolChange( - frontResolutions && toDeviceIdResols(...frontResolutions), - backResolutions && toDeviceIdResols(...backResolutions), - externalResolutions.map((ext) => toDeviceIdResols(...ext))); - chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); -}; - -/** - * @param {string} deviceId - * @param {number} width - * @param {number} height - * @override - */ -cca.views.camera.PhotoResolPreferrer.prototype.updateCurrentResolution = - function(deviceId, width, height) { - this.deviceId_ = deviceId; - this.prefResolution_[deviceId] = {width, height}; - chrome.storage.local.set({devicePhotoResolution: this.prefResolution_}); - this.resolBroker_.notifyPhotoPrefResolChange(deviceId, width, height); -}; - -/** - * Finds and pairs photo resolutions and preview resolutions with the same - * aspect ratio. - * @param {ResolList} captureResolutions Available photo capturing resolutions. - * @param {ResolList} previewResolutions Available preview resolutions. - * @return {Array<[ResolList, ResolList]>} Each item of returned array is a pair - * of capture and preview resolutions of same aspect ratio. - */ -cca.views.camera.PhotoResolPreferrer.prototype.pairCapturePreviewResolutions_ = - function(captureResolutions, previewResolutions) { - const toAspectRatio = (w, h) => (w / h).toFixed(4); - const previewRatios = previewResolutions.reduce((rs, [w, h]) => { - const key = toAspectRatio(w, h); - rs[key] = rs[key] || []; - rs[key].push([w, h]); - return rs; - }, {}); - const captureRatios = captureResolutions.reduce((rs, [w, h]) => { - const key = toAspectRatio(w, h); - if (key in previewRatios) { - rs[key] = rs[key] || []; - rs[key].push([w, h]); - } - return rs; - }, {}); - return Object.entries(captureRatios) - .map(([aspectRatio, - captureRs]) => [captureRs, previewRatios[aspectRatio]]); -}; - -/** - * @param {string} deviceId - * @param {ResolList} previewResolutions - * @return {Array<[number, number, Array<Object>]>} - * @override - */ -cca.views.camera.PhotoResolPreferrer.prototype.getSortedCandidates = function( - deviceId, previewResolutions) { - const photoResolutions = this.deviceResolutions_[deviceId]; - const prefR = this.prefResolution_[deviceId] || {width: 0, height: -1}; - return this - .pairCapturePreviewResolutions_(photoResolutions, previewResolutions) - .map(([captureRs, previewRs]) => { - if (captureRs.some(([w, h]) => w == prefR.width && h == prefR.height)) { - var captureR = [prefR.width, prefR.height]; - } else { - var captureR = captureRs.reduce( - (captureR, r) => (r[0] > captureR[0] ? r : captureR), [0, -1]); - } - - const candidates = previewRs.sort(([w, h], [w2, h2]) => w2 - w) - .map(([width, height]) => ({ - audio: false, - video: { - deviceId: {exact: deviceId}, - frameRate: {min: 24}, - width, - height, - }, - })); - // Format of map result: - // [ - // [[CaptureW 1, CaptureH 1], [CaptureW 2, CaptureH 2], ...], - // [PreviewConstraint 1, PreviewConstraint 2, ...] - // ] - return [captureR, candidates]; - }) - .sort(([[w, h]], [[w2, h2]]) => { - if (w == w2 && h == h2) { - return 0; - } - if (w == prefR.width && h == prefR.height) { - return -1; - } - if (w2 == prefR.width && h2 == prefR.height) { - return 1; - } - return w2 * h2 - w * h; - }); -};
diff --git a/chrome/browser/resources/chromeos/camera/src/strings/camera_strings.grd b/chrome/browser/resources/chromeos/camera/src/strings/camera_strings.grd index 2bd7b40..834cc21 100644 --- a/chrome/browser/resources/chromeos/camera/src/strings/camera_strings.grd +++ b/chrome/browser/resources/chromeos/camera/src/strings/camera_strings.grd
@@ -285,6 +285,9 @@ <message desc="Label for the button of grid-type options." name="IDS_GRID_TYPE_BUTTON"> Grid type </message> + <message desc="Label for the checkbox to toggle 60 FPS recording." name="IDS_TOGGLE_60FPS_BUTTON"> + 60 FPS + </message> <message desc="Label for the back button." name="IDS_BACK_BUTTON"> Go back </message>
diff --git a/chrome/browser/resources/chromeos/camera/src/strings/camera_strings_grd/IDS_TOGGLE_60FPS_BUTTON.png.sha1 b/chrome/browser/resources/chromeos/camera/src/strings/camera_strings_grd/IDS_TOGGLE_60FPS_BUTTON.png.sha1 new file mode 100644 index 0000000..e9018f8 --- /dev/null +++ b/chrome/browser/resources/chromeos/camera/src/strings/camera_strings_grd/IDS_TOGGLE_60FPS_BUTTON.png.sha1
@@ -0,0 +1 @@ +3a593c1ca0c47bd934e16bdc366adbe125ab3e6b \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html index 87ec1d6..3e2f55f 100644 --- a/chrome/browser/resources/chromeos/camera/src/views/main.html +++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -36,7 +36,7 @@ <script src="../js/views/camera/options.js"></script> <script src="../js/views/camera/preview.js"></script> <script src="../js/views/camera/recordtime.js"></script> - <script src="../js/views/camera/resolution_preference.js"></script> + <script src="../js/views/camera/constraints_preferrer.js"></script> <script src="../js/views/camera/timertick.js"></script> <script src="../js/views/camera/modes.js"></script> <script src="../js/views/dialog.js"></script> @@ -131,6 +131,8 @@ data-key="toggleGrid"> <input type="checkbox" id="toggle-mirror" tabindex="0" i18n-label="toggle_mirror_button" data-state="mirror" checked> + <input type="checkbox" id="toggle-fps" tabindex="0" + i18n-label="toggle_60fps_button"> </div> <div class="top-stripe left-stripe buttons"> <button id="open-settings" tabindex="0"
diff --git a/chrome/browser/resources/discards/graph_tab.js b/chrome/browser/resources/discards/graph_tab.js index 0231a772..e300a07 100644 --- a/chrome/browser/resources/discards/graph_tab.js +++ b/chrome/browser/resources/discards/graph_tab.js
@@ -99,10 +99,12 @@ onWebViewReady_: function() { this.changeListener_ = new graph_tab.WebUIGraphChangeStreamImpl(this.$.webView.contentWindow); - const client = new performanceManager.mojom - .WebUIGraphChangeStream(this.changeListener_) - .createProxy(); + this.client_ = new performanceManager.mojom.WebUIGraphChangeStream( + this.changeListener_); + // Save helper to work around closure compiler bug: https://crbug.com/969212 + const helper = this.client_.$; + // Subscribe for graph updates. - this.graphDump_.subscribeToChanges(client); + this.graphDump_.subscribeToChanges(helper.createProxy()); }, });
diff --git a/chrome/browser/resources/downloads/browser_proxy.js b/chrome/browser/resources/downloads/browser_proxy.js index 7dc6c8ee..924df0f 100644 --- a/chrome/browser/resources/downloads/browser_proxy.js +++ b/chrome/browser/resources/downloads/browser_proxy.js
@@ -13,7 +13,7 @@ const factory = downloads.mojom.PageHandlerFactory.getProxy(); factory.createPageHandler( - this.callbackRouter.createProxy(), this.handler.$.createRequest()); + this.callbackRouter.$.createProxy(), this.handler.$.createRequest()); } }
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js index 40a7d07b..c02243f 100644 --- a/chrome/browser/resources/interventions_internals/index.js +++ b/chrome/browser/resources/interventions_internals/index.js
@@ -704,7 +704,7 @@ // Set up client side mojo interface. pageImpl = new InterventionsInternalPageImpl(); const client = new mojom.InterventionsInternalsPage(pageImpl); - pageHandler.setClientPage(client.createProxy()); + pageHandler.setClientPage(client.$.createProxy()); } interventions_internals.init(pageHandler);
diff --git a/chrome/browser/resources/local_ntp/animations.css b/chrome/browser/resources/local_ntp/animations.css index 26ac65f2..3725006 100644 --- a/chrome/browser/resources/local_ntp/animations.css +++ b/chrome/browser/resources/local_ntp/animations.css
@@ -22,29 +22,29 @@ } .ripple-effect { - background-color: rgba(var(--GB600-rgb), 0.1); + background-color: rgba(var(--GB600-rgb), .1); border-radius: 50%; height: 1px; pointer-events: none; transition: width, height, margin, background-color 400ms 250ms; transition-duration: 400ms; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(.4, 0, .2, 1); width: 1px; } @media (prefers-color-scheme: dark) { .ripple-effect { - background-color: rgba(var(--GB300-rgb), 0.32); + background-color: rgba(var(--GB300-rgb), .32); } } button.primary .ripple-effect { - background-color: rgba(255, 255, 255, 0.32); + background-color: rgba(255, 255, 255, .32); } @media (prefers-color-scheme: dark) { button.primary .ripple-effect { - background-color: rgba(0, 0, 0, 0.08); + background-color: rgba(0, 0, 0, .08); } } @@ -59,7 +59,7 @@ position: relative; transition-duration: 200ms; transition-property: background-color, color, box-shadow, border; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(.4, 0, .2, 1); } button.paper:disabled { @@ -92,8 +92,8 @@ button.paper.primary:hover:not(:disabled) { background-color: rgb(41, 123, 231); - box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), 0.3), - 0 1px 3px 1px rgba(var(--GB500-rgb), 0.15); + box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), .3), + 0 1px 3px 1px rgba(var(--GB500-rgb), .15); } @media (prefers-color-scheme: dark) { @@ -103,15 +103,15 @@ } button.paper.primary:active:not(:disabled) { - box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), 0.3), - 0 3px 6px 2px rgba(var(--GB500-rgb), 0.15); + box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), .3), + 0 3px 6px 2px rgba(var(--GB500-rgb), .15); } @media (prefers-color-scheme: dark) { button.paper.primary:active:not(:disabled) { background-color: rgb(115, 160, 223); - box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), 0.3), - 0 3px 6px 2px rgba(var(--GB500-rgb), 0.15); + box-shadow: 0 1px 2px 0 rgba(var(--GB500-rgb), .3), + 0 3px 6px 2px rgba(var(--GB500-rgb), .15); } } @@ -142,31 +142,31 @@ } button.paper.secondary:hover:not(:disabled) { - background-color: rgba(var(--GB500-rgb), 0.04); + background-color: rgba(var(--GB500-rgb), .04); border-color: rgb(var(--GB100-rgb)); } @media (prefers-color-scheme: dark) { button.paper.secondary:hover:not(:disabled) { - background-color: rgba(var(--GB300-rgb), 0.04); - border-color: rgba(var(--GB300-rgb), 0.5); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), - 0 1px 3px 1px rgba(0, 0, 0, 0.15); + background-color: rgba(var(--GB300-rgb), .04); + border-color: rgba(var(--GB300-rgb), .5); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .3), + 0 1px 3px 1px rgba(0, 0, 0, .15); } } button.paper.secondary:active:not(:disabled) { background-color: white; border-color: white; - box-shadow: 0 1px 2px 0 rgba(var(--GG800-rgb), 0.3), - 0 3px 6px 2px rgba(var(--GG800-rgb), 0.15); + box-shadow: 0 1px 2px 0 rgba(var(--GG800-rgb), .3), + 0 3px 6px 2px rgba(var(--GG800-rgb), .15); } @media (prefers-color-scheme: dark) { button.paper.secondary:active:not(:disabled) { - background-color: rgba(var(--GB300-rgb), 0.08); - border-color: rgba(var(--GB300-rgb), 0.5); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), - 0 3px 6px 2px rgba(0, 0, 0, 0.15); + background-color: rgba(var(--GB300-rgb), .08); + border-color: rgba(var(--GB300-rgb), .5); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .3), + 0 3px 6px 2px rgba(0, 0, 0, .15); } }
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css index 86f72137..b0edd041 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.css +++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -15,8 +15,8 @@ border: none; border-radius: 8px; bottom: 0; - box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), 0.3), - 0 4px 8px 3px rgba(var(--GG800-rgb), 0.15); + box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), .3), + 0 4px 8px 3px rgba(var(--GG800-rgb), .15); margin: auto; min-width: 320px; padding: 16px; @@ -27,8 +27,8 @@ @media (prefers-color-scheme: dark) { #edit-link-dialog { background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); } } @@ -95,14 +95,14 @@ @media (prefers-color-scheme: dark) { input { - background-color: rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, .3); caret-color: rgb(var(--GB300-rgb)); color: rgb(var(--GG200-rgb)); } } input::placeholder { - color: rgba(var(--GG900-rgb), 0.38); + color: rgba(var(--GG900-rgb), .38); } @media (prefers-color-scheme: dark) {
diff --git a/chrome/browser/resources/local_ntp/customize.css b/chrome/browser/resources/local_ntp/customize.css index 0dad8581..b2d6f1b 100644 --- a/chrome/browser/resources/local_ntp/customize.css +++ b/chrome/browser/resources/local_ntp/customize.css
@@ -33,7 +33,7 @@ #edit-bg.ep-enhanced { background-color: rgb(255, 255, 255); - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 1px 2px rgba(0, 0, 0, 0.23); + box-shadow: 0 3px 6px rgba(0, 0, 0, .16), 0 1px 2px rgba(0, 0, 0, .23); } #edit-bg:hover, @@ -134,8 +134,8 @@ border-radius: 8px; border-width: thin; bottom: 44px; - box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), 0.3), - 0 4px 8px 3px rgba(var(--GG800-rgb), 0.15); + box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), .3), + 0 4px 8px 3px rgba(var(--GG800-rgb), .15); left: auto; padding: 0; position: fixed; @@ -145,8 +145,8 @@ @media (prefers-color-scheme: dark) { #edit-bg-dialog { background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); } } @@ -220,12 +220,12 @@ } .bg-option.bg-option-disabled { - opacity: 0.28; + opacity: .28; } @media (prefers-color-scheme: dark) { .bg-option.bg-option-disabled { - opacity: 0.38; + opacity: .38; } } @@ -254,7 +254,7 @@ @media (prefers-color-scheme: dark) { #edit-bg-divider { - border-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, .1); } } @@ -286,8 +286,8 @@ border: none; border-radius: 8px; bottom: 0; - box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), 0.3), - 0 4px 8px 3px rgba(var(--GG800-rgb), 0.15); + box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), .3), + 0 4px 8px 3px rgba(var(--GG800-rgb), .15); height: 400px; padding: 0 0 0 0; position: fixed; @@ -301,8 +301,8 @@ @media (prefers-color-scheme: dark) { #bg-sel-menu { background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); } } @@ -339,7 +339,7 @@ @media (prefers-color-scheme: dark) { #bg-sel-title-bar { - border-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, .1); } } @@ -478,7 +478,7 @@ @media (prefers-color-scheme: dark) { #bg-sel-footer { - border-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, .1); } } @@ -629,7 +629,7 @@ } .bg-sel-tile-title { - background-color: rgba(var(--GG900-rgb), 0.71); + background-color: rgba(var(--GG900-rgb), .71); bottom: 0; box-sizing: border-box; color: #FFF; @@ -660,7 +660,7 @@ max-width: 80%; padding: 8px 8px 8px 8px; position: fixed; - text-shadow: 0 0 16px rgba(0, 0, 0, 0.3); + text-shadow: 0 0 16px rgba(0, 0, 0, .3); z-index: -1; }
diff --git a/chrome/browser/resources/local_ntp/doodles.css b/chrome/browser/resources/local_ntp/doodles.css index 6e70f2b5..f767928 100644 --- a/chrome/browser/resources/local_ntp/doodles.css +++ b/chrome/browser/resources/local_ntp/doodles.css
@@ -144,7 +144,7 @@ width: 37.5%; } .use-notifier #logo-doodle-notifier .inner { - animation: anim-pos 880ms cubic-bezier(0.445, 0.05, 0.55, 0.95) + animation: anim-pos 880ms cubic-bezier(.445, .05, .55, .95) infinite alternate; border-radius: 50%; height: 100%; @@ -189,7 +189,7 @@ cursor: pointer; display: inline-block; height: 26px; - opacity: 0.8; + opacity: .8; position: absolute; width: 26px; } @@ -210,7 +210,7 @@ background: #fff; border: none; border-radius: 8px; - box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.2); + box-shadow: 0 4px 16px 0 rgba(0, 0, 0, .2); left: 0; margin: auto; min-height: 100px; @@ -224,7 +224,19 @@ } #ddlsd::backdrop { - background-color: rgba(255, 255, 255, 0.9); + background-color: rgba(255, 255, 255, .9); +} + +@media (prefers-color-scheme: dark) { + #ddlsd { + background-color: rgb(41, 42, 45); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), + 0 4px 8px 3px rgba(0, 0, 0, 0.15); + } + + #ddlsd::backdrop { + background-color: rgba(0, 0, 0, 0.4); + } } #ddlsd button { @@ -233,7 +245,7 @@ } #ddlsd button:hover { - opacity: 0.8; + opacity: .8; } #ddlsd-title { @@ -242,6 +254,12 @@ padding: 0 40px 16px 0; } +@media (prefers-color-scheme: dark) { + #ddlsd-title { + color: rgb(var(--GG200-rgb)); + } +} + #ddlsd-close { background: url(icons/close.svg) no-repeat; height: 24px; @@ -265,7 +283,7 @@ #ddlsd-text { border: 2px solid #aaa; - border-color: rgba(0, 0, 0, 0.15); + border-color: rgba(0, 0, 0, .15); border-radius: 4px; color: #555; display: inline-block; @@ -274,6 +292,13 @@ width: 100%; } +@media (prefers-color-scheme: dark) { + #ddlsd-text { + background-color: rgba(0, 0, 0, 0.3); + color: rgb(var(--GG200-rgb)); + } +} + #ddlsd-copy { background: url(icons/copy.svg) no-repeat center; background-size: contain;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css index dc690338..a265b36 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.css +++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -455,7 +455,7 @@ @media (prefers-color-scheme: dark) { body:not(.light-chip) #mv-notice { background-color: rgb(var(--GG900-rgb)); - border-color: rgba(0, 0, 0, 0.1); + border-color: rgba(0, 0, 0, .1); } } @@ -498,7 +498,7 @@ #mv-notice-links span:hover, #mv-notice-links span:active { - background-color: rgba(var(--GB600-rgb), 0.1); + background-color: rgba(var(--GB600-rgb), .1); text-decoration: none; transition: background-color 200ms; } @@ -506,7 +506,7 @@ @media (prefers-color-scheme: dark) { body:not(.light-chip) #mv-notice-links :-webkit-any(span:hover, span:active) { - background-color: rgba(var(--GB400-dark-rgb), 0.1); + background-color: rgba(var(--GB400-dark-rgb), .1); } } @@ -566,7 +566,7 @@ @media (prefers-color-scheme: dark) { .customize-dialog::backdrop { - background-color: rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, .4); } } @@ -631,7 +631,7 @@ @media (prefers-color-scheme: dark) { body:not(.light-chip) #error-notice { background-color: rgb(var(--GG900-rgb)); - border-color: rgba(0, 0, 0, 0.1); + border-color: rgba(0, 0, 0, .1); color: rgb(var(--GR500-dark-rgb)); } } @@ -695,7 +695,7 @@ #error-notice-link:hover, #error-notice-link:active { - background-color: rgba(var(--GB600-rgb), 0.1); + background-color: rgba(var(--GB600-rgb), .1); text-decoration: none; transition: background-color 200ms; } @@ -703,7 +703,7 @@ @media (prefers-color-scheme: dark) { body:not(.light-chip) #error-notice-link:hover, body:not(.light-chip) #error-notice-link:active { - background-color: rgba(var(--GB400-dark-rgb), 0.1); + background-color: rgba(var(--GB400-dark-rgb), .1); } } @@ -743,7 +743,7 @@ @media (prefers-color-scheme: dark) { body:not(.light-chip) #promo > div { background-color: rgb(var(--GG900-rgb)); - border-color: rgba(0, 0, 0, 0.1); + border-color: rgba(0, 0, 0, .1); color: rgb(var(--GG200-rgb)); } } @@ -818,8 +818,8 @@ @media (prefers-color-scheme: dark) { #customization-menu { background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); color: rgb(var(--GG200-rgb)); } } @@ -947,7 +947,7 @@ @media (prefers-color-scheme: dark) { #menu-footer { - border-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, .1); } }
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css index 40e0593a..e25b90de 100644 --- a/chrome/browser/resources/local_ntp/most_visited_single.css +++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -139,8 +139,8 @@ .reorder { background-color: white; border-radius: 4px; - box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), 0.3), - 0 4px 8px 3px rgba(var(--GG800-rgb), 0.15); + box-shadow: 0 1px 3px 0 rgba(var(--GG800-rgb), .3), + 0 4px 8px 3px rgba(var(--GG800-rgb), .15); color: rgb(var(--GG800-rgb)); transition-duration: 200ms; } @@ -148,8 +148,8 @@ @media (prefers-color-scheme: dark) { .reorder { background-color: rgb(var(--dark-mode-bg-rgb)); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), - 0 4px 8px 3px rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .4), + 0 4px 8px 3px rgba(0, 0, 0, .25); color: rgb(var(--GG100-rgb)); } } @@ -164,19 +164,19 @@ body:not(.reordering) .md-tile:hover, .grid-reorder .md-tile { - background-color: rgba(var(--GG900-rgb), 0.06); + background-color: rgba(var(--GG900-rgb), .06); } @media (prefers-color-scheme: dark) { body:not(.reordering) .md-tile:hover, .grid-reorder .md-tile { - background-color: rgba(255, 255, 255, 0.1); + background-color: rgba(255, 255, 255, .1); } } body.dark-theme:not(.reordering) .md-tile:hover, body.dark-theme .grid-reorder .md-tile { - background-color: rgba(255, 255, 255, 0.1); + background-color: rgba(255, 255, 255, .1); } body:not(.reordering) .md-tile:hover .md-menu { @@ -267,7 +267,7 @@ /* Apply when a custom background is set. */ body.custom-background .md-tile:not(.reorder) .md-title { - filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.35)); + filter: drop-shadow(0 0 6px rgba(0, 0, 0, .35)); } /* Apply only when a theme with image is installed. */
diff --git a/chrome/browser/resources/local_ntp/voice.css b/chrome/browser/resources/local_ntp/voice.css index 9cbaabbb..fde0cac 100644 --- a/chrome/browser/resources/local_ntp/voice.css +++ b/chrome/browser/resources/local_ntp/voice.css
@@ -181,9 +181,9 @@ @media (prefers-color-scheme: dark) { .button { background-color: rgb(var(--GG900-rgb)); - border-color: rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + border-color: rgba(0, 0, 0, .1); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); } }
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js index 190b77c..385479d2d5 100644 --- a/chrome/browser/resources/omnibox/omnibox.js +++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -68,7 +68,7 @@ /** @private {!mojom.OmniboxPageHandlerProxy} */ this.handler_ = mojom.OmniboxPageHandler.getProxy(); - this.handler_.setClientPage(this.callbackRouter_.createProxy()); + this.handler_.setClientPage(this.callbackRouter_.$.createProxy()); /** @private {Request} */ this.lastRequest; @@ -260,7 +260,7 @@ currentUrl: "", pageClassification: "4" } - ], + ], }; console.error(`Invalid batch specifier data. Expected format: \n${ JSON.stringify(expected, null, 2)}`);
diff --git a/chrome/browser/resources/snippets_internals/snippets_internals.js b/chrome/browser/resources/snippets_internals/snippets_internals.js index a76d8b3..d3d057d16 100644 --- a/chrome/browser/resources/snippets_internals/snippets_internals.js +++ b/chrome/browser/resources/snippets_internals/snippets_internals.js
@@ -261,7 +261,7 @@ snippetsInternals.mojom.PageHandlerFactory.getProxy(); // Give backend mojo a reference to frontend mojo. - const client = new snippetsInternals.mojom.Page(page).createProxy(); + const client = new snippetsInternals.mojom.Page(page).$.createProxy(); pageHandlerFactory.createPageHandler(client).then((response) => { pageHandler = response.handler;
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc index a93d5c34..667a659c 100644 --- a/chrome/browser/signin/signin_ui_util.cc +++ b/chrome/browser/signin/signin_ui_util.cc
@@ -215,8 +215,7 @@ for (auto& account_info : accounts_with_tokens) { DCHECK(!account_info.IsEmpty()); if (!identity::IsUsernameAllowedByPatternFromPrefs( - g_browser_process->local_state(), account_info.email, - prefs::kGoogleServicesUsernamePattern)) { + g_browser_process->local_state(), account_info.email)) { continue; } if (account_info.account_id == default_account_id)
diff --git a/chrome/browser/signin/signin_util.cc b/chrome/browser/signin/signin_util.cc index ae4781b..cd0efe39 100644 --- a/chrome/browser/signin/signin_util.cc +++ b/chrome/browser/signin/signin_util.cc
@@ -222,8 +222,7 @@ CoreAccountInfo primary_account = identity_manager->GetPrimaryAccountInfo(); if (profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed) && identity::IsUsernameAllowedByPatternFromPrefs( - g_browser_process->local_state(), primary_account.email, - prefs::kGoogleServicesUsernamePattern)) { + g_browser_process->local_state(), primary_account.email)) { return; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 389bd318..6d1c8776b 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -3385,10 +3385,6 @@ "app_list/search/chrome_search_result.h", "app_list/search/common/url_icon_source.cc", "app_list/search/common/url_icon_source.h", - "app_list/search/crostini/crostini_repository_search_provider.cc", - "app_list/search/crostini/crostini_repository_search_provider.h", - "app_list/search/crostini/crostini_repository_search_result.cc", - "app_list/search/crostini/crostini_repository_search_result.h", "app_list/search/extension_app_result.cc", "app_list/search/extension_app_result.h", "app_list/search/mixer.cc", @@ -3568,8 +3564,6 @@ "ash/launcher/shelf_spinner_item_controller.h", "views/arc_app_dialog_view.cc", "views/arc_data_removal_dialog_view.cc", - "views/crostini/crostini_app_installer_view.cc", - "views/crostini/crostini_app_installer_view.h", "views/crostini/crostini_app_restart_view.cc", "views/crostini/crostini_app_restart_view.h", "views/crostini/crostini_app_uninstaller_view.cc", @@ -3691,6 +3685,8 @@ "web_applications/app_browser_controller.h", "web_applications/system_web_app_ui_utils_chromeos.cc", "web_applications/system_web_app_ui_utils_chromeos.h", + "web_applications/web_app_dialog_manager.cc", + "web_applications/web_app_dialog_manager.h", "web_applications/web_app_dialog_utils.cc", "web_applications/web_app_dialog_utils.h", "web_applications/web_app_metrics.cc",
diff --git a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.cc b/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.cc deleted file mode 100644 index 0dd08d98..0000000 --- a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.h" - -#include <stddef.h> - -#include "base/strings/utf_string_conversions.h" -#include "base/bind.h" -#include "chrome/browser/chromeos/crostini/crostini_manager.h" -#include "chrome/browser/chromeos/crostini/crostini_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.h" - -namespace app_list { - -CrostiniRepositorySearchProvider::CrostiniRepositorySearchProvider( - Profile* profile) - : profile_(profile), weak_ptr_factory_(this) {} - -CrostiniRepositorySearchProvider::~CrostiniRepositorySearchProvider() = default; - -void CrostiniRepositorySearchProvider::OnStart( - const std::vector<std::string>& app_names) { - SearchProvider::Results new_results; - new_results.reserve(app_names.size()); - for (auto& app_name : app_names) { - new_results.emplace_back( - std::make_unique<CrostiniRepositorySearchResult>(profile_, app_name)); - // Todo(https://crbug.com/921429): Improve relevance logic, this will likely - // be implemented in garcon then piped to Chrome - new_results.back()->set_relevance(static_cast<float>(query_.size()) / - app_name.size()); - } - SwapResults(&new_results); -} - -void CrostiniRepositorySearchProvider::Start(const base::string16& query) { - // Only perform search when Crostini is running. - if (!crostini::IsCrostiniRunning(profile_)) { - return; - } - if (query.empty()) { - ClearResults(); - return; - } - query_ = base::UTF16ToUTF8(query); - - crostini::CrostiniManager::GetForProfile(profile_)->SearchApp( - crostini::kCrostiniDefaultVmName, crostini::kCrostiniDefaultContainerName, - query_, - base::BindOnce(&CrostiniRepositorySearchProvider::OnStart, - weak_ptr_factory_.GetWeakPtr())); -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.h b/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.h deleted file mode 100644 index fcb3e55..0000000 --- a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_PROVIDER_H_ -#define CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_PROVIDER_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/ui/app_list/search/search_provider.h" - -class Profile; - -namespace app_list { - -// Search provider for Crostini repository search. -class CrostiniRepositorySearchProvider : public SearchProvider { - public: - explicit CrostiniRepositorySearchProvider(Profile* profile); - ~CrostiniRepositorySearchProvider() override; - - // SearchProvider overrides: - void Start(const base::string16& query) override; - - private: - // Callback for CrostiniRepositorySearchProvider::Start. - void OnStart(const std::vector<std::string>& app_names); - - // Plaintext query to be searched. - std::string query_; - - // Unowned pointer to associated profile. - Profile* const profile_; - - base::WeakPtrFactory<CrostiniRepositorySearchProvider> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(CrostiniRepositorySearchProvider); -}; - -} // namespace app_list - -#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_PROVIDER_H_
diff --git a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.cc b/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.cc deleted file mode 100644 index a659f096..0000000 --- a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.h" - -#include <stddef.h> - -#include "ash/public/cpp/app_list/app_list_config.h" -#include "ash/public/cpp/app_list/vector_icons/vector_icons.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/browser/chromeos/crostini/crostini_package_service.h" -#include "chrome/browser/chromeos/crostini/crostini_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/grit/generated_resources.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace app_list { - -namespace { - -// TODO(https://crbug.com/921429): Need UX spec. -constexpr SkColor kListIconColor = SkColorSetARGB(0xDE, 0x00, 0x00, 0x00); - -} // namespace - -CrostiniRepositorySearchResult::CrostiniRepositorySearchResult( - Profile* profile, - const std::string& app_name) - : profile_(profile), app_name_(app_name), weak_ptr_factory_(this) { - // TODO(https://crbug.com/921429): Need UX spec. - set_id("crostini:" + app_name_); - SetResultType(ash::SearchResultType::kOmnibox); - - // TODO(https://crbug.com/921429): Need UX spec. - const gfx::VectorIcon& icon = kFileDownloadIcon; - SetIcon(gfx::CreateVectorIcon( - icon, AppListConfig::instance().search_list_icon_dimension(), - kListIconColor)); - SetTitle(l10n_util::GetStringFUTF16( - IDS_CROSTINI_REPOSITORY_SEARCH_RESULT_TITLE_PLACEHOLDER_TEXT, - base::UTF8ToUTF16(app_name_))); - SetDetails(l10n_util::GetStringUTF16( - IDS_CROSTINI_REPOSITORY_SEARCH_RESULT_DETAILS_PLACEHOLDER_TEXT)); -} - -CrostiniRepositorySearchResult::~CrostiniRepositorySearchResult() = default; - -void CrostiniRepositorySearchResult::OnOpen( - const crostini::LinuxPackageInfo& package_info) { - // TODO(https://crbug.com/921429): Handle when |package_info| fails. - if (package_info.success) { - crostini::ShowCrostiniAppInstallerView(profile_, package_info); - } -} - -void CrostiniRepositorySearchResult::Open(int event_flags) { - crostini::CrostiniManager::GetForProfile(profile_) - ->GetLinuxPackageInfoFromApt( - crostini::kCrostiniDefaultVmName, - crostini::kCrostiniDefaultContainerName, app_name_, - base::BindOnce(&CrostiniRepositorySearchResult::OnOpen, - weak_ptr_factory_.GetWeakPtr())); -} - -SearchResultType CrostiniRepositorySearchResult::GetSearchResultType() const { - return CROSTINI_APP; -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.h b/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.h deleted file mode 100644 index 9154a0b0..0000000 --- a/chrome/browser/ui/app_list/search/crostini/crostini_repository_search_result.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_RESULT_H_ -#define CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_RESULT_H_ - -#include <string> - -#include "ash/public/cpp/app_list/app_list_metrics.h" -#include "base/macros.h" -#include "chrome/browser/chromeos/crostini/crostini_manager.h" -#include "chrome/browser/ui/app_list/app_context_menu_delegate.h" -#include "chrome/browser/ui/app_list/search/chrome_search_result.h" - -class Profile; - -namespace app_list { - -class CrostiniRepositorySearchResult : public ChromeSearchResult { - public: - CrostiniRepositorySearchResult(Profile* profile, const std::string& app_name); - ~CrostiniRepositorySearchResult() override; - - // ChromeSearchResult overrides: - void Open(int event_flags) override; - SearchResultType GetSearchResultType() const override; - - private: - void OnOpen(const crostini::LinuxPackageInfo& package); - - Profile* profile_; - std::string app_name_; - base::WeakPtrFactory<CrostiniRepositorySearchResult> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(CrostiniRepositorySearchResult); -}; - -} // namespace app_list - -#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_CROSTINI_CROSTINI_REPOSITORY_SEARCH_RESULT_H_
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index baccde2..46ef031 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -21,7 +21,6 @@ #include "chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider.h" #include "chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h" #include "chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h" -#include "chrome/browser/ui/app_list/search/crostini/crostini_repository_search_provider.h" #include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h" #include "chrome/browser/ui/app_list/search/mixer.h" #include "chrome/browser/ui/app_list/search/omnibox_provider.h" @@ -63,9 +62,6 @@ constexpr float kBoostOfSettingsShortcut = 10.0f; constexpr float kBoostOfApps = 8.0f; -// TODO(danielng): Need UX spec. -constexpr size_t kMaxCrostiniRepositoryResults = 2; - } // namespace std::unique_ptr<SearchController> CreateSearchController( @@ -159,16 +155,6 @@ kMaxAppShortcutResults, profile, list_controller, app_ranker)); } - // TODO(https://crbug.com/921429): Put feature switch in ash/public/app_list/ - // like the other search providers. - if (base::FeatureList::IsEnabled(features::kCrostiniAppSearch)) { - size_t crostini_repository_group_id = - controller->AddGroup(kMaxCrostiniRepositoryResults, 1.0, 0.0); - controller->AddProvider( - crostini_repository_group_id, - std::make_unique<CrostiniRepositorySearchProvider>(profile)); - } - return controller; }
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc index da62ded..15db2ed 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h" +#include <utility> + #include "base/time/time.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/frecency_store.pb.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/histogram_util.h" @@ -37,6 +39,18 @@ return counts_; } +void FakePredictor::Cleanup(const std::vector<unsigned int>& valid_targets) { + std::map<unsigned int, float> new_counts; + + for (unsigned int id : valid_targets) { + const auto& it = counts_.find(id); + if (it != counts_.end()) + new_counts[id] = it->second; + } + + counts_.swap(new_counts); +} + void FakePredictor::ToProto(RecurrencePredictorProto* proto) const { auto* counts = proto->mutable_fake_predictor()->mutable_counts(); for (auto& pair : counts_) @@ -117,6 +131,49 @@ return result; } +void ConditionalFrequencyPredictor::Cleanup( + const std::vector<unsigned int>& valid_targets) { + for (auto iter = table_.begin(); iter != table_.end();) { + auto& events = iter->second; + + std::map<unsigned int, float> new_freqs; + float new_total = 0.0f; + for (unsigned int id : valid_targets) { + const auto& it = events.freqs.find(id); + if (it != events.freqs.end()) { + new_freqs[id] = it->second; + new_total += it->second; + } + } + + // Delete the whole condition out of the table if it contains no valid + // targets. + if (new_freqs.empty()) { + // C++11: the return value of erase(iter) is an iterator pointing to the + // next element in the container. + iter = table_.erase(iter); + } else { + ++iter; + events.freqs.swap(new_freqs); + events.total = new_total; + } + } +} + +void ConditionalFrequencyPredictor::CleanupConditions( + const std::vector<unsigned int>& valid_conditions) { + std::map<unsigned int, ConditionalFrequencyPredictor::Events> new_table; + + for (unsigned int id : valid_conditions) { + const auto& it = table_.find(id); + if (it != table_.end()) { + new_table[id] = std::move(it->second); + } + } + + table_.swap(new_table); +} + void ConditionalFrequencyPredictor::ToProto( RecurrencePredictorProto* proto) const { auto* predictor = proto->mutable_conditional_frequency_predictor(); @@ -169,6 +226,19 @@ return result; } +void FrecencyPredictor::Cleanup( + const std::vector<unsigned int>& valid_targets) { + std::map<unsigned int, FrecencyPredictor::TargetData> new_targets; + + for (unsigned int id : valid_targets) { + const auto& it = targets_.find(id); + if (it != targets_.end()) + new_targets[id] = it->second; + } + + targets_.swap(new_targets); +} + void FrecencyPredictor::ToProto(RecurrencePredictorProto* proto) const { auto* predictor = proto->mutable_frecency_predictor(); @@ -280,6 +350,10 @@ return ranks; } +// TODO(921444): Unify the hour bin predictor with the cleanup system used for +// other predictors. This is different than other predictors so as to be exactly +// the same as the Roselle predictor. + void HourBinPredictor::ToProto(RecurrencePredictorProto* proto) const { *proto->mutable_hour_bin_predictor() = proto_; } @@ -349,6 +423,11 @@ return std::map<unsigned int, float>(); } +void MarkovPredictor::Cleanup(const std::vector<unsigned int>& valid_targets) { + frequencies_.CleanupConditions(valid_targets); + frequencies_.Cleanup(valid_targets); +} + void MarkovPredictor::ToProto(RecurrencePredictorProto* proto) const { auto* predictor = proto->mutable_markov_predictor(); frequencies_.ToProto(predictor->mutable_frequencies());
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h index 8d7424eb..62d7a50 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.h
@@ -7,6 +7,7 @@ #include <map> #include <memory> +#include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -45,6 +46,13 @@ // under this predictor. Scores must be within the range [0,1]. virtual std::map<unsigned int, float> Rank(unsigned int condition) = 0; + // Called when the ranker detects that the predictor's rankings are + // significantly different to the set of valid targets, and can optionally be + // used to clean up internal state. For efficiency reasons, Cleanup is + // supplied a const reference to the FrecencyStore's internal state. However + // it is likely that only id field in the values is of interest. + virtual void Cleanup(const std::vector<unsigned int>& valid_targets) {} + virtual void ToProto(RecurrencePredictorProto* proto) const = 0; virtual void FromProto(const RecurrencePredictorProto& proto) = 0; virtual const char* GetPredictorName() const = 0; @@ -64,6 +72,7 @@ // RecurrencePredictor: void Train(unsigned int target, unsigned int condition) override; std::map<unsigned int, float> Rank(unsigned int condition) override; + void Cleanup(const std::vector<unsigned int>& valid_targets) override; void ToProto(RecurrencePredictorProto* proto) const override; void FromProto(const RecurrencePredictorProto& proto) override; const char* GetPredictorName() const override; @@ -128,10 +137,17 @@ void Train(unsigned int target, unsigned int condition) override; // The scores in the returned map sum to 1 if the map is non-empty. std::map<unsigned int, float> Rank(unsigned int condition) override; + void Cleanup(const std::vector<unsigned int>& valid_targets) override; void ToProto(RecurrencePredictorProto* proto) const override; void FromProto(const RecurrencePredictorProto& proto) override; const char* GetPredictorName() const override; + // Deletes all information about conditions not in |valid_conditions|. This is + // analogous to Cleanup for targets. Note that Cleanup already deletes + // conditions if they have no associated targets, so CleanupTargets is useful + // only in the case of having extra information about invalid conditions. + void CleanupConditions(const std::vector<unsigned int>& valid_conditions); + static const char kPredictorName[]; // Add |delta| to the relative frequency of |target| given |condition|. @@ -165,6 +181,7 @@ // RecurrencePredictor: void Train(unsigned int target, unsigned int condition) override; std::map<unsigned int, float> Rank(unsigned int condition) override; + void Cleanup(const std::vector<unsigned int>& valid_targets) override; void ToProto(RecurrencePredictorProto* proto) const override; void FromProto(const RecurrencePredictorProto& proto) override; const char* GetPredictorName() const override; @@ -250,6 +267,7 @@ // RecurrencePredictor: void Train(unsigned int target, unsigned int condition) override; std::map<unsigned int, float> Rank(unsigned int condition) override; + void Cleanup(const std::vector<unsigned int>& valid_targets) override; void ToProto(RecurrencePredictorProto* proto) const override; void FromProto(const RecurrencePredictorProto& proto) override; const char* GetPredictorName() const override; @@ -257,6 +275,7 @@ static const char kPredictorName[]; private: + FRIEND_TEST_ALL_PREFIXES(MarkovPredictorTest, Cleanup); FRIEND_TEST_ALL_PREFIXES(MarkovPredictorTest, ToAndFromProto); // Stores transition probabilities: P(target | previous_target).
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc index a2e4b90..525c691b 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
@@ -71,6 +71,15 @@ } } +TEST_F(FrecencyPredictorTest, Cleanup) { + for (int i = 0; i < 6; ++i) + predictor_->Train(i, 0u); + predictor_->Cleanup({0u, 2u, 4u}); + + EXPECT_THAT(predictor_->Rank(0u), + UnorderedElementsAre(Pair(0u, _), Pair(2u, _), Pair(4u, _))); +} + TEST_F(FrecencyPredictorTest, ToAndFromProto) { predictor_->Train(1u, 0u); predictor_->Train(3u, 0u); @@ -108,6 +117,27 @@ Pair(2u, FloatEq(2.0f / 5.0f)))); } +TEST_F(ConditionalFrequencyPredictorTest, Cleanup) { + ConditionalFrequencyPredictor cfp; + + cfp.Train(0u, 0u); + for (int i = 0; i < 6; ++i) { + cfp.Train(i, 0u); + cfp.Train(2 * i, 1u); + cfp.Train(2 * i + 1, 2u); + } + cfp.Cleanup({0u, 2u, 4u}); + + EXPECT_THAT(cfp.Rank(0u), UnorderedElementsAre(Pair(0u, FloatEq(0.5f)), + Pair(2u, FloatEq(0.25f)), + Pair(4u, FloatEq(0.25f)))); + EXPECT_THAT(cfp.Rank(1u), + UnorderedElementsAre(Pair(0u, FloatEq(1.0f / 3.0f)), + Pair(2u, FloatEq(1.0f / 3.0f)), + Pair(4u, FloatEq(1.0f / 3.0f)))); + EXPECT_TRUE(cfp.Rank(2u).empty()); +} + TEST_F(ConditionalFrequencyPredictorTest, ToFromProto) { ConditionalFrequencyPredictor cfp1; @@ -418,6 +448,33 @@ Pair(3u, FloatEq(1.0f / 3.0f)))); } +TEST_F(MarkovPredictorTest, Cleanup) { + // 0 -> {1, 3} and all i -> {i+1}. + for (int i = 0; i < 6; ++i) + predictor_->Train(i, 0u); + predictor_->Train(0, 0u); + predictor_->Train(3, 0u); + + predictor_->Cleanup({0u, 1u, 2u}); + + // Expect 0 -> {1} with target 3 deleted. + predictor_->previous_target_ = 0u; + EXPECT_THAT(predictor_->Rank(0u), + UnorderedElementsAre(Pair(1u, FloatEq(1.0f)))); + // Expect 1 -> {2} with nothing deleted. + predictor_->previous_target_ = 1u; + EXPECT_THAT(predictor_->Rank(1u), + UnorderedElementsAre(Pair(2u, FloatEq(1.0f)))); + + // Conditions 2, 3, 4, 5 should have been cleaned up. For 2, all targets are + // deleted so the condition itself should be too. For the remainder, the + // condition is invalid so should be deleted directly. + for (int i = 3; i < 6; ++i) { + predictor_->previous_target_ = i; + EXPECT_TRUE(predictor_->Rank(0u).empty()); + } +} + TEST_F(MarkovPredictorTest, ToAndFromProto) { // Some complicated transitions. for (int i = 0; i < 10; ++i) {
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc index 4e09ce6..6e956a8 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
@@ -33,6 +33,11 @@ using base::Time; using base::TimeDelta; +// A predictor may return scores for target IDs that have been deleted. If less +// than this proportion of IDs are valid, the ranker triggers a cleanup of the +// predictor's state on a call to RecurrenceRanker::Rank. +constexpr float kMinValidTargetProportionBeforeCleanup = 0.5f; + void SaveProtoToDisk(const base::FilePath& filepath, const RecurrenceRankerProto& proto) { std::string proto_str; @@ -92,9 +97,25 @@ return sorted_ranks; } -std::map<std::string, float> ZipTargetsWithScores( +// Given a FrecencyStore's map from target names to IDs, and a +// RecurrencePredictor's map of IDs to scores, returns a pair containing the +// following: +// +// - A map from target names to scores. +// - The proportion of IDs returned by the predictor that are 'valid', ie. +// that exist in the target frecency store. +// +// The second value can be used to decide when to trigger a cleanup of the +// predictor's internal state. +std::pair<std::map<std::string, float>, float> ZipTargetsWithScores( const FrecencyStore::ScoreTable& target_to_id, const std::map<unsigned int, float>& id_to_score) { + // Early exit if the predictor's ranks are empty. In this case make the + // proportion of valid IDs 1.0, as a cleanup would be a noop. + if (id_to_score.empty()) + return {{}, 1.0f}; + + float num_valid_targets = 0.0f; std::map<std::string, float> target_to_score; for (const auto& pair : target_to_id) { DCHECK(pair.second.last_num_updates == @@ -102,10 +123,11 @@ const auto& it = id_to_score.find(pair.second.id); if (it != id_to_score.end()) { target_to_score[pair.first] = it->second; + num_valid_targets += 1.0f; } } - return target_to_score; + return {std::move(target_to_score), num_valid_targets / id_to_score.size()}; } std::map<std::string, float> GetScoresFromFrecencyStore( @@ -255,8 +277,22 @@ if (condition_id == base::nullopt) return {}; - return ZipTargetsWithScores(targets_->GetAll(), - predictor_->Rank(condition_id.value())); + const auto& targets = targets_->GetAll(); + const auto& zipped = + ZipTargetsWithScores(targets, predictor_->Rank(condition_id.value())); + MaybeCleanup(zipped.second, targets); + return std::move(zipped.first); +} + +void RecurrenceRanker::MaybeCleanup(float proportion_valid, + const FrecencyStore::ScoreTable& targets) { + if (proportion_valid > kMinValidTargetProportionBeforeCleanup) + return; + + std::vector<unsigned int> valid_targets; + for (const auto& target_data : targets) + valid_targets.push_back(target_data.second.id); + predictor_->Cleanup(valid_targets); } std::vector<std::pair<std::string, float>> RecurrenceRanker::RankTopN(
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h index 78aa6d1..f32a558 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h
@@ -70,9 +70,6 @@ int n, const std::string& condition = std::string()); - // TODO(921444): Create a system for cleaning up internal predictor state that - // is stored indepent of the target/condition frecency stores. - // Force saving all model state to disk. If the user is an ephemeral user, // this does nothing. This is not necessary in normal operation, as the ranker // automatically saves at regular intervals. Example use: syncing to disk @@ -95,6 +92,7 @@ SavedRankerRejectedIfConfigMismatched); FRIEND_TEST_ALL_PREFIXES(RecurrenceRankerTest, LoadFromDisk); FRIEND_TEST_ALL_PREFIXES(RecurrenceRankerTest, SaveToDisk); + FRIEND_TEST_ALL_PREFIXES(RecurrenceRankerTest, Cleanup); // Finishes initialisation by populating |this| with data from the given // proto. @@ -105,6 +103,14 @@ void ToProto(RecurrenceRankerProto* proto); void FromProto(const RecurrenceRankerProto& proto); + // Possibly triggers a cleanup of |prdictor_|'s internal state. + // |proportion_valid| should be the proportion of targets returned by the + // predictor that exist in the target frecency store. If a cleanup is + // triggered, RecurrencePredictor::Cleanup is called with a list of valid + // targets derived from |targets|. + void MaybeCleanup(float proportion_valid, + const FrecencyStore::ScoreTable& targets); + // Internal predictor that drives ranking. std::unique_ptr<RecurrencePredictor> predictor_;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc index 43e6fd0..3dc6fca2 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
@@ -343,6 +343,42 @@ ConfigurationError::kHashMismatch, 1); } +TEST_F(RecurrenceRankerTest, Cleanup) { + auto ranker = MakeSimpleRanker(); + + // Targets to forget. + ranker->Record("A"); + ranker->Record("B"); + ranker->Record("C"); + + // Valid proportion is 1 so cleanup shouldn't be called. Rank is called once + // on the ranker to possibly trigger the cleanup, and a second time on the + // predictor to observe the effects without ever triggering a cleanup. + ranker->Rank(); + EXPECT_THAT(ranker->predictor_->Rank(0u), + UnorderedElementsAre(Pair(0u, _), Pair(1u, _), Pair(2u, _))); + + // Record enough times that A should be removed from the ranker's store. + for (int i = 0; i < 100; ++i) { + ranker->Record("B"); + ranker->Record("C"); + } + + // Valid proportion is 2/3 so cleanup still shouldn't be called. + ranker->Rank(); + EXPECT_THAT(ranker->predictor_->Rank(0u), + UnorderedElementsAre(Pair(0u, _), Pair(1u, _), Pair(2u, _))); + + // Record enough times that B and C be removed from the ranker's store + for (int i = 0; i < 100; ++i) + ranker->Record("D"); + + // Valid proportion is 1/4 so cleanup should be called. Examining the internal + // state, the predictor should only contain the ID for D. + ranker->Rank(); + EXPECT_THAT(ranker->predictor_->Rank(0u), UnorderedElementsAre(Pair(3u, _))); +} + TEST_F(RecurrenceRankerTest, EphemeralUsersUseDefaultPredictor) { RecurrenceRanker ephemeral_ranker(ranker_filepath_, MakeSimpleConfig(), true); Wait();
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc index 771fb2a..ef0c369 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -15,6 +15,8 @@ #include "chrome/browser/ui/browser_window_state.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/web_applications/web_app_dialog_manager.h" +#include "chrome/browser/ui/web_applications/web_app_ui_service.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h" @@ -30,8 +32,6 @@ #include "content/public/common/web_preferences.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" -#include "extensions/browser/management_policy.h" -#include "extensions/browser/uninstall_reason.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "third_party/blink/public/mojom/renderer_preferences.mojom.h" @@ -309,17 +309,19 @@ } bool HostedAppBrowserController::CanUninstall() const { - return extensions::ExtensionSystem::Get(browser()->profile()) - ->management_policy() - ->UserMayModifySettings(GetExtension(), nullptr); + auto* web_app_ui_service = + web_app::WebAppUiService::Get(browser()->profile()); + DCHECK(web_app_ui_service); + return web_app_ui_service->dialog_manager().CanUninstallWebApp(extension_id_); } void HostedAppBrowserController::Uninstall() { - uninstall_dialog_ = ExtensionUninstallDialog::Create( - browser()->profile(), browser()->window()->GetNativeWindow(), this); - uninstall_dialog_->ConfirmUninstall( - GetExtension(), extensions::UNINSTALL_REASON_USER_INITIATED, - extensions::UNINSTALL_SOURCE_HOSTED_APP_MENU); + auto* web_app_ui_service = + web_app::WebAppUiService::Get(browser()->profile()); + DCHECK(web_app_ui_service); + web_app_ui_service->dialog_manager().UninstallWebApp( + extension_id_, web_app::WebAppDialogManager::UninstallSource::kAppMenu, + browser()->window(), base::DoNothing()); } bool HostedAppBrowserController::IsInstalled() const {
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h index a985c3c..f261a1e 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -5,13 +5,11 @@ #ifndef CHROME_BROWSER_UI_EXTENSIONS_HOSTED_APP_BROWSER_CONTROLLER_H_ #define CHROME_BROWSER_UI_EXTENSIONS_HOSTED_APP_BROWSER_CONTROLLER_H_ -#include <memory> #include <string> #include "base/macros.h" #include "base/optional.h" #include "base/strings/string16.h" -#include "chrome/browser/extensions/extension_uninstall_dialog.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "third_party/skia/include/core/SkColor.h" @@ -35,8 +33,7 @@ // Class to encapsulate logic to control the browser UI for extension based web // apps. -class HostedAppBrowserController : public ExtensionUninstallDialog::Delegate, - public web_app::AppBrowserController { +class HostedAppBrowserController : public web_app::AppBrowserController { public: // Functions to set preferences that are unique to app windows. static void SetAppPrefsForWebContents( @@ -108,7 +105,6 @@ const std::string extension_id_; const bool created_for_installed_pwa_; - std::unique_ptr<ExtensionUninstallDialog> uninstall_dialog_; DISALLOW_COPY_AND_ASSIGN(HostedAppBrowserController); };
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc index ce1ae50..42af222 100644 --- a/chrome/browser/ui/login/login_handler_browsertest.cc +++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -13,6 +13,7 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/net/proxy_test_utils.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/prerender/prerender_origin.h" #include "chrome/browser/ssl/ssl_blocking_page.h" @@ -52,6 +53,60 @@ namespace { +void TestProxyAuth(Browser* browser, const GURL& test_page) { + bool https = test_page.SchemeIs(url::kHttpsScheme); + + content::WebContents* contents = + browser->tab_strip_model()->GetActiveWebContents(); + NavigationController* controller = &contents->GetController(); + LoginPromptBrowserTestObserver observer; + observer.Register(content::Source<NavigationController>(controller)); + + { + WindowedAuthNeededObserver auth_needed_waiter(controller); + browser->OpenURL(OpenURLParams(test_page, Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + auth_needed_waiter.Wait(); + } + + // On HTTPS pages, no error page content should be renderer to avoid origin + // confusion issues. + if (https) { + EXPECT_EQ(true, content::EvalJs(contents, "document.body === null")); + } + + // Cancel the prompt. On HTTPS pages, the error page content still shouldn't + // be shown. + { + WindowedAuthCancelledObserver auth_cancelled_waiter(controller); + LoginHandler* handler = observer.handlers().front(); + handler->CancelAuth(); + auth_cancelled_waiter.Wait(); + if (https) { + EXPECT_EQ(true, content::EvalJs(contents, "document.body === null")); + } + } + + // Reload; this time, supply credentials and check that the page loads. + { + WindowedAuthNeededObserver auth_needed_waiter(controller); + browser->OpenURL(OpenURLParams(test_page, Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + auth_needed_waiter.Wait(); + } + + WindowedAuthSuppliedObserver auth_supplied_waiter(controller); + LoginHandler* handler = observer.handlers().front(); + handler->SetAuth(base::UTF8ToUTF16("foo"), base::UTF8ToUTF16("bar")); + auth_supplied_waiter.Wait(); + + base::string16 expected_title = base::ASCIIToUTF16("OK"); + content::TitleWatcher title_watcher(contents, expected_title); + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); +} + content::InterstitialPageDelegate* GetInterstitialDelegate( content::WebContents* tab) { security_interstitials::SecurityInterstitialTabHelper* helper = @@ -1699,4 +1754,26 @@ EXPECT_EQ(0u, observer.handlers().size()); } +// Tests that basic proxy auth works as expected, for HTTPS pages. +IN_PROC_BROWSER_TEST_F(ProxyBrowserTest, ProxyAuthHTTPS) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + features::kHTTPAuthCommittedInterstitials); + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.AddDefaultHandlers(GetChromeTestDataDir()); + ASSERT_TRUE(https_server.Start()); + ASSERT_NO_FATAL_FAILURE( + TestProxyAuth(browser(), https_server.GetURL("/simple.html"))); +} + +// 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); + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_NO_FATAL_FAILURE( + TestProxyAuth(browser(), embedded_test_server()->GetURL("/simple.html"))); +} + } // namespace
diff --git a/chrome/browser/ui/login/login_tab_helper.cc b/chrome/browser/ui/login/login_tab_helper.cc index b3765b867..044a35a 100644 --- a/chrome/browser/ui/login/login_tab_helper.cc +++ b/chrome/browser/ui/login/login_tab_helper.cc
@@ -21,7 +21,53 @@ content::NavigationHandle* navigation_handle) { // When navigating away, the LoginHandler for the previous navigation (if any) // should get cleared. + + // Do not clear the login prompt for subframe or same-document navigations; + // these could happen in the case of 401/407 error pages that have fancy + // response bodies that have subframes or can trigger same-document + // navigations. + if (!navigation_handle->IsInMainFrame() || + navigation_handle->IsSameDocument()) + return; + + if (!delegate_) + return; + + // TODO(https://crbug.com/943610): this is a very hacky special-case for a + // particular issue that arises when the server sends an empty body for the + // 401 or 407 response. In this case, the renderer commits an error page for + // the HTTP status code (see + // ChromeContentRendererClient::PrepareErrorPageForHttpStatusError). Error + // pages are a second commit from the browser's perspective, which runs + // DidStartNavigation again and therefore would dismiss the prompt if this + // special case weren't here. To make matters worse, at the error page's + // second commit, the browser process does not have a NavigationRequest + // available (see |is_commit_allowed_to_proceed| in + // RenderFrameHostImpl::DidCommitNavigationInternal), and therefore no + // AuthChallengeInfo to use to re-show the prompt after it has been + // dismissed. This whole mess should be fixed in https://crbug.com/943610, + // which is about enforcing that the browser always has a NavigationRequest + // available at commit time; once error pages no longer have second commits + // for which NavigationRequests are manufactured, this special case will no + // longer be needed. + // + // For now, we can hack around it by preserving the login prompt when starting + // a navigation to the same URL for which we are currently showing a login + // prompt. There is a possibility that the starting navigation is actually due + // to the user refreshing rather than the error page committing, and when the + // user refreshes the server might no longer serve an auth challenge. But we + // can't distinguish the two scenarios (error page committing vs user + // refreshing) at this point, so we clear the prompt in DidFinishNavigation if + // it's not an error page. This behavior could lead to a slight oddness where + // the prompt lingers around for a bit too long, but this should only happen + // in the perfect storm where a server's auth response has an empty body, + // the user refreshes when the prompt is showing, and the server no longer + // requires auth on the refresh. + if (navigation_handle->GetURL() == url_for_delegate_) + return; + delegate_.reset(); + url_for_delegate_ = GURL(); } void LoginTabHelper::DidFinishNavigation( @@ -29,6 +75,12 @@ DCHECK( base::FeatureList::IsEnabled(features::kHTTPAuthCommittedInterstitials)); + // See TODO(https://crbug.com/943610) in DidStartNavigation(). + if (delegate_ && !navigation_handle->IsErrorPage()) { + delegate_.reset(); + url_for_delegate_ = GURL(); + } + if (!navigation_handle->GetAuthChallengeInfo()) { return; } @@ -50,6 +102,7 @@ challenge_ = navigation_handle->GetAuthChallengeInfo().value(); + url_for_delegate_ = navigation_handle->GetURL(); delegate_ = CreateLoginPrompt( navigation_handle->GetAuthChallengeInfo().value(), navigation_handle->GetWebContents(), @@ -72,10 +125,13 @@ void LoginTabHelper::HandleCredentials( const base::Optional<net::AuthCredentials>& credentials) { + delegate_.reset(); + url_for_delegate_ = GURL(); + if (!credentials.has_value()) { - delegate_.reset(); return; } + // Pass a weak pointer for the callback, as the WebContents (and thus this // LoginTabHelper) could be destroyed while the network service is processing // the new cache entry.
diff --git a/chrome/browser/ui/login/login_tab_helper.h b/chrome/browser/ui/login/login_tab_helper.h index c67be75..541b8a4 100644 --- a/chrome/browser/ui/login/login_tab_helper.h +++ b/chrome/browser/ui/login/login_tab_helper.h
@@ -44,6 +44,7 @@ void Reload(); std::unique_ptr<content::LoginDelegate> delegate_; + GURL url_for_delegate_; net::AuthChallengeInfo challenge_;
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index f798328..55fcb0a 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -48,6 +48,7 @@ #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/common/buildflags.h" #include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" @@ -76,6 +77,7 @@ #include "chromeos/cryptohome/cryptohome_parameters.h" #include "components/user_manager/user_manager.h" #else +#include "chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h" #include "chrome/browser/ui/user_manager.h" #endif @@ -684,6 +686,20 @@ silent_launch = true; } +#if !defined(OS_CHROMEOS) + if (!process_startup && + base::FeatureList::IsEnabled(features::kOnConnectNative) && + command_line.HasSwitch(switches::kNativeMessagingConnectHost) && + command_line.HasSwitch(switches::kNativeMessagingConnectExtension)) { + silent_launch = true; + extensions::LaunchNativeMessageHostFromNativeApp( + command_line.GetSwitchValueASCII( + switches::kNativeMessagingConnectExtension), + command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectHost), + last_used_profile); + } +#endif + // If --no-startup-window is specified and Chrome is already running then do // not open a new window. if (!process_startup && command_line.HasSwitch(switches::kNoStartupWindow))
diff --git a/chrome/browser/ui/views/crostini/crostini_app_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_app_installer_view.cc deleted file mode 100644 index ace83c9..0000000 --- a/chrome/browser/ui/views/crostini/crostini_app_installer_view.cc +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/crostini/crostini_app_installer_view.h" - -#include <memory> -#include <utility> - -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/chromeos/crostini/crostini_package_service.h" -#include "chrome/browser/chromeos/crostini/crostini_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser_dialogs.h" -#include "chrome/browser/ui/views/chrome_layout_provider.h" -#include "chrome/grit/generated_resources.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/layout_provider.h" - -namespace crostini { - -constexpr unsigned int kMinScrollHeight = 0; -constexpr unsigned int kMaxScrollHeight = 250; - -// Declaration in crostini_util.h, definition here. Needed because of include -// restrictions. -void ShowCrostiniAppInstallerView(Profile* profile, - const LinuxPackageInfo& package_info) { - views::DialogDelegate::CreateDialogWidget( - new CrostiniAppInstallerView(profile, package_info), nullptr, nullptr) - ->Show(); -} - -} // namespace crostini - -CrostiniAppInstallerView::CrostiniAppInstallerView( - Profile* profile, - const crostini::LinuxPackageInfo& package_info) - : profile_(profile), package_info_(package_info) { - views::LayoutProvider* provider = views::LayoutProvider::Get(); - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, - provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG), - provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL))); - set_margins(provider->GetDialogInsetsForContentType( - views::DialogContentType::TEXT, views::DialogContentType::TEXT)); - - views::Label* message_label_ = new views::Label( - l10n_util::GetStringFUTF16(IDS_CROSTINI_APP_INSTALL_DIALOG_BODY_TEXT, - base::UTF8ToUTF16(package_info_.name))); - message_label_->SetMultiLine(true); - message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(message_label_); - base::string16 description; - - if (package_info_.description.empty()) { - description = l10n_util::GetStringUTF16( - IDS_CROSTINI_APP_INSTALL_DIALOG_NO_DESCRIPTION_TEXT); - } else { - description = base::UTF8ToUTF16(package_info_.description); - } - - base::string16 message = l10n_util::GetStringFUTF16( - IDS_CROSTINI_APP_INSTALL_DIALOG_PACKAGE_TEXT, - base::UTF8ToUTF16(package_info_.version), description); - - auto message_label = std::make_unique<views::Label>(message); - message_label->SetMultiLine(true); - message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - - views::ScrollView* scroll_view = new views::ScrollView; - scroll_view->SetDrawOverflowIndicator(true); - scroll_view->ClipHeightTo(crostini::kMinScrollHeight, - crostini::kMaxScrollHeight); - message_label_ = scroll_view->SetContents(std::move(message_label)); - - AddChildView(scroll_view); -} - -int CrostiniAppInstallerView::GetDialogButtons() const { - return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; -} - -base::string16 CrostiniAppInstallerView::GetDialogButtonLabel( - ui::DialogButton button) const { - if (button == ui::DIALOG_BUTTON_OK) - return l10n_util::GetStringUTF16( - IDS_CROSTINI_APP_INSTALL_DIALOG_INSTALL_BUTTON); - DCHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL); - return l10n_util::GetStringUTF16(IDS_APP_CANCEL); -} - -base::string16 CrostiniAppInstallerView::GetWindowTitle() const { - return l10n_util::GetStringFUTF16(IDS_CROSTINI_APP_INSTALL_DIALOG_TITLE_TEXT, - base::UTF8ToUTF16(package_info_.name)); -} - -bool CrostiniAppInstallerView::ShouldShowCloseButton() const { - return false; -} - -bool CrostiniAppInstallerView::Accept() { - // Start the installation process for the chosen Crosini app. - - // TODO(https://crbug.com/921429): We should handle installation errors. - crostini::CrostiniPackageService::GetForProfile(profile_) - ->InstallLinuxPackageFromApt(crostini::kCrostiniDefaultVmName, - crostini::kCrostiniDefaultContainerName, - package_info_.package_id, base::DoNothing()); - return true; -} - -gfx::Size CrostiniAppInstallerView::CalculatePreferredSize() const { - const int dialog_width = ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) - - margins().width(); - return gfx::Size(dialog_width, GetHeightForWidth(dialog_width)); -} - -CrostiniAppInstallerView::~CrostiniAppInstallerView() = default;
diff --git a/chrome/browser/ui/views/crostini/crostini_app_installer_view.h b/chrome/browser/ui/views/crostini/crostini_app_installer_view.h deleted file mode 100644 index c7fd9270..0000000 --- a/chrome/browser/ui/views/crostini/crostini_app_installer_view.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_INSTALLER_VIEW_H_ -#define CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_INSTALLER_VIEW_H_ - -#include "chrome/browser/chromeos/crostini/crostini_manager.h" -#include "ui/views/window/dialog_delegate.h" - -class Profile; - -// TODO(https://crbug.com/921429): Whole dialog needs a UX spec, this -// iteration is based on some UX recommendations for this feature, but -// a full spec will be required before bringing this feature to live. - -// The Crostini app installer view. Provides information about the app that a -// user is looking to install and confirms if they want to install it or not. -class CrostiniAppInstallerView : public views::DialogDelegateView { - public: - CrostiniAppInstallerView(Profile* profile, - const crostini::LinuxPackageInfo& package_info); - - // views::DialogDelegateView: - int GetDialogButtons() const override; - base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - base::string16 GetWindowTitle() const override; - bool ShouldShowCloseButton() const override; - bool Accept() override; - gfx::Size CalculatePreferredSize() const override; - - private: - ~CrostiniAppInstallerView() override; - - Profile* profile_; - crostini::LinuxPackageInfo package_info_; - - DISALLOW_COPY_AND_ASSIGN(CrostiniAppInstallerView); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_INSTALLER_VIEW_H_
diff --git a/chrome/browser/ui/views/crostini/crostini_app_installer_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_app_installer_view_browsertest.cc deleted file mode 100644 index 36b24d1..0000000 --- a/chrome/browser/ui/views/crostini/crostini_app_installer_view_browsertest.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/crostini/crostini_app_installer_view.h" - -#include "chrome/browser/chromeos/crostini/crostini_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/views/crostini/crostini_browser_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/window/dialog_client_view.h" - -class CrostiniAppInstallerViewBrowserTest : public CrostiniDialogBrowserTest { - public: - CrostiniAppInstallerViewBrowserTest() - : CrostiniDialogBrowserTest(false /*register_termina*/) {} - - // CrostiniDialogBrowserTest: - void ShowUi(const std::string& name) override { - input_.success = true; - input_.package_id = "gedit;1.1;amd64;"; - input_.name = "gedit"; - input_.version = "1.1"; - input_.description = - "A really good package for doing lots of interesting things"; - input_.summary = "An editor"; - view_ = new CrostiniAppInstallerView(browser()->profile(), input_); - views::DialogDelegate::CreateDialogWidget(view_, nullptr, nullptr)->Show(); - } - - CrostiniAppInstallerView* ActiveView() { return view_; } - - bool HasAcceptButton() { - return ActiveView()->GetDialogClientView()->ok_button() != nullptr; - } - - bool HasCancelButton() { - return ActiveView()->GetDialogClientView()->cancel_button() != nullptr; - } - - private: - crostini::LinuxPackageInfo input_; - CrostiniAppInstallerView* view_; - DISALLOW_COPY_AND_ASSIGN(CrostiniAppInstallerViewBrowserTest); -}; - -IN_PROC_BROWSER_TEST_F(CrostiniAppInstallerViewBrowserTest, InvokeUi_default) { - ShowAndVerifyUi(); -} - -IN_PROC_BROWSER_TEST_F(CrostiniAppInstallerViewBrowserTest, AcceptDialog) { - ShowUi("default"); - EXPECT_NE(nullptr, ActiveView()); - - EXPECT_TRUE(HasAcceptButton()); - EXPECT_TRUE(HasCancelButton()); - - ActiveView()->GetDialogClientView()->AcceptWindow(); - EXPECT_TRUE(ActiveView()->GetWidget()->IsClosed()); - // TODO(https://crbug.com/921429): Check to see if the installation process - // is handled appropiately. -} - -IN_PROC_BROWSER_TEST_F(CrostiniAppInstallerViewBrowserTest, CancelDialog) { - ShowUi("default"); - EXPECT_NE(nullptr, ActiveView()); - - EXPECT_TRUE(HasAcceptButton()); - EXPECT_TRUE(HasCancelButton()); - - ActiveView()->GetDialogClientView()->CancelWindow(); - EXPECT_TRUE(ActiveView()->GetWidget()->IsClosed()); -}
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_manager.cc b/chrome/browser/ui/web_applications/web_app_dialog_manager.cc new file mode 100644 index 0000000..015b8112 --- /dev/null +++ b/chrome/browser/ui/web_applications/web_app_dialog_manager.cc
@@ -0,0 +1,115 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/web_applications/web_app_dialog_manager.h" + +#include "base/callback.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/extensions/extension_uninstall_dialog.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_system.h" +#include "extensions/browser/management_policy.h" + +namespace web_app { + +namespace { + +const extensions::Extension* GetExtension(Profile* profile, + const AppId& app_id) { + return extensions::ExtensionRegistry::Get(profile)->GetExtensionById( + app_id, extensions::ExtensionRegistry::EVERYTHING); +} + +} // namespace + +// TODO(loyso): Make it extensions independent. +class DialogInstance : public extensions::ExtensionUninstallDialog::Delegate { + public: + DialogInstance() = default; + ~DialogInstance() override = default; + + void UninstallWebApp(Profile* profile, + BrowserWindow* parent_window, + const AppId& app_id, + WebAppDialogManager::UninstallSource source, + WebAppDialogManager::Callback callback) { + uninstall_dialog_ = extensions::ExtensionUninstallDialog::Create( + profile, parent_window ? parent_window->GetNativeWindow() : nullptr, + this); + + callback_ = std::move(callback); + + auto* app = GetExtension(profile, app_id); + uninstall_dialog_->ConfirmUninstall( + app, extensions::UNINSTALL_REASON_USER_INITIATED, + ConvertSource(source)); + } + + private: + static extensions::UninstallSource ConvertSource( + WebAppDialogManager::UninstallSource source) { + switch (source) { + case WebAppDialogManager::UninstallSource::kAppMenu: + return extensions::UNINSTALL_SOURCE_HOSTED_APP_MENU; + case WebAppDialogManager::UninstallSource::kAppsPage: + return extensions::UNINSTALL_SOURCE_CHROME_APPS_PAGE; + } + } + + // ExtensionUninstallDialog::Delegate: + void OnExtensionUninstallDialogClosed(bool success, + const base::string16& error) override { + // The dialog can be closed by UI system whenever it likes, but + // OnExtensionUninstallDialogClosed will be called anyway. + if (callback_) + std::move(callback_).Run(success); + } + + std::unique_ptr<extensions::ExtensionUninstallDialog> uninstall_dialog_; + WebAppDialogManager::Callback callback_; + + DISALLOW_COPY_AND_ASSIGN(DialogInstance); +}; + +WebAppDialogManager::WebAppDialogManager(Profile* profile) + : profile_(profile) {} + +WebAppDialogManager::~WebAppDialogManager() = default; + +bool WebAppDialogManager::CanUninstallWebApp(const AppId& app_id) const { + auto* app = GetExtension(profile_, app_id); + + return extensions::ExtensionSystem::Get(profile_) + ->management_policy() + ->UserMayModifySettings(app, nullptr); +} + +void WebAppDialogManager::UninstallWebApp(const AppId& app_id, + UninstallSource uninstall_source, + BrowserWindow* parent_window, + Callback callback) { + auto dialog = std::make_unique<DialogInstance>(); + + dialog->UninstallWebApp( + profile_, parent_window, app_id, uninstall_source, + base::BindOnce(&WebAppDialogManager::OnDialogCompleted, + base::Unretained(this), dialog.get(), + std::move(callback))); + + dialogs_.insert(std::move(dialog)); +} + +void WebAppDialogManager::OnDialogCompleted(DialogInstance* dialog, + Callback callback, + bool success) { + DCHECK(dialogs_.contains(dialog)); + dialogs_.erase(dialog); + + std::move(callback).Run(success); +} + +} // namespace web_app
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_manager.h b/chrome/browser/ui/web_applications/web_app_dialog_manager.h new file mode 100644 index 0000000..caa4ac4 --- /dev/null +++ b/chrome/browser/ui/web_applications/web_app_dialog_manager.h
@@ -0,0 +1,60 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_DIALOG_MANAGER_H_ +#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_DIALOG_MANAGER_H_ + +#include <memory> + +#include "base/callback_forward.h" +#include "base/containers/flat_set.h" +#include "base/containers/unique_ptr_adapters.h" +#include "base/macros.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" + +class BrowserWindow; +class Profile; + +namespace web_app { + +// An internal WebAppDialogManager's representation of any running dialog. +class DialogInstance; + +class WebAppDialogManager { + public: + explicit WebAppDialogManager(Profile* profile); + ~WebAppDialogManager(); + + enum class UninstallSource { + kAppMenu, + kAppsPage, + }; + + using Callback = base::OnceCallback<void(bool success)>; + + bool CanUninstallWebApp(const AppId& app_id) const; + // The uninstall dialog will be modal to |parent_window|, or a non-modal if + // |parent_window| is nullptr. + void UninstallWebApp(const AppId& app_id, + UninstallSource uninstall_source, + BrowserWindow* parent_window, + Callback callback); + + private: + void OnDialogCompleted(DialogInstance* dialog, + Callback callback, + bool success); + + // All owned dialogs, running in parallel. + base::flat_set<std::unique_ptr<DialogInstance>, base::UniquePtrComparator> + dialogs_; + + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(WebAppDialogManager); +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_DIALOG_MANAGER_H_
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.h b/chrome/browser/ui/web_applications/web_app_dialog_utils.h index 41159af..a018f298 100644 --- a/chrome/browser/ui/web_applications/web_app_dialog_utils.h +++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.h
@@ -20,7 +20,7 @@ enum class InstallResultCode; // TODO(loyso): Rework these functions (API) once BookmarkAppHelper erased. -// crbug.com/915043. +// crbug.com/915043. Move all of them into WebAppDialogManager. // Returns true if a WebApp installation is allowed for the current page. bool CanCreateWebApp(const Browser* browser);
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service.cc b/chrome/browser/ui/web_applications/web_app_ui_service.cc index f425519..dc95e29 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_service.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_service.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" +#include "chrome/browser/ui/web_applications/web_app_dialog_manager.h" #include "chrome/browser/ui/web_applications/web_app_ui_service_factory.h" #include "chrome/browser/web_applications/system_web_app_manager.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -39,6 +40,8 @@ BrowserList::AddObserver(this); provider_->set_ui_delegate(this); + + dialog_manager_ = std::make_unique<WebAppDialogManager>(profile); } WebAppUiService::~WebAppUiService() {
diff --git a/chrome/browser/ui/web_applications/web_app_ui_service.h b/chrome/browser/ui/web_applications/web_app_ui_service.h index 810dd4ce..5bf41cc 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_service.h +++ b/chrome/browser/ui/web_applications/web_app_ui_service.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_UI_SERVICE_H_ #include <map> +#include <memory> #include <vector> #include "base/callback_forward.h" @@ -22,6 +23,7 @@ namespace web_app { class WebAppProvider; +class WebAppDialogManager; // This KeyedService is a UI counterpart for WebAppProvider. class WebAppUiService : public KeyedService, @@ -36,6 +38,8 @@ // KeyedService void Shutdown() override; + WebAppDialogManager& dialog_manager() { return *dialog_manager_; } + // WebAppUiDelegate size_t GetNumWindowsForApp(const AppId& app_id) override; void NotifyOnAllAppWindowsClosed(const AppId& app_id, @@ -49,6 +53,8 @@ private: base::Optional<AppId> GetAppIdForBrowser(Browser* browser); + std::unique_ptr<WebAppDialogManager> dialog_manager_; + WebAppProvider* provider_; Profile* profile_;
diff --git a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc index e0d749d..baa7800 100644 --- a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc +++ b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc
@@ -71,7 +71,8 @@ void AddSupervisionHandler::GetOAuthToken(GetOAuthTokenCallback callback) { identity::ScopeSet scopes; - scopes.insert(GaiaConstants::kKidFamilyOAuth2Scope); + scopes.insert(GaiaConstants::kKidsSupervisionSetupChildOAuth2Scope); + scopes.insert(GaiaConstants::kPeopleApiReadOnlyOAuth2Scope); oauth2_access_token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
diff --git a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc index e7a7e8c..b907f5a 100644 --- a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc +++ b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
@@ -47,8 +47,7 @@ // Make sure this username is not prohibited by policy. if (!identity::IsUsernameAllowedByPatternFromPrefs( - g_browser_process->local_state(), email, - prefs::kGoogleServicesUsernamePattern)) { + g_browser_process->local_state(), email)) { if (error_message) { error_message->assign( l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED));
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 35dd728a..f8ea981 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -184,11 +184,6 @@ const base::Feature kCrostiniAdditionalEnterpriseReporting{ "CrostiniAdditionalEnterpriseReporting", base::FEATURE_DISABLED_BY_DEFAULT}; -// Enables not installed apps/packages to be searched for and installed in the -// App launcher. -const base::Feature kCrostiniAppSearch{"CrostiniAppSearch", - base::FEATURE_DISABLED_BY_DEFAULT}; - // Enables an uninstall option in the right-click menu of Crostini (Linux) // applications. // TODO(crbug.com/955797): Remove this flag entirely.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 2f6fc351..b7c49424 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -114,8 +114,6 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostiniAdditionalEnterpriseReporting; COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::Feature kCrostiniAppSearch; -COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostiniAppUninstallGui; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostiniAnsibleInfrastructure;
diff --git a/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc b/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc index c535284..397c3f7 100644 --- a/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc +++ b/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc
@@ -51,7 +51,7 @@ auto hosts = std::make_unique<NativelyConnectableHosts>(); for (const auto& host : natively_connectable_hosts->GetList()) { - if (!host.is_string()) { + if (!host.is_string() || host.GetString().empty()) { *error = base::ASCIIToUTF16(manifest_errors::kInvalidNativelyConnectableValue); return false;
diff --git a/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc index fa6f1f3..67e5990 100644 --- a/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc +++ b/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc
@@ -49,4 +49,9 @@ manifest_errors::kInvalidNativelyConnectableValue); } +TEST_F(NativelyConnectableManifestTest, EmptyHost) { + LoadAndExpectError("natively_connectable_empty_host.json", + manifest_errors::kInvalidNativelyConnectableValue); +} + } // namespace extensions
diff --git a/chrome/credential_provider/gaiacp/os_user_manager.cc b/chrome/credential_provider/gaiacp/os_user_manager.cc index ed45672..033478c8 100644 --- a/chrome/credential_provider/gaiacp/os_user_manager.cc +++ b/chrome/credential_provider/gaiacp/os_user_manager.cc
@@ -361,12 +361,13 @@ flags_changed = true; } - base::string16 password_domain = base::StringPrintf(L"\\\\%ls", domain); + base::string16 password_domain = base::StringPrintf(L"%ls", domain); NET_API_STATUS changepassword_nsts = ::NetUserChangePassword( password_domain.c_str(), username, old_password, new_password); if (changepassword_nsts != NERR_Success) { LOGFN(ERROR) << "Unable to change password for '" << username + << "' domain '" << password_domain << "' nsts=" << changepassword_nsts; }
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js index d5875e7..64206e9 100644 --- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -54,7 +54,7 @@ // So |callback| doesn't break if response is not defined. if (!response) - response = {}; + response = []; if (callback) callback(response);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 8fcd94db..2775d4e 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -939,6 +939,8 @@ "../browser/net/nss_context_chromeos_browsertest.cc", "../browser/net/profile_network_context_service_browsertest.cc", "../browser/net/proxy_browsertest.cc", + "../browser/net/proxy_test_utils.cc", + "../browser/net/proxy_test_utils.h", "../browser/net/reporting_browsertest.cc", "../browser/net/system_network_context_manager_browsertest.cc", "../browser/net/variations_http_headers_browsertest.cc", @@ -2171,7 +2173,6 @@ "../browser/ui/ash/volume_controller_browsertest.cc", "../browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc", "../browser/ui/views/arc_app_dialog_view_browsertest.cc", - "../browser/ui/views/crostini/crostini_app_installer_view_browsertest.cc", "../browser/ui/views/crostini/crostini_browser_test_util.cc", "../browser/ui/views/crostini/crostini_browser_test_util.h", "../browser/ui/views/crostini/crostini_installer_view_browsertest.cc", @@ -4358,6 +4359,7 @@ "../browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc", "../browser/extensions/api/messaging/native_message_process_host_unittest.cc", "../browser/extensions/api/messaging/native_messaging_host_manifest_unittest.cc", + "../browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc", "../browser/extensions/api/messaging/native_messaging_policy_handler_unittest.cc", ] }
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.cc b/chrome/test/chromedriver/chrome/navigation_tracker.cc index bf833fa..861f12a 100644 --- a/chrome/test/chromedriver/chrome/navigation_tracker.cc +++ b/chrome/test/chromedriver/chrome/navigation_tracker.cc
@@ -195,6 +195,8 @@ } } else if (method == "Inspector.targetCrashed") { loading_state_ = kNotLoading; + } else if (method == "Page.interstitialShown") { + client_->SendCommand("Page.stopLoading", base::DictionaryValue()); } if (timed_out_) loading_state_ = kNotLoading;
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc index 6d45925d..7695253 100644 --- a/chrome/test/chromedriver/window_commands.cc +++ b/chrome/test/chromedriver/window_commands.cc
@@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" @@ -1918,6 +1919,11 @@ Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url); if (status.IsError()) return status; + if (!base::StartsWith(url, "http://", base::CompareCase::INSENSITIVE_ASCII) && + !base::StartsWith(url, "https://", + base::CompareCase::INSENSITIVE_ASCII) && + !base::StartsWith(url, "ftp://", base::CompareCase::INSENSITIVE_ASCII)) + return Status(kInvalidCookieDomain); std::string domain; if (!GetOptionalString(cookie, "domain", &domain)) return Status(kInvalidArgument, "invalid 'domain'");
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch/manifest.json b/chrome/test/data/extensions/api_test/native_messaging_launch/manifest.json new file mode 100644 index 0000000..2216581f6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/native_messaging_launch/manifest.json
@@ -0,0 +1,20 @@ +{ + // Extension ID: knldjmfmopnpolahpmmgbagdohdnhkik + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", + "version": "1.0.0.0", + "manifest_version": 2, + "name": "native messaging test", + "description": "Test the basic functionality of passing native messages.", + "background": { + "scripts": ["test.js"], + "persistent": false + }, + "natively_connectable": [ + "com.google.chrome.test.echo", + "com.google.chrome.test.inbound_native_echo" + ], + "permissions": [ + "nativeMessaging", + "transientBackground" + ] +}
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch/test.js b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js new file mode 100644 index 0000000..ed8e5e2 --- /dev/null +++ b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js
@@ -0,0 +1,49 @@ +// 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. + +var appName = 'com.google.chrome.test.inbound_native_echo'; + +chrome.runtime.onConnectNative.addListener(port => { + chrome.test.getConfig(function(config) { + chrome.test.runTests([ + function sender() { + chrome.test.assertEq(port.sender.nativeApplication, appName); + chrome.test.succeed(); + }, + + function sendMessages() { + var messagesToSend = + [{'text': 'foo'}, {'text': 'bar', 'funCount': 9001}, {}]; + var currentMessage = 0; + + port.postMessage(messagesToSend[currentMessage]); + + function onMessage(message) { + chrome.test.assertEq(currentMessage + 1, message.id); + chrome.test.assertEq(messagesToSend[currentMessage], message.echo); + chrome.test.assertEq( + message.caller_url, window.location.origin + '/'); + currentMessage++; + + if (currentMessage == messagesToSend.length) { + port.onMessage.removeListener(onMessage); + chrome.test.succeed(); + } else { + port.postMessage(messagesToSend[currentMessage]); + } + }; + port.onMessage.addListener(onMessage); + }, + + // Verify that the case when host stops itself is handled properly. + function stopHost() { + port.onDisconnect.addListener( + chrome.test.callback(function() {}, 'Native host has exited.')); + + // Send first message that should stop the host. + port.postMessage({'stopHostTest': true}); + } + ]); + }); +});
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/manifest.json b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/manifest.json new file mode 100644 index 0000000..2216581f6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/manifest.json
@@ -0,0 +1,20 @@ +{ + // Extension ID: knldjmfmopnpolahpmmgbagdohdnhkik + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", + "version": "1.0.0.0", + "manifest_version": 2, + "name": "native messaging test", + "description": "Test the basic functionality of passing native messages.", + "background": { + "scripts": ["test.js"], + "persistent": false + }, + "natively_connectable": [ + "com.google.chrome.test.echo", + "com.google.chrome.test.inbound_native_echo" + ], + "permissions": [ + "nativeMessaging", + "transientBackground" + ] +}
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js new file mode 100644 index 0000000..5ee4b0f4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js
@@ -0,0 +1,16 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var appName = 'com.google.chrome.test.echo'; + +chrome.runtime.onConnectNative.addListener(port => { + chrome.test.runTests([ + function test() { + chrome.test.assertEq(port.sender.nativeApplication, appName); + port.onDisconnect.addListener(chrome.test.callback( + function() {}, + 'Access to the specified native messaging host is forbidden.')); + }, + ]); +});
diff --git a/chrome/test/data/extensions/api_test/proxy/events/parse_error.js b/chrome/test/data/extensions/api_test/proxy/events/parse_error.js index 0b0079f..9d784e1 100644 --- a/chrome/test/data/extensions/api_test/proxy/events/parse_error.js +++ b/chrome/test/data/extensions/api_test/proxy/events/parse_error.js
@@ -5,17 +5,7 @@ // proxy api test // browser_tests.exe --gtest_filter=ProxySettingsApiTest.ProxyEventsParseError -// TODO(crbug.com/943636): remove old error once -// https://chromium-review.googlesource.com/c/v8/v8/+/1593307 is rolled into -// chromium. - -var expected_error_v1 = { - details: "line: 1: Uncaught SyntaxError: Unexpected token !", - error: "net::ERR_PAC_SCRIPT_FAILED", - fatal: false -}; - -var expected_error_v2 = { +var expected_error = { details: "line: 1: Uncaught SyntaxError: Unexpected token '!'", error: "net::ERR_PAC_SCRIPT_FAILED", fatal: false @@ -24,12 +14,7 @@ function test() { // Install error handler and get the test server config. chrome.proxy.onProxyError.addListener(function (error) { - const actualErrorJson = JSON.stringify(error); - chrome.test.assertTrue( - actualErrorJson == JSON.stringify(expected_error_v1) || - actualErrorJson == JSON.stringify(expected_error_v2), - actualErrorJson - ); + chrome.test.assertEq(expected_error, error); chrome.test.notifyPass(); });
diff --git a/chrome/test/data/extensions/manifest_tests/natively_connectable_empty_host.json b/chrome/test/data/extensions/manifest_tests/natively_connectable_empty_host.json new file mode 100644 index 0000000..fdbd0f2a --- /dev/null +++ b/chrome/test/data/extensions/manifest_tests/natively_connectable_empty_host.json
@@ -0,0 +1,8 @@ +{ + "name": "unit_tests --gtest_filter=NativelyConnectableManifestTest.EmptyHost", + "version": "1", + "manifest_version": 2, + "natively_connectable": [ + "" + ] +}
diff --git a/chrome/test/data/webui/app_management/test_util.js b/chrome/test/data/webui/app_management/test_util.js index 536bd08e..fb3e753b 100644 --- a/chrome/test/data/webui/app_management/test_util.js +++ b/chrome/test/data/webui/app_management/test_util.js
@@ -19,7 +19,7 @@ */ function setupFakeHandler() { const browserProxy = app_management.BrowserProxy.getInstance(); - const callbackRouterProxy = browserProxy.callbackRouter.createProxy(); + const callbackRouterProxy = browserProxy.callbackRouter.$.createProxy(); const fakeHandler = new app_management.FakePageHandler(callbackRouterProxy); browserProxy.handler = fakeHandler;
diff --git a/chrome/test/data/webui/bluetooth_internals_browsertest.js b/chrome/test/data/webui/bluetooth_internals_browsertest.js index 08690f4a..7462fa5db 100644 --- a/chrome/test/data/webui/bluetooth_internals_browsertest.js +++ b/chrome/test/data/webui/bluetooth_internals_browsertest.js
@@ -57,7 +57,7 @@ async getAdapter() { this.methodCalled('getAdapter'); - return {adapter: this.adapterBinding_.createProxy()}; + return {adapter: this.adapterBinding_.$.createProxy()}; } } @@ -82,7 +82,7 @@ assert(this.deviceProxyMap.has(address), 'Device does not exist'); return { result: this.connectResult_, - device: this.deviceProxyMap.get(address).router.createProxy(), + device: this.deviceProxyMap.get(address).router.$.createProxy(), }; } @@ -140,7 +140,7 @@ // lots of methods we don't care to mock here. DeviceCallbackRouter // callback silently discards messages that have no listeners. this.router = new bluetooth.mojom.DeviceCallbackRouter; - this.router.disconnect.addListener(() => this.router.closeBindings()); + this.router.disconnect.addListener(() => this.router.$.close()); this.router.getInfo.addListener(() => this.getInfo()); this.router.getServices.addListener(() => this.getServices()); } @@ -167,7 +167,7 @@ this.adapterFactory = new TestAdapterFactoryProxy(); this.adapterFactoryBinding_ = new mojom.BluetoothInternalsHandler(this.adapterFactory); - this.adapterFactoryBinding_.bindHandle(e.handle); + this.adapterFactoryBinding_.$.bindHandle(e.handle); this.adapterFactory.adapter.setTestDevices([ this.fakeDeviceInfo1(),
diff --git a/chrome/test/data/webui/downloads/test_support.js b/chrome/test/data/webui/downloads/test_support.js index e5757090e..a64334e 100644 --- a/chrome/test/data/webui/downloads/test_support.js +++ b/chrome/test/data/webui/downloads/test_support.js
@@ -8,7 +8,7 @@ this.callbackRouter = new downloads.mojom.PageCallbackRouter(); /** @type {!downloads.mojom.PageInterface} */ - this.pageRouterProxy = this.callbackRouter.createProxy(); + this.pageRouterProxy = this.callbackRouter.$.createProxy(); /** @type {downloads.mojom.PageHandlerInterface} */ this.handler = new TestDownloadsMojoHandler(this.pageRouterProxy);
diff --git a/chrome/test/data/webui/usb_internals_browsertest.js b/chrome/test/data/webui/usb_internals_browsertest.js index c64c027..5b31d2e 100644 --- a/chrome/test/data/webui/usb_internals_browsertest.js +++ b/chrome/test/data/webui/usb_internals_browsertest.js
@@ -56,7 +56,7 @@ this.deviceManager = new FakeDeviceManagerProxy(); this.deviceManagerBinding_ = new device.mojom.UsbDeviceManager(this.deviceManager); - this.deviceManagerBinding_.bindHandle(deviceManagerRequest.handle); + this.deviceManagerBinding_.$.bindHandle(deviceManagerRequest.handle); } async bindTestInterface(testDeviceManagerRequest) { @@ -99,7 +99,7 @@ async getDevice(guid, deviceRequest, deviceClient) { this.methodCalled('getDevice'); const deviceProxy = this.deviceProxyMap.get(guid); - deviceProxy.router.bindHandle(deviceRequest.handle); + deviceProxy.router.$.bindHandle(deviceRequest.handle); } async getDevices() { @@ -271,7 +271,7 @@ this.pageHandler = new FakePageHandlerProxy(); this.pageHandlerBinding_ = new mojom.UsbInternalsPageHandler(this.pageHandler); - this.pageHandlerBinding_.bindHandle(e.handle); + this.pageHandlerBinding_.$.bindHandle(e.handle); }; this.pageHandlerInterceptor.start();
diff --git a/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc b/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc index a165e07..319161e 100644 --- a/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc +++ b/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc
@@ -149,7 +149,7 @@ void DemuxerStreamAdapterTest::OnFlushCompleted() { ASSERT_EQ(frame_received_count_, total_expected_frames_); - ASSERT_FALSE(demuxer_stream_->has_pending_read()); + ASSERT_FALSE(demuxer_stream_->IsReadPending()); base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.cc b/chromecast/media/cma/base/demuxer_stream_for_test.cc index 40270bd..9c585ae 100644 --- a/chromecast/media/cma/base/demuxer_stream_for_test.cc +++ b/chromecast/media/cma/base/demuxer_stream_for_test.cc
@@ -71,6 +71,10 @@ return true; } +bool DemuxerStreamForTest::IsReadPending() const { + return has_pending_read_; +} + void DemuxerStreamForTest::DoRead(const ReadCB& read_cb) { has_pending_read_ = false;
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.h b/chromecast/media/cma/base/demuxer_stream_for_test.h index 81966a4..feec5ca5 100644 --- a/chromecast/media/cma/base/demuxer_stream_for_test.h +++ b/chromecast/media/cma/base/demuxer_stream_for_test.h
@@ -46,8 +46,7 @@ ::media::VideoDecoderConfig video_decoder_config() override; Type type() const override; bool SupportsConfigChanges() override; - - bool has_pending_read() const { return has_pending_read_; } + bool IsReadPending() const override; // Frame duration static const int kDemuxerStreamForTestFrameDuration = 40;
diff --git a/chromeos/components/drivefs/drivefs_auth.cc b/chromeos/components/drivefs/drivefs_auth.cc index 1940b94..296f0b7 100644 --- a/chromeos/components/drivefs/drivefs_auth.cc +++ b/chromeos/components/drivefs/drivefs_auth.cc
@@ -18,8 +18,13 @@ DriveFsAuth::DriveFsAuth(const base::Clock* clock, const base::FilePath& profile_path, + std::unique_ptr<base::OneShotTimer> timer, Delegate* delegate) - : clock_(clock), profile_path_(profile_path), delegate_(delegate) {} + : clock_(clock), + profile_path_(profile_path), + timer_(std::move(timer)), + delegate_(delegate), + weak_ptr_factory_(this) {} DriveFsAuth::~DriveFsAuth() {} @@ -47,12 +52,18 @@ } get_access_token_callback_ = std::move(callback); - GetIdentityAccessor().GetPrimaryAccountWhenAvailable( - base::BindOnce(&DriveFsAuth::AccountReady, base::Unretained(this))); + timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(30), + base::BindOnce(&DriveFsAuth::AuthTimeout, + weak_ptr_factory_.GetWeakPtr())); + GetIdentityAccessor().GetPrimaryAccountWhenAvailable(base::BindOnce( + &DriveFsAuth::AccountReady, weak_ptr_factory_.GetWeakPtr())); } void DriveFsAuth::AccountReady(const CoreAccountInfo& info, const identity::AccountState& state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + weak_ptr_factory_.InvalidateWeakPtrs(); + timer_->Stop(); GetIdentityAccessor().GetAccessToken( delegate_->GetAccountId().GetUserEmail(), {"https://www.googleapis.com/auth/drive"}, kIdentityConsumerId, @@ -91,6 +102,13 @@ last_token_expiry_ = expiry; } +void DriveFsAuth::AuthTimeout() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + weak_ptr_factory_.InvalidateWeakPtrs(); + std::move(get_access_token_callback_) + .Run(mojom::AccessTokenStatus::kAuthError, ""); +} + identity::mojom::IdentityAccessor& DriveFsAuth::GetIdentityAccessor() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!identity_accessor_) {
diff --git a/chromeos/components/drivefs/drivefs_auth.h b/chromeos/components/drivefs/drivefs_auth.h index 49d2c58..94d4c6cc 100644 --- a/chromeos/components/drivefs/drivefs_auth.h +++ b/chromeos/components/drivefs/drivefs_auth.h
@@ -11,7 +11,9 @@ #include "base/component_export.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/time/clock.h" +#include "base/timer/timer.h" #include "chromeos/components/drivefs/mojom/drivefs.mojom.h" #include "services/identity/public/mojom/identity_accessor.mojom.h" @@ -47,6 +49,7 @@ DriveFsAuth(const base::Clock* clock, const base::FilePath& profile_path, + std::unique_ptr<base::OneShotTimer> timer, Delegate* delegate); virtual ~DriveFsAuth(); @@ -80,11 +83,14 @@ void UpdateCachedToken(const std::string& token, base::Time expiry); + void AuthTimeout(); + identity::mojom::IdentityAccessor& GetIdentityAccessor(); SEQUENCE_CHECKER(sequence_checker_); const base::Clock* const clock_; const base::FilePath profile_path_; + const std::unique_ptr<base::OneShotTimer> timer_; Delegate* const delegate_; // The connection to the identity service. Access via |GetIdentityAccessor()|. @@ -96,6 +102,7 @@ std::string last_token_; base::Time last_token_expiry_; + base::WeakPtrFactory<DriveFsAuth> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(DriveFsAuth); };
diff --git a/chromeos/components/drivefs/drivefs_auth_unittest.cc b/chromeos/components/drivefs/drivefs_auth_unittest.cc index f5f11ce..7eeecdda 100644 --- a/chromeos/components/drivefs/drivefs_auth_unittest.cc +++ b/chromeos/components/drivefs/drivefs_auth_unittest.cc
@@ -11,6 +11,7 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/test/simple_test_clock.h" +#include "base/timer/mock_timer.h" #include "services/identity/public/mojom/constants.mojom.h" #include "services/identity/public/mojom/identity_accessor.mojom-test-utils.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -85,6 +86,8 @@ ~FakeIdentityService() override { mock_->bindings_ = nullptr; } + void set_auth_enabled(bool enabled) { auth_enabled_ = enabled; } + private: void OnBindInterface(const service_manager::BindSourceInfo& source, const std::string& interface_name, @@ -100,6 +103,9 @@ // identity::mojom::IdentityAccessorInterceptorForTesting overrides: void GetPrimaryAccountWhenAvailable( GetPrimaryAccountWhenAvailableCallback callback) override { + if (!auth_enabled_) { + return; + } auto account_id = AccountId::FromUserEmailGaiaId("test@example.com", "ID"); CoreAccountInfo account_info; account_info.email = account_id.GetUserEmail(); @@ -128,6 +134,7 @@ service_manager::ServiceBinding binding_; service_manager::BinderRegistry binder_registry_; mojo::BindingSet<identity::mojom::IdentityAccessor> bindings_; + bool auth_enabled_ = true; DISALLOW_COPY_AND_ASSIGN(FakeIdentityService); }; @@ -143,13 +150,19 @@ identity_service_ = std::make_unique<FakeIdentityService>( &mock_identity_accessor_, &clock_, connector_factory_.RegisterInstance(identity::mojom::kServiceName)); + auto timer = std::make_unique<base::MockOneShotTimer>(); + timer_ = timer.get(); delegate_ = std::make_unique<AuthDelegateImpl>( connector_factory_.CreateConnector(), account_id_); - auth_ = std::make_unique<DriveFsAuth>( - &clock_, base::FilePath("/path/to/profile"), delegate_.get()); + auth_ = std::make_unique<DriveFsAuth>(&clock_, + base::FilePath("/path/to/profile"), + std::move(timer), delegate_.get()); } - void TearDown() override { auth_.reset(); } + void TearDown() override { + EXPECT_FALSE(timer_->IsRunning()); + auth_.reset(); + } void ExpectAccessToken(bool use_cached, mojom::AccessTokenStatus expected_status, @@ -176,6 +189,7 @@ std::unique_ptr<AuthDelegateImpl> delegate_; std::unique_ptr<DriveFsAuth> auth_; + base::MockOneShotTimer* timer_ = nullptr; private: DISALLOW_COPY_AND_ASSIGN(DriveFsAuthTest); @@ -205,20 +219,39 @@ ExpectAccessToken(false, mojom::AccessTokenStatus::kTransientError, ""); } -TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) { +TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Timeout) { + identity_service_->set_auth_enabled(false); base::RunLoop run_loop; auto quit_closure = run_loop.QuitClosure(); auth_->GetAccessToken( - false, base::BindOnce( - [](mojom::AccessTokenStatus status, const std::string& token) { - FAIL() << "Unexpected callback"; + false, base::BindLambdaForTesting( + [&](mojom::AccessTokenStatus status, const std::string&) { + EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status); + std::move(quit_closure).Run(); })); + timer_->Fire(); + run_loop.Run(); +} + +TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) { + base::RunLoop run_loop; + EXPECT_CALL(mock_identity_accessor_, + GetAccessToken("test@example.com", _, "drivefs")) + .WillOnce(testing::Return( + std::make_pair("auth token", GoogleServiceAuthError::NONE))); + auto quit_closure = run_loop.QuitClosure(); + auth_->GetAccessToken( + false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status, + const std::string& token) { + EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status); + EXPECT_EQ("auth token", token); + std::move(quit_closure).Run(); + })); auth_->GetAccessToken( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status, const std::string& token) { EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status); EXPECT_TRUE(token.empty()); - std::move(quit_closure).Run(); })); run_loop.Run(); }
diff --git a/chromeos/components/drivefs/drivefs_host.cc b/chromeos/components/drivefs/drivefs_host.cc index 17219ba..b61bf6c8 100644 --- a/chromeos/components/drivefs/drivefs_host.cc +++ b/chromeos/components/drivefs/drivefs_host.cc
@@ -190,7 +190,10 @@ disk_mount_manager_(disk_mount_manager), timer_(std::move(timer)), account_token_delegate_( - std::make_unique<DriveFsAuth>(clock, profile_path, delegate)) { + std::make_unique<DriveFsAuth>(clock, + profile_path, + std::make_unique<base::OneShotTimer>(), + delegate)) { DCHECK(delegate_); DCHECK(mount_observer_); DCHECK(network_connection_tracker_);
diff --git a/chromeos/dbus/cicerone_client.cc b/chromeos/dbus/cicerone_client.cc index 4f6527d..3f21447 100644 --- a/chromeos/dbus/cicerone_client.cc +++ b/chromeos/dbus/cicerone_client.cc
@@ -321,27 +321,6 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } - void SearchApp(const vm_tools::cicerone::AppSearchRequest& request, - DBusMethodCallback<vm_tools::cicerone::AppSearchResponse> - callback) override { - dbus::MethodCall method_call(vm_tools::cicerone::kVmCiceroneInterface, - vm_tools::cicerone::kAppSearchMethod); - dbus::MessageWriter writer(&method_call); - - if (!writer.AppendProtoAsArrayOfBytes(request)) { - LOG(ERROR) << "Failed to encode AppSearchRequest protobuf"; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), base::nullopt)); - return; - } - - cicerone_proxy_->CallMethod( - &method_call, kDefaultTimeout.InMilliseconds(), - base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse< - vm_tools::cicerone::AppSearchResponse>, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); - } - void ExportLxdContainer( const vm_tools::cicerone::ExportLxdContainerRequest& request, DBusMethodCallback<vm_tools::cicerone::ExportLxdContainerResponse>
diff --git a/chromeos/dbus/cicerone_client.h b/chromeos/dbus/cicerone_client.h index 1de4d21c..633221e 100644 --- a/chromeos/dbus/cicerone_client.h +++ b/chromeos/dbus/cicerone_client.h
@@ -210,12 +210,6 @@ DBusMethodCallback<vm_tools::cicerone::SetUpLxdContainerUserResponse> callback) = 0; - // Searches for not installed Linux packages in a container. - // |callback| is called after the method call finishes. - virtual void SearchApp( - const vm_tools::cicerone::AppSearchRequest& request, - DBusMethodCallback<vm_tools::cicerone::AppSearchResponse> callback) = 0; - // Exports the Lxd container. // |callback| is called when the method completes. virtual void ExportLxdContainer(
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc index 103f33d..5650a5f 100644 --- a/chromeos/dbus/fake_cicerone_client.cc +++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -33,10 +33,6 @@ setup_lxd_container_user_response_.set_status( vm_tools::cicerone::SetUpLxdContainerUserResponse::SUCCESS); - vm_tools::cicerone::AppSearchResponse::AppSearchResult* app = - search_app_response_.add_packages(); - app->set_package_name("fake app"); - export_lxd_container_response_.set_status( vm_tools::cicerone::ExportLxdContainerResponse::EXPORTING); @@ -245,13 +241,6 @@ base::BindOnce(std::move(callback), setup_lxd_container_user_response_)); } -void FakeCiceroneClient::SearchApp( - const vm_tools::cicerone::AppSearchRequest& request, - DBusMethodCallback<vm_tools::cicerone::AppSearchResponse> callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), search_app_response_)); -} - void FakeCiceroneClient::ExportLxdContainer( const vm_tools::cicerone::ExportLxdContainerRequest& request, DBusMethodCallback<vm_tools::cicerone::ExportLxdContainerResponse>
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h index 2c38d062..540cb1d 100644 --- a/chromeos/dbus/fake_cicerone_client.h +++ b/chromeos/dbus/fake_cicerone_client.h
@@ -144,12 +144,6 @@ DBusMethodCallback<vm_tools::cicerone::SetUpLxdContainerUserResponse> callback) override; - // Fake version of the method that searches for not installed apps. - // |callback| is called when the method completes. - void SearchApp(const vm_tools::cicerone::AppSearchRequest& request, - DBusMethodCallback<vm_tools::cicerone::AppSearchResponse> - callback) override; - // Fake version of the method that exports the container. // |callback| is called when the method completes. void ExportLxdContainer( @@ -249,11 +243,6 @@ container_app_icon_response_ = container_app_icon_response; } - void set_search_app_response( - const vm_tools::cicerone::AppSearchResponse& search_app_response) { - search_app_response_ = search_app_response; - } - const vm_tools::cicerone::LinuxPackageInfoRequest& get_most_recent_linux_package_info_request() const { return most_recent_linux_package_info_request_; @@ -394,7 +383,6 @@ get_lxd_container_username_response_; vm_tools::cicerone::SetUpLxdContainerUserResponse setup_lxd_container_user_response_; - vm_tools::cicerone::AppSearchResponse search_app_response_; vm_tools::cicerone::ExportLxdContainerResponse export_lxd_container_response_; vm_tools::cicerone::ImportLxdContainerResponse import_lxd_container_response_;
diff --git a/chromeos/printing/epson_driver_matching.cc b/chromeos/printing/epson_driver_matching.cc index 8f1bd00d..d3c7a411 100644 --- a/chromeos/printing/epson_driver_matching.cc +++ b/chromeos/printing/epson_driver_matching.cc
@@ -33,8 +33,16 @@ return base::Contains(sd.supported_document_formats, "application/octet-stream"); - case PrinterSearchData::PrinterDiscoveryType::kUsb: - return base::Contains(sd.printer_id.command_set(), "ESC/P-R"); + case PrinterSearchData::PrinterDiscoveryType::kUsb: { + // For USB printers, the command set is retrieved from the 'CMD' field of + // the printer's IEEE 1284 Device ID. + for (base::StringPiece format : sd.printer_id.command_set()) { + if (format.starts_with("ESCPR")) { + return true; + } + } + return false; + } case PrinterSearchData::PrinterDiscoveryType::kZeroconf: // For printers found through mDNS/DNS-SD discovery,
diff --git a/chromeos/printing/epson_driver_matching_unittest.cc b/chromeos/printing/epson_driver_matching_unittest.cc index 8bf627a..bcbca4b 100644 --- a/chromeos/printing/epson_driver_matching_unittest.cc +++ b/chromeos/printing/epson_driver_matching_unittest.cc
@@ -14,7 +14,7 @@ namespace { const char kOctetStream[] = "application/octet-stream"; -const char kEscPr[] = "ESC/P-R"; +const char kEscPr[] = "ESCPR1"; const char kEpsonEscpr[] = "application/vnd.epson.escpr"; using PrinterDiscoveryType = PrinterSearchData::PrinterDiscoveryType; @@ -113,14 +113,14 @@ sd.printer_id.set_command_set(command_set); EXPECT_FALSE(CanUseEpsonGenericPPD(sd)); - command_set.push_back(std::string(kEscPr) + ":asfd"); + command_set.push_back("abcd" + std::string(kEscPr)); sd.printer_id.set_command_set(command_set); EXPECT_FALSE(CanUseEpsonGenericPPD(sd)); sd.supported_document_formats.push_back(kEscPr); EXPECT_FALSE(CanUseEpsonGenericPPD(sd)); - command_set.push_back(kEscPr); + command_set.push_back(std::string(kEscPr) + "garbage"); sd.printer_id.set_command_set(command_set); EXPECT_TRUE(CanUseEpsonGenericPPD(sd)); }
diff --git a/chromeos/printing/ppd_provider.cc b/chromeos/printing/ppd_provider.cc index 3a3d226..7958605 100644 --- a/chromeos/printing/ppd_provider.cc +++ b/chromeos/printing/ppd_provider.cc
@@ -490,10 +490,11 @@ // Found a hit, satisfy this resolution. RunPpdReferenceResolutionSucceeded(std::move(next.cb), kEpsonGenericPPD); + } else { + // We don't have anything else left to try. We've reached unsupported + // USB printer, try to grab the manufacturer name. + ResolveUsbManufacturer(std::move(next.cb), search_data.usb_vendor_id); } - // We don't have anything else left to try. We've reached unsupported USB - // printer, try to grab the manufacturer name. - ResolveUsbManufacturer(std::move(next.cb), search_data.usb_vendor_id); } // Didn't start any fetches. return false;
diff --git a/chromeos/printing/usb_printer_id.h b/chromeos/printing/usb_printer_id.h index 3df4257..edffbc95 100644 --- a/chromeos/printing/usb_printer_id.h +++ b/chromeos/printing/usb_printer_id.h
@@ -28,9 +28,9 @@ explicit UsbPrinterId(const std::vector<uint8_t>& printer_id_data); // Accessors. - std::string make() const { return make_; } - std::string model() const { return model_; } - std::vector<std::string> command_set() const { return command_set_; } + const std::string& make() const { return make_; } + const std::string& model() const { return model_; } + const std::vector<std::string>& command_set() const { return command_set_; } // Setters (only used in testing). void set_make(std::string make) { make_ = make; }
diff --git a/components/arc/session/arc_session_runner.cc b/components/arc/session/arc_session_runner.cc index f5deb67..fe656884 100644 --- a/components/arc/session/arc_session_runner.cc +++ b/components/arc/session/arc_session_runner.cc
@@ -221,8 +221,9 @@ } void ArcSessionRunner::SetUserIdHashForProfile(const std::string& hash) { + user_id_hash_ = hash; if (arc_session_) - arc_session_->SetUserIdHashForProfile(hash); + arc_session_->SetUserIdHashForProfile(user_id_hash_); } void ArcSessionRunner::SetRestartDelayForTesting( @@ -240,6 +241,8 @@ VLOG(1) << "Starting ARC instance"; if (!arc_session_) { arc_session_ = factory_.Run(); + if (!user_id_hash_.empty()) + arc_session_->SetUserIdHashForProfile(user_id_hash_); arc_session_->AddObserver(this); arc_session_->StartMiniInstance(); // Record the UMA only when |restart_after_crash_count_| is zero to avoid
diff --git a/components/arc/session/arc_session_runner.h b/components/arc/session/arc_session_runner.h index 005bdc9..42e0c18f 100644 --- a/components/arc/session/arc_session_runner.h +++ b/components/arc/session/arc_session_runner.h
@@ -143,6 +143,9 @@ // Parameters to upgrade request. ArcSession::UpgradeParams upgrade_params_; + // A hash string of the profile user ID. + std::string user_id_hash_; + // WeakPtrFactory to use callbacks. base::WeakPtrFactory<ArcSessionRunner> weak_ptr_factory_;
diff --git a/components/background_task_scheduler/BUILD.gn b/components/background_task_scheduler/BUILD.gn index e89bd9d4..be854b8 100644 --- a/components/background_task_scheduler/BUILD.gn +++ b/components/background_task_scheduler/BUILD.gn
@@ -64,6 +64,8 @@ testonly = true java_files = [ + "android/javatests/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplWithMockTest.java", + "android/javatests/src/org/chromium/components/background_task_scheduler/MockBackgroundTaskSchedulerDelegate.java", "android/javatests/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobServiceTest.java", "android/javatests/src/org/chromium/components/background_task_scheduler/BundleToPersistableBundleConverterTest.java", ] @@ -77,6 +79,7 @@ "$google_play_services_package:google_play_services_tasks_java", "//base:base_java", "//base:base_java_test_support", + "//content/public/test/android:content_java_test_support", "//third_party/android_support_test_runner:runner_java", "//third_party/junit", ]
diff --git a/components/background_task_scheduler/DEPS b/components/background_task_scheduler/DEPS new file mode 100644 index 0000000..1356512 --- /dev/null +++ b/components/background_task_scheduler/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+content/public/test/android", +] \ No newline at end of file
diff --git a/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplWithMockTest.java b/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplWithMockTest.java new file mode 100644 index 0000000..67b8520 --- /dev/null +++ b/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplWithMockTest.java
@@ -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. + +package org.chromium.components.background_task_scheduler; + +import android.content.Context; +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.chromium.content_public.browser.test.util.TestThreadUtils; + +import java.util.concurrent.TimeUnit; + +/** + * Tests for {@link BackgroundTaskSchedulerImpl}. + */ +@RunWith(BaseJUnit4ClassRunner.class) +public class BackgroundTaskSchedulerImplWithMockTest { + private static class TestBackgroundTask implements BackgroundTask { + @Override + public boolean onStartTask( + Context context, TaskParameters taskParameters, TaskFinishedCallback callback) { + return false; + } + + @Override + public boolean onStopTask(Context context, TaskParameters taskParameters) { + return false; + } + + @Override + public void reschedule(Context context) {} + } + + private static final int TEST_MINUTES = 10; + + @Test + @SmallTest + public void testOneOffTaskScheduling() { + TaskInfo oneOffTask = TaskInfo.createOneOffTask(TaskIds.TEST, TestBackgroundTask.class, + TimeUnit.MINUTES.toMillis(TEST_MINUTES)) + .build(); + + MockBackgroundTaskSchedulerDelegate delegate = new MockBackgroundTaskSchedulerDelegate(); + BackgroundTaskScheduler taskScheduler = new BackgroundTaskSchedulerImpl(delegate); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { Assert.assertTrue(taskScheduler.schedule(null, oneOffTask)); }); + + Assert.assertEquals(oneOffTask, delegate.getScheduledTaskInfo()); + Assert.assertEquals(0, delegate.getCanceledTaskId()); + } + + @Test + @SmallTest + public void testPeriodicTaskScheduling() { + TaskInfo periodicTask = TaskInfo.createPeriodicTask(TaskIds.TEST, TestBackgroundTask.class, + TimeUnit.MINUTES.toMillis(TEST_MINUTES)) + .build(); + + MockBackgroundTaskSchedulerDelegate delegate = new MockBackgroundTaskSchedulerDelegate(); + BackgroundTaskScheduler taskScheduler = new BackgroundTaskSchedulerImpl(delegate); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { Assert.assertTrue(taskScheduler.schedule(null, periodicTask)); }); + + Assert.assertEquals(periodicTask, delegate.getScheduledTaskInfo()); + Assert.assertEquals(0, delegate.getCanceledTaskId()); + } + + @Test + @SmallTest + public void testTaskCanceling() { + MockBackgroundTaskSchedulerDelegate delegate = new MockBackgroundTaskSchedulerDelegate(); + BackgroundTaskScheduler taskScheduler = new BackgroundTaskSchedulerImpl(delegate); + + TestThreadUtils.runOnUiThreadBlocking(() -> { taskScheduler.cancel(null, TaskIds.TEST); }); + + Assert.assertEquals(null, delegate.getScheduledTaskInfo()); + Assert.assertEquals(TaskIds.TEST, delegate.getCanceledTaskId()); + } +} \ No newline at end of file
diff --git a/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/MockBackgroundTaskSchedulerDelegate.java b/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/MockBackgroundTaskSchedulerDelegate.java new file mode 100644 index 0000000..39227cc --- /dev/null +++ b/components/background_task_scheduler/android/javatests/src/org/chromium/components/background_task_scheduler/MockBackgroundTaskSchedulerDelegate.java
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.background_task_scheduler; + +import android.content.Context; + +/** + * Mock of BackgroundTaskSchedulerDelegate that tracks which methods are called. + * This is used for all delegates that cannot be included in end-to-end testing. + */ +public class MockBackgroundTaskSchedulerDelegate implements BackgroundTaskSchedulerDelegate { + private TaskInfo mScheduledTaskInfo; + private int mCanceledTaskId; + + @Override + public boolean schedule(Context context, TaskInfo taskInfo) { + mScheduledTaskInfo = taskInfo; + mCanceledTaskId = 0; + return true; + } + + @Override + public void cancel(Context context, int taskId) { + mCanceledTaskId = taskId; + mScheduledTaskInfo = null; + } + + public TaskInfo getScheduledTaskInfo() { + return mScheduledTaskInfo; + } + + public int getCanceledTaskId() { + return mCanceledTaskId; + } + + public void clear() { + mScheduledTaskInfo = null; + mCanceledTaskId = 0; + } +} \ No newline at end of file
diff --git a/components/media_message_center/BUILD.gn b/components/media_message_center/BUILD.gn index 72e05fe..a1183f2 100644 --- a/components/media_message_center/BUILD.gn +++ b/components/media_message_center/BUILD.gn
@@ -12,6 +12,8 @@ "media_notification_controller.h", "media_notification_item.cc", "media_notification_item.h", + "media_notification_util.cc", + "media_notification_util.h", "media_notification_view.cc", "media_notification_view.h", ]
diff --git a/components/media_message_center/media_notification_util.cc b/components/media_message_center/media_notification_util.cc new file mode 100644 index 0000000..cfe947d --- /dev/null +++ b/components/media_message_center/media_notification_util.cc
@@ -0,0 +1,30 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/media_message_center/media_notification_util.h" + +#include "base/strings/utf_string_conversions.h" +#include "services/media_session/public/mojom/media_session.mojom.h" + +namespace media_message_center { + +base::string16 GetAccessibleNameFromMetadata( + media_session::MediaMetadata session_metadata) { + std::vector<base::string16> text; + + if (!session_metadata.title.empty()) + text.push_back(session_metadata.title); + + if (!session_metadata.artist.empty()) + text.push_back(session_metadata.artist); + + if (!session_metadata.album.empty()) + text.push_back(session_metadata.album); + + base::string16 accessible_name = + base::JoinString(text, base::ASCIIToUTF16(" - ")); + return accessible_name; +} + +} // namespace media_message_center
diff --git a/components/media_message_center/media_notification_util.h b/components/media_message_center/media_notification_util.h new file mode 100644 index 0000000..8c2b027 --- /dev/null +++ b/components/media_message_center/media_notification_util.h
@@ -0,0 +1,21 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_UTIL_H_ +#define COMPONENTS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_UTIL_H_ + +#include "base/component_export.h" +#include "services/media_session/public/mojom/media_session.mojom.h" + +namespace media_message_center { + +// Creates a string describing media session metadata intended to be read out by +// a screen reader. +COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) +base::string16 GetAccessibleNameFromMetadata( + media_session::MediaMetadata session_metadata); + +} // namespace media_message_center + +#endif // COMPONENTS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_UTIL_H_
diff --git a/components/media_message_center/media_notification_view.cc b/components/media_message_center/media_notification_view.cc index 9119b9a..4ea8af1 100644 --- a/components/media_message_center/media_notification_view.cc +++ b/components/media_message_center/media_notification_view.cc
@@ -6,11 +6,11 @@ #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" -#include "base/strings/utf_string_conversions.h" #include "components/media_message_center/media_notification_background.h" #include "components/media_message_center/media_notification_constants.h" #include "components/media_message_center/media_notification_container.h" #include "components/media_message_center/media_notification_item.h" +#include "components/media_message_center/media_notification_util.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" #include "services/media_session/public/mojom/media_session.mojom.h" @@ -297,24 +297,16 @@ artist_label_->SetText(metadata.artist); header_row_->SetSummaryText(metadata.album); - std::vector<base::string16> text; + accessible_name_ = GetAccessibleNameFromMetadata(metadata); - if (!metadata.title.empty()) { - text.push_back(metadata.title); + if (!metadata.title.empty()) RecordMetadataHistogram(Metadata::kTitle); - } - if (!metadata.artist.empty()) { - text.push_back(metadata.artist); + if (!metadata.artist.empty()) RecordMetadataHistogram(Metadata::kArtist); - } - if (!metadata.album.empty()) { - text.push_back(metadata.album); + if (!metadata.album.empty()) RecordMetadataHistogram(Metadata::kAlbum); - } - - accessible_name_ = base::JoinString(text, base::ASCIIToUTF16(" - ")); RecordMetadataHistogram(Metadata::kCount);
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index a1b05e5..a4626821 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1104,6 +1104,10 @@ if (delegate_->OverridePrint(web_frame)) return; + // Detached documents can't be printed. + if (!web_frame->GetDocument().GetFrame()) + return; + if (g_is_preview_enabled) { #if BUILDFLAG(ENABLE_PRINT_PREVIEW) print_preview_context_.InitWithFrame(web_frame);
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn index ab5bc9ad..e638b5f 100644 --- a/components/signin/core/browser/BUILD.gn +++ b/components/signin/core/browser/BUILD.gn
@@ -281,6 +281,7 @@ "device_id_helper_unittest.cc", "dice_account_reconcilor_delegate_unittest.cc", "gaia_cookie_manager_service_unittest.cc", + "identity_utils_unittest.cc", "mice_account_reconcilor_delegate_unittest.cc", "mutable_profile_oauth2_token_service_delegate_unittest.cc", "oauth_multilogin_helper_unittest.cc",
diff --git a/components/signin/core/browser/identity_utils.cc b/components/signin/core/browser/identity_utils.cc index f5551f9..57ea8f1 100644 --- a/components/signin/core/browser/identity_utils.cc +++ b/components/signin/core/browser/identity_utils.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/prefs/pref_service.h" +#include "components/signin/core/browser/signin_pref_names.h" #include "third_party/icu/source/i18n/unicode/regex.h" namespace identity { @@ -52,10 +53,9 @@ } // namespace bool IsUsernameAllowedByPatternFromPrefs(const PrefService* prefs, - const std::string& username, - const std::string& pattern_pref_name) { - return IsUsernameAllowedByPattern(username, - prefs->GetString(pattern_pref_name)); + const std::string& username) { + return IsUsernameAllowedByPattern( + username, prefs->GetString(prefs::kGoogleServicesUsernamePattern)); } } // namespace identity
diff --git a/components/signin/core/browser/identity_utils.h b/components/signin/core/browser/identity_utils.h index 27afddf1..b28d452 100644 --- a/components/signin/core/browser/identity_utils.h +++ b/components/signin/core/browser/identity_utils.h
@@ -19,10 +19,10 @@ namespace identity { // Returns true if the username is allowed based on a pattern registered -// as |pattern_pref_name| with the preferences service referenced by |prefs|. +// |prefs::kGoogleServicesUsernamePattern| with the preferences service +// referenced by |prefs|. bool IsUsernameAllowedByPatternFromPrefs(const PrefService* prefs, - const std::string& username, - const std::string& pattern_pref_name); + const std::string& username); } // namespace identity #endif // COMPONENTS_SIGNIN_CORE_BROWSER_IDENTITY_UTILS_H_
diff --git a/components/signin/core/browser/identity_utils_unittest.cc b/components/signin/core/browser/identity_utils_unittest.cc index 62e8c47..e0cd47e5 100644 --- a/components/signin/core/browser/identity_utils_unittest.cc +++ b/components/signin/core/browser/identity_utils_unittest.cc
@@ -7,6 +7,7 @@ #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/testing_pref_service.h" +#include "components/signin/core/browser/signin_pref_names.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -25,14 +26,13 @@ const char kNonMatchingPattern[] = ".*foo.*"; const char kNonMatchingUsernamePattern[] = "foo@test.com"; const char kNonMatchingDomainPattern[] = "test@foo.com"; - -const char kRegisteredPattern[] = "test.registered.username_pattern"; } // namespace class IdentityUtilsTest : public testing::Test { public: IdentityUtilsTest() { - prefs_.registry()->RegisterStringPref(kRegisteredPattern, std::string()); + prefs_.registry()->RegisterStringPref(prefs::kGoogleServicesUsernamePattern, + std::string()); } TestingPrefServiceSimple* prefs() { return &prefs_; } @@ -42,13 +42,13 @@ }; TEST_F(IdentityUtilsTest, IsUsernameAllowedByPatternFromPrefs_EmptyPatterns) { - prefs()->SetString(kRegisteredPattern, ""); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(),kUsername, kRegisteredPattern); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, ""); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, " "); - EXPECT_FALSE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, " "); + EXPECT_FALSE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); } TEST_F(IdentityUtilsTest, @@ -56,50 +56,55 @@ // identity::IsUsernameAllowedByPatternFromPrefs should recognize invalid // wildcard patterns like "*@foo.com" and insert a "." before them // automatically. - prefs()->SetString(kRegisteredPattern, kValidWildcardPattern); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, + kValidWildcardPattern); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kInvalidWildcardPattern); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, + kInvalidWildcardPattern); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); } TEST_F(IdentityUtilsTest, IsUsernameAllowedByPatternFromPrefs_MatchingWildcardPatterns) { - prefs()->SetString(kRegisteredPattern, kMatchingPattern1); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern1); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kMatchingPattern2); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern2); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kMatchingPattern3); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern3); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kMatchingPattern4); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern4); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kMatchingPattern5); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern5); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kMatchingPattern6); - EXPECT_TRUE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, kMatchingPattern6); + EXPECT_TRUE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kNonMatchingPattern); - EXPECT_FALSE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, + kNonMatchingPattern); + EXPECT_FALSE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kNonMatchingUsernamePattern); - EXPECT_FALSE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, + kNonMatchingUsernamePattern); + EXPECT_FALSE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); - prefs()->SetString(kRegisteredPattern, kNonMatchingDomainPattern); - EXPECT_FALSE(identity::IsUsernameAllowedByPatternFromPrefs( - prefs(), kUsername, kRegisteredPattern)); + prefs()->SetString(prefs::kGoogleServicesUsernamePattern, + kNonMatchingDomainPattern); + EXPECT_FALSE( + identity::IsUsernameAllowedByPatternFromPrefs(prefs(), kUsername)); }
diff --git a/components/signin/core/browser/primary_account_policy_manager_impl.cc b/components/signin/core/browser/primary_account_policy_manager_impl.cc index d6c10b3..514f12a 100644 --- a/components/signin/core/browser/primary_account_policy_manager_impl.cc +++ b/components/signin/core/browser/primary_account_policy_manager_impl.cc
@@ -107,6 +107,5 @@ if (!local_state) return true; - return identity::IsUsernameAllowedByPatternFromPrefs( - local_state, username, prefs::kGoogleServicesUsernamePattern); + return identity::IsUsernameAllowedByPatternFromPrefs(local_state, username); }
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index ca61367..6def139 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -162,10 +162,9 @@ observer.OnDisplayDestroyed(); observers_.Clear(); - for (auto& callback_list : pending_presented_callbacks_) { - for (auto& callback : callback_list.second) - std::move(callback).Run(gfx::PresentationFeedback::Failure()); - } + // Send gfx::PresentationFeedback::Failure() to any surfaces expecting + // feedback. + pending_surfaces_with_presentation_helpers_.clear(); // Only do this if Initialize() happened. if (client_) { @@ -538,16 +537,17 @@ scheduler_->current_frame_time(), 1); } - std::vector<Surface::PresentedCallback> callbacks; + std::vector<std::unique_ptr<Surface::PresentationHelper>> + presentation_helper_list; for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first); - Surface::PresentedCallback callback; - if (surface && surface->TakePresentedCallback(&callback)) { - callbacks.emplace_back(std::move(callback)); + if (surface) { + presentation_helper_list.push_back( + surface->TakePresentationHelperForPresentNotification()); } } - pending_presented_callbacks_.emplace_back( - std::make_pair(now_time, std::move(callbacks))); + pending_surfaces_with_presentation_helpers_.emplace_back( + std::make_pair(now_time, std::move(presentation_helper_list))); ui::LatencyInfo::TraceIntermediateFlowEvents(frame.metadata.latency_info, "Display::DrawAndSwap"); @@ -615,12 +615,13 @@ // and should not be popped until DidReceivePresentationFeedback. Therefore // we must not have an empty list when getting the SwapBuffers ACK (this is // required to happen between those two events). - DCHECK(!pending_presented_callbacks_.empty()); + DCHECK(!pending_surfaces_with_presentation_helpers_.empty()); // Check that the swap timings correspond with the timestamp from when // the swap was triggered. Note that not all output surfaces provide timing // information, hence the check for a valid swap_start. - const auto swap_time = pending_presented_callbacks_.front().first; + const auto swap_time = + pending_surfaces_with_presentation_helpers_.front().first; if (!timings.swap_start.is_null()) { DCHECK_LE(swap_time, timings.swap_start); base::TimeDelta delta = @@ -652,7 +653,7 @@ void Display::DidReceivePresentationFeedback( const gfx::PresentationFeedback& feedback) { - if (pending_presented_callbacks_.empty()) { + if (pending_surfaces_with_presentation_helpers_.empty()) { DLOG(ERROR) << "Received unexpected PresentationFeedback"; return; } @@ -660,16 +661,19 @@ TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( "viz,benchmark", "Graphics.Pipeline.DrawAndSwap", last_presented_trace_id_, feedback.timestamp); - auto& callbacks = pending_presented_callbacks_.front().second; - const auto swap_time = pending_presented_callbacks_.front().first; + auto& presentation_helper_list = + pending_surfaces_with_presentation_helpers_.front().second; + const auto swap_time = + pending_surfaces_with_presentation_helpers_.front().first; auto copy_feedback = SanitizePresentationFeedback(feedback, swap_time); TRACE_EVENT_INSTANT_WITH_TIMESTAMP0( "benchmark,viz", "Display::FrameDisplayed", TRACE_EVENT_SCOPE_THREAD, copy_feedback.timestamp); - for (auto& callback : callbacks) { - std::move(callback).Run(copy_feedback); + for (auto& presentation_helper : presentation_helper_list) { + if (presentation_helper) + presentation_helper->DidPresent(feedback); } - pending_presented_callbacks_.pop_front(); + pending_surfaces_with_presentation_helpers_.pop_front(); } void Display::DidFinishLatencyInfo(
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h index cf97b87f..623c1b4 100644 --- a/components/viz/service/display/display.h +++ b/components/viz/service/display/display.h
@@ -10,6 +10,7 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" @@ -201,9 +202,14 @@ std::vector<ui::LatencyInfo> stored_latency_info_; std::vector<SurfaceId> surfaces_to_ack_on_next_draw_; + // |pending_surfaces_with_presentation_helpers_| is a list of lists of + // Surface::PresentationHelpers. The lists are grouped by swap (each surface + // involved in an individual Swap is added to the list. These are then + // notified of presentation after the appropriate Swap is completed. base::circular_deque< - std::pair<base::TimeTicks, std::vector<Surface::PresentedCallback>>> - pending_presented_callbacks_; + std::pair<base::TimeTicks, + std::vector<std::unique_ptr<Surface::PresentationHelper>>>> + pending_surfaces_with_presentation_helpers_; // Callback that will be run after all pending swaps have acked. base::OnceClosure no_pending_swaps_callback_;
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc index eed28b34..d01b0a8 100644 --- a/components/viz/service/surfaces/surface.cc +++ b/components/viz/service/surfaces/surface.cc
@@ -26,6 +26,25 @@ namespace viz { +Surface::PresentationHelper::PresentationHelper(base::WeakPtr<Surface> surface, + uint32_t frame_token) + : surface_(std::move(surface)), frame_token_(frame_token) {} + +Surface::PresentationHelper::~PresentationHelper() { + // The class that called TakePresentationHelperForPresentNotification + // should have called present on this helper. If not, give a Failure feedback + // to the appropriate surface. + DidPresent(gfx::PresentationFeedback::Failure()); +} + +void Surface::PresentationHelper::DidPresent( + const gfx::PresentationFeedback& feedback) { + if (surface_ && frame_token_) + surface_->DidPresentSurface(frame_token_, feedback); + + surface_ = nullptr; +} + Surface::Surface(const SurfaceInfo& surface_info, SurfaceManager* surface_manager, SurfaceAllocationGroup* allocation_group, @@ -565,15 +584,15 @@ is_latency_info_taken_ = true; } -bool Surface::TakePresentedCallback(PresentedCallback* callback) { - if (active_frame_data_ && !active_frame_data_->is_presented_callback_bound) { - *callback = - base::BindOnce(&Surface::DidPresentSurface, weak_factory_.GetWeakPtr(), - active_frame_data_->frame.metadata.frame_token); - active_frame_data_->is_presented_callback_bound = true; - return true; +std::unique_ptr<Surface::PresentationHelper> +Surface::TakePresentationHelperForPresentNotification() { + if (active_frame_data_ && + !active_frame_data_->will_be_notified_of_presentation) { + active_frame_data_->will_be_notified_of_presentation = true; + return std::make_unique<PresentationHelper>( + GetWeakPtr(), active_frame_data_->frame.metadata.frame_token); } - return false; + return nullptr; } void Surface::DidPresentSurface(uint32_t presentation_token, @@ -622,9 +641,9 @@ if (!frame_data->frame_acked) surface_client_->OnSurfaceProcessed(this); - // If we have not bound a presented callback, we'll notify the client when - // the frame is unref'd. - if (!frame_data->is_presented_callback_bound) + // If we won't be getting a presented notification, we'll notify the client + // when the frame is unref'd. + if (!frame_data->will_be_notified_of_presentation) DidPresentSurface(frame_data->frame.metadata.frame_token, gfx::PresentationFeedback::Failure()); }
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h index 8c9ee36..183db2b 100644 --- a/components/viz/service/surfaces/surface.h +++ b/components/viz/service/surfaces/surface.h
@@ -76,6 +76,20 @@ // the event of missing dependencies at display time. class VIZ_SERVICE_EXPORT Surface final { public: + class PresentationHelper { + public: + PresentationHelper(base::WeakPtr<Surface> surface, uint32_t frame_token); + ~PresentationHelper(); + + void DidPresent(const gfx::PresentationFeedback& feedback); + + private: + base::WeakPtr<Surface> surface_; + const uint32_t frame_token_; + + DISALLOW_COPY_AND_ASSIGN(PresentationHelper); + }; + using PresentedCallback = base::OnceCallback<void(const gfx::PresentationFeedback&)>; enum QueueFrameResult { REJECTED, ACCEPTED_ACTIVE, ACCEPTED_PENDING }; @@ -168,7 +182,10 @@ void TakeActiveLatencyInfo(std::vector<ui::LatencyInfo>* latency_info); void TakeActiveAndPendingLatencyInfo( std::vector<ui::LatencyInfo>* latency_info); - bool TakePresentedCallback(PresentedCallback* callback); + // Callers of this function must call |DidPresent| on the returned + // PresentationHelper, at the appropriate point in the future. + std::unique_ptr<Surface::PresentationHelper> + TakePresentationHelperForPresentNotification(); void DidPresentSurface(uint32_t presentation_token, const gfx::PresentationFeedback& feedback); void SendAckToClient(); @@ -231,6 +248,8 @@ void ActivateIfDeadlinePassed(); + base::WeakPtr<Surface> GetWeakPtr() { return weak_factory_.GetWeakPtr(); } + private: struct FrameData { FrameData(CompositorFrame&& frame, uint64_t frame_index); @@ -243,10 +262,10 @@ // Whether the frame has been displayed or not. bool frame_drawn = false; bool frame_acked = false; - // Whether there is a presentation feedback callback bound to this frame. + // Whether there is a pending presentation callback (via DidPresentSurface). // This typically happens when a frame is swapped - the Display will ask // for a callback that will supply presentation feedback to the client. - bool is_presented_callback_bound = false; + bool will_be_notified_of_presentation = false; }; // Updates surface references of the surface using the referenced
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 5e68b592..9a5a0ea 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -35,6 +35,7 @@ #include "content/browser/web_package/signed_exchange_envelope.h" #include "content/browser/web_package/signed_exchange_error.h" #include "content/common/navigation_params.h" +#include "content/common/web_package/signed_exchange_utils.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -1872,22 +1873,15 @@ } signatures->emplace_back(std::move(signature)); - const net::SHA256HashValue header_integrity = - envelope->ComputeHeaderIntegrity(); - std::string header_integrity_base64; - base::Base64Encode( - base::StringPiece(reinterpret_cast<const char*>(header_integrity.data), - sizeof(header_integrity.data)), - &header_integrity_base64); - signed_exchange_info->SetHeader( Network::SignedExchangeHeader::Create() .SetRequestUrl(envelope->request_url().url.spec()) .SetResponseCode(envelope->response_code()) .SetResponseHeaders(Object::fromValue(headers_dict.get(), nullptr)) .SetSignatures(std::move(signatures)) - .SetHeaderIntegrity(std::string("sha256-") + - header_integrity_base64) + .SetHeaderIntegrity( + signed_exchange_utils::CreateHeaderIntegrityHashString( + envelope->ComputeHeaderIntegrity())) .Build()); } if (ssl_info)
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index d1165f6..4575aa23 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -2067,8 +2067,6 @@ } if (subresource_loader_params_ && !subresource_loader_params_->prefetched_signed_exchanges.empty()) { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch)); commit_params_.prefetched_signed_exchanges = std::move(subresource_loader_params_->prefetched_signed_exchanges); }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 36e6f08..ad82e369 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -126,6 +126,7 @@ #include "content/common/render_message_filter.mojom.h" #include "content/common/renderer.mojom.h" #include "content/common/swapped_out_messages.h" +#include "content/common/unfreezable_frame_messages.h" #include "content/common/widget.mojom.h" #include "content/public/browser/ax_event_notification_details.h" #include "content/public/browser/browser_accessibility_state.h" @@ -1027,10 +1028,10 @@ // flight. // 3. The RenderFrame can be detached, as part of removing a subtree (due to // navigation, swap out, or DOM mutation). In this case, the browser sends - // a FrameMsg_Delete for the RenderFrame to detach itself and release its - // associated resources. If the subframe contains an unload handler, - // |unload_state_| is advanced to UnloadState::InProgress to track that the - // detach is in progress; otherwise, it is advanced directly to + // a UnfreezableFrameMsg_Delete for the RenderFrame to detach itself and + // release its associated resources. If the subframe contains an unload + // handler, |unload_state_| is advanced to UnloadState::InProgress to track + // that the detach is in progress; otherwise, it is advanced directly to // UnloadState::Completed. // // The browser side gives the renderer a small timeout to finish processing @@ -1043,8 +1044,9 @@ // // TODO(dcheng): Due to how frame detach is signalled today, there are some // bugs in this area. In particular, subtree detach is reported from the - // bottom up, so the replicated FrameMsg_Delete messages actually operate on a - // node-by-node basis rather than detaching an entire subtree at once... + // bottom up, so the replicated UnfreezableFrameMsg_Delete messages actually + // operate on a node-by-node basis rather than detaching an entire subtree at + // once... // // Note that this logic is fairly subtle. It needs to include all subframes // and all speculative frames, but it should exclude case #1 (a main @@ -1894,7 +1896,7 @@ return; if (render_frame_created_) { - Send(new FrameMsg_Delete(routing_id_, intent)); + Send(new UnfreezableFrameMsg_Delete(routing_id_, intent)); if (!frame_tree_node_->IsMainFrame() && IsCurrent()) { // If this subframe has an unload handler (and isn't speculative), ensure @@ -2171,7 +2173,7 @@ FrameDeleteIntention::kNotMainFrame); // Speculative RenderFrameHosts are deleted by the FrameTreeNode's // RenderFrameHostManager's destructor. RenderFrameProxyHosts send - // FrameMsg_Delete automatically in the destructor. + // UnfreezableFrameMsg_Delete automatically in the destructor. // TODO(dcheng): This is horribly confusing. Refactor this logic so it's // more understandable. node_to_delete.reset(); @@ -7191,12 +7193,6 @@ scoped_refptr<PrefetchedSignedExchangeCache> RenderFrameHostImpl::EnsurePrefetchedSignedExchangeCache() { - if (!base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch) && - !base::FeatureList::IsEnabled( - features::kSignedExchangePrefetchCacheForNavigations)) { - return nullptr; - } if (!prefetched_signed_exchange_cache_) { prefetched_signed_exchange_cache_ = base::MakeRefCounted<PrefetchedSignedExchangeCache>();
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 911d687..8d406e4 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -706,10 +706,6 @@ std::string accept_langs) { DCHECK(!IsNavigationLoaderOnUIEnabled()); if (prefetched_signed_exchange_cache) { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch) || - base::FeatureList::IsEnabled( - features::kSignedExchangePrefetchCacheForNavigations)); std::unique_ptr<NavigationLoaderInterceptor> prefetched_signed_exchange_interceptor = prefetched_signed_exchange_cache->MaybeCreateInterceptor(
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc index c9486c24..d7a5a56 100644 --- a/content/browser/loader/prefetch_url_loader.cc +++ b/content/browser/loader/prefetch_url_loader.cc
@@ -65,10 +65,6 @@ network::kAcceptHeader, kSignedExchangeEnabledAcceptHeaderForPrefetch); if (prefetched_signed_exchange_cache) { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch) || - base::FeatureList::IsEnabled( - features::kSignedExchangePrefetchCacheForNavigations)); prefetched_signed_exchange_cache_adapter_ = std::make_unique<PrefetchedSignedExchangeCacheAdapter>( std::move(prefetched_signed_exchange_cache),
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index dcf3078..f1ada24 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -207,6 +207,7 @@ #include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/sandbox/switches.h" #include "services/service_manager/zygote/common/zygote_buildflags.h" +#include "storage/browser/database/database_tracker.h" #include "storage/browser/fileapi/sandbox_file_system_backend.h" #include "third_party/blink/public/common/page/launching_process_state.h" #include "third_party/blink/public/common/user_agent/user_agent_metadata.h" @@ -2073,6 +2074,11 @@ AddUIThreadInterface(registry.get(), base::BindRepeating(&ClipboardHostImpl::Create)); + AddUIThreadInterface( + registry.get(), + base::BindRepeating(&RenderProcessHostImpl::BindWebDatabaseHostImpl, + base::Unretained(this))); + registry->AddInterface( base::BindRepeating(&MimeRegistryImpl::Create), base::CreateSequencedTaskRunnerWithTraits( @@ -2121,12 +2127,6 @@ &viz::GpuClient::Add, base::Unretained(gpu_client_.get()))); } - registry->AddInterface( - base::BindRepeating( - &WebDatabaseHostImpl::Create, GetID(), - base::WrapRefCounted(storage_partition_impl_->GetDatabaseTracker())), - storage_partition_impl_->GetDatabaseTracker()->task_runner()); - MediaStreamManager* media_stream_manager = BrowserMainLoop::GetInstance()->media_stream_manager(); @@ -2324,6 +2324,16 @@ video_decoder_proxy_->Add(std::move(request)); } +void RenderProcessHostImpl::BindWebDatabaseHostImpl( + blink::mojom::WebDatabaseHostRequest request) { + storage::DatabaseTracker* db_tracker = + storage_partition_impl_->GetDatabaseTracker(); + db_tracker->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&WebDatabaseHostImpl::Create, GetID(), + base::WrapRefCounted(db_tracker), std::move(request))); +} + void RenderProcessHostImpl::CreateRendererHost( mojom::RendererHostAssociatedRequest request) { renderer_host_binding_.Bind(std::move(request));
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index ba2efb91..b95e993 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -66,6 +66,7 @@ #include "third_party/blink/public/mojom/filesystem/file_system.mojom.h" #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" +#include "third_party/blink/public/mojom/webdatabase/web_database.mojom.h" #include "ui/gfx/gpu_memory_buffer.h" #if defined(OS_ANDROID) @@ -565,6 +566,7 @@ blink::mojom::BroadcastChannelProviderRequest request); void CreateRendererHost(mojom::RendererHostAssociatedRequest request); void BindVideoDecoderService(media::mojom::InterfaceFactoryRequest request); + void BindWebDatabaseHostImpl(blink::mojom::WebDatabaseHostRequest request); // Control message handlers. void OnUserMetricsRecordAction(const std::string& action);
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 41dd994..c552643 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -376,7 +376,7 @@ mouse_capture_target_ = nullptr; if (view == touchscreen_gesture_target_) - touchscreen_gesture_target_ = nullptr; + SetTouchscreenGestureTarget(nullptr); if (view == touchpad_gesture_target_) touchpad_gesture_target_ = nullptr; @@ -417,6 +417,9 @@ for (auto entry : owner_map_) entry.second->RemoveObserver(this); owner_map_.clear(); + viz::HostFrameSinkManager* manager = GetHostFrameSinkManager(); + if (manager) + manager->RemoveHitTestRegionObserver(this); } RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate( @@ -451,7 +454,11 @@ event_targeter_(std::make_unique<RenderWidgetTargeter>(this)), use_viz_hit_test_(features::IsVizHitTestingEnabled()), touch_event_ack_queue_(new TouchEventAckQueue(this)), - weak_ptr_factory_(this) {} + weak_ptr_factory_(this) { + viz::HostFrameSinkManager* manager = GetHostFrameSinkManager(); + DCHECK(manager); + manager->AddHitTestRegionObserver(this); +} RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { // We may be destroyed before some of the owners in the map, so we must @@ -1522,7 +1529,6 @@ // unique_touch_event_id of 0. They must have a non-null target in order // to get the coordinate transform. DCHECK(target); - touchscreen_gesture_target_ = target; fallback_target_location = target_location; } else if (no_matching_id && is_gesture_start) { // A long-standing Windows issues where occasionally a GestureStart is @@ -1542,20 +1548,27 @@ // Re https://crbug.com/796656): Since we are already in an error case, // don't worry about the fact we're ignoring |result.should_query_view|, as // this is the best we can do until we fix https://crbug.com/595422. - touchscreen_gesture_target_ = result.view; + target = result.view; fallback_target_location = transformed_point; } else if (is_gesture_start) { - touchscreen_gesture_target_ = gesture_target_it->second; + target = gesture_target_it->second; touchscreen_gesture_target_map_.erase(gesture_target_it); // Abort any scroll bubbling in progress to avoid double entry. - CancelScrollBubblingIfConflicting(touchscreen_gesture_target_); + CancelScrollBubblingIfConflicting(target); + } + + if (gesture_event.unique_touch_event_id == 0 || is_gesture_start) { + bool moved_recently = touchscreen_gesture_target_moved_recently_; + if (is_gesture_start) + moved_recently = target->ScreenRectIsUnstableFor(gesture_event); + SetTouchscreenGestureTarget(target, moved_recently); } // If we set a target and it's not in the map, we won't get notified if the // target goes away, so drop the target and the resulting events. if (touchscreen_gesture_target_ && !IsViewInMap(touchscreen_gesture_target_)) - touchscreen_gesture_target_ = nullptr; + SetTouchscreenGestureTarget(nullptr); if (!touchscreen_gesture_target_) { root_view->GestureEventAck(gesture_event, @@ -1564,6 +1577,8 @@ } blink::WebGestureEvent event(gesture_event); + if (touchscreen_gesture_target_moved_recently_) + event.SetTargetFrameMovedRecently(); gfx::PointF point_in_target; // This |fallback_target_location| is fast path when @@ -1601,7 +1616,7 @@ gesture_event.GetType() == blink::WebInputEvent::kGestureFlingStart; if (is_gesture_end) - touchscreen_gesture_target_ = nullptr; + SetTouchscreenGestureTarget(nullptr); } void RenderWidgetHostInputEventRouter::RouteTouchscreenGestureEvent( @@ -1789,12 +1804,21 @@ events_being_flushed_ = events_being_flushed; } +void RenderWidgetHostInputEventRouter::SetTouchscreenGestureTarget( + RenderWidgetHostViewBase* target, + bool moved_recently) { + touchscreen_gesture_target_ = target; + touchscreen_gesture_target_moved_recently_ = moved_recently; +} + void RenderWidgetHostInputEventRouter::DispatchEventToTarget( RenderWidgetHostViewBase* root_view, RenderWidgetHostViewBase* target, const blink::WebInputEvent& event, const ui::LatencyInfo& latency, const base::Optional<gfx::PointF>& target_location) { + if (target && target->ScreenRectIsUnstableFor(event)) + event.SetTargetFrameMovedRecently(); if (blink::WebInputEvent::IsMouseEventType(event.GetType())) { DispatchMouseEvent(root_view, target, static_cast<const blink::WebMouseEvent&>(event), latency, @@ -1909,6 +1933,16 @@ rwhi->ShowContextMenuAtPoint(point, source_type); } +void RenderWidgetHostInputEventRouter::OnAggregatedHitTestRegionListUpdated( + const viz::FrameSinkId& frame_sink_id, + const std::vector<viz::AggregatedHitTestRegion>& hit_test_data) { + for (auto& region : hit_test_data) { + auto iter = owner_map_.find(region.frame_sink_id); + if (iter != owner_map_.end()) + iter->second->NotifyHitTestRegionUpdated(region); + } +} + void RenderWidgetHostInputEventRouter::SetMouseCaptureTarget( RenderWidgetHostViewBase* target, bool capture) {
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h index 3fee278b..6afcdf10 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.h +++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -17,6 +17,7 @@ #include "base/memory/weak_ptr.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/host/hit_test/hit_test_query.h" +#include "components/viz/host/hit_test/hit_test_region_observer.h" #include "components/viz/service/surfaces/surface_hittest_delegate.h" #include "content/browser/renderer_host/event_with_latency_info.h" #include "content/browser/renderer_host/input/touch_emulator_client.h" @@ -74,7 +75,8 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter : public RenderWidgetHostViewBaseObserver, public RenderWidgetTargeter::Delegate, - public TouchEmulatorClient { + public TouchEmulatorClient, + public viz::HitTestRegionObserver { public: RenderWidgetHostInputEventRouter(); ~RenderWidgetHostInputEventRouter() final; @@ -166,6 +168,11 @@ void ShowContextMenuAtPoint(const gfx::Point& point, const ui::MenuSourceType source_type) override; + // HitTestRegionObserver + void OnAggregatedHitTestRegionListUpdated( + const viz::FrameSinkId& frame_sink_id, + const std::vector<viz::AggregatedHitTestRegion>& hit_test_data) override; + bool HasEventsPendingDispatch() const; size_t TouchEventAckQueueLengthForTesting() const; @@ -328,10 +335,14 @@ return forced_last_fling_start_target_to_stop_flinging_for_test_; } + void SetTouchscreenGestureTarget(RenderWidgetHostViewBase* target, + bool moved_recently = false); + FrameSinkIdOwnerMap owner_map_; TargetMap touchscreen_gesture_target_map_; RenderWidgetHostViewBase* touch_target_ = nullptr; RenderWidgetHostViewBase* touchscreen_gesture_target_ = nullptr; + bool touchscreen_gesture_target_moved_recently_ = false; RenderWidgetHostViewBase* touchpad_gesture_target_ = nullptr; RenderWidgetHostViewBase* bubbling_gesture_scroll_target_ = nullptr; RenderWidgetHostViewChildFrame* bubbling_gesture_scroll_origin_ = nullptr;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index a2902ad..5a3b90ec 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -624,6 +624,11 @@ host()->DidProcessFrame(frame_token); } +bool RenderWidgetHostViewBase::ScreenRectIsUnstableFor( + const blink::WebInputEvent& event) { + return false; +} + viz::FrameSinkId RenderWidgetHostViewBase::FrameSinkIdAtPoint( viz::SurfaceHittestDelegate* delegate, const gfx::PointF& point,
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 81bdc91..a5f11d9 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -336,6 +336,14 @@ virtual const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() const = 0; + // Called whenever the browser receives updated hit test data from viz. + virtual void NotifyHitTestRegionUpdated( + const viz::AggregatedHitTestRegion& region) {} + + // Indicates whether the widget has resized or moved within its embedding + // page during the 500 milliseconds prior to the event. + virtual bool ScreenRectIsUnstableFor(const blink::WebInputEvent& event); + // When there are multiple RenderWidgetHostViews for a single page, input // events need to be targeted to the correct one for handling. The following // methods are invoked on the RenderWidgetHostView that should be able to
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index f09d356..1eaeb082 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -678,6 +678,36 @@ return viz::ParentLocalSurfaceIdAllocator::InvalidLocalSurfaceIdAllocation(); } +void RenderWidgetHostViewChildFrame::NotifyHitTestRegionUpdated( + const viz::AggregatedHitTestRegion& region) { + gfx::RectF screen_rect(region.rect); + if (!region.transform().TransformRectReverse(&screen_rect)) { + last_stable_screen_rect_ = gfx::RectF(); + screen_rect_stable_since_ = base::TimeTicks::Now(); + return; + } + if ((ToRoundedSize(screen_rect.size()) != + ToRoundedSize(last_stable_screen_rect_.size())) || + (std::abs(last_stable_screen_rect_.x() - screen_rect.x()) + + std::abs(last_stable_screen_rect_.y() - screen_rect.y()) > + blink::kMaxChildFrameScreenRectMovement)) { + last_stable_screen_rect_ = screen_rect; + screen_rect_stable_since_ = base::TimeTicks::Now(); + } +} + +bool RenderWidgetHostViewChildFrame::ScreenRectIsUnstableFor( + const blink::WebInputEvent& event) { + if (event.TimeStamp() - + base::TimeDelta::FromMilliseconds(blink::kMinScreenRectStableTimeMs) < + screen_rect_stable_since_) { + return true; + } + if (RenderWidgetHostViewBase* parent = GetParentView()) + return parent->ScreenRectIsUnstableFor(event); + return false; +} + void RenderWidgetHostViewChildFrame::PreProcessTouchEvent( const blink::WebTouchEvent& event) { if (event.GetType() == blink::WebInputEvent::kTouchStart &&
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h index e3f7971..2658bd9 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.h +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -140,6 +140,8 @@ const viz::FrameSinkId& GetFrameSinkId() const override; const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() const override; + void NotifyHitTestRegionUpdated(const viz::AggregatedHitTestRegion&) override; + bool ScreenRectIsUnstableFor(const blink::WebInputEvent& event) override; void PreProcessTouchEvent(const blink::WebTouchEvent& event) override; viz::FrameSinkId GetRootFrameSinkId() override; viz::SurfaceId GetCurrentSurfaceId() const override; @@ -311,6 +313,9 @@ viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink_ = nullptr; + gfx::RectF last_stable_screen_rect_; + base::TimeTicks screen_rect_stable_since_; + gfx::Insets insets_; std::unique_ptr<TouchSelectionControllerClientChildFrame>
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc index 2f540fb..0749033 100644 --- a/content/browser/renderer_host/render_widget_targeter.cc +++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -465,6 +465,7 @@ FlushEventQueue(true); return; } + delegate_->DispatchEventToTarget(root_view, target, event, latency, target_location); FlushEventQueue(false);
diff --git a/content/browser/renderer_host/web_database_host_impl.cc b/content/browser/renderer_host/web_database_host_impl.cc index 5405fef8..195dd66 100644 --- a/content/browser/renderer_host/web_database_host_impl.cc +++ b/content/browser/renderer_host/web_database_host_impl.cc
@@ -17,7 +17,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/origin_util.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "storage/browser/database/database_util.h" #include "storage/browser/database/vfs_backend.h" #include "storage/browser/quota/quota_manager.h" @@ -90,11 +90,11 @@ void WebDatabaseHostImpl::Create( int process_id, scoped_refptr<storage::DatabaseTracker> db_tracker, - blink::mojom::WebDatabaseHostRequest request) { + mojo::PendingReceiver<blink::mojom::WebDatabaseHost> receiver) { DCHECK(db_tracker->task_runner()->RunsTasksInCurrentSequence()); - mojo::MakeStrongBinding( + mojo::MakeSelfOwnedReceiver( std::make_unique<WebDatabaseHostImpl>(process_id, std::move(db_tracker)), - std::move(request)); + std::move(receiver)); } void WebDatabaseHostImpl::OpenFile(const base::string16& vfs_file_name, @@ -450,15 +450,17 @@ base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI}, base::BindOnce( - [](int process_id, blink::mojom::WebDatabaseRequest request) { + [](int process_id, + mojo::PendingReceiver<blink::mojom::WebDatabase> receiver) { RenderProcessHost* host = RenderProcessHost::FromID(process_id); if (host) { - content::BindInterface(host, std::move(request)); + host->BindInterface(blink::mojom::WebDatabase::Name_, + receiver.PassPipe()); } }, - process_id_, mojo::MakeRequest(&database_provider_))); + process_id_, database_provider_.BindNewPipeAndPassReceiver())); } - return *database_provider_; + return *database_provider_.get(); } void WebDatabaseHostImpl::ValidateOrigin(const url::Origin& origin,
diff --git a/content/browser/renderer_host/web_database_host_impl.h b/content/browser/renderer_host/web_database_host_impl.h index 546eac43..4f4b790 100644 --- a/content/browser/renderer_host/web_database_host_impl.h +++ b/content/browser/renderer_host/web_database_host_impl.h
@@ -12,6 +12,8 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/remote.h" #include "storage/browser/database/database_tracker.h" #include "third_party/blink/public/mojom/webdatabase/web_database.mojom.h" @@ -29,9 +31,10 @@ scoped_refptr<storage::DatabaseTracker> db_tracker); ~WebDatabaseHostImpl() override; - static void Create(int process_id, - scoped_refptr<storage::DatabaseTracker> db_tracker, - blink::mojom::WebDatabaseHostRequest request); + static void Create( + int process_id, + scoped_refptr<storage::DatabaseTracker> db_tracker, + mojo::PendingReceiver<blink::mojom::WebDatabaseHost> receiver); private: FRIEND_TEST_ALL_PREFIXES(WebDatabaseHostImplTest, BadMessagesUnauthorized); @@ -148,7 +151,7 @@ storage::DatabaseConnections database_connections_; // Interface to the render process WebDatabase. - blink::mojom::WebDatabasePtr database_provider_; + mojo::Remote<blink::mojom::WebDatabase> database_provider_; // The database tracker for the current browser context. const scoped_refptr<storage::DatabaseTracker> db_tracker_;
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 0042e01..0f28cbdc 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -203,13 +203,11 @@ scoped_refptr<ServiceWorkerVersion> version, blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr* out_provider_info) { - blink::mojom::ServiceWorkerContainerAssociatedPtrInfo client_ptr_info; - (*out_provider_info)->client_request = mojo::MakeRequest(&client_ptr_info); auto host = base::WrapUnique(new ServiceWorkerProviderHost( blink::mojom::ServiceWorkerProviderType::kForServiceWorker, - true /* is_parent_frame_secure */, FrameTreeNode::kFrameTreeNodeInvalidId, + /*is_parent_frame_secure=*/true, FrameTreeNode::kFrameTreeNodeInvalidId, mojo::MakeRequest(&((*out_provider_info)->host_ptr_info)), - std::move(client_ptr_info), context)); + /*client_ptr_info=*/nullptr, context)); host->running_hosted_version_ = std::move(version); auto weak_ptr = host->AsWeakPtr(); @@ -284,11 +282,15 @@ // controller, and |render_thread_id_| will be set when the service worker // context gets started. render_thread_id_ = kInvalidEmbeddedWorkerThreadId; + + DCHECK(!client_ptr_info); + } else { + DCHECK(client_ptr_info.is_valid()); } context_->RegisterProviderHostByClientID(client_uuid_, this); - DCHECK(client_ptr_info.is_valid() && host_request.is_pending()); + DCHECK(host_request.is_pending()); container_.Bind(std::move(client_ptr_info)); binding_.Bind(std::move(host_request)); }
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc index 8495aec..2699d8b1 100644 --- a/content/browser/service_worker/service_worker_test_utils.cc +++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -233,7 +233,6 @@ void ServiceWorkerRemoteProviderEndpoint::BindForServiceWorker( blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr info) { - client_request_ = std::move(info->client_request); host_ptr_.Bind(std::move(info->host_ptr_info)); }
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 7a540c1..77aefd5 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -30,6 +30,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view.h" #include "content/common/frame_messages.h" +#include "content/common/unfreezable_frame_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/file_select_listener.h" #include "content/public/browser/invalidate_type.h" @@ -3042,6 +3043,44 @@ EXPECT_GT(next_text_length, text_length); } +// Checks that UnfreezableFrameMsg IPCs are executed even when the page is +// frozen. +IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FrozenAndUnfrozenIPC) { + EXPECT_TRUE(embedded_test_server()->Start()); + + GURL url_a(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b,c)")); + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + RenderFrameHostImpl* rfh_a = + static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root() + ->current_frame_host(); + + RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host(); + RenderFrameHostImpl* rfh_c = rfh_a->child_at(1)->current_frame_host(); + RenderFrameDeletedObserver delete_rfh_b(rfh_b); + RenderFrameDeletedObserver delete_rfh_c(rfh_c); + + // Delete an iframe when the page is active(not frozen), which should succeed. + rfh_b->Send(new UnfreezableFrameMsg_Delete( + rfh_b->routing_id(), FrameDeleteIntention::kNotMainFrame)); + delete_rfh_b.WaitUntilDeleted(); + EXPECT_TRUE(delete_rfh_b.deleted()); + EXPECT_FALSE(delete_rfh_c.deleted()); + + // Freeze the blink page. + shell()->web_contents()->WasHidden(); + shell()->web_contents()->SetPageFrozen(true); + + // Try to delete an iframe, and succeeds because the message is unfreezable. + rfh_c->Send(new UnfreezableFrameMsg_Delete( + rfh_c->routing_id(), FrameDeleteIntention::kNotMainFrame)); + delete_rfh_c.WaitUntilDeleted(); + EXPECT_TRUE(delete_rfh_c.deleted()); +} + IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, PopupWindowBrowserNavResumeLoad) { // This test verifies a pop up that requires navigation from browser side @@ -3480,7 +3519,7 @@ std::vector<int> deleted_routing_ids; auto watcher = base::BindRepeating( [](std::vector<int>* deleted_routing_ids, const IPC::Message& message) { - if (message.type() == FrameMsg_Delete::ID) { + if (message.type() == UnfreezableFrameMsg_Delete::ID) { deleted_routing_ids->push_back(message.routing_id()); } },
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.cc b/content/browser/web_package/prefetched_signed_exchange_cache.cc index 1517c606..8c61557 100644 --- a/content/browser/web_package/prefetched_signed_exchange_cache.cc +++ b/content/browser/web_package/prefetched_signed_exchange_cache.cc
@@ -568,14 +568,9 @@ return clone; } -PrefetchedSignedExchangeCache::PrefetchedSignedExchangeCache() { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch) || - base::FeatureList::IsEnabled( - features::kSignedExchangePrefetchCacheForNavigations)); -} +PrefetchedSignedExchangeCache::PrefetchedSignedExchangeCache() = default; -PrefetchedSignedExchangeCache::~PrefetchedSignedExchangeCache() {} +PrefetchedSignedExchangeCache::~PrefetchedSignedExchangeCache() = default; void PrefetchedSignedExchangeCache::Store( std::unique_ptr<const Entry> cached_exchange) { @@ -658,13 +653,6 @@ const base::Time& now) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch)) { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangePrefetchCacheForNavigations)); - return std::vector<PrefetchedSignedExchangeInfo>(); - } - std::vector<PrefetchedSignedExchangeInfo> info_list; const url::Origin outer_url_origin = url::Origin::Create(outer_url); const url::Origin inner_url_origin = url::Origin::Create(inner_url);
diff --git a/content/browser/web_package/signed_exchange_utils.cc b/content/browser/web_package/signed_exchange_utils.cc index a7248ef..f0b23a54 100644 --- a/content/browser/web_package/signed_exchange_utils.cc +++ b/content/browser/web_package/signed_exchange_utils.cc
@@ -223,16 +223,12 @@ std::string buf; std::string link_header; if (!is_fallback_redirect && - base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch) && outer_response.headers) { outer_response.headers->GetNormalizedHeader("link", &link_header); } if (link_header.empty()) { buf = base::StringPrintf("HTTP/1.1 %d %s\r\n", 303, "See Other"); } else { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch)); buf = base::StringPrintf( "HTTP/1.1 %d %s\r\n" "link: %s\r\n",
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 831ca5d..bf3a9ee4 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -356,8 +356,8 @@ if (base::FeatureList::IsEnabled(features::kBuiltInModuleKvStorage)) WebRuntimeFeatures::EnableBuiltInModuleKvStorage(true); - if (base::FeatureList::IsEnabled(blink::features::kLayoutNG)) - WebRuntimeFeatures::EnableLayoutNG(true); + WebRuntimeFeatures::EnableFeatureFromString( + "LayoutNG", base::FeatureList::IsEnabled(blink::features::kLayoutNG)); WebRuntimeFeatures::EnableLazyInitializeMediaControls( base::FeatureList::IsEnabled(features::kLazyInitializeMediaControls));
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index a9ffc95..e0efc58 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -249,6 +249,8 @@ "view_messages.h", "visual_properties.cc", "visual_properties.h", + "web_package/signed_exchange_utils.cc", + "web_package/signed_exchange_utils.h", "widget_messages.h", ]
diff --git a/content/common/cursors/webcursor_aurawin.cc b/content/common/cursors/webcursor_aurawin.cc index 435b85c..a41028e2 100644 --- a/content/common/cursors/webcursor_aurawin.cc +++ b/content/common/cursors/webcursor_aurawin.cc
@@ -18,7 +18,7 @@ if (platform_cursor_) return platform_cursor_; - platform_cursor_ = IconUtil::CreateCursorFromSkBitmap(info_.custom_image, + platform_cursor_ = IconUtil::CreateCursorFromSkBitmap(cursor.GetBitmap(), cursor.GetHotspot()) .release(); return platform_cursor_;
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index ec5376b..06dfed6 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -796,9 +796,6 @@ // commit, activation and frame swap of the current DOM tree in blink. IPC_MESSAGE_ROUTED1(FrameMsg_VisualStateRequest, uint64_t /* id */) -// Instructs the renderer to delete the RenderFrame. -IPC_MESSAGE_ROUTED1(FrameMsg_Delete, content::FrameDeleteIntention) - // Instructs the renderer to invoke the frame's beforeunload event handler. // Expects the result to be returned via FrameHostMsg_BeforeUnload_ACK. IPC_MESSAGE_ROUTED1(FrameMsg_BeforeUnload, bool /* is_reload */)
diff --git a/content/common/unfreezable_frame_messages.h b/content/common/unfreezable_frame_messages.h index df3a4a9..a8b3665 100644 --- a/content/common/unfreezable_frame_messages.h +++ b/content/common/unfreezable_frame_messages.h
@@ -27,4 +27,7 @@ bool /* is_loading */, content::FrameReplicationState /* replication_state */) +// Instructs the renderer to delete the RenderFrame. +IPC_MESSAGE_ROUTED1(UnfreezableFrameMsg_Delete, content::FrameDeleteIntention) + #endif // CONTENT_COMMON_UNFREEZABLE_FRAME_MESSAGES_H_
diff --git a/content/common/web_package/OWNERS b/content/common/web_package/OWNERS new file mode 100644 index 0000000..b02bd90 --- /dev/null +++ b/content/common/web_package/OWNERS
@@ -0,0 +1,4 @@ +file://content/browser/web_package/OWNERS + +# TEAM: loading-dev@chromium.org +# COMPONENT: Blink>Loader>WebPackaging
diff --git a/content/common/web_package/signed_exchange_utils.cc b/content/common/web_package/signed_exchange_utils.cc new file mode 100644 index 0000000..5b39ec6 --- /dev/null +++ b/content/common/web_package/signed_exchange_utils.cc
@@ -0,0 +1,23 @@ +// 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/common/web_package/signed_exchange_utils.h" + +#include "base/base64.h" + +namespace content { +namespace signed_exchange_utils { + +std::string CreateHeaderIntegrityHashString( + const net::SHA256HashValue& header_integrity) { + std::string header_integrity_base64; + base::Base64Encode( + base::StringPiece(reinterpret_cast<const char*>(header_integrity.data), + sizeof(header_integrity.data)), + &header_integrity_base64); + return std::string("sha256-") + header_integrity_base64; +} + +} // namespace signed_exchange_utils +} // namespace content
diff --git a/content/common/web_package/signed_exchange_utils.h b/content/common/web_package/signed_exchange_utils.h new file mode 100644 index 0000000..a60d759f --- /dev/null +++ b/content/common/web_package/signed_exchange_utils.h
@@ -0,0 +1,23 @@ +// 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 CONTENT_COMMON_WEB_PACKAGE_SIGNED_EXCHANGE_UTILS_H_ +#define CONTENT_COMMON_WEB_PACKAGE_SIGNED_EXCHANGE_UTILS_H_ + +#include <string> + +#include "net/base/hash_value.h" + +namespace content { +namespace signed_exchange_utils { + +// Serializes the |header_integrity| hash in the form of +// "sha256-<base64-hash-value>". +std::string CreateHeaderIntegrityHashString( + const net::SHA256HashValue& header_integrity); + +} // namespace signed_exchange_utils +} // namespace content + +#endif // CONTENT_COMMON_WEB_PACKAGE_SIGNED_EXCHANGE_UTILS_H_
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc index 9376447..5cbaa35 100644 --- a/content/renderer/loader/navigation_body_loader.cc +++ b/content/renderer/loader/navigation_body_loader.cc
@@ -53,7 +53,7 @@ redirect_info, redirect_response); WebURLLoaderImpl::PopulateURLResponse( url, redirect_response, &redirect.redirect_response, - false /* report_security_info */, request_id); + response_head.ssl_info.has_value(), request_id); if (url.SchemeIs(url::kDataScheme)) redirect.redirect_response.SetHttpStatusCode(200); redirect.new_url = redirect_info.new_url; @@ -69,7 +69,7 @@ WebURLLoaderImpl::PopulateURLResponse( url, response_head, &navigation_params->response, - false /* report_security_info */, request_id); + response_head.ssl_info.has_value(), request_id); if (url.SchemeIs(url::kDataScheme)) navigation_params->response.SetHttpStatusCode(200);
diff --git a/content/renderer/loader/navigation_body_loader_unittest.cc b/content/renderer/loader/navigation_body_loader_unittest.cc index 18ee5033..77655230 100644 --- a/content/renderer/loader/navigation_body_loader_unittest.cc +++ b/content/renderer/loader/navigation_body_loader_unittest.cc
@@ -9,6 +9,9 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/test/scoped_task_environment.h" +#include "net/cert/x509_util.h" +#include "net/ssl/ssl_connection_status_flags.h" +#include "net/test/cert_test_util.h" #include "services/network/public/cpp/url_loader_completion_status.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -285,6 +288,41 @@ EXPECT_TRUE(error_.has_value()); } +// 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(); + net::CertificateList certs; + ASSERT_TRUE(net::LoadCertificateFiles( + {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs)); + ASSERT_EQ(2U, certs.size()); + + base::StringPiece cert0_der = + net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer()); + base::StringPiece cert1_der = + net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()); + + response.ssl_info->cert = + net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der}); + net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2, + &response.ssl_info->connection_status); + + CommonNavigationParams common_params; + common_params.url = GURL("https://example.test"); + + blink::WebNavigationParams navigation_params; + auto endpoints = network::mojom::URLLoaderClientEndpoints::New(); + NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader( + common_params, CommitNavigationParams(), 1 /* request_id */, response, + mojo::ScopedDataPipeConsumerHandle() /* response_body */, + std::move(endpoints), + blink::scheduler::GetSingleThreadTaskRunnerForTesting(), + 2 /* render_frame_id */, true /* is_main_frame */, &navigation_params); + EXPECT_TRUE( + navigation_params.response.SecurityDetailsForTesting().has_value()); +} + } // namespace } // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 4217051..f03ce01d8 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -11,7 +11,6 @@ #include <vector> #include "base/auto_reset.h" -#include "base/base64.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" @@ -66,7 +65,9 @@ #include "content/common/savable_subframe.h" #include "content/common/service_worker/service_worker_types.h" #include "content/common/swapped_out_messages.h" +#include "content/common/unfreezable_frame_messages.h" #include "content/common/view_messages.h" +#include "content/common/web_package/signed_exchange_utils.h" #include "content/public/common/bind_interface_helpers.h" #include "content/public/common/bindings_policy.h" #include "content/public/common/content_constants.h" @@ -494,8 +495,6 @@ navigation_params->was_discarded = commit_params.was_discarded; if (!commit_params.prefetched_signed_exchanges.empty()) { - DCHECK(base::FeatureList::IsEnabled( - features::kSignedExchangeSubresourcePrefetch)); navigation_params->prefetched_signed_exchanges = WebVector<std::unique_ptr< blink::WebNavigationParams::PrefetchedSignedExchange>>(); @@ -504,18 +503,13 @@ WebURLLoaderImpl::PopulateURLResponse( exchange.inner_url, exchange.inner_response, &web_response, false /* report_security_info*/, -1 /* request_id */); - std::string header_integrity_base64; - base::Base64Encode( - base::StringPiece( - reinterpret_cast<const char*>(exchange.header_integrity.data), - sizeof(exchange.header_integrity.data)), - &header_integrity_base64); navigation_params->prefetched_signed_exchanges.emplace_back( std::make_unique< blink::WebNavigationParams::PrefetchedSignedExchange>( exchange.outer_url, - WebString::FromLatin1(std::string("sha256-") + - header_integrity_base64), + WebString::FromLatin1( + signed_exchange_utils::CreateHeaderIntegrityHashString( + exchange.header_integrity)), exchange.inner_url, web_response, mojo::ScopedMessagePipeHandle(exchange.loader_factory_handle))); } @@ -2223,7 +2217,6 @@ IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload) IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut) IPC_MESSAGE_HANDLER(FrameMsg_SwapIn, OnSwapIn) - IPC_MESSAGE_HANDLER(FrameMsg_Delete, OnDeleteFrame) IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop) IPC_MESSAGE_HANDLER(FrameMsg_DroppedNavigation, OnDroppedNavigation) IPC_MESSAGE_HANDLER(FrameMsg_Collapse, OnCollapse) @@ -2281,6 +2274,7 @@ IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems) #endif #endif + IPC_MESSAGE_HANDLER(UnfreezableFrameMsg_Delete, OnDeleteFrame) IPC_END_MESSAGE_MAP()
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index 0ed20199..fb0791715 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -20,6 +20,7 @@ #include "content/common/frame_messages.h" #include "content/common/frame_owner_properties.h" #include "content/common/renderer.mojom.h" +#include "content/common/unfreezable_frame_messages.h" #include "content/common/widget_messages.h" #include "content/public/common/content_switches.h" #include "content/public/common/previews_state.h" @@ -459,7 +460,8 @@ 1, "foo", true /* match_case */, true /* forward */, false /* find_next */, true /* force */, false /* wrap_within_frame */); - FrameMsg_Delete delete_message(0, FrameDeleteIntention::kNotMainFrame); + UnfreezableFrameMsg_Delete delete_message( + 0, FrameDeleteIntention::kNotMainFrame); frame()->OnMessageReceived(delete_message); }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 28b5e17d..b37f47d 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -2435,12 +2435,17 @@ bool RenderThreadImpl::UnfreezableMessageFilter::OnMessageReceived( const IPC::Message& message) { if ((IPC_MESSAGE_CLASS(message) == UnfreezableFrameMsgStart)) { - return GetUnfreezableTaskRunner(message.routing_id()) - ->PostTask(FROM_HERE, - base::BindOnce( - base::IgnoreResult(&RenderThreadImpl::OnMessageReceived), - base::Unretained(render_thread_impl_), message)); + auto task_runner = GetUnfreezableTaskRunner(message.routing_id()); + if (task_runner) + return task_runner->PostTask( + FROM_HERE, + base::BindOnce( + base::IgnoreResult(&RenderThreadImpl::OnMessageReceived), + base::Unretained(render_thread_impl_), message)); } + // If unfreezable task runner is not found or the message class is not + // UnfreezableFrameMsgStart, return false so that this filter is skipped and + // other handlers can continue executing and handle this message. return false; } @@ -2464,7 +2469,7 @@ auto it = unfreezable_task_runners_.find(routing_id); if (it != unfreezable_task_runners_.end()) return it->second; - return base::ThreadTaskRunnerHandle::Get(); + return nullptr; } RenderThreadImpl::UnfreezableMessageFilter::~UnfreezableMessageFilter() {}
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 2322a9ed..a0d2c24 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -47,17 +47,18 @@ # Conformance expectations # ======================== +# Recent regression of invariance rules +# TODO(kbr): re-add suppressions below once this is removed. +crbug.com/980675 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] + +crbug.com/953120 conformance/programs/program-handling.html [ Failure ] +# TODO(kbr): restore suppression for Android / Qualcomm below after this is fixed. +crbug.com/949249 conformance2/extensions/ovr_multiview2.html [ Failure ] + # Failing new test crbug.com/874620 [ linux nvidia ] conformance2/glsl3/const-struct-from-array-as-function-parameter.html [ Failure ] crbug.com/874620 [ opengl win nvidia ] conformance2/glsl3/const-struct-from-array-as-function-parameter.html [ Failure ] -# Unsuppress after both -# https://chromium-review.googlesource.com/1558678 and -# https://github.com/KhronosGroup/WebGL/pull/2878 land and are rolled -# in. -# TODO(kbr): this is actually crbug.com/angleproject/3285 . -crbug.com/angleproject/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] - # Too slow (take about one hour to run) crbug.com/619403 deqp/functional/gles3/builtinprecision/* [ Skip ] @@ -91,6 +92,9 @@ crbug.com/angleproject/1465 [ win ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ] crbug.com/951628 [ win no-passthrough ] conformance/rendering/blending.html [ Failure ] +# Win / D3D11 backend +crbug.com/angleproject/3388 [ win d3d11 ] conformance2/uniforms/large-uniform-buffers.html [ Failure ] + # Win / NVidia crbug.com/631317 [ d3d11 win nvidia ] deqp/functional/gles3/fbomultisample* [ RetryOnFailure ] crbug.com/679639 [ d3d11 win nvidia ] conformance2/rendering/draw-with-integer-texture-base-level.html [ Failure ] @@ -739,7 +743,8 @@ # Qualcomm (Pixel 2) failures crbug.com/906737 [ android qualcomm ] conformance/extensions/webgl-compressed-texture-astc.html [ Failure ] -crbug.com/906739 [ android qualcomm ] conformance2/extensions/ovr_multiview2.html [ Failure ] +# TODO(kbr): uncomment after http://crbug.com/949249 fixed +# crbug.com/906739 [ android qualcomm ] conformance2/extensions/ovr_multiview2.html [ Failure ] crbug.com/906742 [ android qualcomm ] conformance2/glsl3/compare-structs-containing-arrays.html [ Failure ] crbug.com/906735 [ android qualcomm ] conformance2/textures/video/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html [ Failure ] crbug.com/949321 [ android qualcomm ] deqp/functional/gles3/framebufferblit/default_framebuffer_02.html [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index d039bae9..9d6a10d5 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -66,12 +66,9 @@ # https://github.com/KhronosGroup/WebGL/pull/2607 crbug.com/849572 conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] -# Unsuppress after both -# https://chromium-review.googlesource.com/1558678 and -# https://github.com/KhronosGroup/WebGL/pull/2878 land and are rolled -# in. -# TODO(kbr): this is actually crbug.com/angleproject/3285 . -crbug.com/angleproject/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] +# Recent regression of invariance rules +# TODO(kbr): re-add suppressions below once this is removed. +crbug.com/980675 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] # Nvidia bugs fixed in latest driver # TODO(http://crbug.com/887241): Upgrade the drivers on the bots. @@ -88,6 +85,7 @@ crbug.com/735483 conformance/rendering/texture-switch-performance.html [ Skip ] crbug.com/951628 [ passthrough ] conformance/rendering/blending.html [ Failure ] +crbug.com/953120 conformance/programs/program-handling.html [ Failure ] # TODO(shrekshao): Restore failure expectation for # ['win', 'nvidia', 'passthrough', 'd3d11'], bug=737016 # as Flaky after 953120 is fixed.
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index 799efd0e..26c974a 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision 6f0b34abee8dba611c253738d955c59f703c147a +Current webgl revision 91350f8ecf9ab2922ee062c114e4a759f24bd8d0
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 4aa72fe0..897ef554 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc
@@ -561,7 +561,7 @@ const char kInvalidNativelyConnectable[] = "Invalid natively_connectable. Must be a list."; const char kInvalidNativelyConnectableValue[] = - "Invalid natively_connectable value. Must be a string."; + "Invalid natively_connectable value. Must be a non-empty string."; const char kInvalidNaClModules[] = "Invalid value for 'nacl_modules'."; const char kInvalidNaClModulesPath[] =
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc index fe5e92c..fa8c20f 100644 --- a/extensions/common/permissions/permissions_data.cc +++ b/extensions/common/permissions/permissions_data.cc
@@ -212,12 +212,6 @@ default_policy_allowed_hosts.Clone(); } -void PermissionsData::SetActivePermissions( - std::unique_ptr<const PermissionSet> active) const { - AutoLockOnValidThread lock(runtime_lock_, thread_checker_.get()); - active_permissions_unsafe_ = std::move(active); -} - void PermissionsData::UpdateTabSpecificPermissions( int tab_id, const PermissionSet& permissions) const {
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h index 8131675d..e56cf72e 100644 --- a/extensions/common/permissions/permissions_data.h +++ b/extensions/common/permissions/permissions_data.h
@@ -136,9 +136,6 @@ const URLPatternSet& default_policy_blocked_hosts, const URLPatternSet& default_policy_allowed_hosts); - // Sets the active permissions, leaving withheld the same. - void SetActivePermissions(std::unique_ptr<const PermissionSet> active) const; - // Updates the tab-specific permissions of |tab_id| to include those from // |permissions|. void UpdateTabSpecificPermissions(int tab_id,
diff --git a/google_apis/gaia/gaia_constants.cc b/google_apis/gaia/gaia_constants.cc index 72c9da4..49f84ad 100644 --- a/google_apis/gaia/gaia_constants.cc +++ b/google_apis/gaia/gaia_constants.cc
@@ -42,9 +42,9 @@ const char kChromeSyncSupervisedOAuth2Scope[] = "https://www.googleapis.com/auth/chromesync_playpen"; -// OAuth2 scope for access to Google Family Link kid scope. -const char kKidFamilyOAuth2Scope[] = - "https://www.googleapis.com/auth/kid.family.readonly"; +// OAuth2 scope for access to Google Family Link Supervision Setup. +const char kKidsSupervisionSetupChildOAuth2Scope[] = + "https://www.googleapis.com/auth/kids.supervision.setup.child"; // OAuth2 scope for access to Google Talk APIs (XMPP). const char kGoogleTalkOAuth2Scope[] = @@ -55,7 +55,11 @@ const char kGoogleUserInfoProfile[] = "https://www.googleapis.com/auth/userinfo.profile"; - // Used to mint uber auth tokens when needed. +// OAuth scope for access to the people API (read-only). +const char kPeopleApiReadOnlyOAuth2Scope[] = + "https://www.googleapis.com/auth/peopleapi.readonly"; + +// Used to mint uber auth tokens when needed. const char kGaiaSid[] = "sid"; const char kGaiaLsid[] = "lsid"; const char kGaiaOAuthToken[] = "oauthToken";
diff --git a/google_apis/gaia/gaia_constants.h b/google_apis/gaia/gaia_constants.h index 42e8076..d25d5ff5 100644 --- a/google_apis/gaia/gaia_constants.h +++ b/google_apis/gaia/gaia_constants.h
@@ -26,10 +26,11 @@ extern const char kAnyApiOAuth2Scope[]; extern const char kChromeSyncOAuth2Scope[]; extern const char kChromeSyncSupervisedOAuth2Scope[]; -extern const char kKidFamilyOAuth2Scope[]; +extern const char kKidsSupervisionSetupChildOAuth2Scope[]; extern const char kGoogleTalkOAuth2Scope[]; extern const char kGoogleUserInfoEmail[]; extern const char kGoogleUserInfoProfile[]; +extern const char kPeopleApiReadOnlyOAuth2Scope[]; // Used with uber auth tokens when needed. extern const char kGaiaSid[];
diff --git a/headless/test/data/protocol/sanity/renderer-javascript-console-errors-expected.txt b/headless/test/data/protocol/sanity/renderer-javascript-console-errors-expected.txt index 82f579b2..6d50619 100644 --- a/headless/test/data/protocol/sanity/renderer-javascript-console-errors-expected.txt +++ b/headless/test/data/protocol/sanity/renderer-javascript-console-errors-expected.txt
@@ -1,6 +1,6 @@ Tests renderer: verify JavaScript console errors reporting. requested url: http://example.com/foobar -Uncaught SyntaxError: Unexpected token < +Uncaught SyntaxError: Unexpected token '<' Uncaught ReferenceError: func1 is not defined Uncaught ReferenceError: func2 is not defined Hello, Script!
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc index 536f634..30bc779 100644 --- a/headless/test/headless_browser_test.cc +++ b/headless/test/headless_browser_test.cc
@@ -214,9 +214,9 @@ } void HeadlessBrowserTest::RunAsynchronousTest() { - base::MessageLoopCurrent::ScopedNestableTaskAllower nestable_allower; EXPECT_FALSE(run_loop_); - run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_ = std::make_unique<base::RunLoop>( + base::RunLoop::Type::kNestableTasksAllowed); PreRunAsynchronousTest(); run_loop_->Run(); PostRunAsynchronousTest();
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc index 931fc0fe..503cba1 100644 --- a/headless/test/headless_protocol_browsertest.cc +++ b/headless/test/headless_protocol_browsertest.cc
@@ -345,11 +345,8 @@ HEADLESS_PROTOCOL_COMPOSITOR_TEST( RendererOverrideTitleJsDisabled, "sanity/renderer-override-title-js-disabled.js") -// TODO(crbug.com/943636): rebaseline and re-enable once -// https://chromium-review.googlesource.com/c/v8/v8/+/1593307 is rolled into -// chromium. HEADLESS_PROTOCOL_COMPOSITOR_TEST( - DISABLED_RendererJavaScriptConsoleErrors, + RendererJavaScriptConsoleErrors, "sanity/renderer-javascript-console-errors.js") HEADLESS_PROTOCOL_COMPOSITOR_TEST(RendererDelayedCompletion, "sanity/renderer-delayed-completion.js")
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index 1835994..477063e 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -119,6 +119,7 @@ "//base", "//components/strings", "//ios/chrome/browser/signin:feature_flags", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/collection_view", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/content_suggestions/cells:cells_ui",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn index 7b4f0ed4..3cce84d 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -54,6 +54,7 @@ deps = [ "//base", "//ios/chrome/app/strings", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/collection_view", "//ios/chrome/browser/ui/colors", "//ios/chrome/browser/ui/content_suggestions/identifier",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm index 9233be5..a01a3d0 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/i18n_string.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" @@ -71,15 +72,6 @@ @implementation ContentSuggestionsCell -@synthesize titleLabel = _titleLabel; -@synthesize imageContainer = _imageContainer; -@synthesize noImageIcon = _noImageIcon; -@synthesize additionalInformationLabel = _additionalInformationLabel; -@synthesize contentImageView = _contentImageView; -@synthesize faviconView = _faviconView; -@synthesize imageSizeConstraint = _imageSizeConstraint; -@synthesize displayImage = _displayImage; - - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { @@ -202,6 +194,10 @@ CGFloat additionalInfoHeight = [additionalInfoLabel sizeThatFits:sizeForLabels].height; labelHeight += MAX(additionalInfoHeight, kFaviconSize); + // Add extra space at the bottom for separators between cells. + if (base::FeatureList::IsEnabled(kOptionalArticleThumbnail)) { + return MAX(minimalHeight, labelHeight) + kStandardSpacing; + } return MAX(minimalHeight, labelHeight); } @@ -287,7 +283,7 @@ [_faviconView.widthAnchor constraintEqualToAnchor:_faviconView.heightAnchor], [_faviconView.topAnchor - constraintGreaterThanOrEqualToAnchor:self.titleLabel.bottomAnchor + constraintGreaterThanOrEqualToAnchor:_titleLabel.bottomAnchor constant:kSmallSpacing], // No image icon. @@ -299,6 +295,15 @@ [_noImageIcon.heightAnchor constraintEqualToAnchor:_noImageIcon.widthAnchor] ]]; + // Prevent _additionalInformationLabel from overlapping with _titleLabel when + // a11y font size is used. + if (base::FeatureList::IsEnabled(kOptionalArticleThumbnail)) { + [_additionalInformationLabel.topAnchor + constraintGreaterThanOrEqualToAnchor:_titleLabel.bottomAnchor + constant:kSmallSpacing] + .active = YES; + } + AddSameConstraints(_contentImageView, _imageContainer); _imageTitleHorizontalSpacing = [_titleLabel.leadingAnchor
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm index e13f1274..f7cb214 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -228,8 +228,6 @@ self.headerView = base::mac::ObjCCastStrict<ContentSuggestionsHeaderView>(self.view); [self addFakeTapView]; - if (IsIdentityDiscFeatureEnabled()) - [self addIdentityDisc]; [self addFakeOmnibox]; [self.headerView addSubview:self.logoVendor.view]; @@ -239,6 +237,11 @@ [self.headerView addSeparatorToSearchField:self.fakeOmnibox]; + // Identity disc needs to be added after the Google logo/doodle since it + // needs to respond to user taps first. + if (IsIdentityDiscFeatureEnabled()) + [self addIdentityDisc]; + // -headerForView is regularly called before self.headerView has been added // to the view hierarchy, so there's no simple way to get the correct // safeAreaInsets. Since this situation is universally called for the full
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm index ebe9d32f..adba584 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -25,6 +25,7 @@ #import "ios/chrome/browser/ui/ntp_tile_views/ntp_tile_layout_util.h" #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" @@ -398,12 +399,19 @@ CGSize size = [super collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:indexPath]; + + // No need to add extra spacing if kOptionalArticleThumbnail is enabled, + // because each cell already has spacing at top and bottom for separators. + if (base::FeatureList::IsEnabled(kOptionalArticleThumbnail)) { + return size; + } + // Special case for last item to add extra spacing before the footer. if ([self.collectionUpdater isContentSuggestionsSection:indexPath.section] && indexPath.row == - [self.collectionView numberOfItemsInSection:indexPath.section] - 1) + [self.collectionView numberOfItemsInSection:indexPath.section] - 1) { size.height += [ContentSuggestionsCell standardSpacing]; - + } return size; } @@ -511,6 +519,12 @@ - (BOOL)collectionView:(UICollectionView*)collectionView shouldHideItemSeparatorAtIndexPath:(NSIndexPath*)indexPath { + // If kOptionalArticleThumbnail is enabled, show separators for all cells in + // content suggestion sections. + if (base::FeatureList::IsEnabled(kOptionalArticleThumbnail)) { + return ! + [self.collectionUpdater isContentSuggestionsSection:indexPath.section]; + } // Special case, show a seperator between the last regular item and the // footer. if (![self.collectionUpdater
diff --git a/media/base/demuxer_stream.h b/media/base/demuxer_stream.h index fff2f3a..83bdd16 100644 --- a/media/base/demuxer_stream.h +++ b/media/base/demuxer_stream.h
@@ -73,6 +73,10 @@ typedef base::Callback<void(Status, scoped_refptr<DecoderBuffer>)> ReadCB; virtual void Read(const ReadCB& read_cb) = 0; + // Returns true if a Read() call has been made but the |read_cb| has not yet + // been run. + virtual bool IsReadPending() const = 0; + // Returns the audio/video decoder configuration. It is an error to call the // audio method on a video stream and vice versa. After |kConfigChanged| is // returned in a Read(), the caller should call this method again to retrieve
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc index fe74fc7..5f601f1 100644 --- a/media/base/fake_demuxer_stream.cc +++ b/media/base/fake_demuxer_stream.cc
@@ -79,6 +79,10 @@ DoRead(); } +bool FakeDemuxerStream::IsReadPending() const { + return !read_cb_.is_null(); +} + AudioDecoderConfig FakeDemuxerStream::audio_decoder_config() { DCHECK(task_runner_->BelongsToCurrentThread()); NOTREACHED();
diff --git a/media/base/fake_demuxer_stream.h b/media/base/fake_demuxer_stream.h index 88e9120..590b32a 100644 --- a/media/base/fake_demuxer_stream.h +++ b/media/base/fake_demuxer_stream.h
@@ -30,6 +30,7 @@ // DemuxerStream implementation. void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; Type type() const override;
diff --git a/media/base/fake_text_track_stream.cc b/media/base/fake_text_track_stream.cc index e92287f..43178a6 100644 --- a/media/base/fake_text_track_stream.cc +++ b/media/base/fake_text_track_stream.cc
@@ -37,6 +37,10 @@ } } +bool FakeTextTrackStream::IsReadPending() const { + return !read_cb_.is_null(); +} + DemuxerStream::Type FakeTextTrackStream::type() const { return DemuxerStream::TEXT; }
diff --git a/media/base/fake_text_track_stream.h b/media/base/fake_text_track_stream.h index d93e546..2e121c1c 100644 --- a/media/base/fake_text_track_stream.h +++ b/media/base/fake_text_track_stream.h
@@ -26,6 +26,7 @@ // DemuxerStream implementation. void Read(const ReadCB&) override; + bool IsReadPending() const override; MOCK_METHOD0(audio_decoder_config, AudioDecoderConfig()); MOCK_METHOD0(video_decoder_config, VideoDecoderConfig()); Type type() const override;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index df5cb56..4b522e27 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -183,6 +183,7 @@ Type type() const override; Liveness liveness() const override; MOCK_METHOD1(Read, void(const ReadCB& read_cb)); + MOCK_CONST_METHOD0(IsReadPending, bool()); AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; MOCK_METHOD0(EnableBitstreamConverter, void());
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 18255d9..843d4f54 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc
@@ -307,6 +307,11 @@ CompletePendingReadIfPossible_Locked(); } +bool ChunkDemuxerStream::IsReadPending() const { + base::AutoLock auto_lock(lock_); + return !read_cb_.is_null(); +} + DemuxerStream::Type ChunkDemuxerStream::type() const { return type_; } DemuxerStream::Liveness ChunkDemuxerStream::liveness() const {
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index c7d06c3f6..f1951f01 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h
@@ -119,6 +119,7 @@ // DemuxerStream methods. void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; Type type() const override; Liveness liveness() const override; AudioDecoderConfig audio_decoder_config() override;
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index ba9fc08..c5dbfb7 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc
@@ -89,6 +89,10 @@ base::Bind(&DecryptingDemuxerStream::DecryptBuffer, weak_this_)); } +bool DecryptingDemuxerStream::IsReadPending() const { + return !read_cb_.is_null(); +} + void DecryptingDemuxerStream::Reset(const base::Closure& closure) { DVLOG(2) << __func__ << " - state: " << state_; DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h index b0e03731..14b0809 100644 --- a/media/filters/decrypting_demuxer_stream.h +++ b/media/filters/decrypting_demuxer_stream.h
@@ -56,6 +56,7 @@ // DemuxerStream implementation. void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; Type type() const override;
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 19b29d8..7514b53 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc
@@ -760,6 +760,10 @@ SatisfyPendingRead(); } +bool FFmpegDemuxerStream::IsReadPending() const { + return !read_cb_.is_null(); +} + void FFmpegDemuxerStream::EnableBitstreamConverter() { DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 8246f09..322dc1a7 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h
@@ -113,6 +113,7 @@ Type type() const override; Liveness liveness() const override; void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; void EnableBitstreamConverter() override; bool SupportsConfigChanges() override; AudioDecoderConfig audio_decoder_config() override;
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc index d1f4194..7262689 100644 --- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc +++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
@@ -436,6 +436,9 @@ output_buffer_coded_size_.SetSize(format.fmt.pix_mp.width, format.fmt.pix_mp.height); output_buffer_num_planes_ = format.fmt.pix_mp.num_planes; + for (size_t i = 0; i < output_buffer_num_planes_; ++i) { + output_bytesperlines_[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline; + } VideoPixelFormat output_format = V4L2Device::V4L2PixFmtToVideoPixelFormat(output_buffer_pixelformat_); @@ -714,12 +717,13 @@ } } else if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV420M || output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV422M) { + DCHECK(output_buffer_num_planes_ == 3); uint8_t* src_y = static_cast<uint8_t*>(output_buffer.address[0]); uint8_t* src_u = static_cast<uint8_t*>(output_buffer.address[1]); uint8_t* src_v = static_cast<uint8_t*>(output_buffer.address[2]); - size_t src_y_stride = output_buffer_coded_size_.width(); - size_t src_u_stride = output_buffer_coded_size_.width() / 2; - size_t src_v_stride = output_buffer_coded_size_.width() / 2; + size_t src_y_stride = output_bytesperlines_[0]; + size_t src_u_stride = output_bytesperlines_[1]; + size_t src_v_stride = output_bytesperlines_[2]; if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV420M) { if (libyuv::I420Copy(src_y, src_y_stride, src_u, src_u_stride, src_v, src_v_stride, dst_y, dst_y_stride, dst_u,
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h index b0c9442c..3cdc97e 100644 --- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h +++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
@@ -139,6 +139,7 @@ // Number of physical planes the output buffers have. size_t output_buffer_num_planes_; + size_t output_bytesperlines_[VIDEO_MAX_PLANES]; // ChildThread's task runner. scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter.cc b/media/mojo/services/mojo_demuxer_stream_adapter.cc index 9f2f7f7..eb7f91f8 100644 --- a/media/mojo/services/mojo_demuxer_stream_adapter.cc +++ b/media/mojo/services/mojo_demuxer_stream_adapter.cc
@@ -43,6 +43,10 @@ weak_factory_.GetWeakPtr())); } +bool MojoDemuxerStreamAdapter::IsReadPending() const { + return !read_cb_.is_null(); +} + AudioDecoderConfig MojoDemuxerStreamAdapter::audio_decoder_config() { DCHECK_EQ(type_, AUDIO); return audio_config_;
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter.h b/media/mojo/services/mojo_demuxer_stream_adapter.h index a20950b..4a43715 100644 --- a/media/mojo/services/mojo_demuxer_stream_adapter.h +++ b/media/mojo/services/mojo_demuxer_stream_adapter.h
@@ -38,6 +38,7 @@ // DemuxerStream implementation. void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; Type type() const override;
diff --git a/media/remoting/fake_media_resource.cc b/media/remoting/fake_media_resource.cc index 61a854e..6b6c3e9 100644 --- a/media/remoting/fake_media_resource.cc +++ b/media/remoting/fake_media_resource.cc
@@ -49,6 +49,10 @@ read_cb.Run(kOk, buffer); } +bool FakeDemuxerStream::IsReadPending() const { + return !pending_read_cb_.is_null(); +} + AudioDecoderConfig FakeDemuxerStream::audio_decoder_config() { return audio_config_; }
diff --git a/media/remoting/fake_media_resource.h b/media/remoting/fake_media_resource.h index 5d4f9795..65db686 100644 --- a/media/remoting/fake_media_resource.h +++ b/media/remoting/fake_media_resource.h
@@ -23,6 +23,7 @@ // DemuxerStream implementation. MOCK_METHOD1(Read, void(const ReadCB& read_cb)); void FakeRead(const ReadCB& read_cb); + bool IsReadPending() const override; AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; Type type() const override;
diff --git a/media/remoting/stream_provider.cc b/media/remoting/stream_provider.cc index 12598b59..3bc559e 100644 --- a/media/remoting/stream_provider.cc +++ b/media/remoting/stream_provider.cc
@@ -35,6 +35,7 @@ // DemuxerStream implementation. void Read(const ReadCB& read_cb) override; + bool IsReadPending() const override; AudioDecoderConfig audio_decoder_config() override; VideoDecoderConfig video_decoder_config() override; DemuxerStream::Type type() const override; @@ -315,6 +316,10 @@ CompleteRead(DemuxerStream::kOk); } +bool MediaStream::IsReadPending() const { + return !read_complete_callback_.is_null(); +} + void MediaStream::CompleteRead(DemuxerStream::Status status) { DVLOG(3) << __func__ << ": " << status; switch (status) {
diff --git a/mojo/public/js/interface_support.js b/mojo/public/js/interface_support.js index 5c5423cb..36ec5dd7 100644 --- a/mojo/public/js/interface_support.js +++ b/mojo/public/js/interface_support.js
@@ -520,20 +520,28 @@ }; /** - * Listens for incoming request messages on a message pipe, dispatching them to - * any registered handlers. Handlers are registered against a specific ordinal - * message number. + * Generic helper that listens for incoming request messages on a message pipe, + * dispatching them to any registered handlers. Handlers are registered against + * a specific ordinal message number. It has methods to perform operations + * related to the interface pipe e.g. bind the pipe, close it, etc. Should only + * be used by the generated receiver classes. + * @template T * @export */ -mojo.internal.interfaceSupport.InterfaceReceiver = class { - /** @public */ - constructor() { +mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal = class { + /** + * @param {!function(new:T)} remoteType + * @public + */ + constructor(remoteType) { /** * @private {!Map<MojoHandle, * !mojo.internal.interfaceSupport.HandleReader>} */ this.readers_ = new Map; + /** @private {!function(new:T)} */ + this.remoteType_ = remoteType; /** * @private {!Map<number, !mojo.internal.interfaceSupport.MessageHandler>} */ @@ -575,6 +583,16 @@ new mojo.internal.interfaceSupport.ControlMessageHandler(handle); } + /** + * @return {!T} + * @export + */ + bindNewPipeAndPassRemote() { + let remote = new this.remoteType_; + this.bindHandle(remote.$.bindNewPipeAndPassReceiver().handle); + return remote; + } + /** @export */ closeBindings() { for (const reader of this.readers_.values()) @@ -663,9 +681,68 @@ }; /** + * Generic helper used to perform operations related to the interface pipe e.g. + * bind the pipe, close it, flush it for testing, etc. Wraps + * mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal and exposes a + * subset of methods that meant to be used by users of a receiver class. + * + * @template T + * @export + */ +mojo.internal.interfaceSupport.InterfaceReceiverHelper = class { + /** + * @param {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<T>} + * helper_internal + * @public + */ + constructor(helper_internal) { + /** + * @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<T>} + */ + this.helper_internal_ = helper_internal; + } + + /** + * Binds a new handle to this object. Messages which arrive on the handle will + * be read and dispatched to this object. + * + * @param {!MojoHandle} handle + * @export + */ + bindHandle(handle) { + this.helper_internal_.bindHandle(handle); + } + + // TODO(ortuno): Remove once new names are used in the exposed interfaces. + /** + * Returns a remote for this interface which sends messages directly to this + * object. Any number of proxies may be created to the same object. + * + * @return {!T} + * @export + */ + createProxy() { + return this.helper_internal_.bindNewPipeAndPassRemote(); + } + + /** + * @return {!T} + * @export + */ + bindNewPipeAndPassRemote() { + return this.helper_internal_.bindNewPipeAndPassRemote(); + } + + /** @export */ + close() { + this.helper_internal_.closeBindings(); + } +} + +/** * Watches a MojoHandle for readability or peer closure, forwarding either event * to one of two callbacks on the reader. Used by both InterfaceRemoteBase and - * InterfaceReceiver to watch for incoming messages. + * InterfaceReceiverHelperInternal to watch for incoming messages. */ mojo.internal.interfaceSupport.HandleReader = class { /**
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl index afe81e5..4109319 100644 --- a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
@@ -114,11 +114,19 @@ * @param {!{{module.namespace}}.{{interface.name}}Interface } impl */ constructor(impl) { - this.receiver_ = new mojo.internal.interfaceSupport.InterfaceReceiver; + /** @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<!{{module.namespace}}.{{interface.name}}Proxy>} */ + this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal( + {{module.namespace}}.{{interface.name}}Proxy); + + /** + * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}Proxy>} + */ + this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_); + {% for method in interface.methods %} {%- set interface_message_id = interface.mojom_name ~ "_" ~ method.mojom_name %} - this.receiver_.registerHandler( + this.helper_internal_.registerHandler( {{method.ordinal}}, {{module.namespace}}.{{interface_message_id}}_ParamsSpec.$, {%- if method.response_parameters != None %} @@ -129,27 +137,7 @@ impl.{{method.name}}.bind(impl)); {%- endfor %} /** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */ - this.onConnectionError = this.receiver_.getConnectionErrorEventRouter(); - } - - /** - * Binds a new handle to this object. Messages which arrive on the handle will - * be read and dispatched to this object. - * - * @param {!MojoHandle} handle - * @export - */ - bindHandle(handle) { - this.receiver_.bindHandle(handle); - } - - /** - * Closes all bindings bound to this target. - * - * @export - */ - closeBindings() { - this.receiver_.closeBindings(); + this.onConnectionError = this.helper_internal_.getConnectionErrorEventRouter(); } /** @@ -166,19 +154,6 @@ proxy.$.bindNewPipeAndPassReceiver().handle); return proxy; } - - /** - * Returns a proxy for this interface which sends messages directly to this - * object. Any number of proxies may be created to the same object. - * - * @return {!{{module.namespace}}.{{interface.name}}Proxy} - * @export - */ - createProxy() { - let proxy = new {{module.namespace}}.{{interface.name}}Proxy; - this.receiver_.bindHandle(proxy.$.bindNewPipeAndPassReceiver().handle); - return proxy; - } }; {#--- Enums #} @@ -206,7 +181,14 @@ */ {{module.namespace}}.{{interface.name}}CallbackRouter = class { constructor() { - this.receiver_ = new mojo.internal.interfaceSupport.InterfaceReceiver; + this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal( + {{module.namespace}}.{{interface.name}}Proxy); + + /** + * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}Proxy>} + */ + this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_); + this.router_ = new mojo.internal.interfaceSupport.CallbackRouter; {% for method in interface.methods %} {%- set interface_message_id = @@ -218,7 +200,7 @@ new mojo.internal.interfaceSupport.InterfaceCallbackReceiver( this.router_); - this.receiver_.registerHandler( + this.helper_internal_.registerHandler( {{method.ordinal}}, {{module.namespace}}.{{interface_message_id}}_ParamsSpec.$, {%- if method.response_parameters != None %} @@ -230,39 +212,7 @@ {%- endif %} {%- endfor %} /** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */ - this.onConnectionError = this.receiver_.getConnectionErrorEventRouter(); - } - - /** - * Binds a new handle to this object. Messages which arrive on the handle will - * be read and dispatched as callbacks on this object. - * - * @param {!MojoHandle} handle - * @export - */ - bindHandle(handle) { - this.receiver_.bindHandle(handle); - } - - /** - * Closes all bindings bound to this receiver. The receiver will not receive any - * further message message events unless rebound to one or more handles. - */ - closeBindings() { - this.receiver_.closeBindings(); - } - - /** - * Returns a proxy for this interface which sends messages directly to this - * object. Any number of proxies may be created to the same object. - * - * @return {!{{module.namespace}}.{{interface.name}}Proxy} - * @export - */ - createProxy() { - let proxy = new {{module.namespace}}.{{interface.name}}Proxy; - this.receiver_.bindHandle(proxy.$.bindNewPipeAndPassReceiver().handle); - return proxy; + this.onConnectionError = this.helper_internal_.getConnectionErrorEventRouter(); } /**
diff --git a/net/BUILD.gn b/net/BUILD.gn index ae69336d..b271a568 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -574,6 +574,7 @@ "cert/ev_root_ca_metadata.h", "cert/internal/system_trust_store.cc", "cert/internal/system_trust_store.h", + "cert/internal/system_trust_store_nss.h", "cert/internal/trust_store_mac.cc", "cert/internal/trust_store_mac.h", "cert/internal/trust_store_nss.cc", @@ -878,6 +879,8 @@ "nqe/effective_connection_type_observer.h", "nqe/event_creator.cc", "nqe/event_creator.h", + "nqe/network_congestion_analyzer.cc", + "nqe/network_congestion_analyzer.h", "nqe/network_id.cc", "nqe/network_id.h", "nqe/network_qualities_prefs_manager.cc", @@ -1952,6 +1955,7 @@ if (!use_nss_certs) { sources -= [ + "cert/internal/system_trust_store_nss.h", "cert/internal/trust_store_nss.cc", "cert/internal/trust_store_nss.h", "cert/known_roots_nss.cc", @@ -5095,6 +5099,7 @@ "cert/internal/revocation_util_unittest.cc", "cert/internal/signature_algorithm_unittest.cc", "cert/internal/simple_path_builder_delegate_unittest.cc", + "cert/internal/system_trust_store_nss_unittest.cc", "cert/internal/test_helpers.cc", "cert/internal/test_helpers.h", "cert/internal/trust_store_collection_unittest.cc", @@ -5225,6 +5230,7 @@ "log/trace_net_log_observer_unittest.cc", "nqe/effective_connection_type_unittest.cc", "nqe/event_creator_unittest.cc", + "nqe/network_congestion_analyzer_unittest.cc", "nqe/network_id_unittest.cc", "nqe/network_qualities_prefs_manager_unittest.cc", "nqe/network_quality_estimator_params_unittest.cc", @@ -5862,6 +5868,7 @@ if (!use_nss_certs) { sources -= [ + "cert/internal/system_trust_store_nss_unittest.cc", "cert/internal/trust_store_nss_unittest.cc", "cert/nss_cert_database_unittest.cc", "cert/x509_util_nss_unittest.cc",
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc index 29cd2b83..906b843 100644 --- a/net/cert/cert_verify_proc.cc +++ b/net/cert/cert_verify_proc.cc
@@ -461,8 +461,10 @@ scoped_refptr<CertVerifyProc> CertVerifyProc::CreateDefault( scoped_refptr<CertNetFetcher> cert_net_fetcher) { #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) - if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature)) - return CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher)); + if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature)) { + return CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher), + /*system_trust_store_provider=*/nullptr); + } #endif #if defined(USE_NSS_CERTS) return new CertVerifyProcNSS(); @@ -475,7 +477,8 @@ #elif defined(OS_WIN) return new CertVerifyProcWin(); #elif defined(OS_FUCHSIA) - return CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher)); + return CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher), + /*system_trust_store_provider=*/nullptr); #else #error Unsupported platform #endif
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc index 60706a5..1b883e0 100644 --- a/net/cert/cert_verify_proc_builtin.cc +++ b/net/cert/cert_verify_proc_builtin.cc
@@ -258,7 +258,9 @@ class CertVerifyProcBuiltin : public CertVerifyProc { public: - explicit CertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher); + CertVerifyProcBuiltin( + scoped_refptr<CertNetFetcher> net_fetcher, + std::unique_ptr<SystemTrustStoreProvider> system_trust_store_provider); bool SupportsAdditionalTrustAnchors() const override; @@ -276,11 +278,14 @@ CertVerifyResult* verify_result) override; scoped_refptr<CertNetFetcher> net_fetcher_; + std::unique_ptr<SystemTrustStoreProvider> system_trust_store_provider_; }; CertVerifyProcBuiltin::CertVerifyProcBuiltin( - scoped_refptr<CertNetFetcher> net_fetcher) - : net_fetcher_(std::move(net_fetcher)) {} + scoped_refptr<CertNetFetcher> net_fetcher, + std::unique_ptr<SystemTrustStoreProvider> system_trust_store_provider) + : net_fetcher_(std::move(net_fetcher)), + system_trust_store_provider_(std::move(system_trust_store_provider)) {} CertVerifyProcBuiltin::~CertVerifyProcBuiltin() = default; @@ -589,7 +594,9 @@ // Parse the additional trust anchors and setup trust store. std::unique_ptr<SystemTrustStore> ssl_trust_store = - CreateSslSystemTrustStore(); + system_trust_store_provider_ + ? system_trust_store_provider_->CreateSystemTrustStore() + : CreateSslSystemTrustStore(); for (const auto& x509_cert : additional_trust_anchors) { scoped_refptr<ParsedCertificate> cert = @@ -676,8 +683,10 @@ } // namespace scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin( - scoped_refptr<CertNetFetcher> net_fetcher) { - return base::MakeRefCounted<CertVerifyProcBuiltin>(std::move(net_fetcher)); + scoped_refptr<CertNetFetcher> net_fetcher, + std::unique_ptr<SystemTrustStoreProvider> system_trust_store_provider) { + return base::MakeRefCounted<CertVerifyProcBuiltin>( + std::move(net_fetcher), std::move(system_trust_store_provider)); } } // namespace net
diff --git a/net/cert/cert_verify_proc_builtin.h b/net/cert/cert_verify_proc_builtin.h index 97b7741..da2ddac 100644 --- a/net/cert/cert_verify_proc_builtin.h +++ b/net/cert/cert_verify_proc_builtin.h
@@ -5,6 +5,8 @@ #ifndef NET_CERT_CERT_VERIFY_PROC_BUILTIN_H_ #define NET_CERT_CERT_VERIFY_PROC_BUILTIN_H_ +#include <memory> + #include "base/memory/ref_counted.h" #include "net/base/net_export.h" @@ -12,12 +14,33 @@ class CertNetFetcher; class CertVerifyProc; +class SystemTrustStore; + +// Will be used to create the system trust store. Implementations must be +// thread-safe - CreateSystemTrustStore may be invoked concurrently on worker +// threads. +class NET_EXPORT SystemTrustStoreProvider { + public: + virtual ~SystemTrustStoreProvider() {} + + // Create and return a SystemTrustStore to be used during certificate + // verification. + // This function may be invoked concurrently on worker threads and must be + // thread-safe. However, the returned SystemTrustStore will only be used on + // a single thread. + virtual std::unique_ptr<SystemTrustStore> CreateSystemTrustStore() = 0; +}; // TODO(crbug.com/649017): This is not how other cert_verify_proc_*.h are // implemented -- they expose the type in the header. Use a consistent style // here too. +// If |system_trust_store_provider| is null, the default SystemTrustStore will +// be created. +// If |system_trust_store_provider| is non-null, it will be used to create the +// SystemTrustStore instance for certificate verification. NET_EXPORT scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin( - scoped_refptr<CertNetFetcher> net_fetcher); + scoped_refptr<CertNetFetcher> net_fetcher, + std::unique_ptr<SystemTrustStoreProvider> system_trust_store_provider); } // namespace net
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc index b5e8795..64dd416 100644 --- a/net/cert/cert_verify_proc_unittest.cc +++ b/net/cert/cert_verify_proc_unittest.cc
@@ -211,7 +211,9 @@ return new CertVerifyProcWin(); #endif case CERT_VERIFY_PROC_BUILTIN: - return CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher)); + return CreateCertVerifyProcBuiltin( + std::move(cert_net_fetcher), + nullptr /* system_trust_store_provider */); default: return nullptr; }
diff --git a/net/cert/internal/system_trust_store.cc b/net/cert/internal/system_trust_store.cc index 4629092e..e8b1e31 100644 --- a/net/cert/internal/system_trust_store.cc +++ b/net/cert/internal/system_trust_store.cc
@@ -5,6 +5,10 @@ #include "net/cert/internal/system_trust_store.h" #if defined(USE_NSS_CERTS) +#include "net/cert/internal/system_trust_store_nss.h" +#endif // defined(USE_NSS_CERTS) + +#if defined(USE_NSS_CERTS) #include <cert.h> #include <pk11pub.h> #elif defined(OS_MACOSX) && !defined(OS_IOS) @@ -73,8 +77,9 @@ class SystemTrustStoreNSS : public BaseSystemTrustStore { public: - explicit SystemTrustStoreNSS() : trust_store_nss_(trustSSL) { - trust_store_.AddTrustStore(&trust_store_nss_); + explicit SystemTrustStoreNSS(std::unique_ptr<TrustStoreNSS> trust_store_nss) + : trust_store_nss_(std::move(trust_store_nss)) { + trust_store_.AddTrustStore(trust_store_nss_.get()); // When running in test mode, also layer in the test-only root certificates. // @@ -112,13 +117,27 @@ } private: - TrustStoreNSS trust_store_nss_; + std::unique_ptr<TrustStoreNSS> trust_store_nss_; }; } // namespace std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { - return std::make_unique<SystemTrustStoreNSS>(); + return std::make_unique<SystemTrustStoreNSS>( + std::make_unique<TrustStoreNSS>(trustSSL)); +} + +std::unique_ptr<SystemTrustStore> +CreateSslSystemTrustStoreNSSWithUserSlotRestriction( + crypto::ScopedPK11Slot user_slot) { + return std::make_unique<SystemTrustStoreNSS>( + std::make_unique<TrustStoreNSS>(trustSSL, std::move(user_slot))); +} + +std::unique_ptr<SystemTrustStore> +CreateSslSystemTrustStoreNSSWithNoUserSlots() { + return std::make_unique<SystemTrustStoreNSS>(std::make_unique<TrustStoreNSS>( + trustSSL, TrustStoreNSS::DisallowTrustForCertsOnUserSlots())); } #elif defined(OS_MACOSX) && !defined(OS_IOS)
diff --git a/net/cert/internal/system_trust_store_nss.h b/net/cert/internal/system_trust_store_nss.h new file mode 100644 index 0000000..b7037d5 --- /dev/null +++ b/net/cert/internal/system_trust_store_nss.h
@@ -0,0 +1,33 @@ +// 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 NET_CERT_INTERNAL_SYSTEM_TRUST_STORE_NSS_H_ +#define NET_CERT_INTERNAL_SYSTEM_TRUST_STORE_NSS_H_ + +#include "crypto/scoped_nss_types.h" +#include "net/base/net_export.h" +#include "net/cert/internal/system_trust_store.h" + +namespace net { + +// Create a SystemTrustStore that will accept trust for: +// (*) built-in certificates +// (*) test root certificates +// (*) additional trust anchors (added through SystemTrustStore::AddTrustAnchor) +// (*) certificates stored on the |user_slot|. +NET_EXPORT std::unique_ptr<SystemTrustStore> +CreateSslSystemTrustStoreNSSWithUserSlotRestriction( + crypto::ScopedPK11Slot user_slot); + +// Create a SystemTrustStore that will accept trust for: +// (*) built-in certificates +// (*) test root certificates +// (*) additional trust anchors (added through SystemTrustStore::AddTrustAnchor) +// It will not accept trust for certificates stored on other slots. +NET_EXPORT std::unique_ptr<SystemTrustStore> +CreateSslSystemTrustStoreNSSWithNoUserSlots(); + +} // namespace net + +#endif // NET_CERT_INTERNAL_SYSTEM_TRUST_STORE_NSS_H_
diff --git a/net/cert/internal/system_trust_store_nss_unittest.cc b/net/cert/internal/system_trust_store_nss_unittest.cc new file mode 100644 index 0000000..9e3e581 --- /dev/null +++ b/net/cert/internal/system_trust_store_nss_unittest.cc
@@ -0,0 +1,163 @@ +// 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 "net/cert/internal/system_trust_store.h" + +#include <cert.h> +#include <certdb.h> + +#include <memory> + +#include "base/macros.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/scoped_test_nss_db.h" +#include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/parsed_certificate.h" +#include "net/cert/internal/system_trust_store_nss.h" +#include "net/cert/test_root_certs.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "net/cert/x509_util_nss.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace net { + +namespace { + +// Parses |x509_cert| as a ParsedCertificate and stores the output in +// *|out_parsed_cert|. Wrap in ASSERT_NO_FATAL_FAILURE on callsites. +::testing::AssertionResult ParseX509Certificate( + const scoped_refptr<X509Certificate>& x509_cert, + scoped_refptr<ParsedCertificate>* out_parsed_cert) { + CertErrors parsing_errors; + *out_parsed_cert = ParsedCertificate::Create( + bssl::UpRef(x509_cert->cert_buffer()), + x509_util::DefaultParseCertificateOptions(), &parsing_errors); + if (!*out_parsed_cert) { + return ::testing::AssertionFailure() + << "ParseCertificate::Create() failed:\n" + << parsing_errors.ToDebugString(); + } + return ::testing::AssertionSuccess(); +} + +class SystemTrustStoreNSSTest : public ::testing::Test { + public: + SystemTrustStoreNSSTest() : test_root_certs_(TestRootCerts::GetInstance()) {} + ~SystemTrustStoreNSSTest() override = default; + + void SetUp() override { + ::testing::Test::SetUp(); + + root_cert_ = + ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"); + ASSERT_TRUE(root_cert_); + ASSERT_NO_FATAL_FAILURE( + ParseX509Certificate(root_cert_, &parsed_root_cert_)); + nss_root_cert_ = + x509_util::CreateCERTCertificateFromX509Certificate(root_cert_.get()); + ASSERT_TRUE(nss_root_cert_); + + ASSERT_TRUE(test_nssdb_.is_open()); + ASSERT_TRUE(other_test_nssdb_.is_open()); + } + + protected: + // Imports |nss_root_cert_| into |slot| and sets trust flags so that it is a + // trusted CA for SSL. + void ImportRootCertAsTrusted(PK11SlotInfo* slot) { + SECStatus srv = PK11_ImportCert(slot, nss_root_cert_.get(), + CK_INVALID_HANDLE, "nickname_root_cert", + PR_FALSE /* includeTrust (unused) */); + ASSERT_EQ(SECSuccess, srv); + + CERTCertTrust trust = {0}; + trust.sslFlags = CERTDB_TRUSTED_CA | CERTDB_VALID_CA; + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nss_root_cert_.get(), + &trust); + ASSERT_EQ(SECSuccess, srv); + } + + crypto::ScopedTestNSSDB test_nssdb_; + crypto::ScopedTestNSSDB other_test_nssdb_; + + TestRootCerts* test_root_certs_; + + scoped_refptr<X509Certificate> root_cert_; + scoped_refptr<ParsedCertificate> parsed_root_cert_; + ScopedCERTCertificate nss_root_cert_; + + private: + DISALLOW_COPY_AND_ASSIGN(SystemTrustStoreNSSTest); +}; + +// Tests that SystemTrustStore respects TestRootCerts. +TEST_F(SystemTrustStoreNSSTest, TrustTestRootCerts) { + std::unique_ptr<SystemTrustStore> system_trust_store = + CreateSslSystemTrustStore(); + + EXPECT_TRUE(test_root_certs_->Add(root_cert_.get())); + CertificateTrust trust; + system_trust_store->GetTrustStore()->GetTrust(parsed_root_cert_.get(), + &trust); + EXPECT_EQ(CertificateTrustType::TRUSTED_ANCHOR, trust.type); + + test_root_certs_->Clear(); + system_trust_store->GetTrustStore()->GetTrust(parsed_root_cert_.get(), + &trust); + EXPECT_EQ(CertificateTrustType::UNSPECIFIED, trust.type); +} + +// Tests that SystemTrustStore created for NSS with a user-slot restriction +// allows certificates stored on the specified user slot to be trusted. +TEST_F(SystemTrustStoreNSSTest, UserSlotRestrictionAllows) { + std::unique_ptr<SystemTrustStore> system_trust_store = + CreateSslSystemTrustStoreNSSWithUserSlotRestriction( + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))); + + ASSERT_NO_FATAL_FAILURE(ImportRootCertAsTrusted(test_nssdb_.slot())); + + CertificateTrust trust; + system_trust_store->GetTrustStore()->GetTrust(parsed_root_cert_.get(), + &trust); + EXPECT_EQ(CertificateTrustType::TRUSTED_ANCHOR, trust.type); +} + +// Tests that SystemTrustStore created for NSS with a user-slot restriction +// does not allows certificates stored only on user slots different from the one +// specified to be trusted. +TEST_F(SystemTrustStoreNSSTest, UserSlotRestrictionDisallows) { + std::unique_ptr<SystemTrustStore> system_trust_store = + CreateSslSystemTrustStoreNSSWithUserSlotRestriction( + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))); + + ASSERT_NO_FATAL_FAILURE(ImportRootCertAsTrusted(other_test_nssdb_.slot())); + + CertificateTrust trust; + system_trust_store->GetTrustStore()->GetTrust(parsed_root_cert_.get(), + &trust); + EXPECT_EQ(CertificateTrustType::UNSPECIFIED, trust.type); +} + +// Tests that SystemTrustStore created for NSS without allowing trust for +// certificate stored on user slots. +TEST_F(SystemTrustStoreNSSTest, NoUserSlots) { + std::unique_ptr<SystemTrustStore> system_trust_store = + CreateSslSystemTrustStoreNSSWithNoUserSlots(); + + ASSERT_NO_FATAL_FAILURE(ImportRootCertAsTrusted(test_nssdb_.slot())); + + CertificateTrust trust; + system_trust_store->GetTrustStore()->GetTrust(parsed_root_cert_.get(), + &trust); + EXPECT_EQ(CertificateTrustType::UNSPECIFIED, trust.type); +} + +} // namespace + +} // namespace net
diff --git a/net/cert/internal/trust_store_nss.cc b/net/cert/internal/trust_store_nss.cc index 3ab6343..6725971 100644 --- a/net/cert/internal/trust_store_nss.cc +++ b/net/cert/internal/trust_store_nss.cc
@@ -11,17 +11,27 @@ #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parsed_certificate.h" #include "net/cert/scoped_nss_types.h" +#include "net/cert/test_root_certs.h" #include "net/cert/x509_util.h" #include "net/cert/x509_util_nss.h" -// TODO(mattm): structure so that supporting ChromeOS multi-profile stuff is -// doable (Have a TrustStoreChromeOS which uses net::NSSProfileFilterChromeOS, -// similar to CertVerifyProcChromeOS.) - namespace net { TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type) - : trust_type_(trust_type) {} + : trust_type_(trust_type), filter_trusted_certs_by_slot_(false) {} + +TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type, + crypto::ScopedPK11Slot user_slot) + : trust_type_(trust_type), + filter_trusted_certs_by_slot_(true), + user_slot_(std::move(user_slot)) { + DCHECK(user_slot_); +} + +TrustStoreNSS::TrustStoreNSS( + SECTrustType trust_type, + DisallowTrustForCertsOnUserSlots disallow_trust_for_certs_on_user_slots) + : trust_type_(trust_type), filter_trusted_certs_by_slot_(true) {} TrustStoreNSS::~TrustStoreNSS() = default; @@ -46,16 +56,24 @@ for (CERTCertListNode* node = CERT_LIST_HEAD(found_certs); !CERT_LIST_END(node, found_certs); node = CERT_LIST_NEXT(node)) { +#if !defined(OS_CHROMEOS) // TODO(mattm): use CERT_GetCertIsTemp when minimum NSS version is >= 3.31. if (node->cert->istemp) { - // Ignore temporary NSS certs. This ensures that during the trial when - // CertVerifyProcNSS and CertVerifyProcBuiltin are being used - // simultaneously, the builtin verifier does not get to "cheat" by using - // AIA fetched certs from CertVerifyProcNSS. + // Ignore temporary NSS certs on platforms other than Chrome OS. This + // ensures that during the trial when CertVerifyProcNSS and + // CertVerifyProcBuiltin are being used simultaneously, the builtin + // verifier does not get to "cheat" by using AIA fetched certs from + // CertVerifyProcNSS. // TODO(https://crbug.com/951479): remove this when CertVerifyProcBuiltin // becomes the default. + // This is not done for Chrome OS because temporary NSS certs are + // currently used there to implement policy-provided untrusted authority + // certificates, and no trials are being done on Chrome OS. + // TODO(https://crbug.com/978854): remove the Chrome OS exception when + // certificates are passed. continue; } +#endif // !defined(OS_CHROMEOS) CertErrors parse_errors; scoped_refptr<ParsedCertificate> cur_cert = ParsedCertificate::Create( @@ -95,6 +113,11 @@ return; } + if (!IsCertAllowedForTrust(nss_cert.get())) { + *out_trust = CertificateTrust::ForUnspecified(); + return; + } + // Determine the trustedness of the matched certificate. CERTCertTrust trust; if (CERT_GetCertTrust(nss_cert.get(), &trust) != SECSuccess) { @@ -124,4 +147,38 @@ return; } +bool TrustStoreNSS::IsCertAllowedForTrust(CERTCertificate* cert) const { + // If |filter_trusted_certs_by_slot_| is false, allow trust for any + // certificate, no matter which slot it is stored on. + if (!filter_trusted_certs_by_slot_) + return true; + + crypto::ScopedPK11SlotList slots_for_cert( + PK11_GetAllSlotsForCert(cert, nullptr)); + if (!slots_for_cert) + return false; + + for (PK11SlotListElement* slot_element = + PK11_GetFirstSafe(slots_for_cert.get()); + slot_element; + slot_element = PK11_GetNextSafe(slots_for_cert.get(), slot_element, + /*restart=*/PR_FALSE)) { + PK11SlotInfo* slot = slot_element->slot; + bool allow_slot = + // Allow the root certs module. + PK11_HasRootCerts(slot) || + // Allow read-only internal slots. + (PK11_IsInternal(slot) && !PK11_IsRemovable(slot)) || + // Allow |user_slot_| if specified. + (user_slot_ && slot == user_slot_.get()); + + if (allow_slot) { + PK11_FreeSlotListElement(slots_for_cert.get(), slot_element); + return true; + } + } + + return false; +} + } // namespace net
diff --git a/net/cert/internal/trust_store_nss.h b/net/cert/internal/trust_store_nss.h index fd66b45d4..9c44093 100644 --- a/net/cert/internal/trust_store_nss.h +++ b/net/cert/internal/trust_store_nss.h
@@ -5,9 +5,11 @@ #ifndef NET_CERT_INTERNAL_TRUST_STORE_NSS_H_ #define NET_CERT_INTERNAL_TRUST_STORE_NSS_H_ +#include <cert.h> #include <certt.h> #include "base/memory/ref_counted.h" +#include "crypto/scoped_nss_types.h" #include "net/base/net_export.h" #include "net/cert/internal/trust_store.h" @@ -17,9 +19,31 @@ // anchors for path building. class NET_EXPORT TrustStoreNSS : public TrustStore { public: + struct DisallowTrustForCertsOnUserSlots {}; + // Creates a TrustStoreNSS which will find anchors that are trusted for // |trust_type|. + // The created TrustStoreNSS will not perform any filtering based on the slot + // certificates are stored on. explicit TrustStoreNSS(SECTrustType trust_type); + + // Creates a TrustStoreNSS which will find anchors that are trusted for + // |trust_type|. + // The created TrustStoreNSS will allow trust for certificates that: + // (*) are built-in certificates + // (*) are stored on a read-only internal slot + // (*) are stored on the |user_slot|. + TrustStoreNSS(SECTrustType trust_type, crypto::ScopedPK11Slot user_slot); + + // Creates a TrustStoreNSS which will find anchors that are trusted for + // |trust_type|. + // The created TrustStoreNSS will allow trust for certificates that: + // (*) are built-in certificates + // (*) are stored on a read-only internal slot + TrustStoreNSS( + SECTrustType trust_type, + DisallowTrustForCertsOnUserSlots disallow_trust_for_certs_on_user_slots); + ~TrustStoreNSS() override; // CertIssuerSource implementation: @@ -31,8 +55,30 @@ CertificateTrust* trust) const override; private: + bool IsCertAllowedForTrust(CERTCertificate* cert) const; + SECTrustType trust_type_; + // |filter_trusted_certs_by_slot_| and |user_slot_| together specify which + // slots certificates must be stored on to be allowed to be trusted. The + // possible combinations are: + // + // |filter_trusted_certs_by_slot_| == false: Allow any certificate to be + // trusted, don't filter by slot. |user_slot_| is ignored in this case. + // + // |filter_trusted_certs_by_slot_| == true and |user_slot_| = nullptr: Allow + // certificates to be trusted if they + // (*) are built-in certificates or + // (*) are stored on a read-only internal slot. + // + // |filter_trusted_certs_by_slot_| == true and |user_slot_| != nullptr: Allow + // certificates to be trusted if they + // (*) are built-in certificates or + // (*) are stored on a read-only internal slot or + // (*) are stored on |user_slot_|. + const bool filter_trusted_certs_by_slot_; + crypto::ScopedPK11Slot user_slot_; + DISALLOW_COPY_AND_ASSIGN(TrustStoreNSS); };
diff --git a/net/cert/internal/trust_store_nss_unittest.cc b/net/cert/internal/trust_store_nss_unittest.cc index 1a7a94c..d22a0360 100644 --- a/net/cert/internal/trust_store_nss_unittest.cc +++ b/net/cert/internal/trust_store_nss_unittest.cc
@@ -6,25 +6,82 @@ #include <cert.h> #include <certdb.h> +#include <secmod.h> #include <memory> #include "base/strings/string_number_conversions.h" +#include "crypto/nss_util_internal.h" #include "crypto/scoped_test_nss_db.h" #include "net/cert/internal/cert_issuer_source_sync_unittest.h" +#include "net/cert/internal/parsed_certificate.h" #include "net/cert/internal/test_helpers.h" #include "net/cert/scoped_nss_types.h" +#include "net/cert/test_root_certs.h" +#include "net/cert/x509_util.h" #include "net/cert/x509_util_nss.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/boringssl/src/include/openssl/pool.h" namespace net { namespace { -class TrustStoreNSSTest : public testing::Test { +// Returns the slot which holds the built-in root certificates. +crypto::ScopedPK11Slot GetRootCertsSlot() { + crypto::AutoSECMODListReadLock auto_lock; + SECMODModuleList* head = SECMOD_GetDefaultModuleList(); + for (SECMODModuleList* item = head; item != NULL; item = item->next) { + int slot_count = item->module->loaded ? item->module->slotCount : 0; + for (int i = 0; i < slot_count; i++) { + PK11SlotInfo* slot = item->module->slots[i]; + if (!PK11_IsPresent(slot)) + continue; + if (PK11_HasRootCerts(slot)) + return crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot)); + } + } + return crypto::ScopedPK11Slot(); +} + +// Returns a built-in trusted root certificte. If multiple ones are available, +// it is not specified which one is returned. If none are available, returns +// nullptr. +scoped_refptr<ParsedCertificate> GetASSLTrustedBuiltinRoot() { + crypto::ScopedPK11Slot root_certs_slot = GetRootCertsSlot(); + if (!root_certs_slot) + return nullptr; + + scoped_refptr<X509Certificate> ssl_trusted_root; + + CERTCertList* cert_list = PK11_ListCertsInSlot(root_certs_slot.get()); + for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { + CERTCertTrust trust; + if (CERT_GetCertTrust(node->cert, &trust) != SECSuccess) + continue; + int trust_flags = SEC_GET_TRUST_FLAGS(&trust, trustSSL); + if ((trust_flags & CERTDB_TRUSTED_CA) == CERTDB_TRUSTED_CA) { + ssl_trusted_root = + x509_util::CreateX509CertificateFromCERTCertificate(node->cert); + break; + } + } + CERT_DestroyCertList(cert_list); + if (!ssl_trusted_root) + return nullptr; + + CertErrors parsing_errors; + return ParsedCertificate::Create(bssl::UpRef(ssl_trusted_root->cert_buffer()), + x509_util::DefaultParseCertificateOptions(), + &parsing_errors); +} + +class TrustStoreNSSTestBase : public ::testing::Test { public: void SetUp() override { ASSERT_TRUE(test_nssdb_.is_open()); + ASSERT_TRUE(other_test_nssdb_.is_open()); ParsedCertificateList chain; ReadCertChainFromFile( "net/data/verify_certificate_chain_unittest/key-rollover/oldchain.pem", @@ -51,31 +108,35 @@ ASSERT_TRUE(newroot_); ASSERT_TRUE(newrootrollover_); - trust_store_nss_.reset(new TrustStoreNSS(trustSSL)); + trust_store_nss_ = CreateTrustStoreNSS(); } + // Creates the TrustStoreNSS instance. Subclasses will customize the slot + // filtering behavior here. + virtual std::unique_ptr<TrustStoreNSS> CreateTrustStoreNSS() = 0; + std::string GetUniqueNickname() { return "trust_store_nss_unittest" + base::NumberToString(nickname_counter_++); } - void AddCertToNSS(const ParsedCertificate* cert) { + void AddCertToNSSSlot(const ParsedCertificate* cert, PK11SlotInfo* slot) { ScopedCERTCertificate nss_cert(x509_util::CreateCERTCertificateFromBytes( cert->der_cert().UnsafeData(), cert->der_cert().Length())); ASSERT_TRUE(nss_cert); - SECStatus srv = PK11_ImportCert( - test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE, - GetUniqueNickname().c_str(), PR_FALSE /* includeTrust (unused) */); + SECStatus srv = PK11_ImportCert(slot, nss_cert.get(), CK_INVALID_HANDLE, + GetUniqueNickname().c_str(), + PR_FALSE /* includeTrust (unused) */); ASSERT_EQ(SECSuccess, srv); } void AddCertsToNSS() { - AddCertToNSS(target_.get()); - AddCertToNSS(oldintermediate_.get()); - AddCertToNSS(newintermediate_.get()); - AddCertToNSS(oldroot_.get()); - AddCertToNSS(newroot_.get()); - AddCertToNSS(newrootrollover_.get()); + AddCertToNSSSlot(target_.get(), test_nssdb_.slot()); + AddCertToNSSSlot(oldintermediate_.get(), test_nssdb_.slot()); + AddCertToNSSSlot(newintermediate_.get(), test_nssdb_.slot()); + AddCertToNSSSlot(oldroot_.get(), test_nssdb_.slot()); + AddCertToNSSSlot(newroot_.get(), test_nssdb_.slot()); + AddCertToNSSSlot(newrootrollover_.get(), test_nssdb_.slot()); // Check that the certificates can be retrieved as expected. EXPECT_TRUE( @@ -192,30 +253,102 @@ scoped_refptr<ParsedCertificate> newintermediate_; scoped_refptr<ParsedCertificate> newrootrollover_; crypto::ScopedTestNSSDB test_nssdb_; + crypto::ScopedTestNSSDB other_test_nssdb_; std::unique_ptr<TrustStoreNSS> trust_store_nss_; unsigned nickname_counter_ = 0; }; -// Without adding any certs to the NSS DB, should get no anchor results for any -// of the test certs. -TEST_F(TrustStoreNSSTest, CertsNotPresent) { +// Specifies which kind of per-slot filtering the TrustStoreNSS is supposed to +// perform in the parametrized TrustStoreNSSTestWithSlotFilterType. +enum class SlotFilterType { + kDontFilter, + kDoNotAllowUserSlots, + kAllowSpecifiedUserSlot +}; + +// Used for testing a TrustStoreNSS with the slot filter type specified by the +// test parameter. +class TrustStoreNSSTestWithSlotFilterType + : public TrustStoreNSSTestBase, + public testing::WithParamInterface<SlotFilterType> { + public: + TrustStoreNSSTestWithSlotFilterType() = default; + ~TrustStoreNSSTestWithSlotFilterType() override = default; + + std::unique_ptr<TrustStoreNSS> CreateTrustStoreNSS() override { + switch (GetParam()) { + case SlotFilterType::kDontFilter: + return std::make_unique<TrustStoreNSS>(trustSSL); + case SlotFilterType::kDoNotAllowUserSlots: + return std::make_unique<TrustStoreNSS>( + trustSSL, TrustStoreNSS::DisallowTrustForCertsOnUserSlots()); + case SlotFilterType::kAllowSpecifiedUserSlot: + return std::make_unique<TrustStoreNSS>( + trustSSL, + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))); + } + } +}; + +// Without adding any certs to the NSS DB, should get no anchor results for +// any of the test certs. +TEST_P(TrustStoreNSSTestWithSlotFilterType, CertsNotPresent) { EXPECT_TRUE(TrustStoreContains(target_, ParsedCertificateList())); EXPECT_TRUE(TrustStoreContains(newintermediate_, ParsedCertificateList())); EXPECT_TRUE(TrustStoreContains(newroot_, ParsedCertificateList())); } +#if !defined(OS_CHROMEOS) // TrustStoreNSS should not return temporary certs. (See // https://crbug.com/951166) -TEST_F(TrustStoreNSSTest, TempCertNotPresent) { +TEST_P(TrustStoreNSSTestWithSlotFilterType, TempCertNotPresent) { ScopedCERTCertificate temp_nss_cert(x509_util::CreateCERTCertificateFromBytes( newintermediate_->der_cert().UnsafeData(), newintermediate_->der_cert().Length())); EXPECT_TRUE(TrustStoreContains(target_, ParsedCertificateList())); } +#else // !defined(OS_CHROMEOS) +// TrustStoreNSS should return temporary certs on Chrome OS, because on Chrome +// OS temporary certs are used to supply policy-provided untrusted authority +// certs. (See https://crbug.com/978854) +TEST_P(TrustStoreNSSTestWithSlotFilterType, TempCertPresent) { + ScopedCERTCertificate temp_nss_cert(x509_util::CreateCERTCertificateFromBytes( + newintermediate_->der_cert().UnsafeData(), + newintermediate_->der_cert().Length())); + EXPECT_TRUE(TrustStoreContains(target_, {newintermediate_})); +} +#endif // !defined(OS_CHROMEOS) + +// Independent of the specified slot-based filtering mode, built-in root certs +// should always be trusted. +TEST_P(TrustStoreNSSTestWithSlotFilterType, TrustAllowedForBuiltinRootCerts) { + auto builtin_root_cert = GetASSLTrustedBuiltinRoot(); + ASSERT_TRUE(builtin_root_cert); + EXPECT_TRUE( + HasTrust({builtin_root_cert}, CertificateTrustType::TRUSTED_ANCHOR)); +} + +INSTANTIATE_TEST_SUITE_P( + TrustStoreNSSTest_AllSlotFilterTypes, + TrustStoreNSSTestWithSlotFilterType, + ::testing::Values(SlotFilterType::kDontFilter, + SlotFilterType::kDoNotAllowUserSlots, + SlotFilterType::kAllowSpecifiedUserSlot)); + +// Tests a TrustStoreNSS that does not filter which certificates +class TrustStoreNSSTestWithoutSlotFilter : public TrustStoreNSSTestBase { + public: + TrustStoreNSSTestWithoutSlotFilter() = default; + ~TrustStoreNSSTestWithoutSlotFilter() override = default; + + std::unique_ptr<TrustStoreNSS> CreateTrustStoreNSS() override { + return std::make_unique<TrustStoreNSS>(trustSSL); + } +}; // If certs are present in NSS DB but aren't marked as trusted, should get no // anchor results for any of the test certs. -TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, CertsPresentButNotTrusted) { AddCertsToNSS(); // None of the certificates are trusted. @@ -225,7 +358,7 @@ } // Trust a single self-signed CA certificate. -TEST_F(TrustStoreNSSTest, TrustedCA) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, TrustedCA) { AddCertsToNSS(); TrustCert(newroot_.get()); @@ -238,7 +371,7 @@ } // Distrust a single self-signed CA certificate. -TEST_F(TrustStoreNSSTest, DistrustedCA) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, DistrustedCA) { AddCertsToNSS(); DistrustCert(newroot_.get()); @@ -251,7 +384,7 @@ } // Trust a single intermediate certificate. -TEST_F(TrustStoreNSSTest, TrustedIntermediate) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, TrustedIntermediate) { AddCertsToNSS(); TrustCert(newintermediate_.get()); @@ -263,7 +396,7 @@ } // Distrust a single intermediate certificate. -TEST_F(TrustStoreNSSTest, DistrustedIntermediate) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, DistrustedIntermediate) { AddCertsToNSS(); DistrustCert(newintermediate_.get()); @@ -274,7 +407,7 @@ } // Trust a single server certificate. -TEST_F(TrustStoreNSSTest, TrustedServer) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, TrustedServer) { AddCertsToNSS(); TrustServerCert(target_.get()); @@ -287,7 +420,7 @@ } // Trust multiple self-signed CA certificates with the same name. -TEST_F(TrustStoreNSSTest, MultipleTrustedCAWithSameSubject) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, MultipleTrustedCAWithSameSubject) { AddCertsToNSS(); TrustCert(oldroot_.get()); TrustCert(newroot_.get()); @@ -301,7 +434,7 @@ // Different trust settings for multiple self-signed CA certificates with the // same name. -TEST_F(TrustStoreNSSTest, DifferingTrustCAWithSameSubject) { +TEST_F(TrustStoreNSSTestWithoutSlotFilter, DifferingTrustCAWithSameSubject) { AddCertsToNSS(); DistrustCert(oldroot_.get()); TrustCert(newroot_.get()); @@ -313,6 +446,62 @@ EXPECT_TRUE(HasTrust({newroot_}, CertificateTrustType::TRUSTED_ANCHOR)); } +// Tests for a TrustStoreNSS which does not allow certificates on user slots +// to be trusted. +class TrustStoreNSSTestDoNotAllowUserSlots : public TrustStoreNSSTestBase { + public: + TrustStoreNSSTestDoNotAllowUserSlots() = default; + ~TrustStoreNSSTestDoNotAllowUserSlots() override = default; + + std::unique_ptr<TrustStoreNSS> CreateTrustStoreNSS() override { + return std::make_unique<TrustStoreNSS>( + trustSSL, TrustStoreNSS::DisallowTrustForCertsOnUserSlots()); + } +}; + +// A certificate that is stored on a "user slot" is not trusted if the +// TrustStoreNSS is not allowed to trust certificates on user slots. +TEST_F(TrustStoreNSSTestDoNotAllowUserSlots, CertOnUserSlot) { + AddCertToNSSSlot(newroot_.get(), test_nssdb_.slot()); + TrustCert(newroot_.get()); + EXPECT_TRUE(HasTrust({newroot_}, CertificateTrustType::UNSPECIFIED)); +} + +// Tests for a TrustStoreNSS which does allows certificates on user slots to +// be only trusted if they are on a specific user slot. +class TrustStoreNSSTestAllowSpecifiedUserSlot : public TrustStoreNSSTestBase { + public: + TrustStoreNSSTestAllowSpecifiedUserSlot() = default; + ~TrustStoreNSSTestAllowSpecifiedUserSlot() override = default; + + std::unique_ptr<TrustStoreNSS> CreateTrustStoreNSS() override { + return std::make_unique<TrustStoreNSS>( + trustSSL, + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))); + } +}; + +// A certificate that is stored on a "user slot" is trusted if the +// TrustStoreNSS is allowed to trust that user slot. +TEST_F(TrustStoreNSSTestAllowSpecifiedUserSlot, CertOnUserSlot) { + AddCertToNSSSlot(newroot_.get(), test_nssdb_.slot()); + TrustCert(newroot_.get()); + EXPECT_TRUE(HasTrust({newroot_}, CertificateTrustType::TRUSTED_ANCHOR)); +} + +// A certificate that is stored on a "user slot" is not trusted if the +// TrustStoreNSS is allowed to trust a user slot, but the certificate is +// stored on another user slot. +TEST_F(TrustStoreNSSTestAllowSpecifiedUserSlot, CertOnOtherUserSlot) { + AddCertToNSSSlot(newroot_.get(), other_test_nssdb_.slot()); + TrustCert(newroot_.get()); + EXPECT_TRUE(HasTrust({newroot_}, CertificateTrustType::UNSPECIFIED)); +} + +// TODO(https://crbug.com/980443): If the internal non-removable slot is +// relevant on Chrome OS, add a test for allowing trust for certificates +// stored on that slot. + class TrustStoreNSSTestDelegate { public: TrustStoreNSSTestDelegate() : trust_store_nss_(trustSSL) {} @@ -345,8 +534,8 @@ CertIssuerSourceSyncTest, TrustStoreNSSTestDelegate); -// NSS doesn't normalize UTF8String values, so use the not-normalized version of -// those tests. +// NSS doesn't normalize UTF8String values, so use the not-normalized version +// of those tests. INSTANTIATE_TYPED_TEST_SUITE_P(TrustStoreNSSNotNormalizedTest, CertIssuerSourceSyncNotNormalizedTest, TrustStoreNSSTestDelegate);
diff --git a/net/features.gni b/net/features.gni index 3cdaf70..26aa4b1 100644 --- a/net/features.gni +++ b/net/features.gni
@@ -47,5 +47,6 @@ # supported and may be switched between using the CertVerifierBuiltin feature # flag. This does not include platforms where the builtin cert verifier is # the only verifier supported. - builtin_cert_verifier_feature_supported = is_desktop_linux || is_mac + builtin_cert_verifier_feature_supported = + is_desktop_linux || is_mac || is_chromeos }
diff --git a/net/nqe/network_congestion_analyzer.cc b/net/nqe/network_congestion_analyzer.cc new file mode 100644 index 0000000..0401585 --- /dev/null +++ b/net/nqe/network_congestion_analyzer.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 <net/nqe/network_congestion_analyzer.h> + +namespace net { + +namespace nqe { + +namespace internal { + +NetworkCongestionAnalyzer::NetworkCongestionAnalyzer() + : recent_active_hosts_count_(0u) {} +NetworkCongestionAnalyzer::~NetworkCongestionAnalyzer() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +size_t NetworkCongestionAnalyzer::GetActiveHostsCount() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return recent_active_hosts_count_; +} + +void NetworkCongestionAnalyzer::ComputeRecentQueueingDelay( + const std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>& + recent_rtt_stats, + const std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>& + historical_rtt_stats, + const int32_t downlink_kbps) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Updates downlink throughput if a new valid observation comes. + if (downlink_kbps != nqe::internal::INVALID_RTT_THROUGHPUT) + set_recent_downlink_throughput_kbps(downlink_kbps); + if (recent_rtt_stats.empty()) + return; + + int32_t delay_sample_sum = 0; + recent_active_hosts_count_ = 0u; + for (const auto& host_stats : recent_rtt_stats) { + nqe::internal::IPHash host = host_stats.first; + // Skip hosts that do not have historical statistics. + if (historical_rtt_stats.find(host) == historical_rtt_stats.end()) + continue; + + // Skip hosts that have one or fewer RTT samples or do not have the min + // value. They cannot provide an effective queueing delay sample. + if (historical_rtt_stats.at(host).observation_count <= 1 || + historical_rtt_stats.at(host).canonical_pcts.find(kStatVal0p) == + historical_rtt_stats.at(host).canonical_pcts.end()) + continue; + + ++recent_active_hosts_count_; + delay_sample_sum += + recent_rtt_stats.at(host).most_recent_val - + historical_rtt_stats.at(host).canonical_pcts.at(kStatVal0p); + } + + if (recent_active_hosts_count_ == 0u) + return; + + DCHECK_LT(0u, recent_active_hosts_count_); + + int32_t delay_ms = + delay_sample_sum / static_cast<int>(recent_active_hosts_count_); + recent_queueing_delay_ = base::TimeDelta::FromMilliseconds(delay_ms); + if (recent_downlink_per_packet_time_ms_ != base::nullopt) { + recent_queue_length_ = static_cast<float>(delay_ms) / + recent_downlink_per_packet_time_ms_.value(); + } +} + +void NetworkCongestionAnalyzer::set_recent_downlink_throughput_kbps( + const int32_t downlink_kbps) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + recent_downlink_throughput_kbps_ = downlink_kbps; + // Time in msec to transmit one TCP packet (1500 Bytes). + // |recent_downlink_per_packet_time_ms_| = 1500 * 8 / + // |recent_downlink_throughput_kbps_|. + recent_downlink_per_packet_time_ms_ = 12000 / downlink_kbps; +} + +} // namespace internal + +} // namespace nqe + +} // namespace net
diff --git a/net/nqe/network_congestion_analyzer.h b/net/nqe/network_congestion_analyzer.h new file mode 100644 index 0000000..f00fbcb --- /dev/null +++ b/net/nqe/network_congestion_analyzer.h
@@ -0,0 +1,101 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_NQE_NETWORK_CONGESTION_ANALYZER_H_ +#define NET_NQE_NETWORK_CONGESTION_ANALYZER_H_ + +#include <cmath> +#include <map> +#include <unordered_map> + +#include "base/macros.h" +#include "base/optional.h" +#include "base/sequence_checker.h" +#include "base/time/time.h" +#include "net/base/net_export.h" +#include "net/nqe/network_quality.h" +#include "net/nqe/network_quality_estimator_util.h" +#include "net/nqe/observation_buffer.h" + +namespace net { + +namespace nqe { + +namespace internal { + +// NetworkCongestionAnalyzer holds the network congestion information, such +// as the recent packet queue length in the mobile edge, recent queueing delay, +// recent downlink throughput. +class NET_EXPORT_PRIVATE NetworkCongestionAnalyzer { + public: + NetworkCongestionAnalyzer(); + ~NetworkCongestionAnalyzer(); + + // Returns the number of hosts that are involved in the last attempt of + // computing the recent queueing delay. These hosts are recent active hosts. + size_t GetActiveHostsCount() const; + + // Computes the recent queueing delay. Records the observed queueing delay + // samples for all recent active hosts. The mean queueing delay is recorded in + // |recent_queueing_delay_|. |recent_rtt_stats| has all canonical statistic + // values of recent observations for active hosts. |historical_rtt_stats| has + // all canonical statistic values of historical observations for active hosts. + // If |downlink_kbps| is valid, updates |recent_downlink_throughput_kbps_| and + // |recent_downlink_per_packet_time_ms_| based on its value. If + // |recent_downlink_per_packet_time_ms_| has a valid value, updates + // |recent_queue_length_| as well. + void ComputeRecentQueueingDelay( + const std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>& + recent_rtt_stats, + const std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>& + historical_rtt_stats, + const int32_t downlink_kbps); + + base::Optional<float> recent_queue_length() const { + return recent_queue_length_; + } + + base::TimeDelta recent_queueing_delay() const { + return recent_queueing_delay_; + } + + private: + // Sets the |recent_downlink_throughput_kbps_| with the estimated downlink + // throughput in kbps. Also, computes the time frame (in millisecond) to + // transmit one TCP packet (1500 Bytes) under this downlink throughput. + void set_recent_downlink_throughput_kbps(const int32_t downlink_kbps); + + base::Optional<int32_t> recent_downlink_throughput_kbps() const { + return recent_downlink_throughput_kbps_; + } + + // Recent downstream throughput estimate. It is the median of most recent + // downstream throughput observations (in kilobits per second). + base::Optional<int32_t> recent_downlink_throughput_kbps_; + // Time of transmitting one 1500-Byte TCP packet under + // |recent_downlink_throughput_kbps_|. + base::Optional<int32_t> recent_downlink_per_packet_time_ms_; + + // The estimate of packet queue length. Computation is done based on the last + // observed downlink throughput. + base::Optional<float> recent_queue_length_; + // The estimate of queueing delay induced by packet queue. + base::TimeDelta recent_queueing_delay_; + + // Counts the number of hosts involved in the last attempt of computing the + // recent queueing delay. + size_t recent_active_hosts_count_; + + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(NetworkCongestionAnalyzer); +}; + +} // namespace internal + +} // namespace nqe + +} // namespace net + +#endif // NET_NQE_NETWORK_CONGESTION_ANALYZER_H_
diff --git a/net/nqe/network_congestion_analyzer_unittest.cc b/net/nqe/network_congestion_analyzer_unittest.cc new file mode 100644 index 0000000..a693e72 --- /dev/null +++ b/net/nqe/network_congestion_analyzer_unittest.cc
@@ -0,0 +1,82 @@ +// 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 "net/nqe/network_congestion_analyzer.h" +#include <map> +#include <unordered_map> + +#include "base/macros.h" +#include "base/optional.h" +#include "base/time/time.h" +#include "net/nqe/network_quality.h" +#include "net/nqe/observation_buffer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace nqe { + +namespace internal { + +namespace { +constexpr float kEpsilon = 0.001f; + +// Verify that the network queueing delay is computed correctly based on RTT +// and downlink throughput observations. +TEST(NetworkCongestionAnalyzerTest, TestComputingQueueingDelay) { + NetworkCongestionAnalyzer analyzer; + std::map<uint64_t, CanonicalStats> recent_rtt_stats; + std::map<uint64_t, CanonicalStats> historical_rtt_stats; + int32_t downlink_kbps = nqe::internal::INVALID_RTT_THROUGHPUT; + + // Checks that no result is updated when providing empty RTT observations and + // an invalid downlink throughput observation. + analyzer.ComputeRecentQueueingDelay(recent_rtt_stats, historical_rtt_stats, + downlink_kbps); + EXPECT_TRUE(analyzer.recent_queueing_delay().is_zero()); + + const uint64_t host_1 = 0x101010UL; + const uint64_t host_2 = 0x202020UL; + // Checks that the queueing delay is updated based on hosts with valid RTT + // observations. For example, the computation should be done by using data + // from host 1 only because host 2 does not provide a valid min RTT value. + std::map<int32_t, int32_t> recent_stat_host_1 = {{kStatVal0p, 1100}}; + std::map<int32_t, int32_t> historical_stat_host_1 = {{kStatVal0p, 600}}; + CanonicalStats recent_rtt_host_1 = + CanonicalStats(recent_stat_host_1, 1400, 5); + CanonicalStats historical_rtt_host_1 = + CanonicalStats(historical_stat_host_1, 1400, 15); + + std::map<int32_t, int32_t> recent_stat_host_2 = {{kStatVal0p, 1200}}; + std::map<int32_t, int32_t> historical_stat_host_2 = {{kStatVal50p, 1200}}; + CanonicalStats recent_rtt_host_2 = + CanonicalStats(recent_stat_host_2, 1600, 3); + CanonicalStats historical_rtt_host_2 = + CanonicalStats(historical_stat_host_2, 1600, 8); + recent_rtt_stats.emplace(host_1, recent_rtt_host_1); + recent_rtt_stats.emplace(host_2, recent_rtt_host_2); + historical_rtt_stats.emplace(host_1, historical_rtt_host_1); + historical_rtt_stats.emplace(host_2, historical_rtt_host_2); + + analyzer.ComputeRecentQueueingDelay(recent_rtt_stats, historical_rtt_stats, + downlink_kbps); + EXPECT_EQ(800, analyzer.recent_queueing_delay().InMilliseconds()); + + // Checks that the queueing delay is updated correctly based on all hosts when + // RTT observations and the throughput observation are valid. + historical_rtt_stats[host_2].canonical_pcts[kStatVal0p] = 1000; + downlink_kbps = 120; + analyzer.ComputeRecentQueueingDelay(recent_rtt_stats, historical_rtt_stats, + downlink_kbps); + EXPECT_EQ(700, analyzer.recent_queueing_delay().InMilliseconds()); + EXPECT_NEAR(7.0, analyzer.recent_queue_length().value_or(0), kEpsilon); +} + +} // namespace + +} // namespace internal + +} // namespace nqe + +} // namespace net \ No newline at end of file
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc index 2aa2322..9eafc5fa 100644 --- a/net/nqe/network_quality_estimator.cc +++ b/net/nqe/network_quality_estimator.cc
@@ -161,6 +161,7 @@ params_->weight_multiplier_per_signal_strength_level())}, effective_connection_type_at_last_main_frame_( EFFECTIVE_CONNECTION_TYPE_UNKNOWN), + queueing_delay_update_interval_(base::TimeDelta::FromMilliseconds(2000)), effective_connection_type_recomputation_interval_( base::TimeDelta::FromSeconds(10)), rtt_observations_size_at_last_ect_computation_(0), @@ -716,6 +717,62 @@ EFFECTIVE_CONNECTION_TYPE_LAST); } +bool NetworkQualityEstimator::ShouldComputeNetworkQueueingDelay() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const base::TimeTicks now = tick_clock_->NowTicks(); + // Recomputes the queueing delay estimate if |queueing_delay_update_interval_| + // has passed. + return (now - last_queueing_delay_computation_ >= + queueing_delay_update_interval_); +} + +void NetworkQualityEstimator::ComputeNetworkQueueingDelay() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!ShouldComputeNetworkQueueingDelay()) + return; + + const base::TimeTicks now = tick_clock_->NowTicks(); + last_queueing_delay_computation_ = now; + // The time after which observations are considered as recent data. + const base::TimeTicks recent_start_time = + now - base::TimeDelta::FromMilliseconds(1000); + // The time after which observations are considered as historical data. + const base::TimeTicks historical_start_time = + now - base::TimeDelta::FromMilliseconds(30000); + + // Checks if a valid downlink throughput estimation is available. + int32_t downlink_kbps = 0; + if (!GetRecentDownlinkThroughputKbps(recent_start_time, &downlink_kbps)) + downlink_kbps = nqe::internal::INVALID_RTT_THROUGHPUT; + + // Gets recent RTT statistic values. + std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats> + recent_rtt_stats = + rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT] + .GetCanonicalStatsKeyedByHosts(recent_start_time, + std::set<nqe::internal::IPHash>()); + + if (recent_rtt_stats.empty()) + return; + + // Gets the set of active hosts. Only computes the historical stats for recent + // active hosts. + std::set<nqe::internal::IPHash> active_hosts; + for (const auto& host_stat : recent_rtt_stats) + active_hosts.insert(host_stat.first); + + std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats> + historical_rtt_stats = + rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT] + .GetCanonicalStatsKeyedByHosts(historical_start_time, + active_hosts); + + network_congestion_analyzer_.ComputeRecentQueueingDelay( + recent_rtt_stats, historical_rtt_stats, downlink_kbps); +} + void NetworkQualityEstimator::ComputeEffectiveConnectionType() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -1330,11 +1387,12 @@ const base::Optional<nqe::internal::IPHash>& host) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds()); - Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(), current_network_id_.signal_strength, ProtocolSourceToObservationSource(protocol), host); AddAndNotifyObserversOfRTT(observation); + + ComputeNetworkQueueingDelay(); } void NetworkQualityEstimator::AddAndNotifyObserversOfRTT(
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h index 81c1b3b..3c111ea 100644 --- a/net/nqe/network_quality_estimator.h +++ b/net/nqe/network_quality_estimator.h
@@ -29,6 +29,7 @@ #include "net/nqe/effective_connection_type.h" #include "net/nqe/effective_connection_type_observer.h" #include "net/nqe/event_creator.h" +#include "net/nqe/network_congestion_analyzer.h" #include "net/nqe/network_id.h" #include "net/nqe/network_quality.h" #include "net/nqe/network_quality_estimator_params.h" @@ -51,8 +52,8 @@ namespace nqe { namespace internal { class ThroughputAnalyzer; -} -} +} // namespace internal +} // namespace nqe class URLRequest; @@ -392,6 +393,12 @@ // the signal quality. virtual int32_t GetCurrentSignalStrength() const; + // Computes the recent network queueing delay. It updates the recent + // per-packet queueing delay introduced by the packet queue in the mobile + // edge. Also, it tracks the recent downlink throughput and computes the + // packet queue length. Results are kept in |network_congestion_analyzer_|. + void ComputeNetworkQueueingDelay(); + // Forces computation of effective connection type, and notifies observers // if there is a change in its value. void ComputeEffectiveConnectionType(); @@ -435,6 +442,8 @@ ObservationDiscardedIfCachedEstimateAvailable); FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestRttThroughputObservers); + FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, + TestComputingNetworkQueueingDelay); // Returns the RTT value to be used when the valid RTT is unavailable. Readers // should discard RTT if it is set to the value returned by |InvalidRTT()|. @@ -463,6 +472,9 @@ // Returns true only if the |request| can be used for RTT estimation. bool RequestProvidesRTTObservation(const URLRequest& request) const; + // Returns true if the network queueing delay should be evaluated. + bool ShouldComputeNetworkQueueingDelay() const; + // Returns true if ECT should be recomputed. bool ShouldComputeEffectiveConnectionType() const; @@ -615,6 +627,13 @@ // estimating the throughput. std::unique_ptr<nqe::internal::ThroughputAnalyzer> throughput_analyzer_; + // Minimum duration between two consecutive attampts of computing the network + // queueing delay. + const base::TimeDelta queueing_delay_update_interval_; + + // Time when the computation of network queueing delay was last attempted. + base::TimeTicks last_queueing_delay_computation_; + // Minimum duration between two consecutive computations of effective // connection type. Set to non-zero value as a performance optimization. const base::TimeDelta effective_connection_type_recomputation_interval_; @@ -642,6 +661,10 @@ nqe::internal::NetworkQuality network_quality_; base::Optional<base::TimeDelta> end_to_end_rtt_; + // Recent network congestion status cache. It has methods to update + // information related to network congestion. + nqe::internal::NetworkCongestionAnalyzer network_congestion_analyzer_; + // Current effective connection type. It is updated on connection change // events. It is also updated every time there is network traffic (provided // the last computation was more than
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc index 2852a3f..39b7d5f 100644 --- a/net/nqe/network_quality_estimator_unittest.cc +++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -202,6 +202,7 @@ } // namespace +constexpr float kEpsilon = 0.001f; using NetworkQualityEstimatorTest = TestWithScopedTaskEnvironment; TEST_F(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { @@ -565,6 +566,88 @@ EXPECT_EQ(0U, throughput_observer.observations().size()); } +// Tests that the network queueing delay is updated correctly. +TEST_F(NetworkQualityEstimatorTest, TestComputingNetworkQueueingDelay) { + base::SimpleTestTickClock tick_clock; + std::map<std::string, std::string> variation_params; + variation_params["add_default_platform_observations"] = "false"; + TestNetworkQualityEstimator estimator(variation_params); + estimator.SetTickClockForTesting(&tick_clock); + + // Adds historical and recent RTT observations. Active hosts are + // 0x101010-0x303030. Host 0x404040 did not receive any transport RTT sample + // recently. Host 0x505050 did not have enough RTT samples. + tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); + const base::TimeTicks history = tick_clock.NowTicks(); + + std::map<uint64_t, base::TimeDelta> historical_rtts = { + {0x101010UL, base::TimeDelta::FromMilliseconds(600)}, + {0x202020UL, base::TimeDelta::FromMilliseconds(1000)}, + {0x303030UL, base::TimeDelta::FromMilliseconds(1400)}, + {0x303030UL, base::TimeDelta::FromMilliseconds(1600)}, + {0x303030UL, base::TimeDelta::FromMilliseconds(1800)}, + {0x404040UL, base::TimeDelta::FromMilliseconds(3000)}}; + for (const auto& host_rtt : historical_rtts) { + const uint64_t host = host_rtt.first; + NetworkQualityEstimator::Observation historical_rtt( + historical_rtts[host].InMilliseconds(), history, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, host); + estimator.AddAndNotifyObserversOfRTT(historical_rtt); + } + + // Sets the start time of the current window for computing queueing delay. + tick_clock.Advance(base::TimeDelta::FromMilliseconds(28000)); + const base::TimeTicks window_start_time = tick_clock.NowTicks(); + estimator.last_queueing_delay_computation_ = window_start_time; + + tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); + const base::TimeTicks recent = tick_clock.NowTicks(); + + std::map<uint64_t, base::TimeDelta> recent_rtts = { + {0x101010UL, base::TimeDelta::FromMilliseconds(1500)}, + {0x202020UL, base::TimeDelta::FromMilliseconds(2000)}, + {0x303030UL, base::TimeDelta::FromMilliseconds(2500)}, + {0x505050UL, base::TimeDelta::FromMilliseconds(2000)}}; + for (const auto& host_rtt : recent_rtts) { + const uint64_t host = host_rtt.first; + NetworkQualityEstimator::Observation recent_rtt( + recent_rtts[host].InMilliseconds(), recent, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, host); + estimator.AddAndNotifyObserversOfRTT(recent_rtt); + } + + // Checks that the queueing delay should not be updated because the last + // computation was done within the last 2 seconds. + EXPECT_FALSE(estimator.ShouldComputeNetworkQueueingDelay()); + + // Checks that the number of active hosts is 3. Also, checks that the queueing + // delay is computed correctly based on their RTT observations. + tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); + EXPECT_TRUE(estimator.ShouldComputeNetworkQueueingDelay()); + estimator.ComputeNetworkQueueingDelay(); + EXPECT_EQ(3u, estimator.network_congestion_analyzer_.GetActiveHostsCount()); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), + estimator.network_congestion_analyzer_.recent_queueing_delay()); + EXPECT_EQ(base::nullopt, + estimator.network_congestion_analyzer_.recent_queue_length()); + + // Adds a recent throughput observation. + NetworkQualityEstimator::Observation throughput_observation( + 120, recent, INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, + base::nullopt); + estimator.AddAndNotifyObserversOfThroughput(throughput_observation); + int32_t downlink_kbps = 0; + EXPECT_TRUE( + estimator.GetRecentDownlinkThroughputKbps(recent, &downlink_kbps)); + + // Checks the queue length is updated when the downlink throughput is valid. + estimator.last_queueing_delay_computation_ = window_start_time; + estimator.ComputeNetworkQueueingDelay(); + EXPECT_NEAR( + estimator.network_congestion_analyzer_.recent_queue_length().value_or(0), + 10.0, kEpsilon); +} + TEST_F(NetworkQualityEstimatorTest, QuicObservations) { base::HistogramTester histogram_tester; std::map<std::string, std::string> variation_params;
diff --git a/net/nqe/observation_buffer.cc b/net/nqe/observation_buffer.cc index 8332ba3..4633ea1 100644 --- a/net/nqe/observation_buffer.cc +++ b/net/nqe/observation_buffer.cc
@@ -21,6 +21,24 @@ namespace nqe { namespace internal { +CanonicalStats::CanonicalStats() = default; + +CanonicalStats::CanonicalStats(std::map<int32_t, int32_t>& canonical_pcts, + int32_t most_recent_val, + size_t observation_count) + : canonical_pcts(canonical_pcts), + most_recent_val(most_recent_val), + observation_count(observation_count) {} + +CanonicalStats::CanonicalStats(const CanonicalStats& other) + : canonical_pcts(other.canonical_pcts), + most_recent_val(other.most_recent_val), + observation_count(other.observation_count) {} + +CanonicalStats::~CanonicalStats() = default; + +CanonicalStats& CanonicalStats::operator=(const CanonicalStats& other) = + default; ObservationBuffer::ObservationBuffer( const NetworkQualityEstimatorParams* params, @@ -112,6 +130,65 @@ return weighted_observations.at(weighted_observations.size() - 1).value; } +std::map<IPHash, CanonicalStats> +ObservationBuffer::GetCanonicalStatsKeyedByHosts( + const base::TimeTicks& begin_timestamp, + const std::set<IPHash>& target_hosts) const { + DCHECK_GE(Capacity(), Size()); + + // Computes for all hosts if |target_hosts| is empty. Otherwise, only + // updates map entries for hosts in |target_hosts| and ignores observations + // from other hosts. + bool filter_on_target_hosts = !(target_hosts.empty()); + + // Split observations into several subgroups keyed by their corresponding + // hosts. Skip observations without a host tag. Filter observations based + // on begin_timestamp. If |target_hosts| is not empty, filter obesrvations + // that do not belong to any host in the set. + std::map<IPHash, std::vector<int32_t>> host_keyed_observations; + for (const auto& observation : observations_) { + if (!observation.host()) + continue; + if (observation.timestamp() < begin_timestamp) + continue; + // Skip zero values. Transport RTTs can have zero values in the beginning + // of a connection. It happens because the implementation of TCP's + // Exponentially Weighted Moving Average (EWMA) starts from zero. + if (observation.value() < 1) + continue; + + IPHash host = observation.host().value(); + if (filter_on_target_hosts && target_hosts.find(host) == target_hosts.end()) + continue; + + // Create the map entry if it did not already exist. + host_keyed_observations.emplace(host, std::vector<int32_t>()); + host_keyed_observations[host].push_back(observation.value()); + } + + std::map<IPHash, CanonicalStats> host_keyed_stats; + if (host_keyed_observations.empty()) + return host_keyed_stats; + + // Calculate the canonical percentile values for each host. + for (auto& host_observations : host_keyed_observations) { + const IPHash& host = host_observations.first; + auto& observations = host_observations.second; + host_keyed_stats.emplace(host, CanonicalStats()); + size_t count = observations.size(); + + std::sort(observations.begin(), observations.end()); + for (size_t i = 0; i < base::size(kCanonicalPercentiles); ++i) { + int pct_index = (count - 1) * kCanonicalPercentiles[i] / 100; + host_keyed_stats[host].canonical_pcts[kCanonicalPercentiles[i]] = + observations[pct_index]; + } + host_keyed_stats[host].most_recent_val = observations.back(); + host_keyed_stats[host].observation_count = count; + } + return host_keyed_stats; +} + void ObservationBuffer::RemoveObservationsWithSource( bool deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_MAX]) { base::EraseIf(observations_,
diff --git a/net/nqe/observation_buffer.h b/net/nqe/observation_buffer.h index d3526581..300f7b3 100644 --- a/net/nqe/observation_buffer.h +++ b/net/nqe/observation_buffer.h
@@ -33,7 +33,34 @@ namespace nqe { namespace internal { +constexpr int32_t kStatVal0p = 0; +constexpr int32_t kStatVal5p = 5; +constexpr int32_t kStatVal50p = 50; +constexpr int32_t kStatVal95p = 95; +constexpr int32_t kStatVal99p = 99; +constexpr int32_t kCanonicalPercentiles[] = { + kStatVal0p, kStatVal5p, kStatVal50p, kStatVal95p, kStatVal99p}; +struct NET_EXPORT_PRIVATE CanonicalStats { + CanonicalStats(); + CanonicalStats(std::map<int32_t, int32_t>& canonical_pcts, + int32_t most_recent_val, + size_t observation_count); + CanonicalStats(const CanonicalStats& other); + ~CanonicalStats(); + + CanonicalStats& operator=(const CanonicalStats& other); + + // Canonical percentiles values for a distribution. + std::map<int32_t, int32_t> canonical_pcts; + + // The most recent value. + int32_t most_recent_val = 0; + + // Counts the number of observations that were available for + // computing these results. + size_t observation_count = 0; +}; struct WeightedObservation; // Stores observations sorted by time and provides utility functions for @@ -79,6 +106,16 @@ int percentile, size_t* observations_count) const; + // Computes canonical statistic values of the observations for all hosts if + // |target_hosts| is empty. Otherwise, computes canonical statistic values + // only for hosts that are in the |target_hosts| set. Only observations made + // on or after |begin_timestamp| are considered. Returns all canonical + // statistics keyed by hosts. These include canonical percentile values, the + // most recent value, and the number of observations to compute these values. + std::map<IPHash, CanonicalStats> GetCanonicalStatsKeyedByHosts( + const base::TimeTicks& begin_timestamp, + const std::set<IPHash>& target_hosts) const; + void SetTickClockForTesting(const base::TickClock* tick_clock) { tick_clock_ = tick_clock; }
diff --git a/net/nqe/observation_buffer_unittest.cc b/net/nqe/observation_buffer_unittest.cc index f5d946f..4ccd9b5 100644 --- a/net/nqe/observation_buffer_unittest.cc +++ b/net/nqe/observation_buffer_unittest.cc
@@ -87,6 +87,91 @@ EXPECT_LT(result_lowest, result_highest); } +// Verifies that the percentiles are correctly computed when results must be +// update for each individual host. All observations can have the same timestamp +// or different timestamps. +TEST(NetworkQualityObservationBufferTest, GetPercentileStatsForAllHosts) { + std::map<std::string, std::string> variation_params; + NetworkQualityEstimatorParams params(variation_params); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromMinutes(1)); + // The observation buffer holds mixed observations for different hosts. + ObservationBuffer mixed_buffer(¶ms, &tick_clock, 0.5, 1.0); + const base::TimeTicks now = tick_clock.NowTicks(); + const base::TimeTicks history = now - base::TimeDelta::FromMilliseconds(1); + const base::TimeTicks future = now + base::TimeDelta::FromMilliseconds(1); + const uint64_t host_1 = 0x101010UL; + const uint64_t host_2 = 0x202020UL; + const size_t total_observaions_count = 100; + + // Inserts samples from {1,2,3,...,100} for |host_1|. Insert samples from + // {1,1,2,2,3,3,...,50,50} for |host_2|. Verifies all percentiles are + // computed correctly for both hosts. + for (size_t i = 1; i <= total_observaions_count; ++i) { + mixed_buffer.AddObservation(Observation( + i, now, INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, host_1)); + mixed_buffer.AddObservation( + Observation((i + 1) / 2, now, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, host_2)); + } + EXPECT_EQ(total_observaions_count * 2, mixed_buffer.Size()); + + std::set<uint64_t> empty_hosts_set; + std::map<uint64_t, CanonicalStats> recent_rtt_stats = + mixed_buffer.GetCanonicalStatsKeyedByHosts(history, empty_hosts_set); + + // All observations are categories into two groups keyed by two hosts. + // In each group, all percentile statistics are updated and the number of + // available observations are also updated correctly. + EXPECT_EQ(2u, recent_rtt_stats.size()); + EXPECT_EQ(total_observaions_count, + recent_rtt_stats[host_1].observation_count); + EXPECT_EQ(total_observaions_count, + recent_rtt_stats[host_2].observation_count); + + // Checks all canonical percentile values are correct. + // For |host_1|, percentile_val = percentile. + EXPECT_EQ(1, recent_rtt_stats[host_1].canonical_pcts[kStatVal0p]); + EXPECT_EQ(5, recent_rtt_stats[host_1].canonical_pcts[kStatVal5p]); + EXPECT_EQ(50, recent_rtt_stats[host_1].canonical_pcts[kStatVal50p]); + EXPECT_EQ(95, recent_rtt_stats[host_1].canonical_pcts[kStatVal95p]); + EXPECT_EQ(99, recent_rtt_stats[host_1].canonical_pcts[kStatVal99p]); + // For |host_2|, percentile_val = (percentile + 1) / 2. + EXPECT_EQ(1, recent_rtt_stats[host_2].canonical_pcts[kStatVal0p]); + EXPECT_EQ(3, recent_rtt_stats[host_2].canonical_pcts[kStatVal5p]); + EXPECT_EQ(25, recent_rtt_stats[host_2].canonical_pcts[kStatVal50p]); + EXPECT_EQ(48, recent_rtt_stats[host_2].canonical_pcts[kStatVal95p]); + EXPECT_EQ(50, recent_rtt_stats[host_2].canonical_pcts[kStatVal99p]); + + // Checks results are cleared because all buffered observations expire. + // Expects the result map is empty. + recent_rtt_stats = + mixed_buffer.GetCanonicalStatsKeyedByHosts(future, empty_hosts_set); + + EXPECT_TRUE(recent_rtt_stats.empty()); + + // Checks results contain stats only for hosts that were in the set. + std::set<uint64_t> target_hosts_set = {host_1}; + recent_rtt_stats = + mixed_buffer.GetCanonicalStatsKeyedByHosts(history, target_hosts_set); + EXPECT_EQ(1u, recent_rtt_stats.size()); + EXPECT_EQ(total_observaions_count, + recent_rtt_stats[host_1].observation_count); + EXPECT_EQ(1, recent_rtt_stats[host_1].canonical_pcts[kStatVal0p]); + EXPECT_EQ(5, recent_rtt_stats[host_1].canonical_pcts[kStatVal5p]); + EXPECT_EQ(50, recent_rtt_stats[host_1].canonical_pcts[kStatVal50p]); + EXPECT_EQ(95, recent_rtt_stats[host_1].canonical_pcts[kStatVal95p]); + EXPECT_EQ(99, recent_rtt_stats[host_1].canonical_pcts[kStatVal99p]); + // Checks that host 2 does not present in the results. + EXPECT_TRUE(recent_rtt_stats.find(host_2) == recent_rtt_stats.end()); + + bool deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_MAX] = { + false}; + deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_TCP] = true; + mixed_buffer.RemoveObservationsWithSource(deleted_observation_sources); + EXPECT_EQ(0u, mixed_buffer.Size()); +} + // Verifies that the percentiles are correctly computed. All observations have // the same timestamp. TEST(NetworkQualityObservationBufferTest, PercentileSameTimestamps) {
diff --git a/net/quic/platform/impl/quic_chromium_clock.cc b/net/quic/platform/impl/quic_chromium_clock.cc index 7e3ff3b5..f6be6b2 100644 --- a/net/quic/platform/impl/quic_chromium_clock.cc +++ b/net/quic/platform/impl/quic_chromium_clock.cc
@@ -4,13 +4,14 @@ #include "net/quic/platform/impl/quic_chromium_clock.h" -#include "base/memory/singleton.h" +#include "base/no_destructor.h" #include "base/time/time.h" namespace quic { QuicChromiumClock* QuicChromiumClock::GetInstance() { - return base::Singleton<QuicChromiumClock>::get(); + static base::NoDestructor<QuicChromiumClock> instance; + return instance.get(); } QuicChromiumClock::QuicChromiumClock() {}
diff --git a/net/tools/cert_verify_tool/cert_verify_tool.cc b/net/tools/cert_verify_tool/cert_verify_tool.cc index 75600e71..ef089bd 100644 --- a/net/tools/cert_verify_tool/cert_verify_tool.cc +++ b/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -188,7 +188,9 @@ if (impl_name == "builtin") { return std::make_unique<CertVerifyImplUsingProc>( "CertVerifyProcBuiltin", - net::CreateCertVerifyProcBuiltin(std::move(cert_net_fetcher))); + net::CreateCertVerifyProcBuiltin( + std::move(cert_net_fetcher), + nullptr /* system_trust_store_provider */)); } if (impl_name == "pathbuilder")
diff --git a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java index 39d0a6a7..b16743d 100644 --- a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java +++ b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
@@ -228,7 +228,7 @@ } if (mPendingPushOperation == null) { - callback.call(createError(NfcErrorType.NOT_FOUND)); + callback.call(createError(NfcErrorType.CANNOT_CANCEL)); } else { completePendingPushOperation(createError(NfcErrorType.OPERATION_CANCELLED)); callback.call(null); @@ -376,11 +376,9 @@ */ private NfcError checkIfReady() { if (!mHasPermission || mActivity == null) { - return createError(NfcErrorType.SECURITY); - } else if (mNfcManager == null || mNfcAdapter == null) { - return createError(NfcErrorType.NOT_SUPPORTED); - } else if (!mNfcAdapter.isEnabled()) { - return createError(NfcErrorType.DEVICE_DISABLED); + return createError(NfcErrorType.NOT_ALLOWED); + } else if (mNfcManager == null || mNfcAdapter == null || !mNfcAdapter.isEnabled()) { + return createError(NfcErrorType.NOT_READABLE); } return null; }
diff --git a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java index 1cb6cf7..817024e 100644 --- a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java +++ b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
@@ -164,7 +164,7 @@ } /** - * Test that error with type NOT_SUPPORTED is returned if NFC is not supported. + * Test that error with type NOT_READABLE is returned if NFC is not supported. */ @Test @Feature({"NFCTest"}) @@ -175,7 +175,7 @@ CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class); nfc.cancelAllWatches(mockCallback); verify(mockCallback).call(mErrorCaptor.capture()); - assertEquals(NfcErrorType.NOT_SUPPORTED, mErrorCaptor.getValue().errorType); + assertEquals(NfcErrorType.NOT_READABLE, mErrorCaptor.getValue().errorType); } /** @@ -191,7 +191,7 @@ CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class); nfc.cancelAllWatches(mockCallback); verify(mockCallback).call(mErrorCaptor.capture()); - assertEquals(NfcErrorType.SECURITY, mErrorCaptor.getValue().errorType); + assertEquals(NfcErrorType.NOT_ALLOWED, mErrorCaptor.getValue().errorType); } /**
diff --git a/services/device/public/mojom/nfc.mojom b/services/device/public/mojom/nfc.mojom index 7c20ad3..9c9757c 100644 --- a/services/device/public/mojom/nfc.mojom +++ b/services/device/public/mojom/nfc.mojom
@@ -5,14 +5,19 @@ module device.mojom; enum NFCErrorType { - SECURITY, + // No permssion. + NOT_ALLOWED, + // Operation is not supported by the NFC Adapter NOT_SUPPORTED, - DEVICE_DISABLED, + // No hardware support, no NFC adapter or the adapter is disabled, + // or the connection cannot be established. + NOT_READABLE, NOT_FOUND, INVALID_MESSAGE, OPERATION_CANCELLED, TIMER_EXPIRED, CANNOT_CANCEL, + // Transfer data error. IO_ERROR };
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc index 2e2561b..b32ad48 100644 --- a/services/identity/public/cpp/identity_manager_unittest.cc +++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -72,12 +72,13 @@ const char kTestEmailWithPeriod[] = "m.e@gmail.com"; #endif -// Subclass of FakeProfileOAuth2TokenService with bespoke behavior. -class CustomFakeProfileOAuth2TokenService - : public FakeProfileOAuth2TokenService { +// Subclass of FakeOAuth2AccessTokenManager with bespoke behavior. +class CustomFakeOAuth2AccessTokenManager : public FakeOAuth2AccessTokenManager { public: - CustomFakeProfileOAuth2TokenService(PrefService* user_prefs) - : FakeProfileOAuth2TokenService(user_prefs) {} + CustomFakeOAuth2AccessTokenManager( + OAuth2TokenService* token_service, + OAuth2AccessTokenManager::Delegate* delegate) + : FakeOAuth2AccessTokenManager(token_service, delegate) {} void set_on_access_token_invalidated_info( CoreAccountId expected_account_id_to_invalidate, @@ -91,7 +92,8 @@ } private: - // OAuth2TokenService: + friend class CustomFakeProfileOAuth2TokenService; + // OAuth2AccessTokenManager: void InvalidateAccessTokenImpl(const CoreAccountId& account_id, const std::string& client_id, const ScopeSet& scopes, @@ -103,7 +105,7 @@ // It should trigger OnAccessTokenRemovedFromCache from // IdentityManager::DiagnosticsObserver. - for (auto& observer : GetAccessTokenDiagnosticsObservers()) + for (auto& observer : GetDiagnosticsObserversForTesting()) observer.OnAccessTokenRemoved(account_id, scopes); std::move(on_access_token_invalidated_callback_).Run(); @@ -116,6 +118,44 @@ base::OnceClosure on_access_token_invalidated_callback_; }; +// Subclass of FakeProfileOAuth2TokenService with bespoke behavior. +class CustomFakeProfileOAuth2TokenService + : public FakeProfileOAuth2TokenService { + public: + CustomFakeProfileOAuth2TokenService(PrefService* user_prefs) + : FakeProfileOAuth2TokenService(user_prefs) { + OverrideAccessTokenManagerForTesting( + std::make_unique<CustomFakeOAuth2AccessTokenManager>( + this /* OAuth2TokenService* */, + this /* OAuth2AccessTokenManager::Delegate* */)); + } + + void set_on_access_token_invalidated_info( + CoreAccountId expected_account_id_to_invalidate, + std::set<std::string> expected_scopes_to_invalidate, + std::string expected_access_token_to_invalidate, + base::OnceClosure callback) { + GetCustomAccessTokenManager()->set_on_access_token_invalidated_info( + expected_account_id_to_invalidate, expected_scopes_to_invalidate, + expected_access_token_to_invalidate, std::move(callback)); + } + + private: + // OAuth2TokenService: + void InvalidateAccessTokenImpl(const CoreAccountId& account_id, + const std::string& client_id, + const ScopeSet& scopes, + const std::string& access_token) override { + GetCustomAccessTokenManager()->InvalidateAccessTokenImpl( + account_id, client_id, scopes, access_token); + } + + CustomFakeOAuth2AccessTokenManager* GetCustomAccessTokenManager() { + return static_cast<CustomFakeOAuth2AccessTokenManager*>( + GetAccessTokenManager()); + } +}; + class TestIdentityManagerDiagnosticsObserver : IdentityManager::DiagnosticsObserver { public:
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 4689fe5..59306bf 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -2134,7 +2134,8 @@ std::move(params_->trial_comparison_cert_verifier_params ->report_client), net::CertVerifyProc::CreateDefault(cert_net_fetcher_), - net::CreateCertVerifyProcBuiltin(cert_net_fetcher_))); + net::CreateCertVerifyProcBuiltin( + cert_net_fetcher_, /*system_trust_store_provider=*/nullptr))); } #endif if (!cert_verifier)
diff --git a/styleguide/python/blink-python.md b/styleguide/python/blink-python.md new file mode 100644 index 0000000..f37dd42 --- /dev/null +++ b/styleguide/python/blink-python.md
@@ -0,0 +1,18 @@ +# Blink Python Style Guide + +Blink follows [PEP-8](https://www.python.org/dev/peps/pep-0008/) unless an +exception is listed below. See +[blink/tools/blinkpy/pylintrc](https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/tools/blinkpy/pylintrc). + +_Note: We likely want to converge with [Chromium style](python.md), so this +style recommendation is likely to change._ + +## Differences from PEP-8 + +* Line length limit is 132 + +## Differences from Chromium style + +* Line length limit is 132 +* Uses four-space indent +* Uses `function_name`, `method_name` rather than `FunctionName`, `MethodName`
diff --git a/styleguide/python/python.md b/styleguide/python/python.md index f6cde0e..12f2c52 100644 --- a/styleguide/python/python.md +++ b/styleguide/python/python.md
@@ -15,6 +15,8 @@ [`//styleguide/python/OWNERS`](https://chromium.googlesource.com/chromium/src/+/master/styleguide/python/OWNERS) get to decide. +Blink code in `third_party/blink` uses [Blink style](blink-python.md). + [TOC] ## Differences from PEP-8 @@ -60,4 +62,4 @@ * For Chromium-specific bugs, please discuss on `python@chromium.org`. #### Editor Integration -See: https://github.com/google/yapf/tree/master/plugins \ No newline at end of file +See: https://github.com/google/yapf/tree/master/plugins
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index 81fceb6..0bf581d 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -985,6 +985,9 @@ "test": "components_browsertests" }, { + "args": [ + "--gtest_filter=-CrashAnalyzerTest.StackTraceCollection" + ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 85a1718a..dc89335 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -408,6 +408,12 @@ 'shards': 5, }, }, + 'linux-chromeos-google-rel': { + # TODO(crbug.com/980748): Remove this filter. + 'args': [ + '--gtest_filter=-CrashAnalyzerTest.StackTraceCollection', + ], + }, }, }, 'content_browsertests': {
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 76f47e2..9c35120 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -80,7 +80,7 @@ base::FEATURE_DISABLED_BY_DEFAULT}; // Enable LayoutNG. -const base::Feature kLayoutNG{"LayoutNG", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kLayoutNG{"LayoutNG", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kMixedContentAutoupgrade{"AutoupgradeMixedContent", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/frame/occlusion_state.h b/third_party/blink/public/common/frame/occlusion_state.h index 1faa8d4..4020be2 100644 --- a/third_party/blink/public/common/frame/occlusion_state.h +++ b/third_party/blink/public/common/frame/occlusion_state.h
@@ -5,6 +5,8 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_OCCLUSION_STATE_H_ #define THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_OCCLUSION_STATE_H_ +#include <stdint.h> + #include "third_party/blink/public/common/common_export.h" namespace blink { @@ -21,6 +23,13 @@ kMaxValue = kGuaranteedNotOccluded, }; +// These values are used to implement a browser intervention: if a cross- +// origin iframe has moved more than 30 screen pixels (manhattan distance) +// within its embedding page's viewport within the last 500 milliseconds, most +// input events targeting the iframe will be quietly discarded. +static const uint32_t kMaxChildFrameScreenRectMovement = 30; +static const uint32_t kMinScreenRectStableTimeMs = 500; + } // namespace blink #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_OCCLUSION_STATE_H_
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom index 4350f427..ad0ff46 100644 --- a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom +++ b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
@@ -29,8 +29,10 @@ // Sent from the browser process to the renderer. Contains parameters for the // WebServiceWorkerNetworkProvider used for starting a service worker. struct ServiceWorkerProviderInfoForStartWorker { + // No methods on |host_ptr_info| are called, but it's needed to keep the host + // implementation in the browser process alive. + // TODO(https://crbug.com/931087): Use a separate interface. associated ServiceWorkerContainerHost host_ptr_info; - associated ServiceWorkerContainer& client_request; // The loader to use for loading the worker's main script and // importScripts().
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index adbd4e62..2c35dd5 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2338,6 +2338,7 @@ kCredentialManagerGetWithUVM = 2949, kCredentialManagerCreateSuccessWithUVM = 2950, kCredentialManagerGetSuccessWithUVM = 2951, + kDiscardInputEventToMovingIframe = 2952, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_input_event.h b/third_party/blink/public/platform/web_input_event.h index 2bff74e..cbb93ce 100644 --- a/third_party/blink/public/platform/web_input_event.h +++ b/third_party/blink/public/platform/web_input_event.h
@@ -258,6 +258,10 @@ // in event sending. kFromDebugger = 1 << 23, + // Indicates this event is targeting an OOPIF, and the iframe or one of its + // ancestor frames moved within its embedding page's viewport recently. + kTargetFrameMovedRecently = 1 << 24, + // The set of non-stateful modifiers that specifically change the // interpretation of the key being pressed. For example; IsLeft, // IsRight, IsComposing don't change the meaning of the key @@ -440,6 +444,10 @@ unsigned size() const { return size_; } + void SetTargetFrameMovedRecently() const { + const_cast<WebInputEvent*>(this)->modifiers_ |= kTargetFrameMovedRecently; + } + protected: // The root frame scale. float frame_scale_;
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc index b947474..8b42160 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
@@ -20,7 +20,8 @@ : ContextLifecycleObserver(ExecutionContext::From(script_state)), state_(kPending), script_state_(script_state), - resolver_(script_state) { + resolver_(script_state), + keep_alive_(PERSISTENT_FROM_HERE) { if (GetExecutionContext()->IsContextDestroyed()) { state_ = kDetached; resolver_.Clear();
diff --git a/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc b/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc index 22ca8a75..c99edeea 100644 --- a/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc +++ b/third_party/blink/renderer/core/animation/list_interpolation_functions_test.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/core/animation/list_interpolation_functions.h" #include <utility> -#include <vector> #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h" @@ -47,7 +46,7 @@ // Creates an InterpolationValue containing a list of interpolable and // non-interpolable values from the pairs of input. InterpolationValue CreateInterpolableList( - const std::vector<std::pair<double, int>>& values) { + const Vector<std::pair<double, int>>& values) { return ListInterpolationFunctions::CreateList( values.size(), [&values](size_t i) { return InterpolationValue( @@ -58,7 +57,7 @@ // Creates an InterpolationValue which contains a list of interpolable values, // but a non-interpolable list of nullptrs. -InterpolationValue CreateInterpolableList(const std::vector<double>& values) { +InterpolationValue CreateInterpolableList(const Vector<double>& values) { return ListInterpolationFunctions::CreateList( values.size(), [&values](size_t i) { return InterpolationValue(
diff --git a/third_party/blink/renderer/core/css/css_image_generator_value.cc b/third_party/blink/renderer/core/css/css_image_generator_value.cc index c2227e8..d3c55fe 100644 --- a/third_party/blink/renderer/core/css/css_image_generator_value.cc +++ b/third_party/blink/renderer/core/css/css_image_generator_value.cc
@@ -70,7 +70,7 @@ } CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType class_type) - : CSSValue(class_type) {} + : CSSValue(class_type), keep_alive_(PERSISTENT_FROM_HERE) {} CSSImageGeneratorValue::~CSSImageGeneratorValue() = default;
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 ad63a673..6625f089 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
@@ -76,8 +76,8 @@ // prevented, we don't need to force the subtree layout, so use exclusive // ancestors in that case. auto ancestor_view = [node] { - if (node->IsElementNode()) { - auto* context = ToElement(node)->GetDisplayLockContext(); + if (auto* element = DynamicTo<Element>(node)) { + auto* context = element->GetDisplayLockContext(); if (context && !context->ShouldLayout(DisplayLockContext::kSelf)) return FlatTreeTraversal::InclusiveAncestorsOf(*node); } @@ -100,16 +100,17 @@ const Element* DisplayLockUtilities::NearestLockedInclusiveAncestor( const Node& node) { - if (!node.IsElementNode()) + auto* element = DynamicTo<Element>(node); + if (!element) return NearestLockedExclusiveAncestor(node); if (!RuntimeEnabledFeatures::DisplayLockingEnabled() || !node.isConnected() || node.GetDocument().LockedDisplayLockCount() == 0 || !node.CanParticipateInFlatTree()) { return nullptr; } - if (auto* context = ToElement(node).GetDisplayLockContext()) { + if (auto* context = element->GetDisplayLockContext()) { if (context->IsLocked()) - return &ToElement(node); + return element; } return NearestLockedExclusiveAncestor(node); } @@ -179,8 +180,9 @@ const Node* node = &source_node; // Special case self-node checking. - if (node->GetDocument().LockedDisplayLockCount() && node->IsElementNode()) { - auto* context = ToElement(node)->GetDisplayLockContext(); + auto* element = DynamicTo<Element>(node); + if (element && node->GetDocument().LockedDisplayLockCount()) { + auto* context = element->GetDisplayLockContext(); if (context && !context->ShouldLayout(DisplayLockContext::kSelf)) return true; }
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc index 9939d396..e25e54d4 100644 --- a/third_party/blink/renderer/core/dom/container_node.cc +++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -976,8 +976,9 @@ DISABLE_CFI_PERF void ContainerNode::AttachLayoutTree(AttachContext& context) { - if (IsElementNode() && ToElement(this)->StyleRecalcBlockedByDisplayLock( - DisplayLockContext::kChildren)) { + auto* element = DynamicTo<Element>(this); + if (element && + element->StyleRecalcBlockedByDisplayLock(DisplayLockContext::kChildren)) { // Since we block style recalc on descendants of this node due to display // locking, none of its descendants should have the NeedsReattachLayoutTree // bit set. @@ -985,9 +986,7 @@ // If an element is locked we shouldn't attach the layout tree for its // descendants. We should notify that we blocked a reattach so that we will // correctly attach the descendants when allowed. - ToElement(this) - ->GetDisplayLockContext() - ->NotifyReattachLayoutTreeWasBlocked(); + element->GetDisplayLockContext()->NotifyReattachLayoutTreeWasBlocked(); Node::AttachLayoutTree(context); return; }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 97f7acb..a532335fb 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -5241,13 +5241,10 @@ } while (previous && !previous->IsElementNode()); return ToElement(previous); } - if (next_node->IsElementNode()) - return ToElement(next_node); - Node* next = next_node; - do { - next = FlatTreeTraversal::Next(*next); - } while (next && !next->IsElementNode()); - return ToElement(next); + for (Node* next = next_node; next; next = FlatTreeTraversal::Next(*next)) { + if (auto* element = DynamicTo<Element>(next)) + return element; + } } return nullptr; }
diff --git a/third_party/blink/renderer/core/events/web_input_event_conversion.h b/third_party/blink/renderer/core/events/web_input_event_conversion.h index 7fa760a..81c55799 100644 --- a/third_party/blink/renderer/core/events/web_input_event_conversion.h +++ b/third_party/blink/renderer/core/events/web_input_event_conversion.h
@@ -31,7 +31,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_WEB_INPUT_EVENT_CONVERSION_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_WEB_INPUT_EVENT_CONVERSION_H_ -#include <vector> #include "third_party/blink/public/platform/web_coalesced_input_event.h" #include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/public/platform/web_keyboard_event.h"
diff --git a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc index 65462aa..bee856da 100644 --- a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc +++ b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -4,9 +4,6 @@ #include "third_party/blink/public/platform/web_document_subresource_filter.h" -#include <string> -#include <vector> - #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/platform.h" @@ -33,7 +30,7 @@ LoadPolicy GetLoadPolicy(const WebURL& resource_url, mojom::RequestContextType) override { - std::string resource_path = WebString(KURL(resource_url).GetPath()).Utf8(); + String resource_path = KURL(resource_url).GetPath(); if (std::find(queried_subresource_paths_.begin(), queried_subresource_paths_.end(), resource_path) == queried_subresource_paths_.end()) { @@ -59,13 +56,13 @@ blacklisted_suffixes_.push_back(suffix); } - const std::vector<std::string>& QueriedSubresourcePaths() const { + const Vector<String>& QueriedSubresourcePaths() const { return queried_subresource_paths_; } private: // Using STL types for compatibility with gtest/gmock. - std::vector<std::string> queried_subresource_paths_; + Vector<String> queried_subresource_paths_; Vector<String> blacklisted_suffixes_; LoadPolicy load_policy_; }; @@ -110,7 +107,7 @@ void LoadDocument(TestDocumentSubresourceFilter::LoadPolicy policy) { client_.SetLoadPolicyFromNextLoad(policy); frame_test_helpers::LoadFrame(MainFrame(), - BaseURL() + "foo_with_image.html"); + BaseURL().Utf8() + "foo_with_image.html"); } void ExpectSubresourceWasLoaded(bool loaded) { @@ -120,17 +117,16 @@ EXPECT_EQ(loaded, !!image_element->naturalWidth()); } - const std::string& BaseURL() const { return base_url_; } + const String& BaseURL() const { return base_url_; } WebLocalFrameImpl* MainFrame() { return web_view_helper_.LocalMainFrame(); } - const std::vector<std::string>& QueriedSubresourcePaths() const { + const Vector<String>& QueriedSubresourcePaths() const { return client_.SubresourceFilter()->QueriedSubresourcePaths(); } private: - void RegisterMockedHttpURLLoad(const std::string& file_name) { + void RegisterMockedHttpURLLoad(const String& file_name) { url_test_helpers::RegisterMockedURLLoadFromBase( - WebString::FromUTF8(base_url_), test::CoreTestDataPath(), - WebString::FromUTF8(file_name)); + WebString(base_url_), test::CoreTestDataPath(), WebString(file_name)); } // testing::Test: @@ -142,7 +138,7 @@ SubresourceFilteringWebFrameClient client_; frame_test_helpers::WebViewHelper web_view_helper_; - std::string base_url_; + String base_url_; }; TEST_F(WebDocumentSubresourceFilterTest, AllowedSubresource) {
diff --git a/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc b/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc index 722965f..93f0974 100644 --- a/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc +++ b/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc
@@ -122,7 +122,7 @@ WebFormElementObserverImpl::WebFormElementObserverImpl( HTMLElement& element, base::OnceClosure callback) - : self_keep_alive_(this) { + : self_keep_alive_(PERSISTENT_FROM_HERE, this) { mutation_callback_ = MakeGarbageCollected<ObserverCallback>(element, std::move(callback)); }
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc index 969f491..f5b634e1 100644 --- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc +++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -496,7 +496,7 @@ : WebRemoteFrame(scope), client_(client), frame_client_(MakeGarbageCollected<RemoteFrameClientImpl>(this)), - self_keep_alive_(this) { + self_keep_alive_(PERSISTENT_FROM_HERE, this) { DCHECK(client); }
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc index 853bfaa..c7f11d4 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -27,7 +27,6 @@ #include <memory> #include <utility> -#include <vector> #include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h" #include "third_party/blink/public/platform/platform.h"
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc index 1792c14..8fb0a2e 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc +++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -6,7 +6,6 @@ #include <memory> #include <utility> -#include <vector> #include "services/network/public/cpp/features.h" #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
diff --git a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc index 099801e..83bd3d8 100644 --- a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc +++ b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
@@ -4,8 +4,6 @@ #include "third_party/blink/renderer/core/frame/csp/source_list_directive.h" -#include <vector> - #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
diff --git a/third_party/blink/renderer/core/frame/dom_timer_test.cc b/third_party/blink/renderer/core/frame/dom_timer_test.cc index add9400a..9f982ed49e 100644 --- a/third_party/blink/renderer/core/frame/dom_timer_test.cc +++ b/third_party/blink/renderer/core/frame/dom_timer_test.cc
@@ -4,8 +4,6 @@ #include "third_party/blink/renderer/core/frame/dom_timer.h" -#include <vector> - #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" @@ -35,7 +33,7 @@ // Expected time between each iterator for setInterval(..., 1) or nested // setTimeout(..., 1) are 1, 1, 1, 1, 4, 4, ... as a minimum clamp of 4ms // is applied from the 5th iteration onwards. - const std::vector<Matcher<double>> kExpectedTimings = { + const Vector<Matcher<double>> kExpectedTimings = { DoubleNear(1., kThreshold), DoubleNear(1., kThreshold), DoubleNear(1., kThreshold), DoubleNear(1., kThreshold), DoubleNear(4., kThreshold), DoubleNear(4., kThreshold),
diff --git a/third_party/blink/renderer/core/frame/frame_view.cc b/third_party/blink/renderer/core/frame/frame_view.cc index 0ae6f08..21081403 100644 --- a/third_party/blink/renderer/core/frame/frame_view.cc +++ b/third_party/blink/renderer/core/frame/frame_view.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/intersection_observer/intersection_geometry.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" +#include "third_party/blink/renderer/core/page/page.h" namespace blink { @@ -70,8 +71,21 @@ IntersectionGeometry geometry(nullptr, *owner_element, {}, {IntersectionObserver::kMinimumThreshold}, geometry_flags); - // geometry.IntersectionRect() is in absolute coordinates of the owning - // document. Map it down to absolute coordinates in the child document. + PhysicalRect new_rect_in_parent = geometry.IntersectionRect(); + if (new_rect_in_parent.size != rect_in_parent_.size || + ((new_rect_in_parent.X() - rect_in_parent_.X()).Abs() + + (new_rect_in_parent.Y() - rect_in_parent_.Y()).Abs() > + LayoutUnit(kMaxChildFrameScreenRectMovement))) { + rect_in_parent_ = new_rect_in_parent; + if (Page* page = GetFrame().GetPage()) { + rect_in_parent_stable_since_ = + base::TimeTicks() + base::TimeDelta::FromSecondsD( + page->Animator().Clock().CurrentTime()); + } else { + rect_in_parent_stable_since_ = base::TimeTicks::Now(); + } + } + PhysicalRect intersection_rect = owner_layout_object->AncestorToLocalRect( nullptr, geometry.IntersectionRect()); // Map from the box coordinates of the owner to the inner frame. @@ -149,4 +163,16 @@ } } +bool FrameView::RectInParentIsStable( + const base::TimeTicks& event_timestamp) const { + if (event_timestamp - rect_in_parent_stable_since_ < + base::TimeDelta::FromMilliseconds(kMinScreenRectStableTimeMs)) { + return false; + } + LocalFrameView* parent = ParentFrameView(); + if (!parent) + return true; + return parent->RectInParentIsStable(event_timestamp); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame_view.h b/third_party/blink/renderer/core/frame/frame_view.h index 2de8435..86b0c41c 100644 --- a/third_party/blink/renderer/core/frame/frame_view.h +++ b/third_party/blink/renderer/core/frame/frame_view.h
@@ -8,6 +8,7 @@ #include "third_party/blink/public/common/frame/occlusion_state.h" #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" #include "third_party/blink/renderer/core/frame/embedded_content_view.h" +#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" #include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -52,6 +53,8 @@ bool subtree_throttled, bool recurse = false); + bool RectInParentIsStable(const base::TimeTicks& timestamp) const; + protected: virtual void SetViewportIntersection(const IntRect& viewport_intersection, FrameOcclusionState occlusion_state) = 0; @@ -63,6 +66,8 @@ void UpdateFrameVisibility(bool); private: + PhysicalRect rect_in_parent_; + base::TimeTicks rect_in_parent_stable_since_; blink::mojom::FrameVisibility frame_visibility_ = blink::mojom::FrameVisibility::kRenderedInViewport; bool hidden_for_throttling_;
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 2bf09644b..b4e75c8b 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -83,6 +83,7 @@ #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/inspector/inspector_task_runner.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h" #include "third_party/blink/renderer/core/layout/hit_test_result.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -1325,6 +1326,16 @@ return LocalFrameRoot().GetOcclusionState(); } +bool LocalFrame::NeedsOcclusionTracking() const { + if (Document* document = GetDocument()) { + if (IntersectionObserverController* controller = + document->GetIntersectionObserverController()) { + return controller->NeedsOcclusionTracking(); + } + } + return false; +} + void LocalFrame::ForceSynchronousDocumentInstall( const AtomicString& mime_type, scoped_refptr<SharedBuffer> data) {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index 44e202a..581f938 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -356,6 +356,7 @@ return remote_viewport_intersection_; } FrameOcclusionState GetOcclusionState() const; + bool NeedsOcclusionTracking() const; // Replaces the initial empty document with a Document suitable for // |mime_type| and populated with the contents of |data|. Only intended for
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 69f4db5..e7f0785 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1036,7 +1036,6 @@ UpdateViewportIntersectionsForSubtree( IntersectionObservation::kImplicitRootObserversNeedUpdate | IntersectionObservation::kIgnoreDelay); - frame_->Owner()->SetNeedsOcclusionTracking(false); } LayoutSVGRoot* LocalFrameView::EmbeddedReplacedContent() const {
diff --git a/third_party/blink/renderer/core/frame/sandbox_flags.h b/third_party/blink/renderer/core/frame/sandbox_flags.h index df8ef0ed..4c5c622 100644 --- a/third_party/blink/renderer/core/frame/sandbox_flags.h +++ b/third_party/blink/renderer/core/frame/sandbox_flags.h
@@ -27,8 +27,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_SANDBOX_FLAGS_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_SANDBOX_FLAGS_H_ -#include <vector> - #include "third_party/blink/public/common/feature_policy/feature_policy.h" #include "third_party/blink/public/common/frame/sandbox_flags.h" #include "third_party/blink/renderer/core/dom/space_split_string.h"
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index e80e5f8..7895029 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -902,7 +902,7 @@ }, { name: "darkModeImagePolicy", - initial: "DarkModeImagePolicy::kFilterAll", + initial: "DarkModeImagePolicy::kFilterNone", type: "DarkModeImagePolicy", invalidate: "Paint", },
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index abe502c..2fcd0d1 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -145,7 +145,7 @@ WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient& client) : WebFrameWidgetBase(client), - self_keep_alive_(this) {} + self_keep_alive_(PERSISTENT_FROM_HERE, this) {} WebFrameWidgetImpl::~WebFrameWidgetImpl() = default;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index 2ea36ad..e55ac915 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -1714,7 +1714,7 @@ interface_registry_(interface_registry), input_method_controller_(*this), spell_check_panel_host_client_(nullptr), - self_keep_alive_(this) { + self_keep_alive_(PERSISTENT_FROM_HERE, this) { DCHECK(client_); g_frame_count++; client_->BindToFrame(this);
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 3941e27..531edb3 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -11,8 +11,9 @@ WebViewFrameWidget::WebViewFrameWidget(WebWidgetClient& client, WebViewImpl& web_view) - : WebFrameWidgetBase(client), web_view_(&web_view), self_keep_alive_(this) { -} + : WebFrameWidgetBase(client), + web_view_(&web_view), + self_keep_alive_(PERSISTENT_FROM_HERE, this) {} WebViewFrameWidget::~WebViewFrameWidget() = default;
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc index b0d1320..4f3c750 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc +++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h" #include <initializer_list> -#include <vector> #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h" #include "third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h" @@ -16,7 +15,7 @@ namespace blink { TEST(CustomElementReactionQueueTest, invokeReactions_one) { - std::vector<char> log; + Vector<char> log; CustomElementReactionQueue* queue = MakeGarbageCollected<CustomElementReactionQueue>(); HeapVector<Member<Command>>* commands = @@ -25,12 +24,12 @@ queue->Add(*MakeGarbageCollected<TestReaction>(commands)); Element* test_element = CreateElement(AtomicString("my-element")); queue->InvokeReactions(*test_element); - EXPECT_EQ(log, std::vector<char>({'a'})) + EXPECT_EQ(log, Vector<char>({'a'})) << "the reaction should have been invoked"; } TEST(CustomElementReactionQueueTest, invokeReactions_many) { - std::vector<char> log; + Vector<char> log; CustomElementReactionQueue* queue = MakeGarbageCollected<CustomElementReactionQueue>(); { @@ -53,12 +52,12 @@ } Element* test_element = CreateElement(AtomicString("my-element")); queue->InvokeReactions(*test_element); - EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'})) + EXPECT_EQ(log, Vector<char>({'a', 'b', 'c'})) << "the reaction should have been invoked"; } TEST(CustomElementReactionQueueTest, invokeReactions_recursive) { - std::vector<char> log; + Vector<char> log; CustomElementReactionQueue* queue = MakeGarbageCollected<CustomElementReactionQueue>(); @@ -87,12 +86,12 @@ queue->Add(*first); Element* test_element = CreateElement(AtomicString("my-element")); queue->InvokeReactions(*test_element); - EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'})) + EXPECT_EQ(log, Vector<char>({'a', 'b', 'c'})) << "the reactions should have been invoked"; } TEST(CustomElementReactionQueueTest, clear_duringInvoke) { - std::vector<char> log; + Vector<char> log; CustomElementReactionQueue* queue = MakeGarbageCollected<CustomElementReactionQueue>(); @@ -119,7 +118,7 @@ Element* test_element = CreateElement(AtomicString("my-element")); queue->InvokeReactions(*test_element); - EXPECT_EQ(log, std::vector<char>({'a'})) + EXPECT_EQ(log, Vector<char>({'a'})) << "only 'a' should be logged; the second log should have been cleared"; }
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc index b46132e..7bfb171 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc +++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h" #include <initializer_list> -#include <vector> #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,7 +16,7 @@ namespace blink { TEST(CustomElementReactionStackTest, one) { - std::vector<char> log; + Vector<char> log; CustomElementReactionStack* stack = MakeGarbageCollected<CustomElementReactionStack>(); @@ -29,12 +28,12 @@ *MakeGarbageCollected<TestReaction>(commands)); stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'a'})) + EXPECT_EQ(log, Vector<char>({'a'})) << "popping the reaction stack should run reactions"; } TEST(CustomElementReactionStackTest, multipleElements) { - std::vector<char> log; + Vector<char> log; CustomElementReactionStack* stack = MakeGarbageCollected<CustomElementReactionStack>(); @@ -55,12 +54,12 @@ } stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'a', 'b'})) + EXPECT_EQ(log, Vector<char>({'a', 'b'})) << "reactions should run in the order the elements queued"; } TEST(CustomElementReactionStackTest, popTopEmpty) { - std::vector<char> log; + Vector<char> log; CustomElementReactionStack* stack = MakeGarbageCollected<CustomElementReactionStack>(); @@ -73,12 +72,12 @@ stack->Push(); stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>()) + EXPECT_EQ(log, Vector<char>()) << "popping the empty top-of-stack should not run any reactions"; } TEST(CustomElementReactionStackTest, popTop) { - std::vector<char> log; + Vector<char> log; CustomElementReactionStack* stack = MakeGarbageCollected<CustomElementReactionStack>(); @@ -100,12 +99,12 @@ } stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'b'})) + EXPECT_EQ(log, Vector<char>({'b'})) << "popping the top-of-stack should only run top-of-stack reactions"; } TEST(CustomElementReactionStackTest, requeueingDoesNotReorderElements) { - std::vector<char> log; + Vector<char> log; Element& element = *CreateElement("a"); @@ -135,12 +134,12 @@ } stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'a', 'b', 'z'})) + EXPECT_EQ(log, Vector<char>({'a', 'b', 'z'})) << "reactions should run together in the order elements were queued"; } TEST(CustomElementReactionStackTest, oneReactionQueuePerElement) { - std::vector<char> log; + Vector<char> log; Element& element = *CreateElement("a"); @@ -178,12 +177,12 @@ } stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'y', 'a', 'b'})) + EXPECT_EQ(log, Vector<char>({'y', 'a', 'b'})) << "reactions should run together in the order elements were queued"; log.clear(); stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'z'})) << "reactions should be run once"; + EXPECT_EQ(log, Vector<char>({'z'})) << "reactions should be run once"; } class EnqueueToStack : public Command { @@ -212,7 +211,7 @@ }; TEST(CustomElementReactionStackTest, enqueueFromReaction) { - std::vector<char> log; + Vector<char> log; Element& element = *CreateElement("a"); @@ -232,9 +231,9 @@ } stack->PopInvokingReactions(); - EXPECT_EQ(log, std::vector<char>({'a'})) << "enqueued reaction from another " - "reaction should run in the same " - "invoke"; + EXPECT_EQ(log, Vector<char>({'a'})) << "enqueued reaction from another " + "reaction should run in the same " + "invoke"; } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h b/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h index a746fe3d..b240c4d 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h +++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
@@ -9,7 +9,6 @@ #include <initializer_list> #include <memory> -#include <vector> #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,13 +59,13 @@ class Log : public Command { public: - Log(char what, std::vector<char>& where) : what_(what), where_(where) {} + Log(char what, Vector<char>& where) : what_(what), where_(where) {} ~Log() override = default; void Run(Element&) override { where_.push_back(what_); } private: char what_; - std::vector<char>& where_; + Vector<char>& where_; DISALLOW_COPY_AND_ASSIGN(Log); };
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h index 6f5062b..e4de6deb 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h +++ b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
@@ -171,7 +171,7 @@ AtomicString namespace_uri_; AtomicString local_name_; AtomicString is_value_; - std::vector<std::pair<QualifiedName, AtomicString>> attributes_; + Vector<std::pair<QualifiedName, AtomicString>> attributes_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc index d31e5eee..869f8a0 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -2065,7 +2065,7 @@ return; for (const auto& record : records) { if (record->type() == "attributes") { - const Element& element = *ToElement(record->target()); + const auto& element = *To<Element>(record->target()); if (record->oldValue() == element.getAttribute(record->attributeName())) continue; } else if (record->type() == "characterData") {
diff --git a/third_party/blink/renderer/core/html/html_slot_element_test.cc b/third_party/blink/renderer/core/html/html_slot_element_test.cc index 085fe72..a0012df 100644 --- a/third_party/blink/renderer/core/html/html_slot_element_test.cc +++ b/third_party/blink/renderer/core/html/html_slot_element_test.cc
@@ -16,7 +16,7 @@ namespace { constexpr int kTableSize = 16; -using Seq = std::vector<char>; +using Seq = Vector<char>; using Backtrack = std::pair<size_t, size_t>; } @@ -28,9 +28,8 @@ std::array<std::array<Backtrack, kTableSize>, kTableSize> backtrack_table_; }; -std::vector<char> HTMLSlotElementTest::LongestCommonSubsequence( - const Seq& seq1, - const Seq& seq2) { +Vector<char> HTMLSlotElementTest::LongestCommonSubsequence(const Seq& seq1, + const Seq& seq2) { HTMLSlotElement::FillLongestCommonSubsequenceDynamicProgrammingTable( seq1, seq2, lcs_table_, backtrack_table_); Seq lcs;
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc index d1bdd7a..61b7cde 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element_event_listeners_test.cc
@@ -211,7 +211,7 @@ Persistent<MediaCustomControlsFullscreenDetector> detector = FullscreenDetector(); - std::vector<blink::WebFullscreenVideoStatus> observed_results; + Vector<blink::WebFullscreenVideoStatus> observed_results; ON_CALL(*WebMediaPlayer(), SetIsEffectivelyFullscreen(_)) .WillByDefault(testing::Invoke(
diff --git a/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/third_party/blink/renderer/core/html/media/html_video_element_test.cc index a0dc8fe..954f311 100644 --- a/third_party/blink/renderer/core/html/media/html_video_element_test.cc +++ b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -119,7 +119,7 @@ // This is testing all possible values of WebFullscreenVideoStatus and then // sets the value back to a value that should put the DisplayType back to // inline. - std::vector<std::pair<WebFullscreenVideoStatus, WebMediaPlayer::DisplayType>> + Vector<std::pair<WebFullscreenVideoStatus, WebMediaPlayer::DisplayType>> tests = { {WebFullscreenVideoStatus::kNotEffectivelyFullscreen, WebMediaPlayer::DisplayType::kInline},
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 344bd58..8e088ae 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -712,6 +712,10 @@ return result; } + if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(), + *frame_)) + return WebInputEventResult::kHandledSuppressed; + std::unique_ptr<UserGestureIndicator> gesture_indicator = LocalFrame::NotifyUserActivation(frame_); frame_->LocalFrameRoot() @@ -1096,28 +1100,35 @@ if (subframe) return PassMouseReleaseEventToSubframe(mev, subframe); - // Mouse events will be associated with the Document where mousedown - // occurred. If, e.g., there is a mousedown, then a drag to a different - // Document and mouseup there, the mouseup's gesture will be associated with - // the mousedown's Document. It's not absolutely certain that this is the - // correct behavior. - std::unique_ptr<UserGestureIndicator> gesture_indicator; - if (frame_->LocalFrameRoot() - .GetEventHandler() - .last_mouse_down_user_gesture_token_) { - gesture_indicator = std::make_unique<UserGestureIndicator>( - std::move(frame_->LocalFrameRoot() - .GetEventHandler() - .last_mouse_down_user_gesture_token_)); - } else { - gesture_indicator = LocalFrame::NotifyUserActivation(frame_); - } + WebInputEventResult event_result = WebInputEventResult::kNotHandled; - WebInputEventResult event_result = DispatchMousePointerEvent( - WebInputEvent::kPointerUp, mev.InnerElement(), mev.CanvasRegionId(), - mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>(), - (GetSelectionController().HasExtendedSelection() && - IsSelectionOverLink(mev))); + std::unique_ptr<UserGestureIndicator> gesture_indicator; + if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(), + *frame_)) { + event_result = WebInputEventResult::kHandledSuppressed; + } else { + // Mouse events will be associated with the Document where mousedown + // occurred. If, e.g., there is a mousedown, then a drag to a different + // Document and mouseup there, the mouseup's gesture will be associated with + // the mousedown's Document. It's not absolutely certain that this is the + // correct behavior. + if (frame_->LocalFrameRoot() + .GetEventHandler() + .last_mouse_down_user_gesture_token_) { + gesture_indicator = std::make_unique<UserGestureIndicator>( + std::move(frame_->LocalFrameRoot() + .GetEventHandler() + .last_mouse_down_user_gesture_token_)); + } else { + gesture_indicator = LocalFrame::NotifyUserActivation(frame_); + } + + event_result = DispatchMousePointerEvent( + WebInputEvent::kPointerUp, mev.InnerElement(), mev.CanvasRegionId(), + mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>(), + (GetSelectionController().HasExtendedSelection() && + IsSelectionOverLink(mev))); + } scroll_manager_->ClearResizeScrollableArea(false); @@ -1498,6 +1509,10 @@ WebInputEventResult EventHandler::HandleGestureEventInFrame( const GestureEventWithHitTestResults& targeted_event) { + if (event_handling_util::ShouldDiscardEventTargetingFrame( + targeted_event.Event(), *frame_)) { + return WebInputEventResult::kHandledSuppressed; + } return gesture_manager_->HandleGestureEventInFrame(targeted_event); }
diff --git a/third_party/blink/renderer/core/input/event_handling_util.cc b/third_party/blink/renderer/core/input/event_handling_util.cc index 0125ff2..fc1d1b9 100644 --- a/third_party/blink/renderer/core/input/event_handling_util.cc +++ b/third_party/blink/renderer/core/input/event_handling_util.cc
@@ -127,6 +127,30 @@ mev); } +bool ShouldDiscardEventTargetingFrame(const WebInputEvent& event, + const LocalFrame& frame) { + if (!RuntimeEnabledFeatures::DiscardInputToMovingIframesEnabled()) + return false; + + // There are two different mechanisms for tracking whether an iframe has moved + // recently, for OOPIF and in-process iframes. For OOPIF's, frame movement is + // tracked in the browser process using hit test data, and it's propagated + // in event.GetModifiers(). For in-process iframes, frame movement is tracked + // during lifecycle updates, in FrameView::UpdateViewportIntersection, and + // propagated via FrameView::RectInParentIsStable. + bool should_discard = false; + if (frame.NeedsOcclusionTracking() && frame.IsCrossOriginSubframe()) { + should_discard = + (event.GetModifiers() & WebInputEvent::kTargetFrameMovedRecently) || + !frame.View()->RectInParentIsStable(event.TimeStamp()); + } + if (should_discard) { + UseCounter::Count(frame.GetDocument(), + WebFeature::kDiscardInputEventToMovingIframe); + } + return should_discard; +} + LocalFrame* SubframeForTargetNode(Node* node, bool* is_remote_frame) { if (!node) return nullptr;
diff --git a/third_party/blink/renderer/core/input/event_handling_util.h b/third_party/blink/renderer/core/input/event_handling_util.h index 36871eb..9d5e6b9 100644 --- a/third_party/blink/renderer/core/input/event_handling_util.h +++ b/third_party/blink/renderer/core/input/event_handling_util.h
@@ -53,6 +53,13 @@ LocalFrame* SubframeForTargetNode(Node*, bool* is_remote_frame = nullptr); +// Intervention: if an input event lands on a cross-origin iframe that has +// moved or resized recently (recent==500ms), and which contains an +// IntersectionObserver that is tracking visibility, then the event is quietly +// discarded. +bool ShouldDiscardEventTargetingFrame(const WebInputEvent& event, + const LocalFrame& frame); + class PointerEventTarget { DISALLOW_NEW();
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc index ee5126d..cf33cd3a 100644 --- a/third_party/blink/renderer/core/input/pointer_event_manager.cc +++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -598,6 +598,30 @@ event_handling_util::PointerEventTarget pointer_event_target = ComputePointerEventTarget(pointer_event); + bool discard = pointer_event_target.target_frame && + event_handling_util::ShouldDiscardEventTargetingFrame( + event, *pointer_event_target.target_frame); + if (discard) { + PointerEvent* pointer_event = pointer_event_factory_.Create( + event, coalesced_events, predicted_events, + pointer_event_target.target_element + ? pointer_event_target.target_element->GetDocument().domWindow() + : nullptr); + SendTouchPointerEvent(pointer_event_target.target_element, + pointer_event_factory_.CreatePointerCancelEvent( + pointer_event->pointerId(), event.TimeStamp()), + event.hovering); + + WebPointerEvent pointer_cancel_event; + pointer_cancel_event.pointer_type = event.pointer_type; + pointer_cancel_event.SetTimeStamp(event.TimeStamp()); + pointer_cancel_event.SetType(WebInputEvent::kPointerCancel); + touch_event_manager_->HandleTouchPoint( + pointer_cancel_event, coalesced_events, pointer_event_target); + + return WebInputEventResult::kHandledSuppressed; + } + // Any finger lifting is a user gesture only when it wasn't associated with a // scroll. // https://docs.google.com/document/d/1oF1T3O7_E4t1PYHV6gyCwHxOi3ystm0eSL5xZu7nvOg/edit#
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.idl b/third_party/blink/renderer/core/intersection_observer/intersection_observer.idl index b53d71e1..f96388f 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.idl +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.idl
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://wicg.github.io/IntersectionObserver/#intersection-observer-callback +// https://www.w3.org/TR/intersection-observer/#intersection-observer-interface callback IntersectionObserverCallback = void (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer); -// https://wicg.github.io/IntersectionObserver/#intersection-observer-interface - [ + Exposed=Window, ActiveScriptWrappable, Constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options), ConstructorCallWith=ScriptState,
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc index 0fe8f35..1da67bf 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc
@@ -69,7 +69,7 @@ bool IntersectionObserverController::ComputeTrackedIntersectionObservations( unsigned flags) { - bool needs_occlusion_tracking = false; + needs_occlusion_tracking_ = false; if (Document* document = To<Document>(GetExecutionContext())) { TRACE_EVENT0("blink", "IntersectionObserverController::" @@ -77,11 +77,11 @@ HeapVector<Member<Element>> elements_to_process; CopyToVector(tracked_observation_targets_, elements_to_process); for (auto& element : elements_to_process) { - needs_occlusion_tracking |= + needs_occlusion_tracking_ |= element->ComputeIntersectionObservations(flags); } } - return needs_occlusion_tracking; + return needs_occlusion_tracking_; } void IntersectionObserverController::AddTrackedTarget(Element& target, @@ -89,6 +89,7 @@ tracked_observation_targets_.insert(&target); if (!track_occlusion) return; + needs_occlusion_tracking_ = true; if (LocalFrameView* frame_view = target.GetDocument().View()) { if (FrameOwner* frame_owner = frame_view->GetFrame().Owner()) { // Set this bit as early as possible, rather than waiting for a lifecycle
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h index 516756a..7986f18 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h
@@ -45,6 +45,7 @@ // observers for which observer->trackVisibility() is true. void AddTrackedTarget(Element&, bool); void RemoveTrackedTarget(Element&); + bool NeedsOcclusionTracking() const { return needs_occlusion_tracking_; } void Trace(blink::Visitor*) override; const char* NameInHeapSnapshot() const override { @@ -68,6 +69,9 @@ // get supported by either of wrapper-tracing or unified GC. HeapVector<Member<IntersectionObserver>> intersection_observers_being_invoked_; + // This is 'true' if any tracked observation target is being tracked by an + // observer for which observer->trackVisibility() is true. + bool needs_occlusion_tracking_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc index 4eb246b..e4a6a64 100644 --- a/third_party/blink/renderer/core/layout/hit_test_result.cc +++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -229,8 +229,8 @@ inner_node_ = area; inner_possibly_pseudo_node_ = area; } - if (inner_node_->IsElementNode()) - inner_element_ = ToElement(inner_node_); + if (auto* element = DynamicTo<Element>(inner_node_.Get())) + inner_element_ = element; else inner_element_ = FlatTreeTraversal::ParentElement(*inner_node_); } @@ -275,8 +275,8 @@ inner_node_->UpdateDistributionForFlatTreeTraversal(); for (Node* title_node = inner_node_.Get(); title_node; title_node = FlatTreeTraversal::Parent(*title_node)) { - if (title_node->IsElementNode()) { - String title = ToElement(title_node)->title(); + if (auto* element = DynamicTo<Element>(title_node)) { + String title = element->title(); if (!title.IsNull()) { if (LayoutObject* layout_object = title_node->GetLayoutObject()) dir = layout_object->StyleRef().Direction();
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 2e9fa45..a1794ba 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2779,7 +2779,7 @@ // get the right dirty rect. Since this is called from // LayoutObject::setStyle, the relative position flag on the LayoutObject // has been cleared, so use the one on the style(). - container_offset += Layer()->OffsetForInFlowPosition(); + container_offset += OffsetForInFlowPosition(); } if (skip_info.FilterSkipped()) {
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index f46d59c..738ec5d 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1425,7 +1425,8 @@ // get the right dirty rect. Since this is called from LayoutObject:: // setStyle, the relative position flag on the LayoutObject has been // cleared, so use the one on the style(). - transform_state.Move(Layer()->OffsetForInFlowPosition(), accumulation); + transform_state.Move(Layer()->GetLayoutObject().OffsetForInFlowPosition(), + accumulation); } LayoutBox* container_box =
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc index 78f3c1f..eb15ec9 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -684,10 +684,39 @@ bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>:: ShouldInsertBreakOpportunityAfterLeadingPreservedSpaces( const String& string, - const ComputedStyle& style) const { - return text_.IsEmpty() && string.length() > 0 && - string[0] == kSpaceCharacter && !style.CollapseWhiteSpace() && - style.AutoWrap(); + const ComputedStyle& style, + unsigned index) const { + DCHECK_LE(index, string.length()); + // Check if we are at a preserved space character and auto-wrap is enabled. + if (style.CollapseWhiteSpace() || !style.AutoWrap() || !string.length() || + index >= string.length() || string[index] != kSpaceCharacter) + return false; + + // Preserved leading spaces must be at the beginning of the first line or just + // after a forced break. + if (index) + return string[index - 1] == kNewlineCharacter; + return text_.IsEmpty() || text_[text_.length() - 1] == kNewlineCharacter; +} + +template <typename OffsetMappingBuilder> +void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>:: + InsertBreakOpportunityAfterLeadingPreservedSpaces( + const String& string, + const ComputedStyle& style, + LayoutText* layout_object, + unsigned* start) { + DCHECK(start); + if (UNLIKELY(ShouldInsertBreakOpportunityAfterLeadingPreservedSpaces( + string, style, *start))) { + wtf_size_t end = *start; + do { + ++end; + } while (end < string.length() && string[end] == kSpaceCharacter); + AppendTextItem(StringView(string, *start, end - *start), layout_object); + AppendGeneratedBreakOpportunity(layout_object); + *start = end; + } } // TODO(yosin): We should remove |style| and |string| parameter because of @@ -707,21 +736,19 @@ // opportunity after leading preserved spaces needs a special code in the line // breaker. Generate an opportunity to make it easy. unsigned start = 0; - if (UNLIKELY(ShouldInsertBreakOpportunityAfterLeadingPreservedSpaces( - string, *style))) { - do { - ++start; - } while (start < string.length() && string[start] == kSpaceCharacter); - AppendTextItem(StringView(string, 0, start), layout_object); - AppendGeneratedBreakOpportunity(layout_object); - } - + InsertBreakOpportunityAfterLeadingPreservedSpaces(string, *style, + layout_object, &start); for (; start < string.length();) { UChar c = string[start]; if (IsControlItemCharacter(c)) { if (c == kNewlineCharacter) { AppendForcedBreak(layout_object); start++; + // A forced break is not a collapsible space, but following collapsible + // spaces are leading spaces and they need a special code in the line + // breaker. Generate an opportunity to make it easy. + InsertBreakOpportunityAfterLeadingPreservedSpaces( + string, *style, layout_object, &start); } else if (c == kTabulationCharacter) { wtf_size_t end = string.Find( [](UChar c) { return c != kTabulationCharacter; }, start + 1);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h index 78cf02d..9645ee7 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -220,7 +220,12 @@ bool ShouldInsertBreakOpportunityAfterLeadingPreservedSpaces( const String&, - const ComputedStyle&) const; + const ComputedStyle&, + unsigned index = 0) const; + void InsertBreakOpportunityAfterLeadingPreservedSpaces(const String&, + const ComputedStyle&, + LayoutText*, + unsigned* start); }; template <>
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc index 71f5399..df95d2f 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -187,7 +187,7 @@ } TEST_F(NGInlineItemsBuilderTest, CollapseNewLines) { - String input("text\ntext \n text\n\ntext"); + String input("text\ntext \ntext\n\ntext"); String collapsed("text text text text"); TestWhitespaceValue(collapsed, input, EWhiteSpace::kNormal); TestWhitespaceValue(collapsed, input, EWhiteSpace::kNowrap); @@ -425,6 +425,9 @@ u"\u200B" "a"), TestAppend({{" a", EWhiteSpace::kPreWrap}})); + EXPECT_EQ(String("a\n" + u" \u200B"), + TestAppend({{"a\n ", EWhiteSpace::kPreWrap}})); } TEST_F(NGInlineItemsBuilderTest, BidiBlockOverride) {
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache.idl b/third_party/blink/renderer/core/loader/appcache/application_cache.idl index e5826d20..b2d793b 100644 --- a/third_party/blink/renderer/core/loader/appcache/application_cache.idl +++ b/third_party/blink/renderer/core/loader/appcache/application_cache.idl
@@ -26,6 +26,7 @@ // https://html.spec.whatwg.org/C/#application-cache-api [ + Exposed=Window, DoNotCheckConstants, SecureContext=RestrictAppCacheToSecureContexts // TODO(foolip): Exposed=(Window,SharedWorker)
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 36f4b8b..fc2d4d8 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -1781,7 +1781,6 @@ void DocumentLoader::InitializePrefetchedSignedExchangeManager() { if (params_->prefetched_signed_exchanges.empty()) return; - DCHECK(RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled()); // |prefetched_signed_exchanges| is set only when the page is loaded from a // signed exchange. DCHECK(GetResponse().IsSignedExchangeInnerResponse());
diff --git a/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc b/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc index bf76226..14196adc 100644 --- a/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc +++ b/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
@@ -95,7 +95,6 @@ } if (prefetched_signed_exchange_manager_) { - DCHECK(RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled()); auto loader = prefetched_signed_exchange_manager_->MaybeCreateURLLoader(webreq); if (loader)
diff --git a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc index 9c563a6..082844f 100644 --- a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc +++ b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
@@ -131,7 +131,6 @@ const String& inner_link_header, WebVector<std::unique_ptr<WebNavigationParams::PrefetchedSignedExchange>> prefetched_signed_exchanges) { - DCHECK(RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled()); if (prefetched_signed_exchanges.empty()) return nullptr; std::unique_ptr<AlternateSignedExchangeResourceInfo> alternative_resources = @@ -163,7 +162,6 @@ : frame_(frame), alternative_resources_(std::move(alternative_resources)), prefetched_exchanges_map_(std::move(prefetched_exchanges_map)) { - DCHECK(RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled()); } PrefetchedSignedExchangeManager::~PrefetchedSignedExchangeManager() {}
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc index aba3ed59..ef4981c 100644 --- a/third_party/blink/renderer/core/loader/preload_helper.cc +++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -504,12 +504,13 @@ LinkLoadParameters params(header, base_url); if (alternate_resource_info && params.rel.IsLinkPreload()) { - DCHECK( - RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled()); + DCHECK(document); + DCHECK(RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled( + document)); KURL url = params.href; base::Optional<ResourceType> resource_type = PreloadHelper::GetResourceTypeFromAsAttribute(params.as); - if (document && resource_type == ResourceType::kImage && + if (resource_type == ResourceType::kImage && !params.image_srcset.IsEmpty()) { // |media_values| is created based on the viewport dimensions of the // current page that prefetched SXGs, not on the viewport of the SXG
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc index d3a056ee..17784531 100644 --- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h" #include <memory> -#include <vector> #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h"
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc index c684aa74..ab60354 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
@@ -145,7 +145,8 @@ response.RemoteIPAddress()); std::unique_ptr<AlternateSignedExchangeResourceInfo> alternate_resource_info; - if (RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled() && + if (RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled( + &frame_or_imported_document_->GetDocument()) && response.IsSignedExchangeInnerResponse() && resource->GetType() == ResourceType::kLinkPrefetch && resource->LastResourceResponse()) {
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc index 3adca3d..c216056 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader.cc +++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -110,7 +110,7 @@ public: explicit DetachedClient(ThreadableLoader* loader) - : self_keep_alive_(this), loader_(loader) {} + : self_keep_alive_(PERSISTENT_FROM_HERE, this), loader_(loader) {} ~DetachedClient() override {} void DidFinishLoading(uint64_t identifier) override {
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc index 5864542..db72b274 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
@@ -68,11 +68,11 @@ ASSERT_EQ(out.message->GetArrayBufferContentsArray().size(), 1U); WTF::ArrayBufferContents& deserialized_contents = out.message->GetArrayBufferContentsArray()[0]; - std::vector<uint8_t> deserialized_data( - static_cast<uint8_t*>(deserialized_contents.Data()), - static_cast<uint8_t*>(deserialized_contents.Data()) + 8); + Vector<uint8_t> deserialized_data; + deserialized_data.Append(static_cast<uint8_t*>(deserialized_contents.Data()), + 8); ASSERT_EQ(deserialized_data.size(), 8U); - for (uint8_t i = 0; i < deserialized_data.size(); i++) { + for (wtf_size_t i = 0; i < deserialized_data.size(); i++) { ASSERT_TRUE(deserialized_data[i] == i); } }
diff --git a/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/third_party/blink/renderer/core/page/context_menu_controller_test.cc index 1a2d7aa4b..a7815a0f 100644 --- a/third_party/blink/renderer/core/page/context_menu_controller_test.cc +++ b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -136,7 +136,7 @@ EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type); EXPECT_EQ(video_url, context_menu_data.src_url.GetString()); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true}, @@ -197,7 +197,7 @@ EXPECT_EQ(WebContextMenuData::kMediaTypeAudio, context_menu_data.media_type); EXPECT_EQ(video_url, context_menu_data.src_url.GetString()); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true}, @@ -254,7 +254,7 @@ EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type); EXPECT_EQ(video_url, context_menu_data.src_url.GetString()); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true}, @@ -311,7 +311,7 @@ EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type); EXPECT_EQ(video_url, context_menu_data.src_url.GetString()); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true}, @@ -369,7 +369,7 @@ GetWebFrameClient().GetContextMenuData(); EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true}, @@ -432,7 +432,7 @@ EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type); EXPECT_EQ(video_url, context_menu_data.src_url.GetString()); - const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>> + const Vector<std::pair<WebContextMenuData::MediaFlags, bool>> expected_media_flags = { {WebContextMenuData::kMediaInError, false}, {WebContextMenuData::kMediaPaused, true},
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index 8bf85ff..b4193c4 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -3513,9 +3513,9 @@ auto* node = GetLayoutObject().GetNode(); if (!node) return false; - if (target == DisplayLockContextLifecycleTarget::kSelf && - node->IsElementNode()) { - if (auto* context = ToElement(node)->GetDisplayLockContext()) { + auto* element = DynamicTo<Element>(node); + if (target == DisplayLockContextLifecycleTarget::kSelf && element) { + if (auto* context = element->GetDisplayLockContext()) { if (!context->ShouldPaint(DisplayLockContext::kSelf)) return true; }
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 954f57fd..45d5f64 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -845,14 +845,8 @@ } } - if (GetLayoutObject().IsInFlowPositioned()) { - PhysicalOffset new_offset = GetLayoutObject().OffsetForInFlowPosition(); - if (rare_data_ || !new_offset.IsZero()) - EnsureRareData().offset_for_in_flow_position = new_offset; - local_point += new_offset; - } else if (rare_data_) { - rare_data_->offset_for_in_flow_position = PhysicalOffset(); - } + if (GetLayoutObject().IsInFlowPositioned()) + local_point += GetLayoutObject().OffsetForInFlowPosition(); location_ = local_point;
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index 31312c27..725923a 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -122,9 +122,6 @@ PaintLayerRareData(); ~PaintLayerRareData(); - // Our current relative position offset. - PhysicalOffset offset_for_in_flow_position; - std::unique_ptr<TransformationMatrix> transform; // Pointer to the enclosing Layer that caused us to be paginated. It is 0 if @@ -345,11 +342,6 @@ PaintLayer* RenderingContextRoot(); const PaintLayer* RenderingContextRoot() const; - PhysicalOffset OffsetForInFlowPosition() const { - return rare_data_ ? rare_data_->offset_for_in_flow_position - : PhysicalOffset(); - } - bool IsStackingContextWithNegativeZOrderChildren() const { DCHECK(!stacking_node_ || GetLayoutObject().StyleRef().IsStackingContext()); return stacking_node_ && !stacking_node_->NegZOrderList().IsEmpty();
diff --git a/third_party/blink/renderer/core/paint/text_element_timing.cc b/third_party/blink/renderer/core/paint/text_element_timing.cc index 62179ed..d61c176 100644 --- a/third_party/blink/renderer/core/paint/text_element_timing.cc +++ b/third_party/blink/renderer/core/paint/text_element_timing.cc
@@ -39,11 +39,13 @@ // static FloatRect TextElementTiming::ComputeIntersectionRect( - Node* node, + const LayoutObject& object, const IntRect& aggregated_visual_rect, const PropertyTreeState& property_tree_state, const LocalFrameView* frame_view) { - if (!NeededForElementTiming(node)) + Node* node = object.GetNode(); + DCHECK(node); + if (!NeededForElementTiming(*node)) return FloatRect(); FloatClipRect float_clip_visual_rect = @@ -55,7 +57,7 @@ return float_clip_visual_rect.Rect(); } -void TextElementTiming::OnTextNodesPainted( +void TextElementTiming::OnTextObjectsPainted( const Deque<base::WeakPtr<TextRecord>>& text_nodes_painted) { DCHECK(performance_); // If the entries cannot be exposed via PerformanceObserver nor added to the @@ -71,7 +73,7 @@ // Text aggregators should be Elements! DCHECK(node->IsElementNode()); - Element* element = ToElement(node); + auto* element = To<Element>(node); const AtomicString& attr = element->FastGetAttribute(html_names::kElementtimingAttr); if (attr.IsEmpty())
diff --git a/third_party/blink/renderer/core/paint/text_element_timing.h b/third_party/blink/renderer/core/paint/text_element_timing.h index 79a2eb2..1c78ee96 100644 --- a/third_party/blink/renderer/core/paint/text_element_timing.h +++ b/third_party/blink/renderer/core/paint/text_element_timing.h
@@ -8,6 +8,7 @@ #include "base/memory/weak_ptr.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/timing/window_performance.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/wtf/deque.h" @@ -33,22 +34,22 @@ static TextElementTiming& From(LocalDOMWindow&); - static inline bool NeededForElementTiming(Node* node) { - return !node->IsInShadowTree() && node->IsElementNode() && - !ToElement(node) + static inline bool NeededForElementTiming(Node& node) { + return !node.IsInShadowTree() && node.IsElementNode() && + !ToElement(&node) ->FastGetAttribute(html_names::kElementtimingAttr) .IsEmpty(); } static FloatRect ComputeIntersectionRect( - Node*, + const LayoutObject&, const IntRect& aggregated_visual_rect, const PropertyTreeState&, const LocalFrameView*); // Called when the swap promise queued by TextPaintTimingDetector has been // resolved. Dispatches PerformanceElementTiming entries to WindowPerformance. - void OnTextNodesPainted(const Deque<base::WeakPtr<TextRecord>>&); + void OnTextObjectsPainted(const Deque<base::WeakPtr<TextRecord>>&); void Trace(blink::Visitor* visitor) override;
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc index 967a94d4..20228cf 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -27,7 +27,7 @@ namespace { -constexpr size_t kTextNodeNumberLimit = 5000; +constexpr size_t kTextObjectNumberLimit = 5000; bool LargeTextFirst(const base::WeakPtr<TextRecord>& a, const base::WeakPtr<TextRecord>& b) { @@ -165,7 +165,7 @@ } } } - records_manager_.AssignPaintTimeToQueuedNodes(timestamp); + records_manager_.AssignPaintTimeToQueuedRecords(timestamp); if (records_manager_.GetLargestTextPaintManager()) records_manager_.GetLargestTextPaintManager()->UpdateCandidate(); awaiting_swap_promise_ = false; @@ -184,7 +184,7 @@ // shadow element or has no elementtiming attribute, then we should not record // its text. if (!records_manager_.IsRecordingLargestTextPaint() && - !TextElementTiming::NeededForElementTiming(node)) + !TextElementTiming::NeededForElementTiming(*node)) return false; DOMNodeId node_id = DOMNodeIds::ExistingIdForNode(node); @@ -200,12 +200,7 @@ const IntRect& aggregated_visual_rect, const PropertyTreeState& property_tree_state) { DCHECK(ShouldWalkObject(aggregator)); - DCHECK(!records_manager_.HasTooManyNodes()); - - Node* node = aggregator.GetNode(); - DCHECK(node); - DOMNodeId node_id = DOMNodeIds::IdForNode(node); - DCHECK_NE(node_id, kInvalidDOMNodeId); + DCHECK(!records_manager_.HasTooManyObjects()); // The caller should check this. DCHECK(!aggregated_visual_rect.IsEmpty()); @@ -221,15 +216,15 @@ records_manager_.RecordVisibleObject( aggregator, aggregated_size, TextElementTiming::ComputeIntersectionRect( - node, aggregated_visual_rect, property_tree_state, frame_view_), - node_id); + aggregator, aggregated_visual_rect, property_tree_state, + frame_view_)); } - if (records_manager_.HasTooManyNodes()) { - TRACE_EVENT_INSTANT2("loading", "TextPaintTimingDetector::OverNodeLimit", - TRACE_EVENT_SCOPE_THREAD, "count_size_non_zero_nodes", + if (records_manager_.HasTooManyObjects()) { + TRACE_EVENT_INSTANT2("loading", "TextPaintTimingDetector::OverRecordLimit", + TRACE_EVENT_SCOPE_THREAD, "count_visible_objects", records_manager_.CountVisibleObjects(), - "count_size_zero_nodes", + "count_invisible_objects", records_manager_.CountInvisibleObjects()); StopRecordEntries(); } @@ -262,12 +257,12 @@ } void TextRecordsManager::RemoveVisibleRecord(const LayoutObject& object) { - DCHECK(visible_node_map_.Contains(&object)); + DCHECK(visible_objects_.Contains(&object)); if (ltp_manager_) { ltp_manager_->RemoveVisibleRecord( - visible_node_map_.at(&object)->AsWeakPtr()); + visible_objects_.at(&object)->AsWeakPtr()); } - visible_node_map_.erase(&object); + visible_objects_.erase(&object); // We don't need to remove elements in |texts_queued_for_paint_time_| and // |cached_largest_paint_candidate_| as they are weak ptr. } @@ -277,11 +272,11 @@ } void TextRecordsManager::RemoveInvisibleRecord(const LayoutObject& object) { - DCHECK(invisible_node_ids_.Contains(&object)); - invisible_node_ids_.erase(&object); + DCHECK(invisible_objects_.Contains(&object)); + invisible_objects_.erase(&object); } -void TextRecordsManager::AssignPaintTimeToQueuedNodes( +void TextRecordsManager::AssignPaintTimeToQueuedRecords( const base::TimeTicks& timestamp) { // If texts_queued_for_paint_time_.size == 0, it means the array has been // consumed in a callback earlier than this one. That violates the assumption @@ -300,7 +295,7 @@ record->paint_time = timestamp; } if (text_element_timing_) - text_element_timing_->OnTextNodesPainted(texts_queued_for_paint_time_); + text_element_timing_->OnTextObjectsPainted(texts_queued_for_paint_time_); texts_queued_for_paint_time_.clear(); if (ltp_manager_) ltp_manager_->SetCachedResultInvalidated(true); @@ -309,11 +304,14 @@ void TextRecordsManager::RecordVisibleObject( const LayoutObject& object, const uint64_t& visual_size, - const FloatRect& element_timing_rect, - DOMNodeId node_id) { - DCHECK(!HasTooManyNodes()); + const FloatRect& element_timing_rect) { + DCHECK(!HasTooManyObjects()); DCHECK_GT(visual_size, 0u); + Node* node = object.GetNode(); + DCHECK(node); + DOMNodeId node_id = DOMNodeIds::IdForNode(node); + DCHECK_NE(node_id, kInvalidDOMNodeId); std::unique_ptr<TextRecord> record = std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect); base::WeakPtr<TextRecord> record_weak_ptr = record->AsWeakPtr(); @@ -321,12 +319,12 @@ ltp_manager_->InsertRecord(record_weak_ptr); QueueToMeasurePaintTime(record_weak_ptr); - visible_node_map_.insert(&object, std::move(record)); + visible_objects_.insert(&object, std::move(record)); } -bool TextRecordsManager::HasTooManyNodes() const { - return visible_node_map_.size() + invisible_node_ids_.size() >= - kTextNodeNumberLimit; +bool TextRecordsManager::HasTooManyObjects() const { + return visible_objects_.size() + invisible_objects_.size() >= + kTextObjectNumberLimit; } base::WeakPtr<TextRecord> LargestTextPaintManager::FindLargestPaintCandidate() { @@ -353,8 +351,8 @@ } void TextRecordsManager::CleanUp() { - visible_node_map_.clear(); - invisible_node_ids_.clear(); + visible_objects_.clear(); + invisible_objects_.clear(); texts_queued_for_paint_time_.clear(); CleanUpLargestTextPaint(); }
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h index d296c9fc..42cf69d8 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -104,33 +104,32 @@ void RemoveVisibleRecord(const LayoutObject&); void RemoveInvisibleRecord(const LayoutObject&); inline void RecordInvisibleObject(const LayoutObject& object) { - DCHECK(!HasTooManyNodes()); - invisible_node_ids_.insert(&object); + DCHECK(!HasTooManyObjects()); + invisible_objects_.insert(&object); } void RecordVisibleObject(const LayoutObject&, const uint64_t& visual_size, - const FloatRect& element_timing_rect, - DOMNodeId); + const FloatRect& element_timing_rect); bool NeedMeausuringPaintTime() const { return !texts_queued_for_paint_time_.IsEmpty(); } - void AssignPaintTimeToQueuedNodes(const base::TimeTicks&); + void AssignPaintTimeToQueuedRecords(const base::TimeTicks&); - bool HasTooManyNodes() const; + bool HasTooManyObjects() const; inline bool HasRecorded(const LayoutObject& object) const { - return visible_node_map_.Contains(&object) || - invisible_node_ids_.Contains(&object); + return visible_objects_.Contains(&object) || + invisible_objects_.Contains(&object); } - size_t CountVisibleObjects() const { return visible_node_map_.size(); } - size_t CountInvisibleObjects() const { return invisible_node_ids_.size(); } + size_t CountVisibleObjects() const { return visible_objects_.size(); } + size_t CountInvisibleObjects() const { return invisible_objects_.size(); } inline bool IsKnownVisible(const LayoutObject& object) const { - return visible_node_map_.Contains(&object); + return visible_objects_.Contains(&object); } inline bool IsKnownInvisible(const LayoutObject& object) const { - return invisible_node_ids_.Contains(&object); + return invisible_objects_.Contains(&object); } void CleanUp(); @@ -159,11 +158,11 @@ texts_queued_for_paint_time_.push_back(std::move(record)); } - // Once LayoutObject* is destroyed, |visible_node_map_| and - // |invisible_node_ids_| must immediately clear the corresponding record from + // Once LayoutObject* is destroyed, |visible_objects_| and + // |invisible_objects_| must immediately clear the corresponding record from // themselves. - HashMap<const LayoutObject*, std::unique_ptr<TextRecord>> visible_node_map_; - HashSet<const LayoutObject*> invisible_node_ids_; + HashMap<const LayoutObject*, std::unique_ptr<TextRecord>> visible_objects_; + HashSet<const LayoutObject*> invisible_objects_; Deque<base::WeakPtr<TextRecord>> texts_queued_for_paint_time_; base::Optional<LargestTextPaintManager> ltp_manager_;
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc index 8cf8e34..4abf3aa 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -50,7 +50,7 @@ wtf_size_t CountVisibleTexts() { DCHECK(GetTextPaintTimingDetector()); return GetTextPaintTimingDetector() - ->records_manager_.visible_node_map_.size(); + ->records_manager_.visible_objects_.size(); } wtf_size_t CountRankingSetSize() {
diff --git a/third_party/blink/renderer/core/scheduler/scheduler_affecting_features_test.cc b/third_party/blink/renderer/core/scheduler/scheduler_affecting_features_test.cc index 2725de3..7c1c09e 100644 --- a/third_party/blink/renderer/core/scheduler/scheduler_affecting_features_test.cc +++ b/third_party/blink/renderer/core/scheduler/scheduler_affecting_features_test.cc
@@ -30,8 +30,8 @@ // Some features (e.g. document.load) are expected to appear in almost // any output. Filter them out to make most of the tests simpler. - std::vector<SchedulingPolicy::Feature> GetNonTrivialMainFrameFeatures() { - std::vector<SchedulingPolicy::Feature> result; + Vector<SchedulingPolicy::Feature> GetNonTrivialMainFrameFeatures() { + Vector<SchedulingPolicy::Feature> result; for (SchedulingPolicy::Feature feature : MainFrameScheduler() ->GetActiveFeaturesTrackedForBackForwardCacheMetrics()) {
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc index 798a062..7150774 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -27,6 +27,7 @@ #include "base/optional.h" #include "build/build_config.h" +#include "cc/input/scrollbar.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_mouse_event.h" #include "third_party/blink/public/platform/web_point.h" @@ -363,11 +364,11 @@ } base::TimeDelta ScrollbarTheme::InitialAutoscrollTimerDelay() { - return base::TimeDelta::FromMilliseconds(250); + return kInitialAutoscrollTimerDelay; } base::TimeDelta ScrollbarTheme::AutoscrollTimerDelay() { - return base::TimeDelta::FromMilliseconds(50); + return base::TimeDelta::FromSecondsD(1.f / kAutoscrollMultiplier); } ScrollbarTheme& ScrollbarTheme::DeprecatedStaticGetTheme() {
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc index b11557be..8efb464 100644 --- a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc +++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
@@ -39,6 +39,26 @@ namespace blink { +struct PriorityCompare { + PriorityCompare(double elapsed) : elapsed_(elapsed) {} + bool operator()(const Member<SVGSMILElement>& a, + const Member<SVGSMILElement>& b) { + // FIXME: This should also consider possible timing relations between the + // elements. + SMILTime a_begin = a->IntervalBegin(); + SMILTime b_begin = b->IntervalBegin(); + // Frozen elements need to be prioritized based on their previous interval. + a_begin = a->IsFrozen() && elapsed_ < a_begin ? a->PreviousIntervalBegin() + : a_begin; + b_begin = b->IsFrozen() && elapsed_ < b_begin ? b->PreviousIntervalBegin() + : b_begin; + if (a_begin == b_begin) + return a->DocumentOrderIndex() < b->DocumentOrderIndex(); + return a_begin < b_begin; + } + double elapsed_; +}; + static constexpr base::TimeDelta kAnimationPolicyOnceDuration = base::TimeDelta::FromSeconds(3); @@ -79,15 +99,16 @@ DCHECK(!prevent_scheduled_animations_changes_); #endif - AttributeAnimationsMap& attribute_map = - scheduled_animations_.insert(target, AttributeAnimationsMap()) - .stored_value->value; - Member<AnimationsLinkedHashSet>& scheduled = + auto& attribute_map = + scheduled_animations_.insert(target, AttributeMap()).stored_value->value; + + auto& scheduled = attribute_map.insert(attribute_name, nullptr).stored_value->value; if (!scheduled) - scheduled = MakeGarbageCollected<AnimationsLinkedHashSet>(); + scheduled = MakeGarbageCollected<ScheduledVector>(); + DCHECK(!scheduled->Contains(animation)); - scheduled->insert(animation); + scheduled->push_back(animation); SMILTime next_fire_time = animation->NextProgressTime(); if (next_fire_time.IsFinite()) @@ -103,18 +124,18 @@ DCHECK(!prevent_scheduled_animations_changes_); #endif - GroupedAnimationsMap::iterator it = scheduled_animations_.find(target); + AnimationsMap::iterator it = scheduled_animations_.find(target); CHECK(it != scheduled_animations_.end()); - AttributeAnimationsMap& attribute_map = it->value; - AttributeAnimationsMap::iterator attribute_map_it = - attribute_map.find(attribute_name); + AttributeMap& attribute_map = it->value; + AttributeMap::iterator attribute_map_it = attribute_map.find(attribute_name); DCHECK(attribute_map_it != attribute_map.end()); - AnimationsLinkedHashSet* scheduled = attribute_map_it->value; - AnimationsLinkedHashSet::iterator it_animation = scheduled->find(animation); - DCHECK(it_animation != scheduled->end()); - scheduled->erase(it_animation); + auto& scheduled = *(attribute_map_it->value); - if (scheduled->IsEmpty()) + auto* position = std::find(scheduled.begin(), scheduled.end(), animation); + DCHECK(scheduled.end() != position); + scheduled.erase(position); + + if (scheduled.IsEmpty()) attribute_map.erase(attribute_map_it); if (attribute_map.IsEmpty()) scheduled_animations_.erase(it); @@ -237,8 +258,7 @@ #endif for (const auto& attribute_entry : scheduled_animations_) { for (const auto& entry : attribute_entry.value) { - const AnimationsLinkedHashSet* scheduled = entry.value; - for (SVGSMILElement* element : *scheduled) { + for (SVGSMILElement* element : *entry.value) { element->Reset(); } } @@ -353,26 +373,6 @@ document_order_indexes_dirty_ = false; } -struct PriorityCompare { - PriorityCompare(double elapsed) : elapsed_(elapsed) {} - bool operator()(const Member<SVGSMILElement>& a, - const Member<SVGSMILElement>& b) { - // FIXME: This should also consider possible timing relations between the - // elements. - SMILTime a_begin = a->IntervalBegin(); - SMILTime b_begin = b->IntervalBegin(); - // Frozen elements need to be prioritized based on their previous interval. - a_begin = a->IsFrozen() && elapsed_ < a_begin ? a->PreviousIntervalBegin() - : a_begin; - b_begin = b->IsFrozen() && elapsed_ < b_begin ? b->PreviousIntervalBegin() - : b_begin; - if (a_begin == b_begin) - return a->DocumentOrderIndex() < b->DocumentOrderIndex(); - return a_begin < b_begin; - } - double elapsed_; -}; - SVGSVGElement& SMILTimeContainer::OwnerSVGElement() const { return *owner_svg_element_; } @@ -426,7 +426,7 @@ #if DCHECK_IS_ON() // This boolean will catch any attempts to schedule/unschedule - // scheduledAnimations during this critical section. Similarly, any elements + // scheduledAnimations during this critical section. Similarly, any elements // removed will unschedule themselves, so this will catch modification of // animationsToApply. prevent_scheduled_animations_changes_ = true; @@ -435,37 +435,38 @@ if (document_order_indexes_dirty_) UpdateDocumentOrderIndexes(); - using AnimationsVector = HeapVector<Member<SVGSMILElement>>; - AnimationsVector animations_to_apply; - AnimationsVector scheduled_animations_in_same_group; for (auto& attribute_entry : scheduled_animations_) { - AttributeAnimationsMap& attribute_map = attribute_entry.value; + AttributeMap& attribute_map = attribute_entry.value; Vector<QualifiedName> invalid_keys; - for (const auto& entry : attribute_map) { - DCHECK(entry.value); - if (entry.value->IsEmpty()) { + for (auto& entry : attribute_map) { + if (entry.value->IsEmpty()) invalid_keys.push_back(entry.key); - continue; + } + attribute_map.RemoveAll(invalid_keys); + } + + HeapVector<ScheduledVector> active_sandwiches; + active_sandwiches.ReserveInitialCapacity(scheduled_animations_.size()); + for (auto& attribute_entry : scheduled_animations_) { + AttributeMap& attribute_map = attribute_entry.value; + for (auto& entry : attribute_map) { + auto& scheduled = *entry.value; + if (!std::is_sorted(scheduled.begin(), scheduled.end(), + PriorityCompare(elapsed))) { + std::sort(scheduled.begin(), scheduled.end(), PriorityCompare(elapsed)); } - - // Sort according to priority. Elements with later begin time have higher - // priority. In case of a tie, document order decides. - // FIXME: This should also consider timing relationships between the - // elements. Dependents have higher priority. - CopyToVector(*entry.value, scheduled_animations_in_same_group); - std::sort(scheduled_animations_in_same_group.begin(), - scheduled_animations_in_same_group.end(), - PriorityCompare(elapsed)); - - AnimationsVector sandwich; - for (const auto& it_animation : scheduled_animations_in_same_group) { + ScheduledVector sandwich; + for (const auto& it_animation : scheduled) { SVGSMILElement* animation = it_animation.Get(); DCHECK_EQ(animation->TimeContainer(), this); DCHECK(animation->HasValidTarget()); // This will calculate the contribution from the animation and update // timing. - if (animation->Progress(elapsed, seek_to_time)) { + if (animation->NeedsToProgress(elapsed, seek_to_time)) { + animation->Progress(elapsed, seek_to_time); + sandwich.push_back(animation); + } else if (animation->IsContributing(elapsed)) { sandwich.push_back(animation); } else { animation->ClearAnimatedType(); @@ -477,23 +478,64 @@ } if (!sandwich.IsEmpty()) { - // Results are accumulated to the first animation that animates and - // contributes to a particular element/attribute pair. - // Only reset the animated type to the base value once for - // the lowest priority animation that animates and - // contributes to a particular element/attribute pair. - SVGSMILElement* result_element = sandwich.front(); - result_element->ResetAnimatedType(); - - // Go through the sandwich from lowest prio to highest and generate - // the animated value (if any.) - for (const auto& animation : sandwich) - animation->UpdateAnimatedValue(result_element); - - animations_to_apply.push_back(result_element); + active_sandwiches.push_back(sandwich); } } - attribute_map.RemoveAll(invalid_keys); + } + + if (active_sandwiches.IsEmpty()) { +#if DCHECK_IS_ON() + prevent_scheduled_animations_changes_ = false; +#endif + return earliest_fire_time; + } + + ScheduledVector animations_to_apply; + for (auto& sandwich : active_sandwiches) { + if (seek_to_time) { + for (auto& animation : sandwich) { + animation->TriggerPendingEvents(elapsed); + } + } + + for (auto& animation : sandwich) { + animation->UpdateNextProgressTime(elapsed); + } + + auto* it = sandwich.begin(); + while (it != sandwich.end()) { + auto* scheduled = it->Get(); + if (scheduled->IsContributing(elapsed)) { + it++; + continue; + } + scheduled->ClearAnimatedType(); + it = sandwich.erase(it); + } + + if (sandwich.IsEmpty()) { + continue; + } + + for (auto& animation : sandwich) { + SMILTime next_fire_time = animation->NextProgressTime(); + if (next_fire_time.IsFinite()) + earliest_fire_time = std::min(next_fire_time, earliest_fire_time); + } + + // Results are accumulated to the first animation that animates and + // contributes to a particular element/attribute pair. + // Only reset the animated type to the base value once for + // the lowest priority animation that animates and + // contributes to a particular element/attribute pair. + SVGSMILElement* result_element = sandwich.front(); + result_element->ResetAnimatedType(); + // Go through the sandwich from lowest prio to highest and generate + // the animated value (if any.) + for (auto& animation : sandwich) { + animation->UpdateAnimatedValue(result_element); + } + animations_to_apply.push_back(result_element); } if (animations_to_apply.IsEmpty()) {
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.h b/third_party/blink/renderer/core/svg/animation/smil_time_container.h index ad3e1ad..24a9ca84 100644 --- a/third_party/blink/renderer/core/svg/animation/smil_time_container.h +++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.h
@@ -45,6 +45,11 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> { public: + // Sorted list + using ScheduledVector = HeapVector<Member<SVGSMILElement>>; + using AttributeMap = HeapHashMap<QualifiedName, Member<ScheduledVector>>; + using AnimationsMap = HeapHashMap<WeakMember<SVGElement>, AttributeMap>; + explicit SMILTimeContainer(SVGSVGElement& owner); ~SMILTimeContainer(); @@ -131,12 +136,7 @@ TaskRunnerTimer<SMILTimeContainer> wakeup_timer_; TaskRunnerTimer<SMILTimeContainer> animation_policy_once_timer_; - using AnimationsLinkedHashSet = HeapLinkedHashSet<WeakMember<SVGSMILElement>>; - using AttributeAnimationsMap = - HeapHashMap<QualifiedName, Member<AnimationsLinkedHashSet>>; - using GroupedAnimationsMap = - HeapHashMap<WeakMember<SVGElement>, AttributeAnimationsMap>; - GroupedAnimationsMap scheduled_animations_; + AnimationsMap scheduled_animations_; Member<SVGSVGElement> owner_svg_element_;
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc index ea22338..4a2118df 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -804,9 +804,9 @@ IntervalSelector interval_selector) const { bool first = interval_selector == kFirstInterval; // See the pseudocode in http://www.w3.org/TR/SMIL3/smil-timing.html#q90. - SMILTime begin_after = - first ? -std::numeric_limits<double>::infinity() : interval_.end; - SMILTime last_interval_temp_end = std::numeric_limits<double>::infinity(); + auto constexpr infinity = std::numeric_limits<double>::infinity(); + SMILTime begin_after = first ? -infinity : interval_.end; + SMILTime last_interval_temp_end = infinity; while (true) { bool equals_minimum_ok = !first || interval_.end > interval_.begin; SMILTime temp_begin = @@ -950,7 +950,7 @@ void SVGSMILElement::SeekToIntervalCorrespondingToTime(double elapsed) { DCHECK(!is_waiting_for_first_interval_); - DCHECK(elapsed >= interval_.begin); + DCHECK(interval_.begin.IsFinite()); // Manually seek from interval to interval, just as if the animation would run // regulary. @@ -988,47 +988,60 @@ } } -float SVGSMILElement::CalculateAnimationPercentAndRepeat( - double elapsed, - unsigned& repeat) const { - SMILTime simple_duration = this->SimpleDuration(); - repeat = 0; +unsigned SVGSMILElement::CalculateAnimationRepeat(double elapsed) const { + const SMILTime simple_duration = SimpleDuration(); + if (simple_duration.IsIndefinite() || !simple_duration) + return 0; + DCHECK(simple_duration.IsFinite()); + DCHECK(interval_.begin.IsFinite()); + + double active_time = std::max(elapsed - interval_.begin.Value(), 0.0); + double simple_duration_value = simple_duration.Value(); + double repeating_duration = RepeatingDuration().Value(); + if (elapsed >= interval_.end || active_time > repeating_duration) { + unsigned repeat = + static_cast<unsigned>(repeating_duration / simple_duration_value); + if (!fmod(repeating_duration, simple_duration_value)) + return repeat - 1; + return repeat; + } + unsigned repeat = static_cast<unsigned>(active_time / simple_duration_value); + return repeat; +} + +float SVGSMILElement::CalculateAnimationPercent(double elapsed) const { + SMILTime simple_duration = SimpleDuration(); if (simple_duration.IsIndefinite()) { - repeat = 0; return 0.f; } if (!simple_duration) { - repeat = 0; return 1.f; } - DCHECK(interval_.begin.IsFinite()); DCHECK(simple_duration.IsFinite()); - double active_time = elapsed - interval_.begin.Value(); - SMILTime repeating_duration = this->RepeatingDuration(); - if (elapsed >= interval_.end || active_time > repeating_duration) { - repeat = static_cast<unsigned>(repeating_duration.Value() / - simple_duration.Value()); - if (!fmod(repeating_duration.Value(), simple_duration.Value())) - repeat--; + DCHECK(interval_.begin.IsFinite()); + double active_time = elapsed - interval_.begin.Value(); + double simple_duration_value = simple_duration.Value(); + double repeating_duration = RepeatingDuration().Value(); + if (elapsed >= interval_.end || active_time > repeating_duration) { // Use the interval to compute the interval position if we've passed the // interval end, otherwise use the "repeating duration". This prevents a // stale interval (with for instance an 'indefinite' end) from yielding an // invalid interval position. - double last_active_duration = - elapsed >= interval_.end - ? interval_.end.Value() - interval_.begin.Value() - : repeating_duration.Value(); - double percent = last_active_duration / simple_duration.Value(); + double last_active_duration; + if (elapsed >= interval_.end) + last_active_duration = interval_.end.Value() - interval_.begin.Value(); + else + last_active_duration = repeating_duration; + double percent = last_active_duration / simple_duration_value; percent = percent - floor(percent); - if (percent < std::numeric_limits<float>::epsilon() || - 1 - percent < std::numeric_limits<float>::epsilon()) + float epsilon = std::numeric_limits<float>::epsilon(); + if (percent < epsilon || 1 - percent < epsilon) return 1.0f; return clampTo<float>(percent); } - repeat = static_cast<unsigned>(active_time / simple_duration.Value()); - double simple_time = fmod(active_time, simple_duration.Value()); - return clampTo<float>(simple_time / simple_duration.Value()); + double simple_time = fmod(active_time, simple_duration_value); + return clampTo<float>(simple_time / simple_duration_value); } SMILTime SVGSMILElement::CalculateNextProgressTime(double elapsed) const { @@ -1069,13 +1082,19 @@ GetActiveState() == kFrozen; } -bool SVGSMILElement::Progress(double elapsed, bool seek_to_time) { +// The first part of the processing of the animation, +// this checks if there are any further calculations needed +// to continue and makes sure the intervals are correct. +bool SVGSMILElement::NeedsToProgress(double elapsed, bool seek_to_time) { + // Check we're connected to something. DCHECK(time_container_); + // Check that we have some form of start or are prepared to find it. DCHECK(is_waiting_for_first_interval_ || interval_.begin.IsFinite()); if (!sync_base_conditions_connected_) ConnectSyncBaseConditions(); + // Check if we need updating, otherwise just return. if (!interval_.begin.IsFinite()) { DCHECK_EQ(GetActiveState(), kInactive); next_progress_time_ = SMILTime::Unresolved(); @@ -1085,8 +1104,7 @@ if (elapsed < interval_.begin) { DCHECK_NE(GetActiveState(), kActive); next_progress_time_ = interval_.begin; - // If the animation is frozen, it's still contributing. - return GetActiveState() == kFrozen; + return false; } previous_interval_begin_ = interval_.begin; @@ -1095,29 +1113,51 @@ is_waiting_for_first_interval_ = false; ResolveFirstInterval(); } + return true; +} +void SVGSMILElement::TriggerPendingEvents(double elapsed) { + if (GetActiveState() == kInactive) + ScheduleEvent(event_type_names::kBeginEvent); + + unsigned repeat = CalculateAnimationRepeat(elapsed); + if (repeat) { + for (unsigned repeat_event_count = 1; repeat_event_count < repeat; + repeat_event_count++) + ScheduleRepeatEvents(repeat_event_count); + if (GetActiveState() == kInactive) + ScheduleRepeatEvents(repeat); + } + + if (GetActiveState() == kInactive || GetActiveState() == kFrozen) + ScheduleEvent(event_type_names::kEndEvent); +} + +void SVGSMILElement::UpdateNextProgressTime(double elapsed) { + next_progress_time_ = CalculateNextProgressTime(elapsed); +} + +void SVGSMILElement::Progress(double elapsed, bool seek_to_time) { // This call may obtain a new interval -- never call - // calculateAnimationPercentAndRepeat() before! + // CalculateAnimation{ Percent, Repeat }() before! if (seek_to_time) { SeekToIntervalCorrespondingToTime(elapsed); if (elapsed < interval_.begin) { // elapsed is not within an interval. next_progress_time_ = interval_.begin; - return false; + return; } } - unsigned repeat = 0; - float percent = CalculateAnimationPercentAndRepeat(elapsed, repeat); - RestartedInterval restarted_interval = MaybeRestartInterval(elapsed); + float percent = CalculateAnimationPercent(elapsed); + unsigned repeat = CalculateAnimationRepeat(elapsed); + bool restarted_interval = MaybeRestartInterval(elapsed); ActiveState old_active_state = GetActiveState(); active_state_ = DetermineActiveState(elapsed); - bool animation_is_contributing = IsContributing(elapsed); - if (animation_is_contributing) { - if (old_active_state == kInactive || - restarted_interval == kDidRestartInterval) { + if (IsContributing(elapsed)) { + if (old_active_state == kInactive || restarted_interval) { ScheduleEvent(event_type_names::kBeginEvent); StartedActiveInterval(); } @@ -1130,30 +1170,10 @@ } if ((old_active_state == kActive && GetActiveState() != kActive) || - restarted_interval == kDidRestartInterval) { + restarted_interval) { ScheduleEvent(event_type_names::kEndEvent); EndedActiveInterval(); } - - // Triggering all the pending events if the animation timeline is changed. - if (seek_to_time) { - if (GetActiveState() == kInactive) - ScheduleEvent(event_type_names::kBeginEvent); - - if (repeat) { - for (unsigned repeat_event_count = 1; repeat_event_count < repeat; - repeat_event_count++) - ScheduleRepeatEvents(repeat_event_count); - if (GetActiveState() == kInactive) - ScheduleRepeatEvents(repeat); - } - - if (GetActiveState() == kInactive || GetActiveState() == kFrozen) - ScheduleEvent(event_type_names::kEndEvent); - } - - next_progress_time_ = CalculateNextProgressTime(elapsed); - return animation_is_contributing; } void SVGSMILElement::NotifyDependentsIntervalChanged() {
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h index 99e646e..9b8be92 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -85,7 +85,12 @@ SMILTime SimpleDuration() const; void SeekToIntervalCorrespondingToTime(double elapsed); - bool Progress(double elapsed, bool seek_to_time); + + bool NeedsToProgress(double elapsed, bool seek_to_time); + void TriggerPendingEvents(double elapsed); + void UpdateNextProgressTime(double elapsed); + void Progress(double elapsed, bool seek_to_time); + SMILTime NextProgressTime() const; void UpdateAnimatedValue(SVGSMILElement* result_element) { UpdateAnimation(last_percent_, last_repeat_, result_element); @@ -240,8 +245,8 @@ return static_cast<ActiveState>(active_state_); } ActiveState DetermineActiveState(SMILTime elapsed) const; - float CalculateAnimationPercentAndRepeat(double elapsed, - unsigned& repeat) const; + float CalculateAnimationPercent(double elapsed) const; + unsigned CalculateAnimationRepeat(double elapsed) const; SMILTime CalculateNextProgressTime(double elapsed) const; Member<SVGElement> target_element_;
diff --git a/third_party/blink/renderer/core/testing/sim/sim_request.cc b/third_party/blink/renderer/core/testing/sim/sim_request.cc index 29a12ec..f078561 100644 --- a/third_party/blink/renderer/core/testing/sim/sim_request.cc +++ b/third_party/blink/renderer/core/testing/sim/sim_request.cc
@@ -4,7 +4,6 @@ #include "third_party/blink/renderer/core/testing/sim/sim_request.h" -#include <vector> #include "third_party/blink/public/platform/web_url_loader_client.h" #include "third_party/blink/renderer/core/testing/sim/sim_network.h" #include "third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h"
diff --git a/third_party/blink/renderer/core/timing/memory_info_test.cc b/third_party/blink/renderer/core/timing/memory_info_test.cc index e930aa6..73eb3803 100644 --- a/third_party/blink/renderer/core/timing/memory_info_test.cc +++ b/third_party/blink/renderer/core/timing/memory_info_test.cc
@@ -127,7 +127,7 @@ // allocated alive even if GC happens. In practice, the objects only get GC'd // after we go out of V8TestingScope. But having them in a vector makes it // impossible for GC to clear them up unexpectedly early. - std::vector<v8::Local<v8::ArrayBuffer>> objects; + Vector<v8::Local<v8::ArrayBuffer>> objects; MemoryInfoTestScopedMockTime mock_time(MemoryInfo::Precision::Bucketized); MemoryInfo* bucketized_memory = @@ -172,7 +172,7 @@ TEST_F(MemoryInfoTest, Precise) { V8TestingScope scope; v8::Isolate* isolate = scope.GetIsolate(); - std::vector<v8::Local<v8::ArrayBuffer>> objects; + Vector<v8::Local<v8::ArrayBuffer>> objects; MemoryInfoTestScopedMockTime mock_time(MemoryInfo::Precision::Precise); MemoryInfo* precise_memory = @@ -217,7 +217,7 @@ ScopedPreciseMemoryInfoForTest precise_memory_info(true); V8TestingScope scope; v8::Isolate* isolate = scope.GetIsolate(); - std::vector<v8::Local<v8::ArrayBuffer>> objects; + Vector<v8::Local<v8::ArrayBuffer>> objects; // Using MemoryInfo::Precision::Bucketized to ensure that the runtime-enabled // flag overrides the Precision passed onto the method. @@ -247,7 +247,7 @@ mock_time.AdvanceClock(base::TimeDelta::FromMicroseconds(100)); V8TestingScope scope; v8::Isolate* isolate = scope.GetIsolate(); - std::vector<v8::Local<v8::ArrayBuffer>> objects; + Vector<v8::Local<v8::ArrayBuffer>> objects; objects.push_back(v8::ArrayBuffer::New(isolate, 100)); MemoryInfo* precise_memory =
diff --git a/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc b/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc index 69d5ac2..65ba66c 100644 --- a/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc +++ b/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
@@ -39,7 +39,7 @@ execution_context->GetScheduler()->RegisterFeature( SchedulingPolicy::Feature::kDedicatedWorkerOrWorklet, {SchedulingPolicy::RecordMetricsForBackForwardCache()})), - keep_alive_(this) { + keep_alive_(PERSISTENT_FROM_HERE, this) { DCHECK(IsParentContextThread()); g_live_messaging_proxy_count++; }
diff --git a/third_party/blink/renderer/devtools/PRESUBMIT.py b/third_party/blink/renderer/devtools/PRESUBMIT.py index 4dcfae3b..0749c1a 100644 --- a/third_party/blink/renderer/devtools/PRESUBMIT.py +++ b/third_party/blink/renderer/devtools/PRESUBMIT.py
@@ -79,7 +79,8 @@ # Also fix semicolon to avoid confusing clang-format. eslint_process = popen([ local_node.node_path(), local_node.eslint_path(), - '--no-eslintrc', '--fix', '--env=es6', '--rule={"curly": [2, "multi-or-nest", "consistent"], "semi": 2}' + '--no-eslintrc', '--fix', '--env=es6', '--parser-options=ecmaVersion:9', + '--rule={"curly": [2, "multi-or-nest", "consistent"], "semi": 2}' ] + affected_files) eslint_process.communicate()
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleContextSelector.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleContextSelector.js index 6ff70fc..c1f67651 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleContextSelector.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleContextSelector.js
@@ -14,7 +14,7 @@ this._dropDown.setRowHeight(36); this._toolbarItem = new UI.ToolbarItem(this._dropDown.element); this._toolbarItem.setEnabled(false); - this._toolbarItem.setTitle(ls`JavaScript contexts`); + this._toolbarItem.setTitle(ls`JavaScript context: Not selected`); this._items.addEventListener( UI.ListModel.Events.ItemsReplaced, () => this._toolbarItem.setEnabled(!!this._items.length)); @@ -314,6 +314,8 @@ */ itemSelected(item) { this._toolbarItem.element.classList.toggle('warning', !this._isTopContext(item) && this._hasTopContext()); + const title = item ? ls`JavaScript context: ${this.titleFor(item)}` : ls`JavaScript context: Not selected`; + this._toolbarItem.setTitle(title); UI.context.setFlavor(SDK.ExecutionContext, item); }
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js index 42ef6f0..2bfe11f 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -1330,6 +1330,7 @@ text = text || Common.UIString('Hide all'); this._levelMenuButton.element.classList.toggle('warning', !isAll && !isDefault); this._levelMenuButton.setText(text); + this._levelMenuButton.setTitle(ls`Log level: ${text}`); } /**
diff --git a/third_party/blink/renderer/devtools/front_end/console/console_strings.grdp b/third_party/blink/renderer/devtools/front_end/console/console_strings.grdp index b51975fa..a0b9c952 100644 --- a/third_party/blink/renderer/devtools/front_end/console/console_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/console/console_strings.grdp
@@ -3,6 +3,9 @@ <message name="IDS_DEVTOOLS_02969932cf572213e2401893f4182af2" desc=""> Remove all expressions </message> + <message name="IDS_DEVTOOLS_0351df5b6bdc3a8cfb762210881619a4" desc=""> + JavaScript context: Not selected + </message> <message name="IDS_DEVTOOLS_047e62ee63b0c14a249a79bc6be0a493" desc=""> Do not group similar messages in console </message> @@ -186,9 +189,6 @@ <message name="IDS_DEVTOOLS_b2f8489bbd55a4e9b9edbbbfe49edf70" desc=""> not available </message> - <message name="IDS_DEVTOOLS_b5735f8c6deff6306a2216612ca80f0e" desc=""> - JavaScript contexts - </message> <message name="IDS_DEVTOOLS_bafd7322c6e97d25b6299b5d6fe8920b" desc=""> No </message> @@ -264,12 +264,18 @@ <message name="IDS_DEVTOOLS_e1dd1b8e32626f508bd3a5612a60ab97" desc=""> Create live expression </message> + <message name="IDS_DEVTOOLS_e6320ee2b5f66ac1520e6156e5ac8fb3" desc=""> + JavaScript context: <ph name="THIS_TITLEFOR_ITEM_">$1s</ph> + </message> <message name="IDS_DEVTOOLS_eacaf2bd1c1414e5086cf04573e154ef" desc=""> e.g. /event\d/ -cdn url:a.com </message> <message name="IDS_DEVTOOLS_ebfab4df1bb91688c62d4523eba870a5" desc=""> Evaluate triggers user activation </message> + <message name="IDS_DEVTOOLS_f0b0e075af71ecd9b3435697417c1f05" desc=""> + Log level: <ph name="TEXT">$1s</ph> + </message> <message name="IDS_DEVTOOLS_f8ec55cf268ca6106fb23a98523b7549" desc=""> user message </message>
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/EditFileSystemView.js b/third_party/blink/renderer/devtools/front_end/persistence/EditFileSystemView.js index 2fe58d0b..9d9d181 100644 --- a/third_party/blink/renderer/devtools/front_end/persistence/EditFileSystemView.js +++ b/third_party/blink/renderer/devtools/front_end/persistence/EditFileSystemView.js
@@ -60,7 +60,6 @@ this._excludedFoldersList.setEmptyPlaceholder(excludedFoldersPlaceholder); this._excludedFoldersList.show(this.contentElement); - this.contentElement.tabIndex = 0; this._update(); }
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js b/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js index cbff5f61..3896a99 100644 --- a/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js +++ b/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js
@@ -8,7 +8,7 @@ this.registerRequiredCSS('persistence/workspaceSettingsTab.css'); const header = this.element.createChild('header'); - header.createChild('h3').createTextChild(Common.UIString('Workspace')); + header.createChild('h1').createTextChild(Common.UIString('Workspace')); this.containerElement = this.element.createChild('div', 'settings-container-wrapper') .createChild('div', 'settings-tab settings-content settings-container');
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/workspaceSettingsTab.css b/third_party/blink/renderer/devtools/front_end/persistence/workspaceSettingsTab.css index ee24213..d6070e9f 100644 --- a/third_party/blink/renderer/devtools/front_end/persistence/workspaceSettingsTab.css +++ b/third_party/blink/renderer/devtools/front_end/persistence/workspaceSettingsTab.css
@@ -9,7 +9,7 @@ border-bottom: 1px solid #EEEEEE; } -header > h3 { +header > h1 { font-size: 18px; font-weight: normal; margin: 0;
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc index 91a5066..be714dbb 100644 --- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc +++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
@@ -233,10 +233,10 @@ state.reset(new AnimationWorkletDispatcherInput); // Last peek request fulfilled. No need to peek. - std::vector<base::Optional<base::TimeDelta>> local_times; - local_times.push_back(base::TimeDelta()); + WebVector<base::Optional<base::TimeDelta>> local_times; + local_times.emplace_back(base::TimeDelta()); AnimationWorkletOutput::AnimationState output_with_value(id); - output_with_value.local_times = local_times; + output_with_value.local_times = local_times.ReleaseVector(); worklet_animation_->SetOutputState(output_with_value); worklet_animation_->UpdateInputState(state.get()); input = state->TakeWorkletState(id.worklet_id);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 721fbdf..1917168f 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -855,10 +855,10 @@ canvas->GetCanvasRenderingContext("2d", attributes)); // Prepare the png file path and call the test routine - std::vector<String> interlace_status = {"", "_interlaced"}; - std::vector<String> color_profiles = {"_sRGB", "_e-sRGB", "_AdobeRGB", - "_DisplayP3", "_ProPhoto", "_Rec2020"}; - std::vector<String> alpha_status = {"_opaque", "_transparent"}; + Vector<String> interlace_status = {"", "_interlaced"}; + Vector<String> color_profiles = {"_sRGB", "_e-sRGB", "_AdobeRGB", + "_DisplayP3", "_ProPhoto", "_Rec2020"}; + Vector<String> alpha_status = {"_opaque", "_transparent"}; StringBuilder path; path.Append(test::CoreTestDataPath());
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc index 7d934f7..6b8e89b1 100644 --- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc +++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -6,9 +6,6 @@ #include <stddef.h> -#include <string> -#include <vector> - #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/strong_associated_binding.h" #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h index 5a9a8c0..e58f1d8 100644 --- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h +++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
@@ -7,8 +7,6 @@ #include <stdint.h> -#include <vector> - #include "base/gtest_prod_util.h" #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h" #include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h b/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h index 6fc4c63..9ab144b 100644 --- a/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h +++ b/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
@@ -28,7 +28,6 @@ #include <unordered_map> #include <utility> -#include <vector> #include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h" #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc index 0ee4e18..d736af9 100644 --- a/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc +++ b/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc
@@ -30,7 +30,7 @@ // of memory, which crashes on memory-constrained systems. const size_t kMaxValueSizeForTesting = 10 * 1024 * 1024; // 10 MB - const std::vector<char> data(kMaxValueSizeForTesting + 1); + const Vector<char> data(kMaxValueSizeForTesting + 1); const scoped_refptr<SharedBuffer> value_data = SharedBuffer::Create(&data.front(), data.size()); const Vector<WebBlobInfo> blob_info; @@ -58,7 +58,7 @@ const size_t kMaxValueSizeForTesting = 10 * 1024 * 1024; // 10 MB const size_t kKeySize = 1024 * 1024; - const std::vector<char> data(kMaxValueSizeForTesting - kKeySize); + const Vector<char> data(kMaxValueSizeForTesting - kKeySize); const scoped_refptr<SharedBuffer> value_data = SharedBuffer::Create(&data.front(), data.size()); const Vector<WebBlobInfo> blob_info;
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 8916dcb..9bc0fea 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -226,6 +226,7 @@ "netinfo/network_information.idl", "nfc/nfc.idl", "nfc/nfc_error_event.idl", + "nfc/nfc_writer.idl", "notifications/notification.idl", "notifications/notification_event.idl", "notifications/timestamp_trigger.idl",
diff --git a/third_party/blink/renderer/modules/nfc/BUILD.gn b/third_party/blink/renderer/modules/nfc/BUILD.gn index c4e3ecd..6e256b1 100644 --- a/third_party/blink/renderer/modules/nfc/BUILD.gn +++ b/third_party/blink/renderer/modules/nfc/BUILD.gn
@@ -24,5 +24,7 @@ "nfc_type_converters.h", "nfc_utils.cc", "nfc_utils.h", + "nfc_writer.cc", + "nfc_writer.h", ] }
diff --git a/third_party/blink/renderer/modules/nfc/nfc.cc b/third_party/blink/renderer/modules/nfc/nfc.cc index 0c5e3b2..ae491f3 100644 --- a/third_party/blink/renderer/modules/nfc/nfc.cc +++ b/third_party/blink/renderer/modules/nfc/nfc.cc
@@ -240,6 +240,7 @@ void NFC::OnConnectionError() { nfc_.reset(); + client_binding_.Close(); callbacks_.clear(); // If NFCService is not available or disappears when NFC hardware is @@ -278,7 +279,7 @@ // WebNFC API must be only accessible from top level browsing context. if (!To<Document>(context)->domWindow()->GetFrame() || !To<Document>(context)->GetFrame()->IsMainFrame()) { - error_message = "Must be in a top-level browsing context"; + error_message = kNfcAccessInNonTopFrame; return false; } @@ -291,7 +292,7 @@ error_message)) { return ScriptPromise::RejectWithDOMException( script_state, MakeGarbageCollected<DOMException>( - DOMExceptionCode::kSecurityError, error_message)); + DOMExceptionCode::kNotAllowedError, error_message)); } if (!nfc_) {
diff --git a/third_party/blink/renderer/modules/nfc/nfc_constants.cc b/third_party/blink/renderer/modules/nfc/nfc_constants.cc index 2ed183c..e5313a81 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_constants.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_constants.cc
@@ -16,7 +16,9 @@ const char kNfcCharSetUTF8[] = ";charset=UTF-8"; // Error messages. -const char kNfcNotSupported[] = "WebNFC is not supported."; +const char kNfcNotSupported[] = "NFC operation not supported."; +const char kNfcNotReadable[] = "No NFC adapter or cannot establish connection."; +const char kNfcNotAllowed[] = "NFC operation not allowed."; const char kNfcTextRecordTypeError[] = "The data for 'text' NDEFRecords must be of String or UnrestrctedDouble."; const char kNfcSetIdError[] = "Cannot set WebNFC Id."; @@ -36,6 +38,7 @@ const char kNfcRecordError[] = "Invalid NDEFRecordType was provided."; const char kNfcMsgTypeError[] = "Invalid NDEFMessageSource type was provided."; const char kNfcEmptyMsg[] = "Empty NDEFMessage was provided."; +const char kNfcInvalidMsg[] = "Invalid NFC message was provided."; const char kNfcMsgConvertError[] = "Cannot convert NDEFMessage."; const char kNfcMsgMaxSizeError[] = "NDEFMessage exceeds maximum supported size."; @@ -43,5 +46,12 @@ const char kNfcInvalidPushTimeout[] = "Invalid NFCPushOptions.timeout value was provided."; const char kNfcWatchIdNotFound[] = "Provided watch id cannot be found."; +const char kNfcAccessInNonTopFrame[] = + "NFC interfaces are only avaliable in a top-level browsing context"; +const char kNfcCancelled[] = "The NFC operation was cancelled."; +const char kNfcTimeout[] = "NFC operation has timed out."; +const char kNfcUnknownError[] = "An unknown NFC error has occurred."; +const char kNfcDataTransferError[] = "NFC data transfer error has occurred."; +const char kNfcNoModificationAllowed[] = "NFC operation cannot be cancelled."; } // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_constants.h b/third_party/blink/renderer/modules/nfc/nfc_constants.h index 74d8dec..4fef80ef 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_constants.h +++ b/third_party/blink/renderer/modules/nfc/nfc_constants.h
@@ -25,6 +25,8 @@ // Error messages. extern const char kNfcNotSupported[]; +extern const char kNfcNotReadable[]; +extern const char kNfcNotAllowed[]; extern const char kNfcTextRecordTypeError[]; extern const char kNfcSetIdError[]; extern const char kNfcTextRecordMediaTypeError[]; @@ -38,11 +40,18 @@ extern const char kNfcRecordError[]; extern const char kNfcMsgTypeError[]; extern const char kNfcEmptyMsg[]; +extern const char kNfcInvalidMsg[]; extern const char kNfcMsgConvertError[]; extern const char kNfcMsgMaxSizeError[]; extern const char kNfcUrlPatternError[]; extern const char kNfcInvalidPushTimeout[]; extern const char kNfcWatchIdNotFound[]; +extern const char kNfcAccessInNonTopFrame[]; +extern const char kNfcCancelled[]; +extern const char kNfcTimeout[]; +extern const char kNfcUnknownError[]; +extern const char kNfcDataTransferError[]; +extern const char kNfcNoModificationAllowed[]; } // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_error.cc b/third_party/blink/renderer/modules/nfc/nfc_error.cc index b1b1de4..af305b0 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_error.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_error.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/nfc/nfc_error.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/modules/nfc/nfc_constants.h" #include "third_party/blink/renderer/platform/heap/heap.h" using device::mojom::blink::NFCErrorType; @@ -14,38 +15,38 @@ DOMException* NFCError::Take(ScriptPromiseResolver*, const NFCErrorType& error_type) { switch (error_type) { - case NFCErrorType::SECURITY: + case NFCErrorType::NOT_ALLOWED: return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kSecurityError, "NFC operation not allowed."); + DOMExceptionCode::kNotAllowedError, kNfcNotAllowed); case NFCErrorType::NOT_SUPPORTED: - case NFCErrorType::DEVICE_DISABLED: return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kNotSupportedError, "NFC operation not supported."); + DOMExceptionCode::kNotSupportedError, kNfcNotSupported); + case NFCErrorType::NOT_READABLE: + return MakeGarbageCollected<DOMException>( + DOMExceptionCode::kNotReadableError, kNfcNotReadable); case NFCErrorType::NOT_FOUND: return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kNotFoundError, - "Invalid NFC watch Id was provided."); + DOMExceptionCode::kNotFoundError, kNfcWatchIdNotFound); case NFCErrorType::INVALID_MESSAGE: - return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kSyntaxError, "Invalid NFC message was provided."); + return MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError, + kNfcInvalidMsg); case NFCErrorType::OPERATION_CANCELLED: - return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kAbortError, "The NFC operation was cancelled."); + return MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError, + kNfcCancelled); case NFCErrorType::TIMER_EXPIRED: return MakeGarbageCollected<DOMException>(DOMExceptionCode::kTimeoutError, - "NFC operation has timed-out."); + kNfcTimeout); case NFCErrorType::CANNOT_CANCEL: return MakeGarbageCollected<DOMException>( DOMExceptionCode::kNoModificationAllowedError, - "NFC operation cannot be canceled."); + kNfcNoModificationAllowed); case NFCErrorType::IO_ERROR: - return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kNetworkError, - "NFC data transfer error has occurred."); + return MakeGarbageCollected<DOMException>(DOMExceptionCode::kNetworkError, + kNfcDataTransferError); } NOTREACHED(); - return MakeGarbageCollected<DOMException>( - DOMExceptionCode::kUnknownError, "An unknown NFC error has occurred."); + // Don't need to handle the case after a NOTREACHED(). + return nullptr; } } // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc index 6bb51f5..1a8bbb1 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -8,6 +8,7 @@ #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/renderer/modules/nfc/nfc_reader.h" +#include "third_party/blink/renderer/modules/nfc/nfc_writer.h" #include "third_party/blink/renderer/platform/mojo/mojo_helper.h" namespace blink { @@ -19,9 +20,7 @@ NFCProxy* NFCProxy::From(Document& document) { // https://w3c.github.io/web-nfc/#security-policies // WebNFC API must be only accessible from top level browsing context. - if (!document.IsInMainFrame()) { - return nullptr; - } + DCHECK(document.IsInMainFrame()); NFCProxy* nfc_proxy = Supplement<Document>::From<NFCProxy>(document); if (!nfc_proxy) { @@ -44,6 +43,7 @@ } void NFCProxy::Trace(blink::Visitor* visitor) { + visitor->Trace(writers_); visitor->Trace(readers_); PageVisibilityObserver::Trace(visitor); Supplement<Document>::Trace(visitor); @@ -71,6 +71,11 @@ } } +void NFCProxy::AddWriter(NFCWriter* writer) { + DCHECK(!writers_.Contains(writer)); + writers_.insert(writer); +} + void NFCProxy::Push(device::mojom::blink::NDEFMessagePtr message, device::mojom::blink::NFCPushOptionsPtr options, device::mojom::blink::NFC::PushCallback cb) { @@ -109,7 +114,7 @@ DCHECK(reader); if (error) { - reader->OnError(*error); + reader->OnReadingError(*error); return; } @@ -121,7 +126,7 @@ DCHECK(reader); if (error) { - reader->OnError(*error); + reader->OnReadingError(*error); } } @@ -138,6 +143,7 @@ WTF::Bind(&NFCProxy::OnMojoConnectionError, WrapWeakPersistent(this))); // Set client for OnWatch event. + DCHECK(!client_binding_); device::mojom::blink::NFCClientPtr client; client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner); nfc_->SetClient(std::move(client)); @@ -145,18 +151,21 @@ void NFCProxy::OnMojoConnectionError() { nfc_.reset(); + client_binding_.Close(); // Notify all active readers about the connection error. - // NFCWriter::push() should wrap the callback using - // mojo::WrapCallbackWithDefaultInvokeIfNotRun() with a default error. - auto error = device::mojom::blink::NFCError::New( - device::mojom::blink::NFCErrorType::NOT_SUPPORTED); for (auto pair : readers_) { - pair.key->OnError(*error); + pair.key->OnMojoConnectionError(); } - // Clear the reader list. readers_.clear(); + + // Notify all writers about the connection error. + for (auto& writer : writers_) { + writer->OnMojoConnectionError(); + } + // Clear the reader list. + writers_.clear(); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.h b/third_party/blink/renderer/modules/nfc/nfc_proxy.h index f5cb556a..2fec61a 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_proxy.h +++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -16,6 +16,7 @@ class Document; class NFCReader; +class NFCWriter; // This is a proxy class used by NFCWriter(s) and NFCReader(s) to connect // to the DeviceService for device::mojom::blink::NFC service. @@ -38,6 +39,11 @@ void Trace(blink::Visitor*) override; + // There is no matching RemoveWriter() method because writers are + // automatically removed from the weak hash set when they are garbage + // collected. + void AddWriter(NFCWriter*); + void AddReader(NFCReader*); void RemoveReader(NFCReader*); void Push(device::mojom::blink::NDEFMessagePtr message, @@ -55,6 +61,7 @@ void OnReaderRegistered(NFCReader* reader, uint32_t id, device::mojom::blink::NFCErrorPtr error); + void OnCancelWatch(NFCReader* reader, device::mojom::blink::NFCErrorPtr error); @@ -66,6 +73,9 @@ using ReaderMap = HeapHashMap<WeakMember<NFCReader>, uint32_t>; ReaderMap readers_; + using WriterSet = HeapHashSet<WeakMember<NFCWriter>>; + WriterSet writers_; + device::mojom::blink::NFCPtr nfc_; mojo::Binding<device::mojom::blink::NFCClient> client_binding_; };
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc index 7402148..4d5378f 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
@@ -63,7 +63,7 @@ void Trace(blink::Visitor* visitor) override { NFCReader::Trace(visitor); } MOCK_METHOD1(OnMessage, void(const NDEFMessage& message)); - MOCK_METHOD1(OnError, void(const NFCError& error)); + MOCK_METHOD1(OnReadingError, void(const NFCError& error)); }; class FakeNfcService : public device::mojom::blink::NFC { @@ -223,7 +223,7 @@ test::RunPendingTasks(); base::RunLoop loop; - EXPECT_CALL(*reader, OnError(_)).WillOnce(Invoke([&](const NFCError&) { + EXPECT_CALL(*reader, OnReadingError(_)).WillOnce(Invoke([&](const NFCError&) { loop.Quit(); })); DestroyNfcService();
diff --git a/third_party/blink/renderer/modules/nfc/nfc_reader.cc b/third_party/blink/renderer/modules/nfc/nfc_reader.cc index 88d42b3..5a92501 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_reader.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_reader.cc
@@ -17,6 +17,13 @@ void NFCReader::OnMessage(const device::mojom::blink::NDEFMessage& message) {} // An reading error has occurred. -void NFCReader::OnError(const device::mojom::blink::NFCError& error) {} +void NFCReader::OnReadingError(const device::mojom::blink::NFCError& error) {} + +// NfcProxy::Observer overrides. +void NFCReader::OnMojoConnectionError() { + auto error = device::mojom::blink::NFCError::New( + device::mojom::blink::NFCErrorType::NOT_READABLE); + OnReadingError(*error); +} } // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_reader.h b/third_party/blink/renderer/modules/nfc/nfc_reader.h index 87f32d57..b5d41e7b 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_reader.h +++ b/third_party/blink/renderer/modules/nfc/nfc_reader.h
@@ -27,7 +27,10 @@ virtual void OnMessage(const device::mojom::blink::NDEFMessage& message); // An reading error has occurred. - virtual void OnError(const device::mojom::blink::NFCError& error); + virtual void OnReadingError(const device::mojom::blink::NFCError& error); + + // Called by NFCProxy for notification about connection error. + void OnMojoConnectionError(); private: device::mojom::blink::NFCReaderOptionsPtr options_;
diff --git a/third_party/blink/renderer/modules/nfc/nfc_writer.cc b/third_party/blink/renderer/modules/nfc/nfc_writer.cc new file mode 100644 index 0000000..dcbfd8da --- /dev/null +++ b/third_party/blink/renderer/modules/nfc/nfc_writer.cc
@@ -0,0 +1,134 @@ +// 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/nfc/nfc_writer.h" + +#include <utility> + +#include "mojo/public/cpp/bindings/callback_helpers.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/modules/nfc/nfc_error.h" +#include "third_party/blink/renderer/modules/nfc/nfc_push_options.h" +#include "third_party/blink/renderer/modules/nfc/nfc_type_converters.h" +#include "third_party/blink/renderer/modules/nfc/nfc_utils.h" + +namespace blink { + +// static +NFCWriter* NFCWriter::Create(ExecutionContext* context) { + return MakeGarbageCollected<NFCWriter>(context); +} + +NFCWriter::NFCWriter(ExecutionContext* context) : ContextClient(context) {} + +void NFCWriter::Trace(blink::Visitor* visitor) { + visitor->Trace(nfc_proxy_); + visitor->Trace(requests_); + ScriptWrappable::Trace(visitor); + ContextClient::Trace(visitor); +} + +// https://w3c.github.io/web-nfc/#writing-or-pushing-content +// https://w3c.github.io/web-nfc/#dom-nfc-push +ScriptPromise NFCWriter::push(ScriptState* script_state, + const NDEFMessageSource& push_message, + const NFCPushOptions* options) { + ExecutionContext* execution_context = GetExecutionContext(); + // https://w3c.github.io/web-nfc/#security-policies + // WebNFC API must be only accessible from top level browsing context. + if (!execution_context || !To<Document>(execution_context)->IsInMainFrame()) { + return ScriptPromise::RejectWithDOMException( + script_state, + MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotAllowedError, + kNfcAccessInNonTopFrame)); + } + + ScriptPromise is_valid_message = + RejectIfInvalidNDEFMessageSource(script_state, push_message); + if (!is_valid_message.IsEmpty()) + return is_valid_message; + + // https://w3c.github.io/web-nfc/#dom-nfc-push + // 9. If timeout value is NaN or negative, reject promise with "TypeError" + // and abort these steps. + if (options->hasTimeout() && + (std::isnan(options->timeout()) || options->timeout() < 0)) { + return ScriptPromise::Reject( + script_state, V8ThrowException::CreateTypeError( + script_state->GetIsolate(), kNfcInvalidPushTimeout)); + } + + auto message = device::mojom::blink::NDEFMessage::From(push_message); + if (!message) { + return ScriptPromise::RejectWithDOMException( + script_state, MakeGarbageCollected<DOMException>( + DOMExceptionCode::kSyntaxError, kNfcMsgConvertError)); + } + + if (!SetNDEFMessageURL(execution_context->GetSecurityOrigin()->ToString(), + message)) { + return ScriptPromise::RejectWithDOMException( + script_state, MakeGarbageCollected<DOMException>( + DOMExceptionCode::kSyntaxError, kNfcSetIdError)); + } + + if (GetNDEFMessageSize(message) > + device::mojom::blink::NDEFMessage::kMaxSize) { + return ScriptPromise::RejectWithDOMException( + script_state, + MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError, + kNfcMsgMaxSizeError)); + } + + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + requests_.insert(resolver); + auto callback = WTF::Bind(&NFCWriter::OnRequestCompleted, + WrapPersistent(this), WrapPersistent(resolver)); + + InitNfcProxyIfNeeded(); + nfc_proxy_->Push(std::move(message), + device::mojom::blink::NFCPushOptions::From(options), + std::move(callback)); + + return resolver->Promise(); +} + +void NFCWriter::OnMojoConnectionError() { + nfc_proxy_.Clear(); + + // If the mojo connection breaks, all push requests will be reject with a + // default error. + for (ScriptPromiseResolver* resolver : requests_) { + resolver->Reject(NFCError::Take( + resolver, device::mojom::blink::NFCErrorType::NOT_READABLE)); + } + requests_.clear(); +} + +void NFCWriter::InitNfcProxyIfNeeded() { + // Init NfcProxy if needed. + if (nfc_proxy_) + return; + + nfc_proxy_ = NFCProxy::From(*To<Document>(GetExecutionContext())); + DCHECK(nfc_proxy_); + + // Add the writer to proxy's writer list for mojo connection error + // notification. + nfc_proxy_->AddWriter(this); +} + +void NFCWriter::OnRequestCompleted(ScriptPromiseResolver* resolver, + device::mojom::blink::NFCErrorPtr error) { + DCHECK(requests_.Contains(resolver)); + requests_.erase(resolver); + + if (error.is_null()) + resolver->Resolve(); + else + resolver->Reject(NFCError::Take(resolver, error->error_type)); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/nfc_writer.h b/third_party/blink/renderer/modules/nfc/nfc_writer.h new file mode 100644 index 0000000..915ec8a --- /dev/null +++ b/third_party/blink/renderer/modules/nfc/nfc_writer.h
@@ -0,0 +1,56 @@ +// 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_NFC_NFC_WRITER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_WRITER_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/modules/nfc/nfc_constants.h" +#include "third_party/blink/renderer/modules/nfc/nfc_proxy.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" + +namespace blink { + +class NFCPushOptions; +class ExecutionContext; +class ScriptPromise; + +class NFCWriter : public ScriptWrappable, public ContextClient { + DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(NFCWriter); + + public: + static NFCWriter* Create(ExecutionContext*); + + explicit NFCWriter(ExecutionContext*); + ~NFCWriter() override = default; + + void Trace(blink::Visitor*) override; + + // Pushes NDEFMessageSource asynchronously to NFC tag / peer. + ScriptPromise push(ScriptState*, + const NDEFMessageSource&, + const NFCPushOptions*); + + // Called by NFCProxy for notification about connection error. + void OnMojoConnectionError(); + + private: + void InitNfcProxyIfNeeded(); + void OnRequestCompleted(ScriptPromiseResolver* resolver, + device::mojom::blink::NFCErrorPtr error); + + // |requests_| are kept here to handle Mojo connection failures because + // in that case the callback passed to Push() won't be called and + // mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink. + // This list will also be used by AbortSignal. + HeapHashSet<Member<ScriptPromiseResolver>> requests_; + Member<NFCProxy> nfc_proxy_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_WRITER_H_
diff --git a/third_party/blink/renderer/modules/nfc/nfc_writer.idl b/third_party/blink/renderer/modules/nfc/nfc_writer.idl new file mode 100644 index 0000000..954fabc --- /dev/null +++ b/third_party/blink/renderer/modules/nfc/nfc_writer.idl
@@ -0,0 +1,11 @@ +typedef (DOMString or ArrayBuffer or NDEFMessage) NDEFMessageSource; + +[ + RuntimeEnabled=WebNFC, + SecureContext, + Constructor(), + ConstructorCallWith=ExecutionContext, + Exposed=Window +] interface NFCWriter { + [CallWith=ScriptState] Promise<void> push (NDEFMessageSource message, optional NFCPushOptions options); +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc index 3a5597ff..9f64e4f4 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc
@@ -75,6 +75,24 @@ GLenum pname) { if (!ValidateWebGLProgramOrShader("getProgramInterfaceParameter", program)) return ScriptValue::CreateNull(script_state); + if (!ValidateProgramInterface( + "getProgramInterfaceParameter", program_interface)) + return ScriptValue::CreateNull(script_state); + if (program_interface == GL_ATOMIC_COUNTER_BUFFER && + pname == GL_MAX_NAME_LENGTH) { + SynthesizeGLError(GL_INVALID_OPERATION, "getProgramInterfaceParameter", + "atomic counter resources are not assigned name strings"); + return ScriptValue::CreateNull(script_state); + } + if (program_interface != GL_ATOMIC_COUNTER_BUFFER && + program_interface != GL_SHADER_STORAGE_BLOCK && + program_interface != GL_UNIFORM_BLOCK && + pname == GL_MAX_NUM_ACTIVE_VARIABLES) { + SynthesizeGLError( + GL_INVALID_OPERATION, "getProgramInterfaceParameter", + "invalid parameter name for the specified program interface"); + return ScriptValue::CreateNull(script_state); + } switch (pname) { case GL_ACTIVE_RESOURCES: @@ -97,7 +115,16 @@ GLenum program_interface, const String& name) { if (!ValidateWebGLProgramOrShader("getProgramResourceIndex", program)) - return 0; + return GL_INVALID_INDEX; + if (!ValidateProgramInterface("getProgramResourceIndex", program_interface)) + return GL_INVALID_INDEX; + if (program_interface == GL_ATOMIC_COUNTER_BUFFER) { + SynthesizeGLError(GL_INVALID_ENUM, "getProgramResourceIndex", + "atomic counter resources are not assigned name strings"); + return GL_INVALID_INDEX; + } + if (!ValidateString("getProgramResourceIndex", name)) + return GL_INVALID_INDEX; return ContextGL()->GetProgramResourceIndex( ObjectOrZero(program), program_interface, name.Utf8().c_str()); @@ -109,15 +136,22 @@ GLuint index) { if (!ValidateWebGLProgramOrShader("getProgramResourceName", program)) return String(); + if (!ValidateProgramInterface("getProgramResourceName", program_interface)) + return String(); + if (program_interface == GL_ATOMIC_COUNTER_BUFFER) { + SynthesizeGLError(GL_INVALID_ENUM, "getProgramResourceName", + "atomic counter resources are not assigned name strings"); + return String(); + } + if (!ValidateProgramResourceIndex( + "getProgramResourceName", program, program_interface, index)) + return String(); GLint max_name_length = -1; ContextGL()->GetProgramInterfaceiv(ObjectOrZero(program), program_interface, GL_MAX_NAME_LENGTH, &max_name_length); - if (max_name_length <= 0) { - SynthesizeGLError(GL_INVALID_VALUE, "getProgramResourceName", - "invalid program interface"); + if (max_name_length <= 0) return String(); - } auto name = std::make_unique<GLchar[]>(max_name_length); GLsizei length = 0; @@ -138,54 +172,34 @@ const Vector<GLenum>& props) { if (!ValidateWebGLProgramOrShader("getProgramResource", program)) return base::nullopt; + if (!ValidateProgramInterface("getProgramResource", program_interface)) + return base::nullopt; + if (props.IsEmpty()) { + SynthesizeGLError(GL_INVALID_VALUE, "getProgramResource", + "resource prop array is empty"); + return base::nullopt; + } + if (!ValidateProgramResourceIndex( + "getProgramResource", program, program_interface, index)) + return base::nullopt; + + // For props with variable-length return values, their lengths will be queried + // first with |auxiliary_props|, and |extended_params| will be adequately + // sized for the whole result after that. Vector<GLenum> auxiliary_props; Vector<GLint> auxiliary_params; Vector<GLenum> extended_props; Vector<GLint> extended_params; - for (GLenum prop : props) { - switch (prop) { - // Handle props with fixed-length return values. - case GL_ARRAY_SIZE: - case GL_ARRAY_STRIDE: - case GL_ATOMIC_COUNTER_BUFFER_INDEX: - case GL_BLOCK_INDEX: - case GL_BUFFER_BINDING: - case GL_BUFFER_DATA_SIZE: - case GL_IS_ROW_MAJOR: - case GL_LOCATION: - case GL_MATRIX_STRIDE: - case GL_NAME_LENGTH: - case GL_NUM_ACTIVE_VARIABLES: - case GL_OFFSET: - case GL_REFERENCED_BY_COMPUTE_SHADER: - case GL_REFERENCED_BY_FRAGMENT_SHADER: - case GL_REFERENCED_BY_VERTEX_SHADER: - case GL_TOP_LEVEL_ARRAY_SIZE: - case GL_TOP_LEVEL_ARRAY_STRIDE: - case GL_TYPE: - extended_props.push_back(prop); - extended_params.push_back(0); - break; - - // Handle props with variable-length return values. For these props, their - // lengths will be queried first by constructing |auxiliary_props| as the - // following, and |extended_params| will be adequately sized for the whole - // result after that. - case GL_ACTIVE_VARIABLES: - auxiliary_props.push_back(GL_NUM_ACTIVE_VARIABLES); - auxiliary_params.push_back(-1); - extended_props.push_back(GL_ACTIVE_VARIABLES); - break; - - default: - SynthesizeGLError(GL_INVALID_ENUM, "getProgramResource", - "invalid program resource property"); - return base::nullopt; - } + if (!ValidateAndExtendProgramResourceProperties( + "getProgramResource", program_interface, props, extended_props)) + return base::nullopt; + extended_params.resize(extended_props.size()); + for (wtf_size_t i = 0; i < extended_props.size() - props.size(); ++i) { + auxiliary_props.push_back(extended_props[i]); + auxiliary_params.push_back(-1); + extended_params.pop_back(); } - extended_props.PrependVector(auxiliary_props); - extended_params.PrependVector(auxiliary_params); if (auxiliary_props.size()) { ContextGL()->GetProgramResourceiv(ObjectOrZero(program), program_interface, @@ -287,6 +301,20 @@ const String& name) { if (!ValidateWebGLProgramOrShader("getProgramResourceLocation", program)) return WrapLocation(script_state, -1, program, program_interface); + if (!ValidateProgramInterface( + "getProgramResourceLocation", program_interface)) + return WrapLocation(script_state, -1, program, program_interface); + if (!ValidateLocationLength("getProgramResourceLocation", name)) + return WrapLocation(script_state, -1, program, program_interface); + if (!ValidateString("getProgramResourceLocation", name)) + return WrapLocation(script_state, -1, program, program_interface); + if (IsPrefixReserved(name)) + return WrapLocation(script_state, -1, program, program_interface); + if (!program->LinkStatus(this)) { + SynthesizeGLError(GL_INVALID_OPERATION, "getProgramResourceLocation", + "program not linked"); + return WrapLocation(script_state, -1, program, program_interface); + } GLint location = ContextGL()->GetProgramResourceLocation( ObjectOrZero(program), program_interface, name.Utf8().c_str()); @@ -410,6 +438,172 @@ WebGL2RenderingContextBase::Trace(visitor); } +bool WebGL2ComputeRenderingContextBase::ValidateProgramInterface( + const char* function_name, + GLenum program_interface) { + switch (program_interface) { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_SHADER_STORAGE_BLOCK: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + return true; + default: + SynthesizeGLError(GL_INVALID_ENUM, function_name, + "invalid program interface"); + return false; + } +} + +bool WebGL2ComputeRenderingContextBase::ValidateProgramResourceIndex( + const char* function_name, + WebGLProgram* program, + GLenum program_interface, + GLuint index) { + DCHECK(program); + if (!program->LinkStatus(this)) { + SynthesizeGLError(GL_INVALID_OPERATION, function_name, + "program not linked"); + return false; + } + GLint active_resources = 0; + ContextGL()->GetProgramInterfaceiv(ObjectOrZero(program), program_interface, + GL_ACTIVE_RESOURCES, &active_resources); + if (index >= static_cast<GLuint>(active_resources)) { + SynthesizeGLError(GL_INVALID_VALUE, function_name, + "invalid program resource index"); + return false; + } + return true; +} + +bool +WebGL2ComputeRenderingContextBase::ValidateAndExtendProgramResourceProperties( + const char* function_name, + GLenum program_interface, + const Vector<GLenum>& props, + Vector<GLenum>& extended_props) { + Vector<GLenum> auxiliary_props; + + for (GLenum prop : props) { + GLenum error = GL_NO_ERROR; + + switch (prop) { + // Handle props with fixed-length return values. + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + if (program_interface != GL_ATOMIC_COUNTER_BUFFER && + program_interface != GL_SHADER_STORAGE_BLOCK && + program_interface != GL_UNIFORM_BLOCK) + error = GL_INVALID_OPERATION; + break; + case GL_ARRAY_SIZE: + if (program_interface != GL_BUFFER_VARIABLE && + program_interface != GL_PROGRAM_INPUT && + program_interface != GL_PROGRAM_OUTPUT && + program_interface != GL_TRANSFORM_FEEDBACK_VARYING && + program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + if (program_interface != GL_BUFFER_VARIABLE && + program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + if (program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + case GL_BUFFER_DATA_SIZE: + if (program_interface != GL_ATOMIC_COUNTER_BUFFER && + program_interface != GL_SHADER_STORAGE_BLOCK && + program_interface != GL_UNIFORM_BLOCK) + error = GL_INVALID_OPERATION; + break; + case GL_LOCATION: + if (program_interface != GL_PROGRAM_INPUT && + program_interface != GL_PROGRAM_OUTPUT && + program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + case GL_NAME_LENGTH: + if (program_interface == GL_ATOMIC_COUNTER_BUFFER) + error = GL_INVALID_OPERATION; + break; + case GL_OFFSET: + if (program_interface != GL_BUFFER_VARIABLE && + program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + if (program_interface != GL_ATOMIC_COUNTER_BUFFER && + program_interface != GL_BUFFER_VARIABLE && + program_interface != GL_PROGRAM_INPUT && + program_interface != GL_PROGRAM_OUTPUT && + program_interface != GL_SHADER_STORAGE_BLOCK && + program_interface != GL_UNIFORM && + program_interface != GL_UNIFORM_BLOCK) + error = GL_INVALID_OPERATION; + break; + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + if (program_interface != GL_BUFFER_VARIABLE) + error = GL_INVALID_OPERATION; + break; + case GL_TYPE: + if (program_interface != GL_BUFFER_VARIABLE && + program_interface != GL_PROGRAM_INPUT && + program_interface != GL_PROGRAM_OUTPUT && + program_interface != GL_TRANSFORM_FEEDBACK_VARYING && + program_interface != GL_UNIFORM) + error = GL_INVALID_OPERATION; + break; + + // Handle props with variable-length return values. + case GL_ACTIVE_VARIABLES: + if (program_interface != GL_ATOMIC_COUNTER_BUFFER && + program_interface != GL_SHADER_STORAGE_BLOCK && + program_interface != GL_UNIFORM_BLOCK) { + error = GL_INVALID_OPERATION; + break; + } + auxiliary_props.push_back(GL_NUM_ACTIVE_VARIABLES); + break; + + default: + error = GL_INVALID_ENUM; + } + + switch (error) { + case GL_NO_ERROR: + break; + case GL_INVALID_ENUM: + SynthesizeGLError(GL_INVALID_ENUM, function_name, + "invalid program resource prop"); + return false; + case GL_INVALID_OPERATION: + SynthesizeGLError( + GL_INVALID_OPERATION, function_name, + "invalid resource prop for the specified program interface"); + return false; + default: + NOTREACHED(); + } + } + + extended_props = auxiliary_props; + extended_props.AppendVector(props); + return true; +} + ScriptValue WebGL2ComputeRenderingContextBase::WrapLocation( ScriptState* script_state, GLint location,
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h index 28b4954..9e6ca07 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h
@@ -74,6 +74,18 @@ bool using_gpu_compositing, const CanvasContextCreationAttributesCore& requested_attributes); + virtual bool ValidateProgramInterface(const char* function_name, + GLenum program_interface); + virtual bool ValidateProgramResourceIndex(const char* function_name, + WebGLProgram*, + GLenum program_interface, + GLuint index); + virtual bool ValidateAndExtendProgramResourceProperties( + const char* function_name, + GLenum program_interface, + const Vector<GLenum>& props, + Vector<GLenum>& extended_props); + ScriptValue WrapLocation(ScriptState*, GLint location, WebGLProgram* program,
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform_test.cc b/third_party/blink/renderer/modules/xr/xr_rigid_transform_test.cc index 20b2e39..0e31b61 100644 --- a/third_party/blink/renderer/modules/xr/xr_rigid_transform_test.cc +++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform_test.cc
@@ -4,8 +4,6 @@ #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" -#include <vector> - #include "third_party/blink/renderer/modules/xr/xr_test_utils.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_test_utils.h b/third_party/blink/renderer/modules/xr/xr_test_utils.h index 93fbe6a2..da35d67 100644 --- a/third_party/blink/renderer/modules/xr/xr_test_utils.h +++ b/third_party/blink/renderer/modules/xr/xr_test_utils.h
@@ -6,7 +6,6 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TEST_UTILS_H_ #include <memory> -#include <vector> #include "third_party/blink/renderer/core/geometry/dom_point_init.h" #include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
diff --git a/third_party/blink/renderer/platform/audio/audio_destination_test.cc b/third_party/blink/renderer/platform/audio/audio_destination_test.cc index d1a43dc2..072ca234 100644 --- a/third_party/blink/renderer/platform/audio/audio_destination_test.cc +++ b/third_party/blink/renderer/platform/audio/audio_destination_test.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/platform/audio/audio_destination.h" #include <memory> -#include <vector> #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_audio_device.h" #include "third_party/blink/public/platform/web_audio_latency_hint.h" @@ -75,7 +74,7 @@ scoped_refptr<AudioDestination> destination = AudioDestination::Create( callback, channel_count, latency_hint, sample_rate); - std::vector<float> channels[channel_count]; + Vector<float> channels[channel_count]; WebVector<float*> dest_data(static_cast<size_t>(channel_count)); for (int i = 0; i < channel_count; ++i) { channels[i].resize(request_frames);
diff --git a/third_party/blink/renderer/platform/audio/push_pull_fifo_multithread_test.cc b/third_party/blink/renderer/platform/audio/push_pull_fifo_multithread_test.cc index ee15599..abdc15b 100644 --- a/third_party/blink/renderer/platform/audio/push_pull_fifo_multithread_test.cc +++ b/third_party/blink/renderer/platform/audio/push_pull_fifo_multithread_test.cc
@@ -172,7 +172,7 @@ std::unique_ptr<PushClient> push_client = std::make_unique<PushClient>( test_fifo.get(), param.push_buffer_size, param.push_jitter_range_ms); - std::vector<base::WaitableEvent*> done_events; + Vector<base::WaitableEvent*> done_events; done_events.push_back( pull_client->Start(param.test_duration_ms, pull_interval_ms)); done_events.push_back(
diff --git a/third_party/blink/renderer/platform/audio/vector_math_test.cc b/third_party/blink/renderer/platform/audio/vector_math_test.cc index 6f8430e..6c48cf6 100644 --- a/third_party/blink/renderer/platform/audio/vector_math_test.cc +++ b/third_party/blink/renderer/platform/audio/vector_math_test.cc
@@ -10,12 +10,12 @@ #include <limits> #include <numeric> #include <random> -#include <vector> #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { namespace vector_math { @@ -440,7 +440,7 @@ TEST_F(VectorMathTest, Zvmul) { constexpr float kMax = std::numeric_limits<float>::max(); - std::vector<std::array<float, kFloatArraySize + 1u>> sources(4u); + Vector<std::array<float, kFloatArraySize + 1u>> sources(4u); for (size_t i = 0u; i < sources.size(); ++i) { // Initialize a local source with a randomized test case source. std::copy_n(GetSource(i), kFloatArraySize, sources[i].begin());
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc index ca57e9e..c26a69f0 100644 --- a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc +++ b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -5,7 +5,6 @@ #include <limits> #include <random> #include <thread> -#include <vector> #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" @@ -35,7 +34,7 @@ constexpr size_t kCompressedSize = 55; String MakeLargeString(char c = 'a') { - std::vector<char> data(kSizeKb * 1000, c); + Vector<char> data(kSizeKb * 1000, c); return String(data.data(), data.size()).ReleaseImpl(); } @@ -140,7 +139,7 @@ // ensure its compressed size is larger than the initial size (at least from // gzip's header). Mersenne-Twister implementation is specified, making the // test deterministic. - std::vector<unsigned char> data(kSizeKb * 1000); + Vector<unsigned char> data(kSizeKb * 1000); std::mt19937 engine(42); // uniform_int_distribution<T> is undefined behavior for T = unsigned char. std::uniform_int_distribution<int> dist( @@ -170,7 +169,7 @@ UChar emoji_grinning_face[2] = {0xd83d, 0xde00}; size_t size_in_chars = 2 * kSizeKb * 1000 / sizeof(UChar); - std::vector<UChar> data(size_in_chars); + Vector<UChar> data(size_in_chars); for (size_t i = 0; i < size_in_chars / 2; ++i) { data[i * 2] = emoji_grinning_face[0]; data[i * 2 + 1] = emoji_grinning_face[1]; @@ -614,13 +613,13 @@ TEST_F(ParkableStringTest, ShouldPark) { String empty_string(""); EXPECT_FALSE(ParkableStringManager::ShouldPark(*empty_string.Impl())); - std::vector<char> data(20 * 1000, 'a'); + Vector<char> data(20 * 1000, 'a'); String parkable(String(data.data(), data.size()).ReleaseImpl()); EXPECT_TRUE(ParkableStringManager::ShouldPark(*parkable.Impl())); std::thread t([]() { - std::vector<char> data(20 * 1000, 'a'); + Vector<char> data(20 * 1000, 'a'); String parkable(String(data.data(), data.size()).ReleaseImpl()); EXPECT_FALSE(ParkableStringManager::ShouldPark(*parkable.Impl())); }); @@ -1004,7 +1003,7 @@ // Need to make the string really large, otherwise unparking takes less than // 1ms, and the 0 bucket is populated. const size_t original_size = 5 * 1000 * 1000; - std::vector<char> data(original_size, 'a'); + Vector<char> data(original_size, 'a'); ParkableString parkable(String(data.data(), data.size()).ReleaseImpl()); ParkAndWait(parkable);
diff --git a/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc b/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc index 52fad8525..08a9c874 100644 --- a/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc +++ b/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/public/platform/web_canonical_cookie.h" #include <memory> -#include <vector> #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_selection_types_test.cc b/third_party/blink/renderer/platform/fonts/font_selection_types_test.cc index dd41e1f..11480c8 100644 --- a/third_party/blink/renderer/platform/fonts/font_selection_types_test.cc +++ b/third_party/blink/renderer/platform/fonts/font_selection_types_test.cc
@@ -10,10 +10,9 @@ namespace blink { TEST(FontSelectionTypesTest, HashCollisions) { - std::vector<int> weights = {100, 200, 300, 400, 500, 600, 700, 800, 900}; - std::vector<float> slopes = {-90, -67.5, -30, -20, -10, 0, - 10, 20, 30, 67.5, 90}; - std::vector<float> widths = {50, 67.5, 75, 100, 125, 150, 167.5, 175, 200}; + Vector<int> weights = {100, 200, 300, 400, 500, 600, 700, 800, 900}; + Vector<float> slopes = {-90, -67.5, -30, -20, -10, 0, 10, 20, 30, 67.5, 90}; + Vector<float> widths = {50, 67.5, 75, 100, 125, 150, 167.5, 175, 200}; HashSet<unsigned> hashes; for (auto weight : weights) {
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc index f009755..2ce9ed84 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc +++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_test.cc
@@ -18,12 +18,12 @@ namespace blink { -void ensureHasNativeSmallCaps(const std::string& font_family_name) { +void ensureHasNativeSmallCaps(const char* font_family_name) { sk_sp<SkTypeface> test_typeface = - SkTypeface::MakeFromName(font_family_name.c_str(), SkFontStyle()); - FontPlatformData font_platform_data(test_typeface, font_family_name.c_str(), - 16, false, false); - ASSERT_EQ(font_platform_data.FontFamilyName(), font_family_name.c_str()); + SkTypeface::MakeFromName(font_family_name, SkFontStyle()); + FontPlatformData font_platform_data(test_typeface, font_family_name, 16, + false, false); + ASSERT_EQ(font_platform_data.FontFamilyName(), font_family_name); OpenTypeCapsSupport caps_support(font_platform_data.GetHarfBuzzFace(), FontDescription::FontVariantCaps::kSmallCaps, @@ -46,13 +46,13 @@ if (!base::mac::IsAtLeastOS10_13()) return; #endif - std::vector<std::string> test_fonts = { + Vector<const char*> test_fonts = { ".SF NS Text", // has OpenType small-caps "Apple Chancery", // has old-style (feature id 3,"Letter Case") // small-caps "Baskerville"}; // has new-style (feature id 38, "Upper Case") // small-case. - for (auto& test_font : test_fonts) + for (auto* test_font : test_fonts) ensureHasNativeSmallCaps(test_font); }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc index b4794c7a..4545b3f4 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -1485,7 +1485,7 @@ HarfBuzzShaper shaper(string); scoped_refptr<ShapeResult> result = shaper.Shape(&font, TextDirection::kRtl); - std::vector<unsigned> safe_to_break_positions; + Vector<unsigned> safe_to_break_positions; #if defined(OS_MACOSX) safe_to_break_positions = {0, 2, 3, 4, 11};
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc index 7bfe3b7..ba873a9 100644 --- a/third_party/blink/renderer/platform/heap/heap_test.cc +++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -917,7 +917,7 @@ class RefCountedAndGarbageCollected : public GarbageCollectedFinalized<RefCountedAndGarbageCollected> { public: - RefCountedAndGarbageCollected() : ref_count_(0) {} + RefCountedAndGarbageCollected() : keep_alive_(PERSISTENT_FROM_HERE) {} ~RefCountedAndGarbageCollected() { ++destructor_calls_; } void AddRef() { @@ -942,7 +942,7 @@ static int destructor_calls_; private: - int ref_count_; + int ref_count_ = 0; SelfKeepAlive<RefCountedAndGarbageCollected> keep_alive_; }; @@ -952,7 +952,7 @@ : public HeapTestOtherSuperClass, public GarbageCollectedFinalized<RefCountedAndGarbageCollected2> { public: - RefCountedAndGarbageCollected2() : ref_count_(0) {} + RefCountedAndGarbageCollected2() : keep_alive_(PERSISTENT_FROM_HERE) {} ~RefCountedAndGarbageCollected2() { ++destructor_calls_; } void Ref() { @@ -977,7 +977,7 @@ static int destructor_calls_; private: - int ref_count_; + int ref_count_ = 0; SelfKeepAlive<RefCountedAndGarbageCollected2> keep_alive_; };
diff --git a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc index 4dbe630..49d9c27 100644 --- a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc +++ b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include <initializer_list> -#include <vector> #include "base/bind.h" #include "testing/gtest/include/gtest/gtest.h" @@ -26,7 +25,7 @@ // store to be in the set of provided objects. class BackingVisitor : public Visitor { public: - BackingVisitor(ThreadState* state, std::vector<void*>* objects) + BackingVisitor(ThreadState* state, Vector<void*>* objects) : Visitor(state), objects_(objects) {} ~BackingVisitor() final {} @@ -41,7 +40,7 @@ void Visit(void* obj, TraceDescriptor desc) final { EXPECT_TRUE(obj); - auto pos = std::find(objects_->begin(), objects_->end(), obj); + auto** pos = std::find(objects_->begin(), objects_->end(), obj); if (objects_->end() != pos) objects_->erase(pos); // The garbage collector will find those objects so we can mark them. @@ -74,7 +73,7 @@ void Visit(const TraceWrapperV8Reference<v8::Value>&) final {} private: - std::vector<void*>* objects_; + Vector<void*>* objects_; }; // Base class for initializing worklists. @@ -158,7 +157,7 @@ headers_.push_back(HeapObjectHeader::FromPayload(object)); EXPECT_FALSE(headers_.back()->IsMarked()); } - EXPECT_FALSE(objects_.empty()); + EXPECT_FALSE(objects_.IsEmpty()); } ~ExpectWriteBarrierFires() { @@ -174,11 +173,11 @@ HeapObjectHeader::FromPayload(item.object)); continue; } - auto pos = std::find(objects_.begin(), objects_.end(), item.object); + auto** pos = std::find(objects_.begin(), objects_.end(), item.object); if (objects_.end() != pos) objects_.erase(pos); } - EXPECT_TRUE(objects_.empty()); + EXPECT_TRUE(objects_.IsEmpty()); // All headers of objects watched should be marked at this point. for (HeapObjectHeader* header : headers_) { EXPECT_TRUE(header->IsMarked()); @@ -188,8 +187,8 @@ } private: - std::vector<void*> objects_; - std::vector<HeapObjectHeader*> headers_; + Vector<void*> objects_; + Vector<HeapObjectHeader*> headers_; BackingVisitor backing_visitor_; }; @@ -204,7 +203,7 @@ EXPECT_TRUE(marking_worklist_->IsGlobalEmpty()); for (void* object : objects_) { HeapObjectHeader* header = HeapObjectHeader::FromPayload(object); - headers_.push_back({header, header->IsMarked()}); + headers_.push_back(std::make_pair(header, header->IsMarked())); } } @@ -217,8 +216,8 @@ } private: - std::vector<void*> objects_; - std::vector<std::pair<HeapObjectHeader*, bool /* was marked */>> headers_; + Vector<void*> objects_; + Vector<std::pair<HeapObjectHeader*, bool /* was marked */>> headers_; }; class Object : public LinkedObject {
diff --git a/third_party/blink/renderer/platform/heap/self_keep_alive.h b/third_party/blink/renderer/platform/heap/self_keep_alive.h index 25550674..3eaff5d5 100644 --- a/third_party/blink/renderer/platform/heap/self_keep_alive.h +++ b/third_party/blink/renderer/platform/heap/self_keep_alive.h
@@ -17,6 +17,7 @@ // // class Opener : public GarbageCollected<Opener> { // public: +// Opener() : keep_alive_(PERSISTENT_FROM_HERE) {} // ... // void Open() { // // Retain a self-reference while in an Open()ed state: @@ -44,9 +45,8 @@ DISALLOW_NEW(); public: - SelfKeepAlive() = default; - - explicit SelfKeepAlive(Self* self) { Assign(self); } + explicit SelfKeepAlive(const PersistentLocation& location) + : keep_alive_(location) {} SelfKeepAlive(const PersistentLocation& location, Self* self) : keep_alive_(location) { Assign(self);
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc index 6eb4223..50b4c78 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc
@@ -41,7 +41,7 @@ (image_size > threshold); } -void ReadFileToVector(const base::FilePath& path, std::vector<char>* contents) { +void ReadFileToVector(const base::FilePath& path, Vector<char>* contents) { std::string raw_image_data; base::ReadFileToString(path, &raw_image_data); contents->resize(raw_image_data.size()); @@ -106,7 +106,7 @@ base::FilePath data_dir; ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &data_dir)); data_dir_ = data_dir.AppendASCII("webkit").AppendASCII("data").AppendASCII( - format_ + "_decoder"); + format_.Utf8() + "_decoder"); if (!base::PathExists(data_dir_)) { const testing::TestInfo* const test_info = testing::UnitTest::GetInstance()->current_test_info(); @@ -123,11 +123,11 @@ return base::FilePath(path.value() + kDecodedDataExtension); } -std::vector<base::FilePath> ImageDecoderBaseTest::GetImageFiles() const { - std::string pattern = "*." + format_; +Vector<base::FilePath> ImageDecoderBaseTest::GetImageFiles() const { + std::string pattern = "*." + format_.Utf8(); base::FileEnumerator enumerator(data_dir_, false, base::FileEnumerator::FILES); - std::vector<base::FilePath> image_files; + Vector<base::FilePath> image_files; for (base::FilePath next_file_name = enumerator.Next(); !next_file_name.empty(); next_file_name = enumerator.Next()) { base::FilePath base_name = next_file_name.BaseName(); @@ -156,8 +156,8 @@ const int64_t threshold) { if (data_dir_.empty()) return; - const std::vector<base::FilePath> image_files(GetImageFiles()); - for (std::vector<base::FilePath>::const_iterator i = image_files.begin(); + const Vector<base::FilePath> image_files(GetImageFiles()); + for (Vector<base::FilePath>::const_iterator i = image_files.begin(); i != image_files.end(); ++i) { if (!ShouldSkipFile(*i, file_selection, threshold)) TestImageDecoder(*i, GetMD5SumPath(*i), kFirstFrameIndex); @@ -173,7 +173,7 @@ return; #endif - std::vector<char> image_contents; + Vector<char> image_contents; ReadFileToVector(image_path, &image_contents); EXPECT_TRUE(image_contents.size()); std::unique_ptr<ImageDecoder> decoder(CreateImageDecoder());
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.h b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.h index bb350da..07ff94e 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.h +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.h
@@ -7,9 +7,6 @@ #include <stdint.h> -#include <string> -#include <vector> - #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/macros.h" @@ -33,7 +30,7 @@ class ImageDecoderBaseTest : public testing::Test { public: - explicit ImageDecoderBaseTest(const std::string& format) : format_(format) {} + explicit ImageDecoderBaseTest(const String& format) : format_(format) {} enum class FileSelection { kAll, @@ -48,7 +45,7 @@ base::FilePath GetMD5SumPath(const base::FilePath& path); // Returns the vector of image files for testing. - std::vector<base::FilePath> GetImageFiles() const; + Vector<base::FilePath> GetImageFiles() const; // Returns true if the image is bogus and should not be successfully decoded. bool ShouldImageFail(const base::FilePath& path) const; @@ -72,7 +69,7 @@ virtual std::unique_ptr<ImageDecoder> CreateImageDecoder() const = 0; // The format to be decoded, like "bmp" or "ico". - std::string format_; + String format_; protected: const base::FilePath& data_dir() const { return data_dir_; }
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc index c243cf6..d4bf881 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -33,7 +33,6 @@ #include <limits> #include <memory> #include <utility> -#include <vector> #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_data.h"
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc index 48d910e..b263c8fc 100644 --- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
@@ -1043,7 +1043,7 @@ bool is_transparent; bool is_high_bit_depth; scoped_refptr<SharedBuffer> png_contents; - std::vector<float> expected_pixels; + Vector<float> expected_pixels; }; static void TestHighBitDepthPNGDecoding(const PNGSample& png_sample, @@ -1092,7 +1092,7 @@ skcms_AlphaFormat_Unpremul, nullptr, decoded_pixels_float_32, skcms_PixelFormat_RGBA_ffff, skcms_AlphaFormat_Unpremul, nullptr, 4)); - std::vector<float> expected_pixels = png_sample.expected_pixels; + Vector<float> expected_pixels = png_sample.expected_pixels; bool test_succeed = true; const float decoding_tolerance = 0.001; for (int i = 0; i < 16; i++) { @@ -1109,7 +1109,7 @@ ASSERT_TRUE(test_succeed); } -static void FillPNGSamplesSourcePixels(std::vector<PNGSample>& png_samples) { +static void FillPNGSamplesSourcePixels(Vector<PNGSample>& png_samples) { // Color components of opaque and transparent 16 bit PNG, read with libpng // in BigEndian and scaled to [0,1]. The values are read from non-interlaced // samples, but used for both interlaced and non-interlaced test cases. @@ -1118,63 +1118,63 @@ // Adobe software created a non-matching color profile (see crbug.com/874939). // Hence, SkEncoder was used to generate the e-sRGB file (see the skia fiddle // here: https://fiddle.skia.org/c/17beedfd66dac1ec930f0c414c50f847). - static const std::vector<float> source_pixels_opaque_srgb = { + static const Vector<float> source_pixels_opaque_srgb = { 0.4986953536, 0.5826657511, 0.7013199054, 1, // Top left pixel 0.907988098, 0.8309605554, 0.492011902, 1, // Top right pixel 0.6233157855, 0.9726558328, 0.9766536965, 1, // Bottom left pixel 0.8946517128, 0.9663080797, 0.9053025101, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_opaque_adobe_rgb = { + static const Vector<float> source_pixels_opaque_adobe_rgb = { 0.4448004883, 0.5216296635, 0.6506294347, 1, // Top left pixel 0.8830548562, 0.7978179599, 0.4323186084, 1, // Top right pixel 0.6841992828, 0.9704280156, 0.9711299306, 1, // Bottom left pixel 0.8874799725, 0.96099794, 0.8875715267, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_opaque_p3 = { + static const Vector<float> source_pixels_opaque_p3 = { 0.515648127, 0.5802243076, 0.6912489509, 1, // Top left pixel 0.8954146639, 0.8337987335, 0.5691767758, 1, // Top right pixel 0.772121767, 0.9671625849, 0.973510338, 1, // Bottom left pixel 0.9118944076, 0.9645685512, 0.9110704204, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_opaque_e_srgb = { + static const Vector<float> source_pixels_opaque_e_srgb = { 0.6977539062, 0.5839843750, 0.4978027344, 1, // Top left pixel 0.4899902344, 0.8310546875, 0.9096679688, 1, // Top right pixel 0.9760742188, 0.9721679688, 0.6230468750, 1, // Bottom left pixel 0.9057617188, 0.9643554688, 0.8940429688, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_opaque_prophoto = { + static const Vector<float> source_pixels_opaque_prophoto = { 0.5032883192, 0.5191271839, 0.6309147784, 1, // Top left pixel 0.8184176394, 0.8002899214, 0.5526970321, 1, // Top right pixel 0.842526894, 0.945616846, 0.9667048142, 1, // Bottom left pixel 0.9119554437, 0.9507133593, 0.9001754788, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_opaque_rec2020 = { + static const Vector<float> source_pixels_opaque_rec2020 = { 0.5390554665, 0.5766842145, 0.6851758602, 1, // Top left pixel 0.871061265, 0.831326772, 0.5805294881, 1, // Top right pixel 0.8386205844, 0.9599603265, 0.9727168688, 1, // Bottom left pixel 0.9235217823, 0.9611200122, 0.9112840467, 1}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_srgb = { + static const Vector<float> source_pixels_transparent_srgb = { 0.3733272297, 0.4783093004, 0.6266422522, 0.8, // Top left pixel 0.8466468299, 0.7182879377, 0.153322652, 0.6, // Top right pixel 0.05831998169, 0.9316395819, 0.9416495003, 0.4, // Bottom left pixel 0.4733043412, 0.8316319524, 0.5266346227, 0.2}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_adobe_rgb = { + static const Vector<float> source_pixels_transparent_adobe_rgb = { 0.305943389, 0.4019836728, 0.5632867933, 0.8, // Top left pixel 0.8051117723, 0.6630197604, 0.05374227512, 0.6, // Top right pixel 0.210482948, 0.926115816, 0.9278248264, 0.4, // Bottom left pixel 0.4374456397, 0.8050812543, 0.4379644465, 0.2}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_p3 = { + static const Vector<float> source_pixels_transparent_p3 = { 0.3945372702, 0.475257496, 0.6140383001, 0.8, // Top left pixel 0.8257114519, 0.7230182345, 0.2819256886, 0.6, // Top right pixel 0.4302738994, 0.9179064622, 0.933806363, 0.4, // Bottom left pixel 0.5595330739, 0.8228122377, 0.5554436561, 0.2}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_e_srgb = { + static const Vector<float> source_pixels_transparent_e_srgb = { 0.6230468750, 0.4782714844, 0.3723144531, 0.8, // Top left pixel 0.1528320312, 0.7172851562, 0.8466796875, 0.6, // Top right pixel 0.9409179688, 0.9331054688, 0.0588073730, 0.4, // Bottom left pixel 0.5253906250, 0.8310546875, 0.4743652344, 0.2}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_prophoto = { + static const Vector<float> source_pixels_transparent_prophoto = { 0.379064622, 0.3988708324, 0.5386282139, 0.8, // Top left pixel 0.6973525597, 0.6671396963, 0.2544289311, 0.6, // Top right pixel 0.6063477531, 0.864103151, 0.9168078126, 0.4, // Bottom left pixel 0.5598077363, 0.7536278325, 0.5009384298, 0.2}; // Bottom right pixel - static const std::vector<float> source_pixels_transparent_rec2020 = { + static const Vector<float> source_pixels_transparent_rec2020 = { 0.4237735561, 0.4708323796, 0.6064698253, 0.8, // Top left pixel 0.7851224537, 0.7188677806, 0.3008468757, 0.6, // Top right pixel 0.5965819791, 0.8999618524, 0.9318532082, 0.4, // Bottom left pixel @@ -1211,12 +1211,12 @@ } } -static std::vector<PNGSample> GetPNGSamplesInfo(bool include_8bit_pngs) { - std::vector<PNGSample> png_samples; - std::vector<String> interlace_status = {"", "_interlaced"}; - std::vector<String> color_spaces = {"sRGB", "AdobeRGB", "DisplayP3", - "e-sRGB", "ProPhoto", "Rec2020"}; - std::vector<String> alpha_status = {"_opaque", "_transparent"}; +static Vector<PNGSample> GetPNGSamplesInfo(bool include_8bit_pngs) { + Vector<PNGSample> png_samples; + Vector<String> interlace_status = {"", "_interlaced"}; + Vector<String> color_spaces = {"sRGB", "AdobeRGB", "DisplayP3", + "e-sRGB", "ProPhoto", "Rec2020"}; + Vector<String> alpha_status = {"_opaque", "_transparent"}; for (String color_space : color_spaces) { for (String alpha : alpha_status) { @@ -1252,7 +1252,7 @@ TEST(StaticPNGTests, DecodeHighBitDepthPngToHalfFloat) { const bool include_8bit_pngs = false; - std::vector<PNGSample> png_samples = GetPNGSamplesInfo(include_8bit_pngs); + Vector<PNGSample> png_samples = GetPNGSamplesInfo(include_8bit_pngs); FillPNGSamplesSourcePixels(png_samples); String path = "/images/resources/png-16bit/"; for (PNGSample& png_sample : png_samples) { @@ -1265,7 +1265,7 @@ TEST(StaticPNGTests, ImageIsHighBitDepth) { const bool include_8bit_pngs = true; - std::vector<PNGSample> png_samples = GetPNGSamplesInfo(include_8bit_pngs); + Vector<PNGSample> png_samples = GetPNGSamplesInfo(include_8bit_pngs); IntSize size(2, 2); String path = "/images/resources/png-16bit/";
diff --git a/third_party/blink/renderer/platform/json/json_parser_test.cc b/third_party/blink/renderer/platform/json/json_parser_test.cc index f07f78b..550023d 100644 --- a/third_party/blink/renderer/platform/json/json_parser_test.cc +++ b/third_party/blink/renderer/platform/json/json_parser_test.cc
@@ -650,7 +650,7 @@ // Test cases. Each pair is a JSON string, and the minimum depth required // to successfully parse that string. - std::vector<std::pair<const char*, int>> test_cases = { + Vector<std::pair<const char*, int>> test_cases = { {"[[[[[]]]]]", 5}, {"[[[[[\"a\"]]]]]", 6}, {"[[],[],[],[],[]]", 2},
diff --git a/third_party/blink/renderer/platform/loader/link_header.cc b/third_party/blink/renderer/platform/loader/link_header.cc index 1972ff9a..9a6942e 100644 --- a/third_party/blink/renderer/platform/loader/link_header.cc +++ b/third_party/blink/renderer/platform/loader/link_header.cc
@@ -108,13 +108,10 @@ // According to Section 5.2 of RFC 5988, "anchor" parameters in Link headers // must be either respected, or the entire header must be ignored: // https://tools.ietf.org/html/rfc5988#section-5.2 - // Blink uses "anchor" parameters only when SignedExchangeSubresourcePrefetch - // is enabled and the rel is "alternate". - if (anchor_.has_value() && - (!RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled() || - rel_ != "alternate")) { + // Blink uses "anchor" parameters only for SignedExchangeSubresourcePrefetch + // and the rel is "alternate". + if (anchor_.has_value() && rel_ != "alternate") is_valid_ = false; - } } LinkHeaderSet::LinkHeaderSet(const String& header) {
diff --git a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc index 7d5531b..7629c5f 100644 --- a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc +++ b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
@@ -6,7 +6,6 @@ #include <atomic> #include <utility> -#include <vector> #include "base/bind.h" #include "base/logging.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 1fd5181..be1635a 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -476,6 +476,10 @@ status: "experimental", }, { + name: "DiscardInputToMovingIframes", + status: "experimental", + }, + { name: "DisplayCutoutAPI", settable_from_internals: true, }, @@ -1453,6 +1457,8 @@ }, { name: "SignedExchangeSubresourcePrefetch", + origin_trial_feature_name: "SignedExchangeSubresourcePrefetch", + status: "experimental", }, { name: "SkipAd",
diff --git a/third_party/blink/renderer/platform/timer_test.cc b/third_party/blink/renderer/platform/timer_test.cc index a72a273..bbd8fb94 100644 --- a/third_party/blink/renderer/platform/timer_test.cc +++ b/third_party/blink/renderer/platform/timer_test.cc
@@ -682,9 +682,8 @@ class TaskObserver : public base::MessageLoop::TaskObserver { public: - TaskObserver( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::vector<scoped_refptr<base::SingleThreadTaskRunner>>* run_order) + TaskObserver(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + Vector<scoped_refptr<base::SingleThreadTaskRunner>>* run_order) : task_runner_(std::move(task_runner)), run_order_(run_order) {} void WillProcessTask(const base::PendingTask&) override {} @@ -695,13 +694,13 @@ private: scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - std::vector<scoped_refptr<base::SingleThreadTaskRunner>>* run_order_; + Vector<scoped_refptr<base::SingleThreadTaskRunner>>* run_order_; }; } // namespace TEST_F(TimerTest, MoveToNewTaskRunnerOneShot) { - std::vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order; + Vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order; scoped_refptr<MainThreadTaskQueue> task_queue1( platform_->GetMainThreadScheduler()->NewTimerTaskQueue( @@ -743,7 +742,7 @@ } TEST_F(TimerTest, MoveToNewTaskRunnerRepeating) { - std::vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order; + Vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order; scoped_refptr<MainThreadTaskQueue> task_queue1( platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG index 041cfba7..5330899 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -25,10 +25,6 @@ # rightsizing-grid.html is truly flaky, show flakiness on reload -# CSS Text 3 test that pass in legacy layout -crbug.com/972992 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html [ Failure ] - - # Needs rebaselining. # Features that do not have active plans to support or turn on. @@ -138,7 +134,6 @@ crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-002.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-003.html [ Pass ] -crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-005.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-shaping-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-000.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-001.html [ Pass ] @@ -167,7 +162,6 @@ crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-002.html [ Pass ] crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Pass ] -crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-inline-006.html [ Failure ] crbug.com/591099 external/wpt/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html [ Failure Pass ] crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests index ec8daf6..056a2c20 100644 --- a/third_party/blink/web_tests/SlowTests +++ b/third_party/blink/web_tests/SlowTests
@@ -645,3 +645,11 @@ crbug.com/874695 virtual/blink-cors/http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-twice.html [ Slow ] crbug.com/874695 virtual/blink-cors/http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-overridesexpires.html [ Slow ] crbug.com/874695 virtual/blink-cors/http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-twice.html [ Slow ] + +crbug.com/980804 fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/fractional_scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/scroll_customization/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/fractional_scrolling_threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] +crbug.com/980804 virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ] \ No newline at end of file
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 4b3244df..295a07c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -710,7 +710,6 @@ crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-atomic-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-atomic-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-001.html [ Failure ] -crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-005.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-009.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-010.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-011.html [ Failure ] @@ -3080,23 +3079,30 @@ crbug.com/953847 [ Mac ] fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/fractional_scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling_threaded/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling_threaded/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/fractional_scrolling_threaded/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/fractional_scrolling_threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ] crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ] +crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ] # Compositor threaded scrollbar scrolls parent of subscroller. # Note: even when fixed will still fail on Mac until crbug.com/953847 @@ -6112,43 +6118,6 @@ crbug.com/964239 external/wpt/css/css-scroll-snap/scroll-margin.html [ Pass Failure ] crbug.com/965389 [ Mac ] media/track/track-cue-rendering-position-auto.html [ Pass Failure ] -# TODO(crbug.com/943636): rebaseline and re-enable once https://chromium-review.googlesource.com/c/v8/v8/+/1593307 is rolled into chromium. -crbug.com/943636 external/wpt/screen-orientation/lock-unlock-check.html [ Pass Failure ] -crbug.com/943636 fast/dom/script-module-inline-error-gc.html [ Pass Failure ] -crbug.com/943636 fast/dom/HTMLAnchorElement/anchor-ismap-crash.html [ Pass Failure ] -crbug.com/943636 fast/dom/SelectorAPI/unknown-pseudo.html [ Pass Failure ] -crbug.com/943636 fast/encoding/meta-in-script.html [ Pass Failure ] -crbug.com/943636 fast/events/attribute-listener-deletion-crash.html [ Pass Failure ] -crbug.com/943636 fast/events/set-attribute-listener-window-onerror-crash.html [ Pass Failure ] -crbug.com/943636 fast/events/window-onerror-05.html [ Pass Failure ] -crbug.com/943636 fast/js/postfix-syntax.html [ Pass Failure ] -crbug.com/943636 fast/parser/entity-end-script-tag.html [ Pass Failure ] -crbug.com/943636 fast/workers/worker-onerror-01.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests1-data.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests1-write.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests18-data.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests18-write.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests7-data.html [ Pass Failure ] -crbug.com/943636 html5lib/generated/run-tests7-write.html [ Pass Failure ] -crbug.com/966932 http/tests/devtools/a11y-axe-core/elements/main-tool-test.js [ Timeout Pass ] -crbug.com/943636 http/tests/devtools/console/console-eval-object-literal.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/console/console-link-to-snippet.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/console/console-log-eval-syntax-error.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/console/console-log-syntax-error.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/console/console-message-from-inline-with-url.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error.js [ Pass Failure ] -crbug.com/943636 http/tests/devtools/sources/debugger/debugger-compile-and-run.js [ Pass Failure ] -crbug.com/943636 inspector-protocol/runtime/runtime-callFunctionOn-async.js [ Pass Failure ] -crbug.com/943636 inspector-protocol/runtime/runtime-runScript-async.js [ Pass Failure ] -crbug.com/943636 paint/invalidation/svg/viewport-mask-update.html [ Pass Failure ] -crbug.com/943636 security/lazy-event-listener.html [ Pass Failure ] -crbug.com/943636 virtual/disable-blink-gen-property-trees/paint/invalidation/svg/viewport-mask-update.html [ Pass Failure ] -crbug.com/943636 virtual/mouseevent_fractional/fast/events/attribute-listener-deletion-crash.html [ Pass Failure ] -crbug.com/943636 virtual/mouseevent_fractional/fast/events/set-attribute-listener-window-onerror-crash.html [ Pass Failure ] -crbug.com/943636 virtual/mouseevent_fractional/fast/events/window-onerror-05.html [ Pass Failure ] -crbug.com/943636 virtual/omt-worker-fetch/fast/workers/worker-onerror-01.html [ Pass Failure ] -crbug.com/943636 virtual/not-omt-sw-fetch/fast/workers/worker-onerror-01.html [ Pass Failure ] - # Sheriff 2019-05-27 crbug.com/942411 [ Win ] http/tests/devtools/network/network-search.js [ Pass Timeout ] @@ -6243,3 +6212,6 @@ crbug.com/979593 [ Linux Win ] virtual/blink-cors/external/wpt/service-workers/service-worker/registration-schedule-job.https.html [ Pass Failure ] crbug.com/979593 [ Linux Win ] virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/registration-schedule-job.https.html [ Pass Failure ] crbug.com/979593 [ Linux Win ] virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/registration-schedule-job.https.html [ Pass Failure ] + +# TODO(crbug.com/980588): reenable once WPT is fixed +crbug.com/980588 external/wpt/screen-orientation/lock-unlock-check.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html index 65f2b50..7b17a41 100644 --- a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html +++ b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
@@ -15,7 +15,7 @@ // Make the relative orientation sensor unavailable and set mock data for // the absolute one. - sensorProvider.setGetSensorShouldFail(device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, true); + sensorProvider.setGetSensorShouldFail('RelativeOrientationEulerAngles', true); setMockOrientationData(sensorProvider, orientationData); return waitForOrientation(orientationData); }, 'Tests that deviceorientation falls back to using absolute orientation data if relative is unavailable.');
diff --git a/third_party/blink/web_tests/device_orientation/resources/device-orientation-helpers.js b/third_party/blink/web_tests/device_orientation/resources/device-orientation-helpers.js index 35e3f0e..747407e2 100644 --- a/third_party/blink/web_tests/device_orientation/resources/device-orientation-helpers.js +++ b/third_party/blink/web_tests/device_orientation/resources/device-orientation-helpers.js
@@ -40,17 +40,17 @@ function setMockMotionData(sensorProvider, motionData) { const degToRad = Math.PI / 180; return Promise.all([ - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, [ + setMockSensorDataForType(sensorProvider, "Accelerometer", [ nullToNan(motionData.accelerationIncludingGravityX), nullToNan(motionData.accelerationIncludingGravityY), nullToNan(motionData.accelerationIncludingGravityZ), ]), - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, [ + setMockSensorDataForType(sensorProvider, "LinearAccelerationSensor", [ nullToNan(motionData.accelerationX), nullToNan(motionData.accelerationY), nullToNan(motionData.accelerationZ), ]), - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, [ + setMockSensorDataForType(sensorProvider, "Gyroscope", [ nullToNan(motionData.rotationRateAlpha) * degToRad, nullToNan(motionData.rotationRateBeta) * degToRad, nullToNan(motionData.rotationRateGamma) * degToRad, @@ -60,8 +60,7 @@ function setMockOrientationData(sensorProvider, orientationData) { let sensorType = orientationData.absolute - ? device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES - : device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES; + ? "AbsoluteOrientationEulerAngles" : "RelativeOrientationEulerAngles"; return setMockSensorDataForType(sensorProvider, sensorType, [ nullToNan(orientationData.beta), nullToNan(orientationData.gamma),
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 d4ae383c..f4e47aa 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
@@ -71061,6 +71061,174 @@ {} ] ], + "css/css-text/white-space/pre-wrap-leading-spaces-001.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-001.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-002.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-002.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-003.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-003.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-004.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-004.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-005.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-005.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-006.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-006.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-007.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-007.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-008.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-008.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-009.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-009.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-010.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-010.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-011.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-011.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-012.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-012.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-013.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-013.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/pre-wrap-leading-spaces-014.html": [ + [ + "css/css-text/white-space/pre-wrap-leading-spaces-014.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text/white-space/tab-stop-threshold-001.html": [ [ "css/css-text/white-space/tab-stop-threshold-001.html", @@ -162128,9 +162296,6 @@ "pointerevents/resources/pointerevent_mouse_pointercapture-iframe.html": [ [] ], - "pointerevents/resources/pointerevent_mouse_pointercapture_inactivate_pointer-iframe.html": [ - [] - ], "pointerevents/resources/pointerevent_pointerId_scope-iframe.html": [ [] ], @@ -162422,6 +162587,9 @@ "presentation-api/receiving-ua/support/stash.py": [ [] ], + "printing/resources/destination.html": [ + [] + ], "priority-hints/META.yml": [ [] ], @@ -196948,6 +197116,12 @@ {} ] ], + "css/CSS2/linebox/inline-negative-margin-001.html": [ + [ + "css/CSS2/linebox/inline-negative-margin-001.html", + {} + ] + ], "css/CSS2/normal-flow/auto-margins-root-element.html": [ [ "css/CSS2/normal-flow/auto-margins-root-element.html", @@ -246613,7 +246787,9 @@ "layout-instability/observe-layout-shift.html": [ [ "layout-instability/observe-layout-shift.html", - {} + { + "testdriver": true + } ] ], "layout-instability/supported-layout-type.html": [ @@ -262354,14 +262530,6 @@ } ] ], - "pointerevents/pointerevent_mouse_pointercapture_inactivate_pointer.html": [ - [ - "pointerevents/pointerevent_mouse_pointercapture_inactivate_pointer.html", - { - "testdriver": true - } - ] - ], "pointerevents/pointerevent_on_event_handlers.html": [ [ "pointerevents/pointerevent_on_event_handlers.html", @@ -262744,9 +262912,9 @@ } ] ], - "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [ + "pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html": [ [ - "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html", + "pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html", { "testdriver": true } @@ -263199,6 +263367,12 @@ {} ] ], + "printing/print-microtask-after-navigate.html": [ + [ + "printing/print-microtask-after-navigate.html", + {} + ] + ], "priority-hints/fetch-api-request.tentative.any.js": [ [ "priority-hints/fetch-api-request.tentative.any.html", @@ -327407,6 +327581,10 @@ "80b72e080b7114fb0f9467272e174a9c76f6bb33", "reftest" ], + "css/CSS2/linebox/inline-negative-margin-001.html": [ + "e8a00ec09bd798d45f110de2ef231fff9c102905", + "testharness" + ], "css/CSS2/linebox/leading-001-ref.xht": [ "2d6e784d2ed2f6b66e4be72d9b6d261d63bc98e7", "support" @@ -376751,6 +376929,62 @@ "af29b0505e0eefbab09b011798c0dd6136598cca", "reftest" ], + "css/css-text/white-space/pre-wrap-leading-spaces-001.html": [ + "6d17921e17c28664533f3e091de9a8075770b544", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-002.html": [ + "082bce78c4ff56dd4b5af1c60a51c04a0df070c2", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-003.html": [ + "2bdef018e72250cd8672ea89fe16cb26971bad7a", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-004.html": [ + "ea409af2ab9da5c6a651f0c937bba5905bcd7b7e", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-005.html": [ + "ccf613051ffa661fc2ba60c563b5fba3d2b09f7d", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-006.html": [ + "cff928c2fd537b4f2db6ed282882c9a14f795452", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-007.html": [ + "ca27b98c2f68940287fc61d4f24709af196ced10", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-008.html": [ + "7331142c2ea0cf56441bd98504610b6ae3150f79", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-009.html": [ + "e2786419c1a56466fc3850fd371bdac45203fdf3", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-010.html": [ + "b1b14ea3afbabbce55996cdcc47a9995a4c5e418", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-011.html": [ + "6167e9ce4538f64baa0a81cd498838be3c759664", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-012.html": [ + "657cd89d89fbbee229ed481d71b73766ff76c0b0", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-013.html": [ + "476f76398daaaa962f09ad5e67f949b529bf8802", + "reftest" + ], + "css/css-text/white-space/pre-wrap-leading-spaces-014.html": [ + "ab2759fdc7b094fa9f4012b557abc27fb6bf8ffd", + "reftest" + ], "css/css-text/white-space/reference/control-chars-000-ref.html": [ "9d5fcb27147a8c53e410d08511cb5035b612f80c", "support" @@ -409072,7 +409306,7 @@ "testharness" ], "element-timing/invisible-images.html": [ - "eb53cd7c2a692c76bb8220062d33edd3c3a48eef", + "06d9bfd07a0f342dbacd00c23bc36b155335f531", "testharness" ], "element-timing/multiple-background-images.html": [ @@ -437708,7 +437942,7 @@ "testharness" ], "layout-instability/observe-layout-shift.html": [ - "db8d3ae406d42b16be4308e329c53b6f0d7f944c", + "25e4950f6a7d830097781923e80d82f130cf23a5", "testharness" ], "layout-instability/resources/slow-image.py": [ @@ -437772,7 +438006,7 @@ "testharness" ], "lint.whitelist": [ - "c344c3a834444db4be24db1d0132c85a4b14395c", + "02b1bb0c78f9765257a35aed076701e2f0aa757e", "support" ], "loading/preloader-css-import-no-quote.tentative.html": [ @@ -450855,10 +451089,6 @@ "83b4c1becc48339f74948fd01bdf15dfd27f96c1", "testharness" ], - "pointerevents/pointerevent_mouse_pointercapture_inactivate_pointer.html": [ - "524d19eecebfce60e4fb1e4a74c2c1d20e0ba770", - "testharness" - ], "pointerevents/pointerevent_on_event_handlers.html": [ "d8cfa7a0f4c482be606e4e98f9a7900a0340a477", "testharness" @@ -450968,7 +451198,7 @@ "support" ], "pointerevents/pointerevent_support.js": [ - "9a491dd677d40749d5dde47dd2ed3b05b545a61d", + "ae9b55c43d2c884b882214924dc459ba516ff42b", "support" ], "pointerevents/pointerevent_suppress_compat_events_on_click.html": [ @@ -451071,8 +451301,8 @@ "2d6147dae562af7efadacee9dfb44cc080005742", "testharness" ], - "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [ - "bdad97df04b2ca67fc1f92e256c979c137a4c66a", + "pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html": [ + "376d0e63a18e8610dd20bf2843e5e804721226ff", "testharness" ], "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture.html": [ @@ -451111,10 +451341,6 @@ "817c6123cf96b0e966c04a48414725d794549c77", "support" ], - "pointerevents/resources/pointerevent_mouse_pointercapture_inactivate_pointer-iframe.html": [ - "d4b4af1fba1d0090ee87038af5fd686495d4cb38", - "support" - ], "pointerevents/resources/pointerevent_pointerId_scope-iframe.html": [ "ab33560b35216ea0976d1c037650122d9336ae39", "support" @@ -451883,6 +452109,14 @@ "5bddc7160f279363cd9ff3368e9420447a773564", "support" ], + "printing/print-microtask-after-navigate.html": [ + "b3f7f769daf243169e76871adda57a70d49d21a4", + "testharness" + ], + "printing/resources/destination.html": [ + "00e89594b253bd45f21d15752d565d4d62b600b9", + "support" + ], "priority-hints/META.yml": [ "487b4013a02209cf35be8c9d5099c4d7842ba915", "support" @@ -461744,7 +461978,7 @@ "support" ], "resources/chromium/webxr-test.js": [ - "e7bb7e9fa8a2580ffa7cbffafe0145b17746568c", + "31bf916caf80bdbd8c2d4173ff6a22e661524b38", "support" ], "resources/chromium/webxr-test.js.headers": [ @@ -467032,7 +467266,7 @@ "testharness" ], "sms/sms_provider.js": [ - "eaa31ebea3113db8ecac51d6d0dec08d2d234444", + "e0689bbd82c6ae668030c167ea17da39e20e6367", "support" ], "sms/sms_receiver.idl": [ @@ -477528,7 +477762,7 @@ "testharness" ], "web-nfc/NFCReader_options_mediaType-manual.https-expected.txt": [ - "37557d299c8198ff566dd4e3e9a37cbfb14b1d95", + "129e4ce74bcb9d8296dd6d2223ae06d4acec807a", "support" ], "web-nfc/NFCReader_options_mediaType-manual.https.html": [ @@ -477536,7 +477770,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt": [ - "ebfd316c80f2a0b469c92f13ad66b89d27f8ca28", + "438f4b6793f044b90d7614a099a29eb243096c7c", "support" ], "web-nfc/NFCReader_options_recordType_empty-manual.https.html": [ @@ -477544,7 +477778,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt": [ - "363ded8f7c6d590dd42a08e24f839bd5e7bf25e0", + "a8f75b34c373b47bf1ac65de29bf802ffcab0012", "support" ], "web-nfc/NFCReader_options_recordType_json-manual.https.html": [ @@ -477552,7 +477786,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt": [ - "84dd5c07528c2eeec9c74e3fb4fac30596dc35b7", + "bd09f8bd971319c6a39dde64c993c4f21339d269", "support" ], "web-nfc/NFCReader_options_recordType_opaque-manual.https.html": [ @@ -477560,7 +477794,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt": [ - "0eee75285691f994dc549d7ff42aceec5a978a9e", + "b2b18c5455fef22f83b55bf9657210fcd214a0ad", "support" ], "web-nfc/NFCReader_options_recordType_text-manual.https.html": [ @@ -477568,7 +477802,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt": [ - "980da2a18eac37e20e9c8f53e5661dececd822c8", + "f53c2e72e5af9901a5cd3d896fe92c99b5622918", "support" ], "web-nfc/NFCReader_options_recordType_url-manual.https.html": [ @@ -477576,7 +477810,7 @@ "manual" ], "web-nfc/NFCReader_options_url-manual.https-expected.txt": [ - "97cc23738ebe96d5e6e719719465ee9c716653cc", + "fdf8c72499da615f36431e0f5b1e3bfa869ea3df", "support" ], "web-nfc/NFCReader_options_url-manual.https.html": [ @@ -477592,7 +477826,7 @@ "testharness" ], "web-nfc/NFCWriter_push.https-expected.txt": [ - "abf8d15019abb2708db843eaaf9829196f31c05d", + "7495de78b148dd6ebcd3c3bc2ba9a315c326dbb0", "support" ], "web-nfc/NFCWriter_push.https.html": [ @@ -477600,7 +477834,7 @@ "testharness" ], "web-nfc/NFCWriter_push_signal-manual.https-expected.txt": [ - "e1a2b1f1d34746fb0d79d9ff03a05ede46f424c7", + "27dd82df88a4bb43fc02733183e89d6ce57b337d", "support" ], "web-nfc/NFCWriter_push_signal-manual.https.html": [ @@ -477612,7 +477846,7 @@ "support" ], "web-nfc/idlharness.https.window-expected.txt": [ - "797a5819e71a32f722ec5d877672d083c5c58bd2", + "975bd5e1d9d8a8207be992fc646ea1938ce8b8b7", "support" ], "web-nfc/idlharness.https.window.js": [ @@ -477620,7 +477854,7 @@ "testharness" ], "web-nfc/nfc_hw_disabled-manual.https-expected.txt": [ - "104d42a9e9a0b5d82ab2b21d9d701dd0a27b9dfa", + "21c4cb1c3cdb39147f12b88075f0a85a889f3994", "support" ], "web-nfc/nfc_hw_disabled-manual.https.html": [ @@ -477632,7 +477866,7 @@ "testharness" ], "web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt": [ - "5d17eaffffb98814dcd28399c8cc03fe608b2d7c", + "9f00a673b4f983c6c0a1d1222dd382108836b6a6", "support" ], "web-nfc/nfc_push_ArrayBuffer-manual.https.html": [ @@ -477640,7 +477874,7 @@ "manual" ], "web-nfc/nfc_push_DOMString-manual.https-expected.txt": [ - "a2ba63b629239d47ee8074afc28c8cfe91bc2a79", + "29791a39dd73e276d92febd8ea82f467e73b6a64", "support" ], "web-nfc/nfc_push_DOMString-manual.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-001.html new file mode 100644 index 0000000..6d17921 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-001.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space at the beginning of the line are breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 50px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 2ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref"><span>XX</span><br>XX</div> +<div class="test"> XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-002.html new file mode 100644 index 0000000..082bce7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-002.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should be breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 25px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 4ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XX<span>XX<br>XXXX</span><br>XXXX<br><span>XXXX</span></div> +<div class="test">XX
 XXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-003.html new file mode 100644 index 0000000..2bdef01 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-003.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should be breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 25px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 4ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XX<span>XX<br>XXXX</span><br>XXXX<br><span>XXXX</span></div> +<div class="test">XX<br> XXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-004.html new file mode 100644 index 0000000..ea409af --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-004.html
@@ -0,0 +1,31 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">XXX<br> XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-005.html new file mode 100644 index 0000000..ccf61305 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-005.html
@@ -0,0 +1,31 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">XXX <br> XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-006.html new file mode 100644 index 0000000..cff928c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-006.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">XXX + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-007.html new file mode 100644 index 0000000..ca27b98 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-007.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">XXX + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-008.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-008.html new file mode 100644 index 0000000..7331142 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-008.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XX<span>XXX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">XX + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-009.html new file mode 100644 index 0000000..e278641 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-009.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">X<span>XXXX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX<br>XXXXX</span></div> +<div class="test">X + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-010.html new file mode 100644 index 0000000..b1b14ea --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-010.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX<br>XXXXX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX</span></div> +<div class="test">XXX<br> + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-011.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-011.html new file mode 100644 index 0000000..6167e9ce --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-011.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: forced breaks create preserverd leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should not be collapsed, honoring white-space: pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref">XXX<span>XX</span><br>XXX<span>XX<br>XXX</span>XX<br><span>XXXXX<br>XXXXX</span></div> +<div class="test">XXX XXX + XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-012.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-012.html new file mode 100644 index 0000000..657cd89d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-012.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should be breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 25px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 4ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref"><span>X</span>X<span>XX<br>XXXX</span><br>XXXX<br><span>XXXX</span></div> +<div class="test"> <span>X </span>
 XXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-013.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-013.html new file mode 100644 index 0000000..476f763 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-013.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should be breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 25px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 4ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref"><span>XX</span>X<span>X<br>XXXX</span><br>XXXX<br><span>XXXX</span></div> +<div class="test"> <span> </span>X
 XXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-014.html new file mode 100644 index 0000000..ab2759fd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-leading-spaces-014.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>CSS Text test: breaking opportunities at leading spaces with white-space:pre-wrap</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" /> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="match" href="reference/white-space-break-spaces-005-ref.html"> +<meta name="assert" content="Preserved white space after forced breaks become leading white-spaces and should be breaking opportunities when white-space is pre-wrap."> + +<style> +div { + font: 20px/1 Ahem; +} +.ref { + position: absolute; + color: red; + z-index: -1; +} +span { color: green; } +.test { + color: green; + width: 5ch; + white-space: pre-wrap; +} +</style> + +<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> +<div class="ref"><span>X</span>X<span>XX</span>X<br><span>XXXXX</span><br>XXXXX<br><span>XXXXX<br>XXXXX</span></div> +<div class="test"> X<span> </span> X
 XXXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist index c344c3a..02b1bb0c 100644 --- a/third_party/blink/web_tests/external/wpt/lint.whitelist +++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -28,6 +28,10 @@ TRAILING WHITESPACE: WebIDL/* TRAILING WHITESPACE: webvtt/* TRAILING WHITESPACE: server-timing/resources/parsing/*.sub.headers +TRAILING WHITESPACE: css/css-text/white-space/pre-wrap-leading-spaces-006.html +TRAILING WHITESPACE: css/css-text/white-space/pre-wrap-leading-spaces-007.html +TRAILING WHITESPACE: css/css-text/white-space/pre-wrap-leading-spaces-008.html +TRAILING WHITESPACE: css/css-text/white-space/pre-wrap-leading-spaces-009.html ## File types that should never be checked ##
diff --git a/third_party/blink/web_tests/external/wpt/printing/print-microtask-after-navigate.html b/third_party/blink/web_tests/external/wpt/printing/print-microtask-after-navigate.html new file mode 100644 index 0000000..b3f7f769 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/printing/print-microtask-after-navigate.html
@@ -0,0 +1,22 @@ +<!doctype HTML> +<meta charset=utf-8> +<title>Printing in microtask after navigation</title> +<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#printing"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +Passes if it does not crash. +<script> + let print_promise = new Promise(function(resolve, reject) { + resolve(); + }); + + // Call print in a microtask. This will execute after the navigation click + // has happened, which will cause the document to become neutered and + // ineligible for the print command. + print_promise.then(() => print()); +</script> + <a href="resources/destination.html"> +<script> + document.getElementsByTagName("a")[0].click(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/printing/resources/destination.html b/third_party/blink/web_tests/external/wpt/printing/resources/destination.html new file mode 100644 index 0000000..00e8959 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/printing/resources/destination.html
@@ -0,0 +1,8 @@ +<!doctype HTML> +<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org"> +Passes if it does not crash. +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> {}, "Did not crash"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/resize-observer/observe.html b/third_party/blink/web_tests/external/wpt/resize-observer/observe.html index ab7521c..7360264 100644 --- a/third_party/blink/web_tests/external/wpt/resize-observer/observe.html +++ b/third_party/blink/web_tests/external/wpt/resize-observer/observe.html
@@ -125,12 +125,12 @@ } function test5() { - let img = createAndAppendElement("img"); + const img = new Image(); img.style.width = "15px"; img.style.height = "15px"; img.src = "resources/image.png"; - var helper = new ResizeTestHelper("test5: observe img",[ + let helper = new ResizeTestHelper("test5: observe img",[ { setup: observer => { observer.observe(img); @@ -148,8 +148,15 @@ } } ]); - return new Promise((resolve, reject) => { - img.onload = () => resolve(); + return img.decode().then(() => { + return new Promise(resolve => { + requestAnimationFrame(() => { + document.body.appendChild(img); + resolve(); + }); + }); + }).catch(error => { + assert_unreached("decode image failed"); }).then(() => { return helper.start(() => img.remove()); });
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js index e7bb7e9..31bf916 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js
@@ -259,7 +259,7 @@ leftDegrees: 50.899, rightDegrees: 35.197 }, - offset: new gfx.mojom.Vector3dF(-0.032, 0, 0), + offset: { x: -0.032, y: 0, z: 0 }, renderWidth: 20, renderHeight: 20 }, @@ -270,7 +270,7 @@ leftDegrees: 50.899, rightDegrees: 35.197 }, - offset: new gfx.mojom.Vector3dF(0.032, 0, 0), + offset: { x: 0.032, y: 0, z: 0 }, renderWidth: 20, renderHeight: 20 }, @@ -303,7 +303,7 @@ leftDegrees: toDegrees(leftTan), rightDegrees: toDegrees(rightTan) }, - offset: new gfx.mojom.Vector3dF(0, 0, 0), + offset: { x: 0, y: 0, z: 0 }, renderWidth: 20, renderHeight: 20 };
diff --git a/third_party/blink/web_tests/external/wpt/sms/sms_provider.js b/third_party/blink/web_tests/external/wpt/sms/sms_provider.js index eaa31ebe..e0689bb 100644 --- a/third_party/blink/web_tests/external/wpt/sms/sms_provider.js +++ b/third_party/blink/web_tests/external/wpt/sms/sms_provider.js
@@ -61,7 +61,7 @@ blink.mojom.SmsReceiver.$interfaceName); interceptor.oninterfacerequest = (e) => { let impl = new blink.mojom.SmsReceiver(provider); - impl.bindHandle(e.handle); + impl.$.bindHandle(e.handle); } interceptor.start();
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt index 37557d299..129e4ce 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that the mediaType of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that the mediaType of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt index ebfd316c8..438f4b6 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'empty'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'empty'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt index 363ded8..a8f75b3 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'json'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'json'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt index 84dd5c07..bd09f8bd 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'opaque'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'opaque'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt index 0eee752..b2b18c54 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'text'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'text'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt index 980da2a..f53c2e72 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'url'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'url'. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt index 97cc2373..fdf8c72 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that the url of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that the url of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt index abf8d150..e7939625 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt
@@ -1,16 +1,16 @@ This is a testharness.js-based test. -FAIL Test that promise is rejected with TypeError if NDEFMessageSource is invalid. NFCWriter is not defined -FAIL 'Test that promise is rejected with SyntaxError if NDEFMessageSource contains invalid records. NFCWriter is not defined -FAIL NFCWriter.push should fail if abort push request before push happends. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" -FAIL NFCWriter.push should fail if signal's aborted flag is set. NFCWriter is not defined -FAIL NFCWriter.push should fail if signal is not an AbortSignal. NFCWriter is not defined -FAIL NFCWriter.push should fail with TypeError when invalid timeout is provided. NFCWriter is not defined -FAIL NFCWriter.push should fail with TypeError when invalid negative timeout value is provided. NFCWriter is not defined -FAIL NFCWriter.push should fail with TimeoutError when timer expires. NFCWriter is not defined -FAIL Reject promise with NotSupportedError if NFC message size exceeds 32KB. NFCWriter is not defined -FAIL Reject promise with SyntaxError if WebNFC Id cannot be created from provided URL. NFCWriter is not defined -FAIL Reject promise with SyntaxError if 'json' record cannot be serialized. NFCWriter is not defined -FAIL NFCWriter.push should fail with TypeError when invalid target value is provided. NFCWriter is not defined -FAIL Test that WebNFC API is not accessible from iframe context. promise_test: Unhandled rejection with value: undefined +PASS Test that promise is rejected with TypeError if NDEFMessageSource is invalid. +PASS 'Test that promise is rejected with SyntaxError if NDEFMessageSource contains invalid records. +FAIL NFCWriter.push should fail if abort push request before push happends. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 0, expected 20 +FAIL NFCWriter.push should fail if signal's aborted flag is set. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 0, expected 20 +FAIL NFCWriter.push should fail if signal is not an AbortSignal. Test bug: unrecognized DOMException code "TypeError" passed to assert_throws() +PASS NFCWriter.push should fail with TypeError when invalid timeout is provided. +PASS NFCWriter.push should fail with TypeError when invalid negative timeout value is provided. +FAIL NFCWriter.push should fail with TimeoutError when timer expires. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException TimeoutError: property "code" is equal to 0, expected 23 +PASS Reject promise with NotSupportedError if NFC message size exceeds 32KB. +PASS Reject promise with SyntaxError if WebNFC Id cannot be created from provided URL. +PASS Reject promise with SyntaxError if 'json' record cannot be serialized. +PASS NFCWriter.push should fail with TypeError when invalid target value is provided. +PASS Test that WebNFC API is not accessible from iframe context. Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https.html index f5bbfcd..5a14b409 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https.html +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https.html
@@ -184,7 +184,7 @@ if (message.data === "Ready") { const onSuccess = () => { parent.postMessage("Failure", "*"); }; const onError = error => { - if (error.name == "SecurityError") { + if (error.name == "NotAllowedError") { parent.postMessage("Success", "*"); } else { parent.postMessage("Failure", "*");
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt index e1a2b1f1..27dd82d 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Synchronously signaled abort. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Synchronously signaled abort. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt index 797a5819..975bd5e 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt
@@ -1,17 +1,17 @@ This is a testharness.js-based test. -Found 50 tests; 11 PASS, 39 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 50 tests; 22 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup -FAIL NFCWriter interface: existence and properties of interface object assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface object length assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface object name assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface: existence and properties of interface prototype object assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter interface: operation push(NDEFMessageSource, NFCPushOptions) assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing -FAIL NFCWriter must be primary interface of new NFCWriter(); assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCWriter is not defined" -FAIL Stringification of new NFCWriter(); assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCWriter is not defined" -FAIL NFCWriter interface: new NFCWriter(); must inherit property "push(NDEFMessageSource, NFCPushOptions)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCWriter is not defined" -FAIL NFCWriter interface: calling push(NDEFMessageSource, NFCPushOptions) on new NFCWriter(); with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCWriter is not defined" +PASS NFCWriter interface: existence and properties of interface object +PASS NFCWriter interface object length +PASS NFCWriter interface object name +PASS NFCWriter interface: existence and properties of interface prototype object +PASS NFCWriter interface: existence and properties of interface prototype object's "constructor" property +PASS NFCWriter interface: existence and properties of interface prototype object's @@unscopables property +PASS NFCWriter interface: operation push(NDEFMessageSource, NFCPushOptions) +PASS NFCWriter must be primary interface of new NFCWriter(); +PASS Stringification of new NFCWriter(); +PASS NFCWriter interface: new NFCWriter(); must inherit property "push(NDEFMessageSource, NFCPushOptions)" with the proper type +PASS NFCWriter interface: calling push(NDEFMessageSource, NFCPushOptions) on new NFCWriter(); with too few arguments must throw TypeError FAIL NFCReader interface: existence and properties of interface object assert_own_property: self does not have own property "NFCReader" expected property "NFCReader" missing FAIL NFCReader interface object length assert_own_property: self does not have own property "NFCReader" expected property "NFCReader" missing FAIL NFCReader interface object name assert_own_property: self does not have own property "NFCReader" expected property "NFCReader" missing
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https-expected.txt index 104d42a..fd955dd5 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. FAIL NFCReader.start should fail if NFC HW is disabled. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" -FAIL NFCWriter.push should fail when NFC HW is disabled. NFCWriter is not defined +PASS NFCWriter.push should fail when NFC HW is disabled. Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt index 5d17eaf..9f00a673b 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that NFCWriter.push succeeds when message is ArrayBuffer. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that NFCWriter.push succeeds when message is ArrayBuffer. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt index a2ba63b..29791a39 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that NFCWriter.push succeeds when message is DOMString. promise_test: Unhandled rejection with value: object "ReferenceError: NFCWriter is not defined" +FAIL Test that NFCWriter.push succeeds when message is DOMString. promise_test: Unhandled rejection with value: object "ReferenceError: NFCReader is not defined" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/fast/dom/HTMLAnchorElement/anchor-ismap-crash.html b/third_party/blink/web_tests/fast/dom/HTMLAnchorElement/anchor-ismap-crash.html index b80bf37..c1217ac 100644 --- a/third_party/blink/web_tests/fast/dom/HTMLAnchorElement/anchor-ismap-crash.html +++ b/third_party/blink/web_tests/fast/dom/HTMLAnchorElement/anchor-ismap-crash.html
@@ -12,6 +12,6 @@ //This error is because of "javascript:" url is not expected in case of ismap //This can not be caught in try-catch block as the click() execution could //finish before Syntax error was thrown from '<a href="javascript:">' - assert_equals(message, 'Uncaught SyntaxError: Unexpected token ?'); + assert_equals(message, 'Uncaught SyntaxError: Unexpected token \'?\''); }); </script>
diff --git a/third_party/blink/web_tests/fast/dom/SelectorAPI/unknown-pseudo-expected.txt b/third_party/blink/web_tests/fast/dom/SelectorAPI/unknown-pseudo-expected.txt index f9888c0a..eca3f0866 100644 --- a/third_party/blink/web_tests/fast/dom/SelectorAPI/unknown-pseudo-expected.txt +++ b/third_party/blink/web_tests/fast/dom/SelectorAPI/unknown-pseudo-expected.txt
@@ -1,3 +1,3 @@ -PASS: document.querySelector(:unknownpseudo) throws: SyntaxError: Unexpected token : -PASS: document.querySelector(:-webkit-any(:unknownpseudo)) throws: SyntaxError: Unexpected token : +PASS: document.querySelector(:unknownpseudo) throws: SyntaxError: Unexpected token ':' +PASS: document.querySelector(:-webkit-any(:unknownpseudo)) throws: SyntaxError: Unexpected token ':'
diff --git a/third_party/blink/web_tests/fast/dom/script-module-inline-error-gc-expected.txt b/third_party/blink/web_tests/fast/dom/script-module-inline-error-gc-expected.txt index 4e30633..1d7d05c6 100644 --- a/third_party/blink/web_tests/fast/dom/script-module-inline-error-gc-expected.txt +++ b/third_party/blink/web_tests/fast/dom/script-module-inline-error-gc-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 12: Uncaught SyntaxError: Unexpected token % +CONSOLE ERROR: line 12: Uncaught SyntaxError: Unexpected token '%' This test pass if no crash.
diff --git a/third_party/blink/web_tests/fast/encoding/meta-in-script-expected.txt b/third_party/blink/web_tests/fast/encoding/meta-in-script-expected.txt index faff75b..af684c74 100644 --- a/third_party/blink/web_tests/fast/encoding/meta-in-script-expected.txt +++ b/third_party/blink/web_tests/fast/encoding/meta-in-script-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE ERROR: line 4: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 4: Uncaught SyntaxError: Unexpected token '<' PASS: windows-1255
diff --git a/third_party/blink/web_tests/fast/events/attribute-listener-deletion-crash-expected.txt b/third_party/blink/web_tests/fast/events/attribute-listener-deletion-crash-expected.txt index 6d66135..24844bd 100644 --- a/third_party/blink/web_tests/fast/events/attribute-listener-deletion-crash-expected.txt +++ b/third_party/blink/web_tests/fast/events/attribute-listener-deletion-crash-expected.txt
@@ -1,21 +1,21 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token | +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '|' PASS
diff --git a/third_party/blink/web_tests/fast/events/set-attribute-listener-window-onerror-crash-expected.txt b/third_party/blink/web_tests/fast/events/set-attribute-listener-window-onerror-crash-expected.txt index 472edbf..09d4c26 100644 --- a/third_party/blink/web_tests/fast/events/set-attribute-listener-window-onerror-crash-expected.txt +++ b/third_party/blink/web_tests/fast/events/set-attribute-listener-window-onerror-crash-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 16: Uncaught SyntaxError: Unexpected token ; +CONSOLE ERROR: line 16: Uncaught SyntaxError: Unexpected token ';' Test passes if it does not crash.
diff --git a/third_party/blink/web_tests/fast/events/window-onerror-05-expected.txt b/third_party/blink/web_tests/fast/events/window-onerror-05-expected.txt index d0aa6a9..4a5598d8 100644 --- a/third_party/blink/web_tests/fast/events/window-onerror-05-expected.txt +++ b/third_party/blink/web_tests/fast/events/window-onerror-05-expected.txt
@@ -1,6 +1,6 @@ -window.onerror: "Uncaught SyntaxError: Unexpected token )" at window-onerror-05.html (Line: 15, Column: 10) +window.onerror: "Uncaught SyntaxError: Unexpected token ')'" at window-onerror-05.html (Line: 15, Column: 10) Stack Trace: -SyntaxError: Unexpected token ) +SyntaxError: Unexpected token ')' Returning 'true': the error should not be reported in the console as an unhandled exception.
diff --git a/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt b/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt index 1a0e561..37012dd 100644 --- a/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt +++ b/third_party/blink/web_tests/fast/js/postfix-syntax-expected.txt
@@ -14,7 +14,7 @@ PASS ((window["x"]))++ is 9 PASS (y, x)++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation. PASS (true ? x : y)++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation. -PASS x++++ threw exception SyntaxError: Unexpected token ++. +PASS x++++ threw exception SyntaxError: Unexpected token '++'. PASS x is 0 PASS y is 0 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/parser/entity-end-script-tag-expected.txt b/third_party/blink/web_tests/fast/parser/entity-end-script-tag-expected.txt index c0a7158..5f8fbef 100644 --- a/third_party/blink/web_tests/fast/parser/entity-end-script-tag-expected.txt +++ b/third_party/blink/web_tests/fast/parser/entity-end-script-tag-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE ERROR: line 11: Uncaught SyntaxError: Unexpected token & +CONSOLE ERROR: line 11: Uncaught SyntaxError: Unexpected token '&' Test parsing of entity-escaped </script> tag for Bug 7931: Escaped elements within a textarea block can cause the textarea box to be closed prematurely On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html new file mode 100644 index 0000000..57a27240 --- /dev/null +++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
@@ -0,0 +1,74 @@ +<!DOCTYPE html> +<title>Tests mouse autoscroll interactions on a non-custom composited div scrollbar.</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/gesture-util.js"></script> +<script src="../../../resources/scrollbar-util.js"></script> +<style> +.appearance { + width: 100px; + height: 100px; + overflow: scroll; + border: 1px solid black; +} +.location { + position: absolute; + top: 100px; + left: 100px; +} +.fast { + will-change: transform; +} +.space { + height: 2000px; + width: 2000px; +} + +</style> + +<!-- Composited non-custom fast scroller --> +<div id="scroller" class="appearance location fast"> + <div class="space"></div> +</div> + +<script> + // Turn off animated scrolling. The "conditionHolds" API expects the scrollTop to + // *not* change for 10 frames. This will fail since the last GSU would still be + // animating if animated scrolling were on. + if (window.internals) + internals.settings.setScrollAnimatorEnabled(false); + + const scroller = document.getElementById("scroller"); + const scrollerRect = scroller.getBoundingClientRect(); + + const TRACK_WIDTH = calculateScrollbarThickness(); + const BUTTON_WIDTH = TRACK_WIDTH; + const SCROLL_CORNER = TRACK_WIDTH; + const SCROLL_DELTA = 400; + const MAX_SCROLLER_OFFSET = 1915; + const PRESS_DURATION = 1000; + const down_arrow_x = scrollerRect.right - BUTTON_WIDTH / 2; + const down_arrow_y = scrollerRect.bottom - SCROLL_CORNER - BUTTON_WIDTH / 2; + + promise_test (async () => { + await waitForCompositorCommit(); + scroller.scrollTop = 0; + + // TODO(arakeri): Split the mousePressOn API calls to mouseDownAt, waitFor + // and mouseUpAt once crbug.com/979408 is fixed. + await mousePressOn(down_arrow_x, down_arrow_y, PRESS_DURATION); + const err = `Autoscroll down failed (scroller.scrollTop = ${scroller.scrollTop})`; + + // Verify that autoscroll happened. + assert_greater_than(scroller.scrollTop, SCROLL_DELTA, err); + + // Since autoscroll for arrows happens at 800 px per second, verify that the + // scrollTop has not reached the end. + assert_less_than(scroller.scrollTop, MAX_SCROLLER_OFFSET, "Reached scroller end."); + + await waitForCompositorCommit(); + const current_offset = scroller.scrollTop; + await conditionHolds(() => { return parseInt(scroller.scrollTop) == parseInt(current_offset); }, + `scroller.scrollTop = ${scroller.scrollTop} current_offset = ${current_offset}`); + },"Test autoscroll down and autoscroll stop."); +</script>
diff --git a/third_party/blink/web_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html b/third_party/blink/web_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html deleted file mode 100644 index 3c632d4..0000000 --- a/third_party/blink/web_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html +++ /dev/null
@@ -1,29 +0,0 @@ -<style> - pre { white-space: pre-wrap; background: silver; width: 7ex; } -</style> -<p> - Test for - <i><a href="https://bugs.webkit.org/show_bug.cgi?id=7216">http://bugzilla.opendarwin.org/show_bug.cgi?id=7216</a> - white-space: pre-wrap collapses leading whitespace following a newline</i>. -</p> -<hr> -<p>Here <code>bar</code> should be right under <code>foo</code>:</p> -<pre>foo bar</pre> -<p>Here <code>bar</code> should be on the right hand side of the second line:</p> -<pre>foo<br> bar</pre> -<pre>foo <br> bar</pre> -<pre>foo - bar</pre> -<pre>foo - bar</pre> -<pre>foo - bar</pre> -<pre>foo - bar</pre> -<pre>foo - bar</pre> -<p>Here <code>bar</code> should be on the right hand side of the third line:</p> -<pre>foo<br> - bar</pre> -<pre>foo baz - bar</pre>
diff --git a/third_party/blink/web_tests/fast/workers/worker-onerror-01-expected.txt b/third_party/blink/web_tests/fast/workers/worker-onerror-01-expected.txt index 0d1faef1..d4d30876 100644 --- a/third_party/blink/web_tests/fast/workers/worker-onerror-01-expected.txt +++ b/third_party/blink/web_tests/fast/workers/worker-onerror-01-expected.txt
@@ -4,7 +4,7 @@ Page-level worker.onerror handler triggered: -PASS errorEvent.message is "Uncaught SyntaxError: Unexpected token }" +PASS errorEvent.message is "Uncaught SyntaxError: Unexpected token '}'" PASS stripURL(errorEvent.filename) is "[blob: URL]" PASS errorEvent.lineno is 2 PASS errorEvent.colno is 9
diff --git a/third_party/blink/web_tests/fast/workers/worker-onerror-01.html b/third_party/blink/web_tests/fast/workers/worker-onerror-01.html index 99233f61..39d8b86 100644 --- a/third_party/blink/web_tests/fast/workers/worker-onerror-01.html +++ b/third_party/blink/web_tests/fast/workers/worker-onerror-01.html
@@ -16,7 +16,7 @@ description("This tests that invalid syntax triggers 'worker.onerror'."); checkErrorEventInHandler({ - message: "Uncaught SyntaxError: Unexpected token }", + message: "Uncaught SyntaxError: Unexpected token '}'", filename: "[blob: URL]", lineno: 2, colno: 9,
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt index b59a26f..7054549 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests1-data-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests1.dat: PASS
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt index b59a26f..7054549 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests1-write-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests1.dat: PASS
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests18-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests18-data-expected.txt index 8e9c739..2a67095 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests18-data-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests18-data-expected.txt
@@ -1,5 +1,5 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests18.dat: PASS
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests18-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests18-write-expected.txt index 8e9c739..2a67095 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests18-write-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests18-write-expected.txt
@@ -1,5 +1,5 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests18.dat: PASS
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt index a34b5b0..d38385f 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests7-data-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests7.dat: PASS
diff --git a/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt b/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt index a34b5b0..d38385f 100644 --- a/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt +++ b/third_party/blink/web_tests/html5lib/generated/run-tests7-write-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token < +CONSOLE ERROR: line 1: Uncaught SyntaxError: Unexpected token '<' ../resources/tests7.dat: PASS
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/resources/mock-navigator-credentials.js b/third_party/blink/web_tests/http/tests/credentialmanager/resources/mock-navigator-credentials.js index 54c96068..9f7f63d 100644 --- a/third_party/blink/web_tests/http/tests/credentialmanager/resources/mock-navigator-credentials.js +++ b/third_party/blink/web_tests/http/tests/credentialmanager/resources/mock-navigator-credentials.js
@@ -186,10 +186,10 @@ setDocumentInterfaceBrokerOverrides({ getAuthenticator: request => { var authenticator = new blink.mojom.Authenticator(mockAuthenticator); - authenticator.bindHandle(request.handle); + authenticator.$.bindHandle(request.handle); }, getCredentialManager: request => { var credentialManager = new blink.mojom.CredentialManager(mockCredentialManager); - credentialManager.bindHandle(request.handle); + credentialManager.$.bindHandle(request.handle); } });
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-object-literal-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-object-literal-expected.txt index f8fa7240..ce2c7dd 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-object-literal-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-object-literal-expected.txt
@@ -5,12 +5,12 @@ {a:1} {a: 1} {var a = 1; eval("{ a:1, b:2 }");} -VM:1 Uncaught SyntaxError: Unexpected token : +VM:1 Uncaught SyntaxError: Unexpected token ':' (anonymous) @ VM:1 { for (var i = 0; i < 5; ++i); } undefined { a: 4 }),({ b: 7 } -VM:1 Uncaught SyntaxError: Unexpected token ) +VM:1 Uncaught SyntaxError: Unexpected token ')' { let a = 4; a; } 4 { let a = 4; }; { let b = 5; };
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet-expected.txt index 23275769..015f5e9 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet-expected.txt
@@ -6,8 +6,8 @@ name1:1 42 Running: testSnippetSyntaxError -Line Message was added: snippet:///name2 Error 'Uncaught SyntaxError: Unexpected token }':1:1 -name2:2 Uncaught SyntaxError: Unexpected token } +Line Message was added: snippet:///name2 Error 'Uncaught SyntaxError: Unexpected token '}'':1:1 +name2:2 Uncaught SyntaxError: Unexpected token '}' Running: testConsoleErrorHighlight Line Message was added: snippet:///name3 Error '42':1:8
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt index 7cac82b..ba13acc4 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt
@@ -1,11 +1,11 @@ Tests that syntax errors in eval are logged into console, contains correct link and doesn't cause browser crash. -VM:1 Uncaught SyntaxError: Unexpected token } +VM:1 Uncaught SyntaxError: Unexpected token '}' at foo (<anonymous>:13:11) foo @ VM:13 setTimeout (async) (anonymous) @ console-log-eval-syntax-error.js:21 -boo.js:2 Uncaught SyntaxError: Unexpected token } +boo.js:2 Uncaught SyntaxError: Unexpected token '}' at boo (<anonymous>:17:11) boo @ VM:17 setTimeout (async)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error-expected.txt index 02fc3d1f..c6b4645 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error-expected.txt
@@ -1,4 +1,4 @@ Tests that syntax errors are logged into console and doesn't cause browser crash. -syntax-error.js:3 Uncaught SyntaxError: Unexpected token ) +syntax-error.js:3 Uncaught SyntaxError: Unexpected token ')'
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt index 3524e238..468142d 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt
@@ -1,7 +1,7 @@ Tests that log message and syntax errors from inline scripts with sourceURL are logged into console, contains correct link and doesn't cause browser crash. foo.js:13 foo -boo.js:1 Uncaught SyntaxError: Unexpected token } +boo.js:1 Uncaught SyntaxError: Unexpected token '}' at addInlineWithSyntaxError (foo.js:21) addInlineWithSyntaxError @ foo.js:21 setTimeout (async)
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-orientation-success.js b/third_party/blink/web_tests/http/tests/devtools/device-orientation-success.js index c8f35e4..8bae72a 100644 --- a/third_party/blink/web_tests/http/tests/devtools/device-orientation-success.js +++ b/third_party/blink/web_tests/http/tests/devtools/device-orientation-success.js
@@ -21,7 +21,7 @@ sensorProvider = sensorMocks(); let mockDataPromise = setMockSensorDataForType( sensorProvider, - device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, + "RelativeOrientationEulerAngles", [mockBeta, mockGamma, mockAlpha]); window.addEventListener("deviceorientation", handler); return mockDataPromise;
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error-expected.txt index f0526df..90f619e 100644 --- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error-expected.txt
@@ -1,5 +1,5 @@ Tests that debugger won't stop on syntax errors even if "pause on uncaught exceptions" is on. -syntax-error.html:4 Uncaught SyntaxError: Unexpected token ) +syntax-error.html:4 Uncaught SyntaxError: Unexpected token ')' syntax-error.html:8 Iframe loaded
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run-expected.txt index fa7e86f..0a7fd9e 100644 --- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run-expected.txt
@@ -21,7 +21,7 @@ Running: testCompileError Compiling script exceptionDetails: - Uncaught SyntaxError: Unexpected token } + Uncaught SyntaxError: Unexpected token '}' line: 0, column: 0 no stack trace attached to exceptionDetails
diff --git a/third_party/blink/web_tests/http/tests/input/discard-events-to-unstable-iframe.html b/third_party/blink/web_tests/http/tests/input/discard-events-to-unstable-iframe.html new file mode 100644 index 0000000..015a2043 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/input/discard-events-to-unstable-iframe.html
@@ -0,0 +1,95 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> + +<style> +html, body { + margin: 0; +} +iframe { + border: 0; + position: absolute; +} +</style> + +<iframe id=iframe src="http://localhost:8080/input/resources/discard-events-to-unstable-iframe-subframe.html" sandbox="allow-scripts"></iframe> + +<script> +async_test(t => { + if (!window.chrome || !chrome.gpuBenchmarking) { + t.done(); + return; + } + + let iframe = document.getElementById("iframe"); + let expectedCounts = {}; + + let tapAndCount = (x, y, mousedownCount, mouseupCount, clickCount) => { + // Use double-rAF to stabilize layout before dispatching input event. + requestAnimationFrame(() => { + requestAnimationFrame(() => { + iframe.contentWindow.postMessage({tap: [x, y]}, "*"); + expectedCounts = { + mousedown: mousedownCount, + mouseup: mouseupCount, + click: clickCount + }; + }); + }); + }; + + let step0 = () => { + tapAndCount(20, 20, 1, 1, 1); + }; + + let step1 = () => { + iframe.style.top = "50px"; + // Iframe moved, but it's not running an IntersectionObserver, so input events + // are unaffected. + tapAndCount(20, 70, 1, 1, 1); + }; + + let step2 = () => { + // Start running IntersectionObserver in the iframe. + iframe.contentWindow.postMessage("observe", "*"); + }; + + let step3 = () => { + iframe.style.left = "50px"; + // Iframe moved, and it's running an IntersectionObserver with + // trackVisibility=true. Input events should be discarded. + tapAndCount(70, 70, 0, 0, 0); + }; + + let step4 = () => { + setTimeout(() => { + // Iframe position has been stable for 500ms, so input events should not + // be discarded. + tapAndCount(70, 70, 1, 1, 1); + }, 500); + }; + + let steps = [step0, step1, step2, step3, step4]; + let runNextStep = () => { + if (steps.length) { + let step = steps.shift(); + step(); + } else { + t.done(); + } + }; + + addEventListener("message", evt => { + if (evt.data.hasOwnProperty("count")) { + t.step(() => { + Object.keys(expectedCounts).forEach(key => { + assert_equals(evt.data["count"][key], expectedCounts[key], key); + }); + }); + } + runNextStep(); + }); + + iframe.addEventListener("load", runNextStep); +}, "Input events targeting a cross-origin iframe which has moved recently, and which is using IntersectionObserver V2, should be discarded."); +</script>
diff --git a/third_party/blink/web_tests/http/tests/input/resources/discard-events-to-unstable-iframe-subframe.html b/third_party/blink/web_tests/http/tests/input/resources/discard-events-to-unstable-iframe-subframe.html new file mode 100644 index 0000000..6807bc69 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/input/resources/discard-events-to-unstable-iframe-subframe.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> + +<div id=target>Hello, world!</div> + +<script> +let eventCounts = {}; +let eventTypes = [ + "mousedown", + "mouseup", + "click"]; +eventTypes.forEach(eventType => { + eventCounts[eventType] = 0; + document.addEventListener(eventType, evt => { + eventCounts[eventType]++; + }); +}); + +addEventListener("message", evt => { + if (evt.data == "observe") { + new IntersectionObserver(entries => { + evt.source.postMessage("didObserve", "*"); + }, {trackVisibility: true, delay: 100}).observe(document.getElementById("target")); + } + if (evt.data.hasOwnProperty("tap")) { + chrome.gpuBenchmarking.tap(evt.data["tap"][0], evt.data["tap"][1], () => { + evt.source.postMessage({count: eventCounts}, "*"); + Object.keys(eventCounts).forEach(key => { eventCounts[key] = 0 }); + }); + } +}); +</script>
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/generate-test-sxgs.sh b/third_party/blink/web_tests/http/tests/loading/sxg/resources/generate-test-sxgs.sh index 1767904..048eaae 100755 --- a/third_party/blink/web_tests/http/tests/loading/sxg/resources/generate-test-sxgs.sh +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/generate-test-sxgs.sh
@@ -104,4 +104,42 @@ -o sxg-larger-than-10k.sxg \ -miRecordSize 100 +# Generate the signed exchange file of sxg-subresource-script-inner.js. +gen-signedexchange \ + -version $sxg_version \ + -uri https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-script.js \ + -status 200 \ + -content sxg-subresource-script-inner.js \ + -certificate $certs_dir/127.0.0.1.sxg.pem \ + -certUrl https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor \ + -validityUrl https://127.0.0.1:8443/loading/sxg/resources/resource.validity.msg \ + -privateKey $certs_dir/127.0.0.1.sxg.key \ + -date 2030-04-01T00:00:00Z \ + -expire 168h \ + -o sxg-subresource-script.sxg \ + -miRecordSize 100 \ + -responseHeader "content-type:text/javascript; charset=utf-8" + +# Get the header integrity hash value of sxg-subresource-script.sxg. +header_integrity=$(dump-signedexchange -i sxg-subresource-script.sxg | \ + grep -o "header integrity: sha256-.*" | \ + grep -o "sha256-.*$") + +# Generate the signed exchange file for Origin Trial test. +gen-signedexchange \ + -version $sxg_version \ + -uri https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-origin-trial-inner-page.html \ + -status 200 \ + -content sxg-subresource-origin-trial-page.html \ + -certificate $certs_dir/127.0.0.1.sxg.pem \ + -certUrl https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor \ + -validityUrl https://127.0.0.1:8443/loading/sxg/resources/resource.validity.msg \ + -privateKey $certs_dir/127.0.0.1.sxg.key \ + -date 2030-04-01T00:00:00Z \ + -expire 168h \ + -o sxg-subresource-origin-trial-page.sxg \ + -miRecordSize 100 \ + -responseHeader "link:<https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-script.js>;rel=allowed-alt-sxg;header-integrity=\"$header_integrity\",<https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-script.js>;rel=preload;as=script" + + rm -fr $tmpdir
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.html b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.html new file mode 100644 index 0000000..5d1ff24 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<head> +<title>Signed Exchange subresource Origin Trial inner page</title> +<script src="./sxg-util.js"></script> +<script> +let value = "empty"; +</script> +<script src="./sxg-subresource-script.js"></script> +</head> +<body> +<script> +(async function() { + await waitUntilDidFinishLoadForFrame; + const div = document.createElement('div'); + div.appendChild(document.createTextNode('Hello ' + value)); + document.body.appendChild(div); + testRunner.notifyDone(); +})() +</script> +</body>
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.php b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.php new file mode 100644 index 0000000..b92628e --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.php
@@ -0,0 +1,6 @@ +<? +header("Content-Type: application/signed-exchange;v=b3"); +header("X-Content-Type-Options: nosniff"); +header("Link: <https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-script.sxg>;rel=alternate;type=\"application/signed-exchange;v=b3\";anchor=\"https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-script.js\";"); +echo(file_get_contents("sxg-subresource-origin-trial-page.sxg")); +?>
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.sxg b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.sxg new file mode 100644 index 0000000..9d80574 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-origin-trial-page.sxg Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script-inner.js b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script-inner.js new file mode 100644 index 0000000..ba0a37ab --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script-inner.js
@@ -0,0 +1 @@ +value = "from sxg";
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script.sxg b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script.sxg new file mode 100644 index 0000000..dba6039 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/sxg-subresource-script.sxg Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https-expected.txt b/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https-expected.txt new file mode 100644 index 0000000..ca4d0c07 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https-expected.txt
@@ -0,0 +1,16 @@ +main frame - DidStartNavigation +main frame - ReadyToCommitNavigation +main frame - didCommitLoadForFrame +main frame - didReceiveTitle: Signed Exchange subresource Origin Trial +main frame - didFinishDocumentLoadForFrame +main frame - didHandleOnloadEventsForFrame +main frame - didFinishLoadForFrame +main frame - BeginNavigation request to 'https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-origin-trial-page.php', http method GET +main frame - DidStartNavigation +main frame - ReadyToCommitNavigation +main frame - didCommitLoadForFrame +main frame - didReceiveTitle: Signed Exchange subresource Origin Trial inner page +main frame - didFinishDocumentLoadForFrame +main frame - didHandleOnloadEventsForFrame +main frame - didFinishLoadForFrame +Hello from sxg
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https.html b/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https.html new file mode 100644 index 0000000..df34bef --- /dev/null +++ b/third_party/blink/web_tests/http/tests/loading/sxg/sxg-subresource-origin-trial.https.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<head> +<title>Signed Exchange subresource Origin Trial</title> +<!-- Generate token with the command: +generate_token.py https://127.0.0.1:8443 SignedExchangeSubresourcePrefetch --expire-timestamp=2000000000 +-- --> +<meta http-equiv="origin-trial" content="AkPuNZ6wN6pkhO5BsawPJCR9+8TDqRn4NUKsrhif+5Hs6l3dbRCdhhBpImxV13ZM8luH7wYH+rC9LYwD9xIQOAwAAABqeyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6ODQ0MyIsICJmZWF0dXJlIjogIlNpZ25lZEV4Y2hhbmdlU3VicmVzb3VyY2VQcmVmZXRjaCIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="> +<script src="./resources/sxg-util.js"></script> +</head> +<body> +<script> +if (window.testRunner) { + testRunner.dumpAsText(); + testRunner.waitUntilDone(); +} +(async function() { + await waitUntilDidFinishLoadForFrame; + const sxg_path = "https://127.0.0.1:8443/loading/sxg/resources/sxg-subresource-origin-trial-page.php"; + new PerformanceObserver((list) => { + for (let e of list.getEntries()) { + if (e.name.endsWith('sxg-subresource-script.sxg')) { + location.href = sxg_path; + } + } + }).observe({ entryTypes: ['resource'] }); + const link = document.createElement('link'); + link.rel = 'prefetch'; + link.href = sxg_path; + document.body.appendChild(link); +})(); +// cache-control: public, max-age=600 +</script> +</body>
diff --git a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js index ee1d6398..22a7523 100644 --- a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js +++ b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
@@ -31,7 +31,7 @@ this.notifyOnReadingChange_ = true; this.reportingMode_ = reportingMode; this.sensorReadingTimerId_ = null; - this.updateReadingFunction_ = null; + this.readingData_ = null; this.suspendCalled_ = null; this.resumeCalled_ = null; this.addConfigurationCalled_ = null; @@ -55,7 +55,7 @@ } // Adds configuration for the sensor and starts reporting fake data - // through updateReadingFunction_ callback. + // through setSensorReading function. addConfiguration(configuration) { assert_not_equals(configuration, null, "Invalid sensor configuration."); @@ -115,7 +115,7 @@ this.startShouldFail_ = false; this.notifyOnReadingChange_ = true; - this.updateReadingFunction_ = null; + this.readingData_ = null; this.requestedFrequencies_ = []; this.suspendCalled_ = null; this.resumeCalled_ = null; @@ -133,9 +133,9 @@ } } - // Sets callback that is used to deliver sensor reading updates. - setUpdateSensorReadingFunction(updateReadingFunction) { - this.updateReadingFunction_ = updateReadingFunction; + // Sets fake data that is used to deliver sensor reading updates. + setSensorReading(readingData) { + this.readingData_ = readingData; return Promise.resolve(this); } @@ -179,13 +179,13 @@ } startReading() { - if (this.updateReadingFunction_ != null) { + if (this.readingData_ != null) { this.stopReading(); let maxFrequencyUsed = this.requestedFrequencies_[0]; let timeout = (1 / maxFrequencyUsed) * 1000; this.sensorReadingTimerId_ = window.setInterval(() => { - if (this.updateReadingFunction_) { - this.updateReadingFunction_(this.buffer_); + if (this.readingData_) { + this.buffer_.set(this.readingData_, 2); // For all tests sensor reading should have monotonically // increasing timestamp in seconds. this.buffer_[1] = window.performance.now() * 0.001; @@ -230,6 +230,17 @@ this.isContinuous_ = false; this.maxFrequency_ = 60; this.minFrequency_ = 1; + this.mojomSensorType_ = new Map([ + ['Accelerometer', device.mojom.SensorType.ACCELEROMETER], + ['LinearAccelerationSensor', device.mojom.SensorType.LINEAR_ACCELERATION], + ['AmbientLightSensor', device.mojom.SensorType.AMBIENT_LIGHT], + ['Gyroscope', device.mojom.SensorType.GYROSCOPE], + ['Magnetometer', device.mojom.SensorType.MAGNETOMETER], + ['AbsoluteOrientationSensor', device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION], + ['AbsoluteOrientationEulerAngles', device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES], + ['RelativeOrientationSensor', device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION], + ['RelativeOrientationEulerAngles', device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES] + ]); this.binding_ = new mojo.Binding(device.mojom.SensorProvider, this); this.interceptor_ = new MojoInterfaceInterceptor( @@ -329,16 +340,17 @@ // Sets flag that forces mock SensorProvider to fail when getSensor() is // invoked. - setGetSensorShouldFail(type, shouldFail) { - this.getSensorShouldFail_.set(type, shouldFail); + setGetSensorShouldFail(sensorType, shouldFail) { + this.getSensorShouldFail_.set(this.mojomSensorType_.get(sensorType), shouldFail); } - setPermissionsDenied(type, permissionsDenied) { - this.permissionsDenied_.set(type, permissionsDenied); + setPermissionsDenied(sensorType, permissionsDenied) { + this.permissionsDenied_.set(this.mojomSensorType_.get(sensorType), permissionsDenied); } // Returns mock sensor that was created in getSensor to the layout test. - getCreatedSensor(type) { + getCreatedSensor(sensorType) { + const type = this.mojomSensorType_.get(sensorType); assert_equals(typeof type, "number", "A sensor type must be specified."); if (this.activeSensors_.has(type)) { @@ -390,9 +402,7 @@ async function setMockSensorDataForType(sensorProvider, sensorType, mockDataArray) { let createdSensor = await sensorProvider.getCreatedSensor(sensorType); - return createdSensor.setUpdateSensorReadingFunction(buffer => { - buffer.set(mockDataArray, 2); - }); + return createdSensor.setSensorReading(mockDataArray); } // Returns a promise that will be resolved when an event equal to the given @@ -443,26 +453,3 @@ }, 500); }); } - -// TODO(Mikhail): Refactor further to remove code duplication -// in <concrete sensor>.html files. -function verify_sensor_reading(pattern, values, timestamp, is_null) { - function round(val) { - return Number.parseFloat(val).toPrecision(6); - } - - if (is_null) { - return (values === null || values.every(r => r === null)) && - timestamp === null; - } - return values.every((r, i) => round(r) === round(pattern[i])) && - timestamp !== null; -} - -function verify_xyz_sensor_reading(pattern, {x, y, z, timestamp}, is_null) { - return verify_sensor_reading(pattern, [x, y, z], timestamp, is_null); -} - -function verify_quat_sensor_reading(pattern, {quaternion, timestamp}, is_null) { - return verify_sensor_reading(pattern, quaternion, timestamp, is_null); -}
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html index 9ba2557..72e04a1 100644 --- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html +++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
@@ -40,23 +40,23 @@ const FAKE_ACCELERATION_DATA = [1, 2, 3]; const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6]; const FAKE_GYROSCOPE_DATA = [7, 8, 9]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, FAKE_ACCELERATION_DATA); - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, FAKE_LINEAR_ACCELERATION_DATA); - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, FAKE_GYROSCOPE_DATA); + setMockSensorDataForType(sensorProvider, 'Accelerometer', FAKE_ACCELERATION_DATA); + setMockSensorDataForType(sensorProvider, 'LinearAccelerationSensor', FAKE_LINEAR_ACCELERATION_DATA); + setMockSensorDataForType(sensorProvider, 'Gyroscope', FAKE_GYROSCOPE_DATA); return waitForLackOfEvent('devicemotion'); }, 'addEventListener() for `devicemotion` does not crash but the handler never fires.'); sensor_test(sensorProvider => { const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA); + setMockSensorDataForType(sensorProvider, 'RelativeOrientationEulerAngles', FAKE_ORIENTATION_DATA); return waitForLackOfEvent('deviceorientation'); }, 'addEventListener() for `deviceorientation` does not crash but the handler never fires.'); sensor_test(sensorProvider => { const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA); + setMockSensorDataForType(sensorProvider, 'AbsoluteOrientationEulerAngles', FAKE_ORIENTATION_DATA); return waitForLackOfEvent('deviceorientationabsolute'); }, 'addEventListener() for `deviceorientationabsolute` does not crash but the handler never fires.');
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html index f3fd011..ef22996 100644 --- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html +++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
@@ -21,9 +21,9 @@ const FAKE_ACCELERATION_DATA = [1, 2, 3]; const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6]; const FAKE_GYROSCOPE_DATA = [7, 8, 9]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, FAKE_ACCELERATION_DATA); - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, FAKE_LINEAR_ACCELERATION_DATA); - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, FAKE_GYROSCOPE_DATA); + setMockSensorDataForType(sensorProvider, 'Accelerometer', FAKE_ACCELERATION_DATA); + setMockSensorDataForType(sensorProvider, 'LinearAccelerationSensor', FAKE_LINEAR_ACCELERATION_DATA); + setMockSensorDataForType(sensorProvider, 'Gyroscope', FAKE_GYROSCOPE_DATA); const radToDeg = 180 / Math.PI; return waitForEvent(new DeviceMotionEvent('devicemotion', { @@ -48,7 +48,7 @@ sensor_test(async sensorProvider => { const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA); + setMockSensorDataForType(sensorProvider, 'RelativeOrientationEulerAngles', FAKE_ORIENTATION_DATA); return waitForEvent(new DeviceOrientationEvent('deviceorientation', { alpha: FAKE_ORIENTATION_DATA[2], @@ -60,7 +60,7 @@ sensor_test(async sensorProvider => { const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3]; - setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA); + setMockSensorDataForType(sensorProvider, 'AbsoluteOrientationEulerAngles', FAKE_ORIENTATION_DATA); return waitForEvent(new DeviceOrientationEvent('deviceorientationabsolute', { alpha: FAKE_ORIENTATION_DATA[2],
diff --git a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt index 19b6e61..b7d8b8f 100644 --- a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt
@@ -14,7 +14,7 @@ columnNumber : 2 exception : { className : SyntaxError - description : SyntaxError: Unexpected token } + description : SyntaxError: Unexpected token '}' objectId : <number> subtype : error type : object @@ -26,7 +26,7 @@ } result : { className : SyntaxError - description : SyntaxError: Unexpected token } + description : SyntaxError: Unexpected token '}' objectId : <string> subtype : error type : object
diff --git a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-runScript-async-expected.txt b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-runScript-async-expected.txt index ddf72f0..2f7c3ea 100644 --- a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-runScript-async-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-runScript-async-expected.txt
@@ -16,7 +16,7 @@ columnNumber : 1 exception : { className : SyntaxError - description : SyntaxError: Unexpected token } + description : SyntaxError: Unexpected token '}' objectId : <number> subtype : error type : object @@ -34,7 +34,7 @@ columnNumber : 0 exception : { className : SyntaxError - description : SyntaxError: Unexpected token } at boo.js:2:2 + description : SyntaxError: Unexpected token '}' at boo.js:2:2 objectId : <number> subtype : error type : object @@ -57,7 +57,7 @@ } result : { className : SyntaxError - description : SyntaxError: Unexpected token } at boo.js:2:2 + description : SyntaxError: Unexpected token '}' at boo.js:2:2 objectId : <string> subtype : error type : object
diff --git a/third_party/blink/web_tests/mojo/bindings-lite.html b/third_party/blink/web_tests/mojo/bindings-lite.html index 16c5eace..5026483 100644 --- a/third_party/blink/web_tests/mojo/bindings-lite.html +++ b/third_party/blink/web_tests/mojo/bindings-lite.html
@@ -25,7 +25,7 @@ promise_test(() => { let impl = new TargetImpl; - let proxy = impl.target.createProxy(); + let proxy = impl.target.$.createProxy(); proxy.poke(); return proxy.ping().then(() => { assert_equals(impl.numPokes, 1); @@ -34,7 +34,7 @@ promise_test(() => { let impl = new TargetImpl; - let proxy = impl.target.createProxy(); + let proxy = impl.target.$.createProxy(); return proxy.repeat(kTestMessage, kTestNumbers) .then(reply => { assert_equals(reply.message, kTestMessage); @@ -44,7 +44,7 @@ promise_test(async (t) => { const impl = new TargetImpl; - const proxy = impl.target.createProxy(); + const proxy = impl.target.$.createProxy(); await proxy.ping(); proxy.$.close(); @@ -54,7 +54,7 @@ promise_test(async (t) => { const impl = new TargetImpl; - const proxy = impl.target.createProxy(); + const proxy = impl.target.$.createProxy(); // None of these promises should successfully resolve because we are // immediately closing the pipe. @@ -78,7 +78,7 @@ let interceptor = new MojoInterfaceInterceptor( liteJsTest.mojom.TestMessageTarget.$interfaceName); interceptor.oninterfacerequest = e => { - impl.target.bindHandle(e.handle); + impl.target.$.bindHandle(e.handle); } interceptor.start(); @@ -91,7 +91,7 @@ promise_test(() => { let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - let proxy = router.createProxy(); + let proxy = router.$.createProxy(); return new Promise(resolve => { router.poke.addListener(resolve); proxy.poke(); @@ -100,7 +100,7 @@ promise_test(() => { let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - let proxy = router.createProxy(); + let proxy = router.$.createProxy(); let numPokes = 0; router.poke.addListener(() => ++numPokes); router.ping.addListener(() => Promise.resolve()); @@ -110,7 +110,7 @@ promise_test(() => { let router = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - let proxy = router.createProxy(); + let proxy = router.$.createProxy(); router.repeat.addListener( (message, numbers) => ({message: message, numbers: numbers})); return proxy.repeat(kTestMessage, kTestNumbers) @@ -122,11 +122,11 @@ promise_test(() => { let targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - let targetProxy = targetRouter.createProxy(); + let targetProxy = targetRouter.$.createProxy(); let subinterfaceRouter = new liteJsTest.mojom.SubinterfaceCallbackRouter; targetRouter.requestSubinterface.addListener((request, client) => { let values = []; - subinterfaceRouter.bindHandle(request.handle); + subinterfaceRouter.$.bindHandle(request.handle); subinterfaceRouter.push.addListener(value => values.push(value)); subinterfaceRouter.flush.addListener(() => { client.didFlush(values); @@ -137,7 +137,7 @@ let clientRouter = new liteJsTest.mojom.SubinterfaceClientCallbackRouter; let subinterfaceProxy = new liteJsTest.mojom.SubinterfaceProxy; targetProxy.requestSubinterface( - subinterfaceProxy.$.createRequest(), clientRouter.createProxy()); + subinterfaceProxy.$.createRequest(), clientRouter.$.createProxy()); return new Promise(resolve => { clientRouter.didFlush.addListener(values => { assert_array_equals(values, kTestNumbers); @@ -151,7 +151,7 @@ promise_test(() => { const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - const targetProxy = targetRouter.createProxy(); + const targetProxy = targetRouter.$.createProxy(); targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)})); return targetProxy.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => { assert_array_equals(reply.values, [1, 2, 3]); @@ -160,7 +160,7 @@ promise_test(() => { const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - const targetProxy = targetRouter.createProxy(); + const targetProxy = targetRouter.$.createProxy(); targetRouter.flattenUnions.addListener(unions => { return {x: unions.filter(u => u.x !== undefined).map(u => u.x), s: unions.filter(u => u.s !== undefined).map(u => u.s.x)}; @@ -176,7 +176,7 @@ promise_test(() => { let impl = new TargetImpl; - let proxy = impl.target.createProxy(); + let proxy = impl.target.$.createProxy(); // Poke a bunch of times. These should never race with the assertion below, // because the |flushForTesting| request/response is ordered against other @@ -191,7 +191,7 @@ promise_test(async(t) => { const impl = new TargetImpl; - const proxy = impl.target.createProxy(); + const proxy = impl.target.$.createProxy(); const disconnectPromise = new Promise(resolve => impl.target.onConnectionError.addListener(resolve)); proxy.$.close(); return disconnectPromise; @@ -199,7 +199,7 @@ promise_test(() => { const router = new liteJsTest.mojom.TestMessageTargetCallbackRouter; - const proxy = router.createProxy(); + const proxy = router.$.createProxy(); const disconnectPromise = new Promise(resolve => router.onConnectionError.addListener(resolve)); proxy.$.close(); return disconnectPromise;
diff --git a/third_party/blink/web_tests/mojo/document-interface-broker-override.html b/third_party/blink/web_tests/mojo/document-interface-broker-override.html index e7d88667..7763c1a 100644 --- a/third_party/blink/web_tests/mojo/document-interface-broker-override.html +++ b/third_party/blink/web_tests/mojo/document-interface-broker-override.html
@@ -25,7 +25,7 @@ brokerProxy.getFrameHostTestInterface(testInterfaceProxyBeforeOverride.$.createRequest()); setDocumentInterfaceBrokerOverrides({ getFrameHostTestInterface: request => { - frameHostTestImpl.bindHandle(request.handle); + frameHostTestImpl.$.bindHandle(request.handle); }}); const testInterfaceProxyAfterOverride = new blink.mojom.FrameHostTestInterfaceProxy; @@ -43,4 +43,4 @@ </script> </body> - </html> \ No newline at end of file + </html>
diff --git a/third_party/blink/web_tests/nfc/push.html b/third_party/blink/web_tests/nfc/push.html index 5a6d231..72ebe4e 100644 --- a/third_party/blink/web_tests/nfc/push.html +++ b/third_party/blink/web_tests/nfc/push.html
@@ -90,13 +90,13 @@ nfc_test(() => { mockNFC.setHWStatus(NFCHWStatus.DISABLED); return assertRejectsWithError(navigator.nfc.push(test_text_data), - 'NotSupportedError'); + 'NotReadableError'); }, 'nfc.push should fail when NFC HW is disabled.'); nfc_test(() => { mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED); return assertRejectsWithError(navigator.nfc.push(test_text_data), - 'NotSupportedError'); + 'NotReadableError'); }, 'nfc.push should fail when NFC HW is not supported.'); nfc_test(() => {
diff --git a/third_party/blink/web_tests/nfc/resources/nfc-helpers.js b/third_party/blink/web_tests/nfc/resources/nfc-helpers.js index 35b9072..f419701 100644 --- a/third_party/blink/web_tests/nfc/resources/nfc-helpers.js +++ b/third_party/blink/web_tests/nfc/resources/nfc-helpers.js
@@ -10,8 +10,11 @@ var test_buffer_view = new Uint8Array(test_buffer_data).set(test_text_byte_array); var NFCHWStatus = {}; +// OS-level NFC setting is ON NFCHWStatus.ENABLED = 1; +// no NFC chip NFCHWStatus.NOT_SUPPORTED = NFCHWStatus.ENABLED + 1; +// OS-level NFC setting OFF NFCHWStatus.DISABLED = NFCHWStatus.NOT_SUPPORTED + 1; function noop() {} @@ -378,9 +381,9 @@ isReady() { if (this.hw_status_ === NFCHWStatus.DISABLED) - return createNFCError(device.mojom.NFCErrorType.DEVICE_DISABLED); + return createNFCError(device.mojom.NFCErrorType.NOT_READABLE); if (this.hw_status_ === NFCHWStatus.NOT_SUPPORTED) - return createNFCError(device.mojom.NFCErrorType.NOT_SUPPORTED); + return createNFCError(device.mojom.NFCErrorType.NOT_READABLE); return null; }
diff --git a/third_party/blink/web_tests/nfc/resources/push-from-iframe.html b/third_party/blink/web_tests/nfc/resources/push-from-iframe.html index cb7faed..82a9c21 100644 --- a/third_party/blink/web_tests/nfc/resources/push-from-iframe.html +++ b/third_party/blink/web_tests/nfc/resources/push-from-iframe.html
@@ -6,7 +6,7 @@ if (message.data === 'Ready') { let onSuccess = () => { parent.postMessage('Failure', '*'); }; let onError = error => { - if (error.name == 'SecurityError') { + if (error.name == 'NotAllowedError') { parent.postMessage('Success', '*'); } else { parent.postMessage('Failure', '*');
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/viewport-mask-update-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/viewport-mask-update-expected.txt index 61212956..7ed4f4c9 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/viewport-mask-update-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/svg/viewport-mask-update-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 8: Uncaught SyntaxError: Unexpected token , +CONSOLE ERROR: line 8: Uncaught SyntaxError: Unexpected token ',' CONSOLE ERROR: line 11: Uncaught ReferenceError: repaintTest is not defined
diff --git a/third_party/blink/web_tests/platform/linux/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/linux/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index 3f09fd1c..0000000 --- a/third_party/blink/web_tests/platform/linux/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index 9e30c7b..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.10/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index dbce636..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/mac/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index aa9aec1b..0000000 --- a/third_party/blink/web_tests/platform/mac/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/win/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index 35863e6..0000000 --- a/third_party/blink/web_tests/platform/win/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png b/third_party/blink/web_tests/platform/win7/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png deleted file mode 100644 index 4715e44..0000000 --- a/third_party/blink/web_tests/platform/win7/fast/text/whitespace/pre-wrap-spaces-after-newline-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/resources/document-interface-broker-helpers.js b/third_party/blink/web_tests/resources/document-interface-broker-helpers.js index e27e910a..aa945bc 100644 --- a/third_party/blink/web_tests/resources/document-interface-broker-helpers.js +++ b/third_party/blink/web_tests/resources/document-interface-broker-helpers.js
@@ -11,7 +11,7 @@ * const testFooImpl = new FooInterfaceCallbackRouter; * ... override FooInterface methods ... * setDocumentInterfaceBrokerOverrides({getFooInterface: request => { - * testFooImpl.bindHandle(request.handle); + * testFooImpl.$.bindHandle(request.handle); * }}); */ function setDocumentInterfaceBrokerOverrides(overrides) { @@ -25,5 +25,5 @@ // Use the real broker (with overrides) as the implementation of the JS-side broker const testBrokerBinding = new blink.mojom.DocumentInterfaceBroker(realBrokerProxy); - testBrokerBinding.bindHandle(handle1); + testBrokerBinding.$.bindHandle(handle1); }
diff --git a/third_party/blink/web_tests/security/lazy-event-listener-expected.txt b/third_party/blink/web_tests/security/lazy-event-listener-expected.txt index 0b63146..96cf2f1c 100644 --- a/third_party/blink/web_tests/security/lazy-event-listener-expected.txt +++ b/third_party/blink/web_tests/security/lazy-event-listener-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 2: Uncaught SyntaxError: Unexpected token } +CONSOLE ERROR: line 2: Uncaught SyntaxError: Unexpected token '}' Test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/sensor/accelerometer.html b/third_party/blink/web_tests/sensor/accelerometer.html index 169304f..732f698e 100644 --- a/third_party/blink/web_tests/sensor/accelerometer.html +++ b/third_party/blink/web_tests/sensor/accelerometer.html
@@ -4,6 +4,7 @@ <script src="../http/tests/resources/sensor-helpers.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/device/public/mojom/sensor_provider.mojom.js"></script> +<script src="resources/generic-sensor-utils.js"></script> <script src="resources/generic-sensor-tests.js"></script> <script> @@ -15,23 +16,17 @@ const kDefaultReading = [1.12345, 2.12345, 3.12345]; const kMappedReading = [-2.12345, 1.12345, 3.12345]; -function update_sensor_reading(buffer) { - buffer.set(kDefaultReading, 2); -} - runGenericSensorTests( Accelerometer, - device.mojom.SensorType.ACCELEROMETER, - update_sensor_reading, - verify_xyz_sensor_reading.bind(null, kDefaultReading), - verify_xyz_sensor_reading.bind(null, kMappedReading), + kDefaultReading, + verifyXyzSensorReading.bind(null, kDefaultReading), + verifyXyzSensorReading.bind(null, kMappedReading), ['accelerometer']); runGenericSensorTests( LinearAccelerationSensor, - device.mojom.SensorType.LINEAR_ACCELERATION, - update_sensor_reading, - verify_xyz_sensor_reading.bind(null, kDefaultReading), - verify_xyz_sensor_reading.bind(null, kMappedReading), + kDefaultReading, + verifyXyzSensorReading.bind(null, kDefaultReading), + verifyXyzSensorReading.bind(null, kMappedReading), ['accelerometer']); </script>
diff --git a/third_party/blink/web_tests/sensor/ambient-light-sensor.html b/third_party/blink/web_tests/sensor/ambient-light-sensor.html index f4ef0ac..18b81b4 100644 --- a/third_party/blink/web_tests/sensor/ambient-light-sensor.html +++ b/third_party/blink/web_tests/sensor/ambient-light-sensor.html
@@ -4,6 +4,7 @@ <script src="../http/tests/resources/sensor-helpers.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/device/public/mojom/sensor_provider.mojom.js"></script> +<script src="resources/generic-sensor-utils.js"></script> <script src="resources/generic-sensor-tests.js"></script> <script> @@ -12,22 +13,12 @@ if (!window.testRunner) debug('This test cannot be run without the TestRunner'); -const kDefaultReadingValue = 3.1415; +const kDefaultReading = [3.1415]; -function update_sensor_reading(buffer) { - buffer[2] = kDefaultReadingValue; -} - -function verify_sensor_reading({illuminance, timestamp}, is_null) { - if (is_null) - return illuminance === null && timestamp === null; - return illuminance === kDefaultReadingValue && timestamp !== null; -} - -runGenericSensorTests(AmbientLightSensor, - device.mojom.SensorType.AMBIENT_LIGHT, - update_sensor_reading, - verify_sensor_reading, - null, - ['ambient-light-sensor']); +runGenericSensorTests( + AmbientLightSensor, + kDefaultReading, + verifyAlsSensorReading.bind(null, kDefaultReading), + null, + ['ambient-light-sensor']); </script>
diff --git a/third_party/blink/web_tests/sensor/gyroscope.html b/third_party/blink/web_tests/sensor/gyroscope.html index 6ebcf9a2..0c34f33b 100644 --- a/third_party/blink/web_tests/sensor/gyroscope.html +++ b/third_party/blink/web_tests/sensor/gyroscope.html
@@ -4,6 +4,7 @@ <script src="../http/tests/resources/sensor-helpers.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/device/public/mojom/sensor_provider.mojom.js"></script> +<script src="resources/generic-sensor-utils.js"></script> <script src="resources/generic-sensor-tests.js"></script> <script> @@ -15,15 +16,10 @@ const kDefaultReading = [1.12345, 2.12345, 3.12345]; const kMappedReading = [-2.12345, 1.12345, 3.12345]; -function update_sensor_reading(buffer) { - buffer.set(kDefaultReading, 2); -} - runGenericSensorTests( Gyroscope, - device.mojom.SensorType.GYROSCOPE, - update_sensor_reading, - verify_xyz_sensor_reading.bind(null, kDefaultReading), - verify_xyz_sensor_reading.bind(null, kMappedReading), + kDefaultReading, + verifyXyzSensorReading.bind(null, kDefaultReading), + verifyXyzSensorReading.bind(null, kMappedReading), ['gyroscope']); </script>
diff --git a/third_party/blink/web_tests/sensor/magnetometer.html b/third_party/blink/web_tests/sensor/magnetometer.html index bdeadc66..930e23d 100644 --- a/third_party/blink/web_tests/sensor/magnetometer.html +++ b/third_party/blink/web_tests/sensor/magnetometer.html
@@ -4,6 +4,7 @@ <script src="../http/tests/resources/sensor-helpers.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/device/public/mojom/sensor_provider.mojom.js"></script> +<script src="resources/generic-sensor-utils.js"></script> <script src="resources/generic-sensor-tests.js"></script> <script> @@ -15,15 +16,10 @@ const kDefaultReading = [-19.2, 12.1, -44.3]; const kMappedReading = [-12.1, -19.2, -44.3]; -function update_sensor_reading(buffer) { - buffer.set(kDefaultReading, 2); -} - runGenericSensorTests( Magnetometer, - device.mojom.SensorType.MAGNETOMETER, - update_sensor_reading, - verify_xyz_sensor_reading.bind(null, kDefaultReading), - verify_xyz_sensor_reading.bind(null, kMappedReading), + kDefaultReading, + verifyXyzSensorReading.bind(null, kDefaultReading), + verifyXyzSensorReading.bind(null, kMappedReading), ['magnetometer']); </script>
diff --git a/third_party/blink/web_tests/sensor/orientation-sensor.html b/third_party/blink/web_tests/sensor/orientation-sensor.html index 2652750..c224d3f 100644 --- a/third_party/blink/web_tests/sensor/orientation-sensor.html +++ b/third_party/blink/web_tests/sensor/orientation-sensor.html
@@ -4,6 +4,7 @@ <script src="../http/tests/resources/sensor-helpers.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/device/public/mojom/sensor_provider.mojom.js"></script> +<script src="resources/generic-sensor-utils.js"></script> <script src="resources/generic-sensor-tests.js"></script> <script> @@ -12,7 +13,7 @@ if (!window.testRunner) debug('This test cannot be run without the TestRunner'); -const kQuaternion = [1, 0, 0, 0]; // 180 degrees around X axis. +const kDefaultReading = [1, 0, 0, 0]; // 180 degrees around X axis. const kRotationMatrix = [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, @@ -21,13 +22,9 @@ // For 'orientation.angle == 270', which is set for tests at // at SensorProxy::GetScreenOrientationAngle(). -const kMappedQuaternion = [-0.707107, 0.707107, 0, 0]; +const kMappedReading = [-0.707107, 0.707107, 0, 0]; -function update_sensor_reading(buffer) { - buffer.set(kQuaternion, 2); -} - -async function checkPopulateMatrix(sensorProvider, sensorType, mojomSensorType) { +async function checkPopulateMatrix(sensorProvider, sensorType) { let sensorObject = new sensorType(); // Throws with insufficient buffer space. @@ -43,8 +40,8 @@ sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(update_sensor_reading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(kDefaultReading); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { // Works for all supported types. @@ -78,31 +75,27 @@ runGenericSensorTests( AbsoluteOrientationSensor, - device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION, - update_sensor_reading, - verify_quat_sensor_reading.bind(null, kQuaternion), - verify_quat_sensor_reading.bind(null, kMappedQuaternion), + kDefaultReading, + verifyQuatSensorReading.bind(null, kDefaultReading), + verifyQuatSensorReading.bind(null, kMappedReading), ['accelerometer', 'gyroscope', 'magnetometer']); sensor_test(sensorProvider => { return checkPopulateMatrix( sensorProvider, - AbsoluteOrientationSensor, - device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION); + AbsoluteOrientationSensor); }, 'Test AbsoluteOrientationSensor.populateMatrix() method works correctly.'); runGenericSensorTests( RelativeOrientationSensor, - device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION, - update_sensor_reading, - verify_quat_sensor_reading.bind(null, kQuaternion), - verify_quat_sensor_reading.bind(null, kMappedQuaternion), + kDefaultReading, + verifyQuatSensorReading.bind(null, kDefaultReading), + verifyQuatSensorReading.bind(null, kMappedReading), ['accelerometer', 'gyroscope']); sensor_test(sensorProvider => { return checkPopulateMatrix( sensorProvider, - RelativeOrientationSensor, - device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION); + RelativeOrientationSensor); }, 'Test RelativeOrientationSensor.populateMatrix() method works correctly.'); </script>
diff --git a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js index c4540b38..8c354df 100644 --- a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js +++ b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
@@ -1,17 +1,19 @@ 'use strict'; -// Run a set of tests for a given |sensorType|. |updateReading| is -// a called by the test to provide the mock values for sensor. |verifyReading| -// is called so that the value read in JavaScript are the values expected (the ones -// sent by |updateReading|). +// Run a set of tests for a given |sensorType|. |readingData| is +// set for providing the mock values for sensor. |verifyReading| +// is called so that the value read in JavaScript are the values expected. +// |verifyRemappedReading| is called for verifying the reading is mapped +// to the screen coordinates for a spatial sensor. |featurePolicies| represents +// the |sensorType|’s associated sensor feature name. + function runGenericSensorTests(sensorType, - mojomSensorType, - updateReading, + readingData, verifyReading, verifyRemappedReading, featurePolicies) { sensor_test(sensorProvider => { - sensorProvider.setGetSensorShouldFail(mojomSensorType, true); + sensorProvider.setGetSensorShouldFail(sensorType.name, true); let sensorObject = new sensorType; sensorObject.start(); return new Promise((resolve, reject) => { @@ -27,7 +29,7 @@ }, `${sensorType.name}: Test that onerror is sent when sensor is not supported.`); sensor_test(sensorProvider => { - sensorProvider.setPermissionsDenied(mojomSensorType, true); + sensorProvider.setPermissionsDenied(sensorType.name, true); let sensorObject = new sensorType; sensorObject.start(); return new Promise((resolve, reject) => { @@ -46,7 +48,7 @@ let sensorObject = new sensorType({frequency: 560}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); mockSensor.setStartShouldFail(true); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { @@ -65,7 +67,7 @@ let sensorObject = new sensorType(); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); mockSensor.setStartShouldFail(true); await mockSensor.addConfigurationCalled(); return mockSensor.removeConfigurationCalled(); @@ -75,7 +77,7 @@ let sensorObject = new sensorType({frequency: 560}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { @@ -93,7 +95,7 @@ sensor_test(async sensorProvider => { let sensorObject = new sensorType(); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { sensorObject.onactivate = () => { @@ -115,7 +117,7 @@ let sensorObject = new sensorType({frequency: 50}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { @@ -136,7 +138,7 @@ let sensorObject = new sensorType({frequency: -1}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { @@ -157,7 +159,7 @@ sensorObject.start(); assert_false(sensorObject.activated); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { assert_true(sensorObject.activated); @@ -175,7 +177,7 @@ let sensorObject = new sensorType(); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { assert_true(sensorObject.activated); @@ -194,7 +196,7 @@ let sensorObject = new sensorType({frequency: 60}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); await mockSensor.addConfigurationCalled(); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { @@ -214,8 +216,8 @@ sensorObject.start(); assert_false(sensorObject.hasReading); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { assert_true(verifyReading(sensorObject)); @@ -244,8 +246,8 @@ let sensorObject = new sensorType({frequency: 60}); sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { assert_true(verifyReading(sensorObject)); @@ -276,8 +278,8 @@ iframe.src = encodeURI(iframeSrc); iframe.allow = "focus-without-user-activation"; - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { @@ -308,8 +310,8 @@ let sensor2 = new sensorType({frequency: 20}); sensor2.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { // Reading values are correct for both sensors. @@ -341,8 +343,8 @@ let slowSensor; // To be initialized later. - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let fastSensorNotifiedCounter = 0; let slowSensorNotifiedCounter = 0; @@ -451,8 +453,8 @@ let timestamp = 0; sensorObject.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(updateReading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper1 = new CallbackWrapper(() => { assert_true(sensorObject.hasReading); @@ -494,8 +496,8 @@ sensor1.start(); sensor2.start(); - let mockSensor = await sensorProvider.getCreatedSensor(mojomSensorType); - await mockSensor.setUpdateSensorReadingFunction(update_sensor_reading); + let mockSensor = await sensorProvider.getCreatedSensor(sensorType.name); + await mockSensor.setSensorReading(readingData); await new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(() => { assert_true(verifyReading(sensor1));
diff --git a/third_party/blink/web_tests/sensor/resources/generic-sensor-utils.js b/third_party/blink/web_tests/sensor/resources/generic-sensor-utils.js new file mode 100644 index 0000000..8cad13b --- /dev/null +++ b/third_party/blink/web_tests/sensor/resources/generic-sensor-utils.js
@@ -0,0 +1,27 @@ +'use strict'; + +function verifySensorReading(pattern, values, timestamp, isNull) { + function round(val) { + return Number.parseFloat(val).toPrecision(6); + } + + if (isNull) { + return (values === null || values.every(r => r === null)) && + timestamp === null; + } + + return values.every((r, i) => round(r) === round(pattern[i])) && + timestamp !== null; +} + +function verifyXyzSensorReading(pattern, {x, y, z, timestamp}, isNull) { + return verifySensorReading(pattern, [x, y, z], timestamp, isNull); +} + +function verifyQuatSensorReading(pattern, {quaternion, timestamp}, isNull) { + return verifySensorReading(pattern, quaternion, timestamp, isNull); +} + +function verifyAlsSensorReading(pattern, {illuminance, timestamp}, isNull) { + return verifySensorReading(pattern, [illuminance], timestamp, isNull); +}
diff --git a/third_party/blink/web_tests/svg/animations/syncbases_with_tangled_dependencies.html b/third_party/blink/web_tests/svg/animations/syncbases_with_tangled_dependencies.html new file mode 100644 index 0000000..fb559092 --- /dev/null +++ b/third_party/blink/web_tests/svg/animations/syncbases_with_tangled_dependencies.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> + +<title>Syncbases with tangled dependencies</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + +<svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg"> + <rect width="100%" height="100%" fill="none"> + <animate id="minani" attributeName="x" fill="freeze" begin="min.click" dur="100ms" values="0; 0"/> + <animate id="maxani" attributeName="x" fill="freeze" begin="max.click" dur="100ms" values="0; 0"/> + </rect> + <rect id="min" width="100" height="100" fill="green"> + <set attributeName="height" fill="freeze" begin="minani.begin" to="0"/> + <set attributeName="height" fill="freeze" begin="maxani.begin+0.1s" to="100"/> + </rect> + <rect id="max" x="110" width="100" height="100" fill="blue"/> +</svg> +<script> + async_test(t => { + let clicks = 3; + let min = document.querySelector("#min"); + let max = document.querySelector("#max"); + let i = setInterval(t.step_func(() => { + clicks--; + if (clicks == 0) { + clearInterval(i); + t.step_timeout(t.step_func_done(() => { + assert_equals(window.getComputedStyle(min, null).height, "100px"); + }), 500); + } + min.dispatchEvent(new Event("click")); + window.setTimeout(() => max.dispatchEvent(new Event("click")), 130); + }), 250); + }); +</script>
diff --git a/third_party/blink/web_tests/vr/resources/vr-test-utils.js b/third_party/blink/web_tests/vr/resources/vr-test-utils.js index 2bac718..c129ade7 100644 --- a/third_party/blink/web_tests/vr/resources/vr-test-utils.js +++ b/third_party/blink/web_tests/vr/resources/vr-test-utils.js
@@ -30,12 +30,12 @@ if (this.pose_.hasOwnProperty(field)) { let val = pose[field]; if (field === "position") { - this.pose_[field] = new gfx.mojom.Point3F(val[0], val[1], val[2]); + this.pose_[field] = { x: val[0], y: val[1], z: val[2] }; } else if (field === "orientation") { - this.pose_[field] = new gfx.mojom.Quaternion(val[0], val[1], val[2], val[3]); + this.pose_[field] = { x: val[0], y: val[1], z: val[2], w: val[3] }; }else if (field === "angularVelocity" || field === "linearVelocity" || - field === "angularAcceleration" || field === "lienarAcceleration") { - this.pose_[field] = new gfx.mojom.Vector3dF(val[0], val[1], val[2]); + field === "angularAcceleration" || field === "linearAcceleration") { + this.pose_[field] = { x: val[0], y: val[1], z: val[2] }; } else { this.pose_[field] = pose[field]; } @@ -86,14 +86,14 @@ let generic_left_eye = { fieldOfView : generic_left_fov, - offset : new gfx.mojom.Vector3dF(-0.03, 0, 0), + offset : { x: -0.03, y: 0, z: 0 }, renderWidth : 1024, renderHeight : 1024 }; let generic_right_eye = { fieldOfView :generic_right_fov, - offset : new gfx.mojom.Vector3dF(0.03, 0, 0), + offset : { x: 0.03, y: 0, z: 0 }, renderWidth : 1024, renderHeight : 1024 }; @@ -152,7 +152,7 @@ leftDegrees : 35.197, rightDegrees : 50.899, }, - offset : new gfx.mojom.Vector3dF(-0.032, 0, 0), + offset : { x: -0.032, y: 0, z: 0 }, renderWidth : 1920, renderHeight : 2160 }, @@ -163,7 +163,7 @@ leftDegrees: 50.899, rightDegrees: 35.197 }, - offset : new gfx.mojom.Vector3dF(0.032, 0, 0), + offset : { x: 0.032, y: 0, z: 0 }, renderWidth : 1920, renderHeight : 2160 },
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 69e48ef9..13b7fc1 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
@@ -4905,6 +4905,10 @@ attribute @@toStringTag getter error method constructor +interface NFCWriter + attribute @@toStringTag + method constructor + method push interface NamedNodeMap attribute @@toStringTag getter length
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 22e9359..9a0b5c2 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -23811,6 +23811,7 @@ <int value="2949" label="CredentialManagerGetWithUVM"/> <int value="2950" label="CredentialManagerCreateSuccessWithUVM"/> <int value="2951" label="CredentialManagerGetSuccessWithUVM"/> + <int value="2952" label="DiscardInputEventToMovingIframe"/> </enum> <enum name="FeaturePolicyAllowlistType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a433eb10..082d932a 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -70323,7 +70323,7 @@ </histogram> <histogram name="Net.HttpAuthPromptType" enum="HttpAuthPromptType" - expires_after="M77"> + expires_after="M80"> <owner>meacer@chromium.org</owner> <summary>Type of the HTTP auth prompt displayed.</summary> </histogram>
diff --git a/tools/perf/cli_tools/soundwave/studies/__init__.py b/tools/perf/cli_tools/soundwave/studies/__init__.py index 72b4e19..8e18c687 100644 --- a/tools/perf/cli_tools/soundwave/studies/__init__.py +++ b/tools/perf/cli_tools/soundwave/studies/__init__.py
@@ -26,11 +26,11 @@ df['reference'] = df['timestamp'].dt.date == df.groupby( 'quarter')['timestamp'].transform('max').dt.date - # Change unit for values in ms to seconds. - # TODO: Get and use unit information from the dashboard instead of trying to - # guess by the measurement name. - is_ms_unit = (df['measurement'].str.startswith('timeTo') | - df['measurement'].str.endswith(':duration')) + # Change units for values in ms to seconds, and percent values. + is_ms_unit = df['units'].str.startswith('ms_') df.loc[is_ms_unit, 'value'] = df['value'] / 1000 + is_percentage = df['units'].str.startswith('n%_') + df.loc[is_percentage, 'value'] = df['value'] * 100 + return df
diff --git a/tools/perf/cli_tools/soundwave/studies/health_study.py b/tools/perf/cli_tools/soundwave/studies/health_study.py index f00115b..4abbf05 100644 --- a/tools/perf/cli_tools/soundwave/studies/health_study.py +++ b/tools/perf/cli_tools/soundwave/studies/health_study.py
@@ -2,46 +2,71 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from core.services import dashboard_service +from cli_tools.soundwave.tables import timeseries + + CLOUD_PATH = 'gs://chrome-health-tvdata/datasets/health_study.csv' -OVERALL_PSS = ('memory:{browser}:all_processes:reported_by_os:system_memory' - ':proportional_resident_size_avg') - -BATTERY = [ - 'power.typical_10_mobile', - 'application_energy_consumption_mwh' +SYSTEM_HEALTH = [ + { + 'test_suite': 'system_health.memory_mobile', + 'measurement': ('memory:{browser}:all_processes:reported_by_os:' + 'private_footprint_size'), + }, + { + 'test_suite': 'system_health.common_mobile', + 'measurement': 'cpu_time_percentage' + } ] STARTUP_BY_BROWSER = { - 'chrome': [ - 'startup.mobile', - 'first_contentful_paint_time_avg', - 'intent_coldish_bbc' - ], - 'webview': [ - 'system_health.webview_startup', - 'webview_startup_wall_time_avg', - 'load_chrome/load_chrome_blank' - ] + 'chrome': { + 'test_suite': 'startup.mobile', + 'measurement': 'first_contentful_paint_time', + 'test_case': 'intent_coldish_bbc' + }, + 'webview': { + 'test_suite': 'system_health.webview_startup', + 'measurement': 'webview_startup_wall_time_avg', + 'test_case': 'load:chrome:blank' + } } def IterSystemHealthBots(): - yield 'ChromiumPerf/android-go-perf' - yield 'ChromiumPerf/android-go_webview-perf' - yield 'ChromiumPerf/android-pixel2-perf' - yield 'ChromiumPerf/android-pixel2_webview-perf' + yield 'ChromiumPerf:android-go-perf' + yield 'ChromiumPerf:android-go_webview-perf' + yield 'ChromiumPerf:android-pixel2-perf' + yield 'ChromiumPerf:android-pixel2_webview-perf' def GetBrowserFromBot(bot): return 'webview' if 'webview' in bot else 'chrome' +def GetHealthCheckStories(): + description = dashboard_service.Describe('system_health.common_mobile') + return description['caseTags']['health_check'] + + def IterTestPaths(): + test_cases = GetHealthCheckStories() for bot in IterSystemHealthBots(): browser = GetBrowserFromBot(bot) - overall_pss = OVERALL_PSS.format(browser=browser) - for story_group in ('foreground', 'background'): - yield '/'.join([bot, 'memory.top_10_mobile', overall_pss, story_group]) - yield '/'.join([bot] + BATTERY) - yield '/'.join([bot] + STARTUP_BY_BROWSER[browser]) + series = STARTUP_BY_BROWSER[browser].copy() + series['bot'] = bot + yield timeseries.Key(**series) + + if bot == 'ChromiumPerf:android-pixel2_webview-perf': + # The pixel2 webview bot incorrectly reports memory as if coming from + # chrome. TODO(crbug.com/972620): Remove this when bug is fixed. + browser = 'chrome' + + for series in SYSTEM_HEALTH: + series = series.copy() + series['bot'] = bot + series['measurement'] = series['measurement'].format(browser=browser) + for test_case in test_cases: + series['test_case'] = test_case + yield timeseries.Key(**series)
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc index e841ba0c..bdc2f60 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -168,7 +168,11 @@ ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary); break; case TextUnit_Paragraph: - return E_NOTIMPL; + start_ = start_->CreatePreviousParagraphStartPosition( + ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary); + end_ = start_->CreateNextParagraphEndPosition( + ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary); + break; // Since web content is not paginated, TextUnit_Page is not supported. // Substituting it by the next larger unit: TextUnit_Document. case TextUnit_Page:
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc index 5c06ac2..b04cbda 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -400,6 +400,8 @@ ui::AXNodeData group1_data; group1_data.id = 2; group1_data.role = ax::mojom::Role::kGenericContainer; + group1_data.AddBoolAttribute( + ax::mojom::BoolAttribute::kIsLineBreakingObject, true); ui::AXNodeData text_data; text_data.id = 3; @@ -484,6 +486,8 @@ ax::mojom::IntListAttribute::kWordStarts, word_start_offsets); paragraph1_text_data.AddIntListAttribute( ax::mojom::IntListAttribute::kWordEnds, word_end_offsets); + paragraph1_data.AddBoolAttribute( + ax::mojom::BoolAttribute::kIsLineBreakingObject, true); paragraph1_data.child_ids = {10}; ui::AXNodeData paragraph2_data; @@ -503,6 +507,8 @@ ax::mojom::IntListAttribute::kWordStarts, word_start_offsets); paragraph2_text_data.AddIntListAttribute( ax::mojom::IntListAttribute::kWordEnds, word_end_offsets); + paragraph1_data.AddBoolAttribute( + ax::mojom::BoolAttribute::kIsLineBreakingObject, true); paragraph2_data.child_ids = {12}; ui::AXNodeData root_data; @@ -1052,6 +1058,67 @@ } TEST_F(AXPlatformNodeTextRangeProviderTest, + TestITextRangeProviderExpandToEnclosingParagraph) { + Init(BuildAXTreeForMove()); + AXNodePosition::SetTreeForTesting(tree_.get()); + AXNode* root_node = GetRootNode(); + + ComPtr<ITextRangeProvider> text_range_provider; + GetTextRangeProviderFromTextNode(text_range_provider, root_node); + + EXPECT_UIA_TEXTRANGE_EQ( + text_range_provider, + L"First line of text\nStandalone line\nbold textParagraph 1Paragraph 2"); + + // Start endpoint is already on a paragraph's start boundary. + int count; + ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( + TextPatternRangeEndpoint_End, TextUnit_Paragraph, /*count*/ -6, &count)); + EXPECT_EQ(-6, count); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L""); + + ASSERT_HRESULT_SUCCEEDED( + text_range_provider->ExpandToEnclosingUnit(TextUnit_Paragraph)); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"First line of text"); + + // Moving the start by two lines will create a degenerate range positioned + // at the next paragraph (skipping the newline) + ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( + TextPatternRangeEndpoint_Start, TextUnit_Line, /*count*/ 2, &count)); + EXPECT_EQ(2, count); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L""); + + ASSERT_HRESULT_SUCCEEDED( + text_range_provider->ExpandToEnclosingUnit(TextUnit_Paragraph)); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Standalone line\n"); + + // Move to the next paragraph via MoveEndpointByUnit (line), then move to + // the middle of the paragraph via Move (word), then expand by paragraph. + ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( + TextPatternRangeEndpoint_Start, TextUnit_Line, /*count*/ 1, &count)); + EXPECT_EQ(1, count); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L""); + EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word, + /*count*/ 1, + /*expected_text*/ + L"", + /*expected_count*/ 1); + ASSERT_HRESULT_SUCCEEDED( + text_range_provider->ExpandToEnclosingUnit(TextUnit_Paragraph)); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"bold text"); + + // Create a degenerate range at the end of the document, then expand by + // paragraph + ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( + TextPatternRangeEndpoint_Start, TextUnit_Document, /*count*/ 1, &count)); + EXPECT_EQ(1, count); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L""); + ASSERT_HRESULT_SUCCEEDED( + text_range_provider->ExpandToEnclosingUnit(TextUnit_Paragraph)); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Paragraph 2"); +} + +TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderExpandToEnclosingFormat) { Init(BuildAXTreeForMoveByFormat()); AXNodePosition::SetTreeForTesting(tree_.get()); @@ -1697,18 +1764,22 @@ // Move forward. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ 1, - /*expected_text*/ L"Standalone line\n", + /*expected_text*/ L"\n", /*expected_count*/ 1); EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ 2, - /*expected_text*/ L"Paragraph 1", + /*expected_text*/ L"bold text", /*expected_count*/ 2); EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ 1, + /*expected_text*/ L"Paragraph 1", + /*expected_count*/ 1); + EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, + /*count*/ 2, /*expected_text*/ L"Paragraph 2", /*expected_count*/ 1); - // Trying to move past the last format should have no effect. + // Trying to move past the last paragraph should have no effect. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ 1, /*expected_text*/ L"Paragraph 2", @@ -1720,16 +1791,16 @@ /*expected_text*/ L"Standalone line\n", /*expected_count*/ -3); EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, - /*count*/ -1, - /*expected_text*/ L"First line of text\n", - /*expected_count*/ -1); + /*count*/ -2, + /*expected_text*/ L"First line of text", + /*expected_count*/ -2); // Moving backward by any number of paragraphs at the start of document // should have no effect. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ -1, /*expected_text*/ - L"First line of text\n", + L"First line of text", /*expected_count*/ 0); // Test degenerate range creation at the beginning of the document. @@ -1741,14 +1812,14 @@ EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph, /*count*/ 1, - /*expected_text*/ L"First line of text\n", + /*expected_text*/ L"First line of text", /*expected_count*/ 1); // Test degenerate range creation at the end of the document. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, - /*count*/ 5, + /*count*/ 6, /*expected_text*/ L"Paragraph 2", - /*expected_count*/ 4); + /*expected_count*/ 5); EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph, /*count*/ 1, @@ -1772,9 +1843,9 @@ // Degenerate range moves. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, - /*count*/ -6, - /*expected_text*/ L"First line of text\n", - /*expected_count*/ -5); + /*count*/ -7, + /*expected_text*/ L"First line of text", + /*expected_count*/ -6); EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph, /*count*/ -1, @@ -1787,7 +1858,7 @@ EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph, /*count*/ 70, /*expected_text*/ L"", - /*expected_count*/ 2); + /*expected_count*/ 3); // Trying to move past the last paragraph should have no effect. EXPECT_UIA_MOVE(text_range_provider, TextUnit_Paragraph,
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index 0a1dcf6..7ac8af38 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -484,7 +484,7 @@ } void Layer::SetClipRect(const gfx::Rect& clip_rect) { - cc_layer_->SetClipRect(clip_rect); + GetAnimator()->SetClipRect(clip_rect); } void Layer::SetOpacity(float opacity) { @@ -1416,6 +1416,11 @@ SetFillsBoundsOpaquely(SkColorGetA(color) == 0xFF); } +void Layer::SetClipRectFromAnimation(const gfx::Rect& clip_rect, + PropertyChangeReason reason) { + cc_layer_->SetClipRect(clip_rect); +} + void Layer::ScheduleDrawForAnimation() { ScheduleDraw(); } @@ -1451,6 +1456,12 @@ solid_color_layer_->background_color() : SK_ColorBLACK; } +gfx::Rect Layer::GetClipRectForAnimation() const { + if (clip_rect().IsEmpty()) + return gfx::Rect(size()); + return clip_rect(); +} + float Layer::GetDeviceScaleFactor() const { return device_scale_factor_; }
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index 25421525..3579e9a 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h
@@ -541,6 +541,8 @@ PropertyChangeReason reason) override; void SetColorFromAnimation(SkColor color, PropertyChangeReason reason) override; + void SetClipRectFromAnimation(const gfx::Rect& clip_rect, + PropertyChangeReason reason) override; void ScheduleDrawForAnimation() override; const gfx::Rect& GetBoundsForAnimation() const override; gfx::Transform GetTransformForAnimation() const override; @@ -549,6 +551,7 @@ float GetBrightnessForAnimation() const override; float GetGrayscaleForAnimation() const override; SkColor GetColorForAnimation() const override; + gfx::Rect GetClipRectForAnimation() const override; float GetDeviceScaleFactor() const override; ui::Layer* GetLayer() override; cc::Layer* GetCcLayer() const override;
diff --git a/ui/compositor/layer_animation_delegate.h b/ui/compositor/layer_animation_delegate.h index fcd0de1..9c700c54 100644 --- a/ui/compositor/layer_animation_delegate.h +++ b/ui/compositor/layer_animation_delegate.h
@@ -38,6 +38,8 @@ PropertyChangeReason reason) = 0; virtual void SetColorFromAnimation(SkColor color, PropertyChangeReason reason) = 0; + virtual void SetClipRectFromAnimation(const gfx::Rect& clip_rect, + PropertyChangeReason reason) = 0; virtual void ScheduleDrawForAnimation() = 0; virtual const gfx::Rect& GetBoundsForAnimation() const = 0; virtual gfx::Transform GetTransformForAnimation() const = 0; @@ -46,6 +48,7 @@ virtual float GetBrightnessForAnimation() const = 0; virtual float GetGrayscaleForAnimation() const = 0; virtual SkColor GetColorForAnimation() const = 0; + virtual gfx::Rect GetClipRectForAnimation() const = 0; virtual float GetDeviceScaleFactor() const = 0; virtual ui::Layer* GetLayer() = 0; virtual cc::Layer* GetCcLayer() const = 0;
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc index 3d965dd..2c7b44e 100644 --- a/ui/compositor/layer_animation_element.cc +++ b/ui/compositor/layer_animation_element.cc
@@ -269,6 +269,40 @@ DISALLOW_COPY_AND_ASSIGN(ColorTransition); }; +// ClipRectTransition ---------------------------------------------------------- + +class ClipRectTransition : public LayerAnimationElement { + public: + ClipRectTransition(const gfx::Rect& target, base::TimeDelta duration) + : LayerAnimationElement(CLIP, duration), target_(target) {} + ~ClipRectTransition() override {} + + protected: + std::string DebugName() const override { return "ClipRectTransition"; } + void OnStart(LayerAnimationDelegate* delegate) override { + start_ = delegate->GetClipRectForAnimation(); + } + + bool OnProgress(double t, LayerAnimationDelegate* delegate) override { + delegate->SetClipRectFromAnimation( + gfx::Tween::RectValueBetween(t, start_, target_), + PropertyChangeReason::FROM_ANIMATION); + return true; + } + + void OnGetTarget(TargetValue* target) const override { + target->clip_rect = target_; + } + + void OnAbort(LayerAnimationDelegate* delegate) override {} + + private: + gfx::Rect start_; + const gfx::Rect target_; + + DISALLOW_COPY_AND_ASSIGN(ClipRectTransition); +}; + // ThreadedLayerAnimationElement ----------------------------------------------- class ThreadedLayerAnimationElement : public LayerAnimationElement { @@ -487,8 +521,8 @@ visibility(delegate ? delegate->GetVisibilityForAnimation() : false), brightness(delegate ? delegate->GetBrightnessForAnimation() : 0.0f), grayscale(delegate ? delegate->GetGrayscaleForAnimation() : 0.0f), - color(delegate ? delegate->GetColorForAnimation() : SK_ColorTRANSPARENT) { -} + color(delegate ? delegate->GetColorForAnimation() : SK_ColorTRANSPARENT), + clip_rect(delegate ? delegate->GetClipRectForAnimation() : gfx::Rect()) {} // LayerAnimationElement ------------------------------------------------------- @@ -698,6 +732,9 @@ case COLOR: str.append("COLOR"); break; + case CLIP: + str.append("CLIP"); + break; case SENTINEL: NOTREACHED(); break; @@ -793,4 +830,10 @@ return std::make_unique<ColorTransition>(color, duration); } +std::unique_ptr<LayerAnimationElement> +LayerAnimationElement::CreateClipRectElement(const gfx::Rect& clip_rect, + base::TimeDelta duration) { + return std::make_unique<ClipRectTransition>(clip_rect, duration); +} + } // namespace ui
diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h index 5088f879..9c5df9b 100644 --- a/ui/compositor/layer_animation_element.h +++ b/ui/compositor/layer_animation_element.h
@@ -46,10 +46,11 @@ BRIGHTNESS = (1 << 4), GRAYSCALE = (1 << 5), COLOR = (1 << 6), + CLIP = (1 << 7), // Used when iterating over properties. FIRST_PROPERTY = TRANSFORM, - SENTINEL = (1 << 7) + SENTINEL = (1 << 8) }; static AnimatableProperty ToAnimatableProperty( @@ -67,6 +68,7 @@ float brightness; float grayscale; SkColor color; + gfx::Rect clip_rect; }; typedef uint32_t AnimatableProperties; @@ -139,6 +141,12 @@ SkColor color, base::TimeDelta duration); + // Creates an element that transitions the clip rect of the layer to the given + // bounds. The caller owns the return value. + static std::unique_ptr<LayerAnimationElement> CreateClipRectElement( + const gfx::Rect& clip_rect, + base::TimeDelta duration); + // Sets the start time for the animation. This must be called before the first // call to {Start, IsFinished}. Once the animation is finished, this must // be called again in order to restart the animation.
diff --git a/ui/compositor/layer_animation_element_unittest.cc b/ui/compositor/layer_animation_element_unittest.cc index 664daed..22a3b22 100644 --- a/ui/compositor/layer_animation_element_unittest.cc +++ b/ui/compositor/layer_animation_element_unittest.cc
@@ -31,6 +31,7 @@ const float kBrightness = 2.358f; const float kGrayscale = 2.5813f; const SkColor kColor = SK_ColorCYAN; + const gfx::Rect kClipRect(2, 3, 4, 5); TestLayerAnimationDelegate delegate; delegate.SetBoundsFromAnimation(kBounds, @@ -47,6 +48,8 @@ PropertyChangeReason::NOT_FROM_ANIMATION); delegate.SetColorFromAnimation(kColor, PropertyChangeReason::NOT_FROM_ANIMATION); + delegate.SetClipRectFromAnimation(kClipRect, + PropertyChangeReason::NOT_FROM_ANIMATION); LayerAnimationElement::TargetValue target_value(&delegate); @@ -57,6 +60,7 @@ EXPECT_FLOAT_EQ(kBrightness, target_value.brightness); EXPECT_FLOAT_EQ(kGrayscale, target_value.grayscale); EXPECT_EQ(SK_ColorCYAN, target_value.color); + EXPECT_EQ(kClipRect, target_value.clip_rect); } // Check that the transformation element progresses the delegate as expected and @@ -365,6 +369,57 @@ copy.GetGrayscaleForAnimation()); } +// Check that the ClipRect element progresses the delegate as expected and +// that the element can be reused after it completes. +TEST(LayerAnimationElementTest, ClipRectElement) { + TestLayerAnimationDelegate delegate; + gfx::Rect start, target, middle; + start = target = middle = gfx::Rect(0, 0, 50, 50); + + start.set_x(-10); + target.set_x(10); + + start.set_y(-20); + target.set_y(20); + + start.set_width(70); + target.set_width(30); + base::TimeTicks start_time; + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + + std::unique_ptr<LayerAnimationElement> element = + LayerAnimationElement::CreateClipRectElement(target, delta); + + for (int i = 0; i < 2; ++i) { + start_time += delta; + element->set_requested_start_time(start_time); + delegate.SetClipRectFromAnimation(start, + PropertyChangeReason::NOT_FROM_ANIMATION); + element->Start(&delegate, 1); + element->Progress(start_time, &delegate); + CheckApproximatelyEqual(start, delegate.GetClipRectForAnimation()); + delegate.ExpectLastPropertyChangeReason( + PropertyChangeReason::FROM_ANIMATION); + element->Progress(start_time + delta / 2, &delegate); + CheckApproximatelyEqual(middle, delegate.GetClipRectForAnimation()); + delegate.ExpectLastPropertyChangeReason( + PropertyChangeReason::FROM_ANIMATION); + + base::TimeDelta element_duration; + EXPECT_TRUE(element->IsFinished(start_time + delta, &element_duration)); + EXPECT_EQ(delta, element_duration); + + element->Progress(start_time + delta, &delegate); + CheckApproximatelyEqual(target, delegate.GetClipRectForAnimation()); + delegate.ExpectLastPropertyChangeReason( + PropertyChangeReason::FROM_ANIMATION); + } + + LayerAnimationElement::TargetValue target_value(&delegate); + element->GetTargetValue(&target_value); + CheckApproximatelyEqual(target, target_value.clip_rect); +} + // Check that a threaded opacity element updates the delegate as expected when // aborted. TEST(LayerAnimationElementTest, AbortOpacityElement) {
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc index c82b179..3b42c54 100644 --- a/ui/compositor/layer_animator.cc +++ b/ui/compositor/layer_animator.cc
@@ -120,6 +120,7 @@ ANIMATED_PROPERTY(float, BRIGHTNESS, Brightness, float, brightness) ANIMATED_PROPERTY(float, GRAYSCALE, Grayscale, float, grayscale) ANIMATED_PROPERTY(SkColor, COLOR, Color, SkColor, color) +ANIMATED_PROPERTY(const gfx::Rect&, CLIP, ClipRect, gfx::Rect, clip_rect) #undef ANIMATED_PROPERTY
diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h index 842f111..0d555b3 100644 --- a/ui/compositor/layer_animator.h +++ b/ui/compositor/layer_animator.h
@@ -100,6 +100,10 @@ virtual void SetColor(SkColor color); SkColor GetTargetColor() const; + // Sets the clip rect on the delegate. May cause an implicit animation. + virtual void SetClipRect(const gfx::Rect& clip_rect); + gfx::Rect GetTargetClipRect() const; + // Returns the default length of animations, including adjustment for slow // animation mode if set. base::TimeDelta GetTransitionDuration() const;
diff --git a/ui/compositor/test/test_layer_animation_delegate.cc b/ui/compositor/test/test_layer_animation_delegate.cc index d4ae03be..e8781fd 100644 --- a/ui/compositor/test/test_layer_animation_delegate.cc +++ b/ui/compositor/test/test_layer_animation_delegate.cc
@@ -109,6 +109,14 @@ last_property_change_reason_is_set_ = true; } +void TestLayerAnimationDelegate::SetClipRectFromAnimation( + const gfx::Rect& clip_rect, + PropertyChangeReason reason) { + clip_rect_ = clip_rect; + last_property_change_reason_ = reason; + last_property_change_reason_is_set_ = true; +} + void TestLayerAnimationDelegate::ScheduleDrawForAnimation() { } @@ -140,6 +148,10 @@ return color_; } +gfx::Rect TestLayerAnimationDelegate::GetClipRectForAnimation() const { + return clip_rect_; +} + float TestLayerAnimationDelegate::GetDeviceScaleFactor() const { return 1.0f; }
diff --git a/ui/compositor/test/test_layer_animation_delegate.h b/ui/compositor/test/test_layer_animation_delegate.h index ea9ed71a..2bac9f25 100644 --- a/ui/compositor/test/test_layer_animation_delegate.h +++ b/ui/compositor/test/test_layer_animation_delegate.h
@@ -60,6 +60,8 @@ PropertyChangeReason reason) override; void SetColorFromAnimation(SkColor color, PropertyChangeReason reason) override; + void SetClipRectFromAnimation(const gfx::Rect& clip_rect, + PropertyChangeReason reason) override; void ScheduleDrawForAnimation() override; const gfx::Rect& GetBoundsForAnimation() const override; gfx::Transform GetTransformForAnimation() const override; @@ -68,6 +70,7 @@ float GetBrightnessForAnimation() const override; float GetGrayscaleForAnimation() const override; SkColor GetColorForAnimation() const override; + gfx::Rect GetClipRectForAnimation() const override; float GetDeviceScaleFactor() const override; LayerAnimatorCollection* GetLayerAnimatorCollection() override; ui::Layer* GetLayer() override; @@ -92,6 +95,7 @@ float brightness_; float grayscale_; SkColor color_; + gfx::Rect clip_rect_; scoped_refptr<cc::Layer> cc_layer_; int frame_number_ = 0;
diff --git a/ui/file_manager/externs/entry_location.js b/ui/file_manager/externs/entry_location.js index b78a238..7174733 100644 --- a/ui/file_manager/externs/entry_location.js +++ b/ui/file_manager/externs/entry_location.js
@@ -7,49 +7,51 @@ * file system. * @interface */ -function EntryLocation() {} +class EntryLocation { + constructor() { + /** + * Volume information. + * @type {!VolumeInfo} + */ + this.volumeInfo; -/** - * Volume information. - * @type {!VolumeInfo} - */ -EntryLocation.prototype.volumeInfo; + /** + * Root type. + * @type {VolumeManagerCommon.RootType} + */ + this.rootType; -/** - * Root type. - * @type {VolumeManagerCommon.RootType} - */ -EntryLocation.prototype.rootType; + /** + * Whether the entry is root entry or not. + * @type {boolean} + */ + this.isRootEntry; -/** - * Whether the entry is root entry or not. - * @type {boolean} - */ -EntryLocation.prototype.isRootEntry; + /** + * Whether the location obtained from the fake entry corresponds to special + * searches. + * @type {boolean} + */ + this.isSpecialSearchRoot; -/** - * Whether the location obtained from the fake entry corresponds to special - * searches. - * @type {boolean} - */ -EntryLocation.prototype.isSpecialSearchRoot; + /** + * Whether the location is under Google Drive or a special search root which + * represents a special search from Google Drive. + * @type {boolean} + */ + this.isDriveBased; -/** - * Whether the location is under Google Drive or a special search root which - * represents a special search from Google Drive. - * @type {boolean} - */ -EntryLocation.prototype.isDriveBased; + /** + * Whether the entry is read only or not. + * @type {boolean} + */ + this.isReadOnly; -/** - * Whether the entry is read only or not. - * @type {boolean} - */ -EntryLocation.prototype.isReadOnly; - -/** - * Whether the entry should be displayed with a fixed name instead of individual - * entry's name. (e.g. "Downloads" is a fixed name) - * @type {boolean} - */ -EntryLocation.prototype.hasFixedLabel; + /** + * Whether the entry should be displayed with a fixed name instead of + * individual entry's name. (e.g. "Downloads" is a fixed name) + * @type {boolean} + */ + this.hasFixedLabel; + } +}
diff --git a/ui/file_manager/file_manager/background/js/entry_location_impl.js b/ui/file_manager/file_manager/background/js/entry_location_impl.js index 90213cf..9c369a7 100644 --- a/ui/file_manager/file_manager/background/js/entry_location_impl.js +++ b/ui/file_manager/file_manager/background/js/entry_location_impl.js
@@ -6,49 +6,52 @@ * Location information which shows where the path points in FileManager's * file system. * - * @param {VolumeInfo} volumeInfo Volume information. - * @param {VolumeManagerCommon.RootType} rootType Root type. - * @param {boolean} isRootEntry Whether the entry is root entry or not. - * @param {boolean} isReadOnly Whether the entry is read only or not. - * @constructor * @implements {EntryLocation} */ -function EntryLocationImpl(volumeInfo, rootType, isRootEntry, isReadOnly) { - /** @override */ - this.volumeInfo = volumeInfo; +class EntryLocationImpl { + /** + * @param {VolumeInfo} volumeInfo Volume information. + * @param {VolumeManagerCommon.RootType} rootType Root type. + * @param {boolean} isRootEntry Whether the entry is root entry or not. + * @param {boolean} isReadOnly Whether the entry is read only or not. + */ + constructor(volumeInfo, rootType, isRootEntry, isReadOnly) { + /** @override */ + this.volumeInfo = volumeInfo; - /** @override */ - this.rootType = rootType; + /** @override */ + this.rootType = rootType; - /** @override */ - this.isRootEntry = isRootEntry; + /** @override */ + this.isRootEntry = isRootEntry; - /** @override */ - this.isSpecialSearchRoot = - this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || - this.rootType === VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME || - this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT || - this.rootType === VolumeManagerCommon.RootType.RECENT; + /** @override */ + this.isSpecialSearchRoot = + this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || + this.rootType === VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME || + this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT || + this.rootType === VolumeManagerCommon.RootType.RECENT; - /** @override */ - this.isDriveBased = this.rootType === VolumeManagerCommon.RootType.DRIVE || - this.rootType === VolumeManagerCommon.RootType.DRIVE_OTHER || - this.rootType === VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME || - this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT || - this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || - this.rootType === VolumeManagerCommon.RootType.SHARED_DRIVES_GRAND_ROOT || - this.rootType === VolumeManagerCommon.RootType.SHARED_DRIVE || - this.rootType === VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT || - this.rootType === VolumeManagerCommon.RootType.COMPUTER; + /** @override */ + this.isDriveBased = this.rootType === VolumeManagerCommon.RootType.DRIVE || + this.rootType === VolumeManagerCommon.RootType.DRIVE_OTHER || + this.rootType === VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME || + this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT || + this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || + this.rootType === + VolumeManagerCommon.RootType.SHARED_DRIVES_GRAND_ROOT || + this.rootType === VolumeManagerCommon.RootType.SHARED_DRIVE || + this.rootType === VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT || + this.rootType === VolumeManagerCommon.RootType.COMPUTER; - /** @override */ - this.isReadOnly = isReadOnly; + /** @override */ + this.isReadOnly = isReadOnly; - /** @type{boolean} */ - this.hasFixedLabel = this.isRootEntry && - (rootType !== VolumeManagerCommon.RootType.SHARED_DRIVE && - rootType !== VolumeManagerCommon.RootType.COMPUTER && - rootType !== VolumeManagerCommon.RootType.REMOVABLE); - - Object.freeze(this); + /** @type{boolean} */ + this.hasFixedLabel = this.isRootEntry && + (rootType !== VolumeManagerCommon.RootType.SHARED_DRIVE && + rootType !== VolumeManagerCommon.RootType.COMPUTER && + rootType !== VolumeManagerCommon.RootType.REMOVABLE); + Object.freeze(this); + } }
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js index 192d493..33bbabb 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_contents.js +++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -106,6 +106,10 @@ } chrome.fileManagerPrivate.searchDrive( {query: this.query_, nextFeed: ''}, (entries, nextFeed) => { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError.message); + } + if (this.cancelled_) { errorCallback(util.createDOMError(util.FileError.ABORT_ERR)); return; @@ -202,6 +206,9 @@ scan(entriesCallback, successCallback, errorCallback) { chrome.fileManagerPrivate.searchDriveMetadata( {query: '', types: this.searchType_, maxResults: 100}, results => { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError.message); + } if (this.cancelled_) { errorCallback(util.createDOMError(util.FileError.ABORT_ERR)); return;
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js index 234d2d0..305f59f 100644 --- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js +++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -872,17 +872,17 @@ // Mount removable volumes. await sendTestMessage({name: 'mountUsbWithPartitions'}); - await sendTestMessage({name: 'mountFakeUsb'}); + await sendTestMessage({name: 'mountFakeUsb', filesystem: 'ext4'}); // Open Files app on local Downloads. const appId = await setupAndWaitUntilReady( RootPath.DOWNLOADS, [ENTRIES.beautiful], []); - // Check the context menu for single partition USB. + // Check the context menu for single partition ext4 USB. await checkContextMenu( appId, '/fake-usb', singleUsbMenus, true /* rootMenu */); - // Check the context menu for a folder inside a singlue USB partition. + // Check the context menu for a folder inside a single USB partition. await checkContextMenu( appId, '/fake-usb/A', folderMenus, false /* rootMenu */); @@ -897,8 +897,7 @@ // Check the context menu for a folder inside a partition1. await checkContextMenu( - appId, '/Drive Label/partition-1/Folder', folderMenus, - false /* rootMenu */); + appId, '/Drive Label/partition-1/A', folderMenus, false /* rootMenu */); }; /**
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.js b/ui/file_manager/integration_tests/file_manager/file_display.js index 428f8ea..3b5f474 100644 --- a/ui/file_manager/integration_tests/file_manager/file_display.js +++ b/ui/file_manager/integration_tests/file_manager/file_display.js
@@ -766,10 +766,7 @@ if (removableDirectory === 'partition-1' || removableDirectory === 'partition-2') { const partitionQuery = `#file-list [file-name="${removableDirectory}"]`; - const partitionFiles = [ - ENTRIES.hello.getExpectedRow(), - ['Folder', '--', 'Folder', Date()], - ]; + const partitionFiles = TestEntryInfo.getExpectedRows(BASIC_FAKE_ENTRY_SET); await remoteCall.callRemoteTestUtil( 'fakeMouseDoubleClick', appId, [partitionQuery]); await remoteCall.waitUntilCurrentDirectoryIsChanged(
diff --git a/ui/file_manager/integration_tests/file_manager/quick_view.js b/ui/file_manager/integration_tests/file_manager/quick_view.js index 8a73f3d..dc3bfde1 100644 --- a/ui/file_manager/integration_tests/file_manager/quick_view.js +++ b/ui/file_manager/integration_tests/file_manager/quick_view.js
@@ -221,11 +221,8 @@ 'fakeMouseClick', appId, [PARTITION_QUERY]), 'fakeMouseClick failed'); - // Check: the 'hello.txt' file should appear in the file list. - const files = [ - ENTRIES.hello.getExpectedRow(), - ['Folder', '--', 'Folder', Date()], - ]; + // Check: the USB files should appear in the file list. + const files = TestEntryInfo.getExpectedRows(BASIC_FAKE_ENTRY_SET); await remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true}); // Open the file in Quick View.
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js index 91c2c23..39052d3 100644 --- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js +++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
@@ -18,7 +18,7 @@ new chromeos.networkConfig.mojom.CrosNetworkConfigObserver(this); network_config.MojoInterfaceProviderImpl.getInstance() .getMojoServiceProxy() - .addObserver(this.observer_.createProxy()); + .addObserver(this.observer_.$.createProxy()); }, // CrosNetworkConfigObserver methods. Override these in the implementation.
diff --git a/ui/webui/resources/cr_elements/cr_button/cr_button.js b/ui/webui/resources/cr_elements/cr_button/cr_button.js index 301a0606..6f006f42 100644 --- a/ui/webui/resources/cr_elements/cr_button/cr_button.js +++ b/ui/webui/resources/cr_elements/cr_button/cr_button.js
@@ -37,9 +37,35 @@ tap: 'onTap_', }, + /** @private {Set<number>} */ + timeoutIds_: null, + /** @override */ ready: function() { cr.ui.FocusOutlineManager.forDocument(document); + this.timeoutIds_ = new Set(); + }, + + /** @override */ + detached: function() { + this.timeoutIds_.forEach(clearTimeout); + this.timeoutIds_.clear(); + }, + + /** + * @param {!Function} fn + * @param {number=} delay + * @private + */ + setTimeout_: function(fn, delay) { + if (!this.isConnected) { + return; + } + const id = setTimeout(() => { + this.timeoutIds_.delete(id); + fn(); + }, delay); + this.timeoutIds_.add(id); }, /** @@ -79,14 +105,17 @@ e.preventDefault(); e.stopPropagation(); + if (e.repeat) { return; } + this.getRipple().uiDownAction(); if (e.key == 'Enter') { this.click(); - } else { - this.getRipple().uiDownAction(); + // Delay was chosen manually as a good time period for the ripple to be + // visible. + this.setTimeout_(() => this.getRipple().uiUpAction(), 100); } }, @@ -95,11 +124,13 @@ * @private */ onKeyUp_: function(e) { - if (e.key == ' ' || e.key == 'Enter') { - e.preventDefault(); - e.stopPropagation(); + if (e.key != ' ' && e.key != 'Enter') { + return; } + e.preventDefault(); + e.stopPropagation(); + if (e.key == ' ') { this.click(); this.getRipple().uiUpAction();