diff --git a/.gn b/.gn index ddf99d1d..9dc1fd1 100644 --- a/.gn +++ b/.gn
@@ -66,6 +66,7 @@ "//extensions:*", # 28 errors "//headless:*", # 107 errors "//ppapi/proxy:ipc_sources", # 13 errors + "//remoting/host/security_key:*", # 10 errors "//third_party/icu/*", "//third_party/libwebp:*", # 7 errors, https://crbug.com/800762
diff --git a/DEPS b/DEPS index a0ff6d8d..0273f608 100644 --- a/DEPS +++ b/DEPS
@@ -213,7 +213,7 @@ 'dawn_standalone': False, # reclient CIPD package version - 'reclient_version': 're_client_version:0.37.0.c6161fa', + 'reclient_version': 're_client_version:0.38.0.5f131f2-gomaip', 'android_git': 'https://android.googlesource.com', 'aomedia_git': 'https://aomedia.googlesource.com', @@ -228,11 +228,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': 'eb342e13d0ed4cdba262bbc8533fb271510a96fd', + 'skia_revision': 'b5de6be2a85db643be308096ee30cd70fa830ca0', # 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': '76d48acb02956cbee98234f32e7167a7750a0497', + 'v8_revision': 'f9a433890547bc1b65b837a8ffb96150a6cf3c6e', # 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. @@ -240,7 +240,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': 'd25c9d7f5bb02ec22e6b9f519e69dc84c4bb2150', + 'angle_revision': '8f214193940b2e7eda70746b7b42f96b0b4ce73b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -299,7 +299,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': 'b35ee4986edcfc8938f649d20906b4adb98a3cfe', + 'catapult_revision': 'abc7ba7d871fe3c25b0a1bec7fc84fb309034cb7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -347,7 +347,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': 'ebbbcc7ecb1cbbaf4c5c12b701c650244dfc7e20', + 'dawn_revision': '5d17ed6541afd44ffcc2e267d533ebd03354c75d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -403,11 +403,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libjxl_revision': '4a981fd8be383703ca8c5dc78c25411c14a01d9f', + 'libjxl_revision': 'c4e0877f93506e880cd922f6c94644d79ae9adff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'highway_revision': 'ca1a57c342cd815053abfcffa29b44eaead4f20b', + 'highway_revision': '424360251cdcfc314cfc528f53c872ecd63af0f0', # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. @@ -550,7 +550,7 @@ 'packages': [ { 'package': 'chromium/chrome/test/data/enterprise/connectors/file_system/captured_sites', - 'version': 'pthwS0AAeS_iCyAZGv69ts0CMdoRfU_3DhdKbghyExwC', + 'version': 'kJXdHLymr3WKkC6vLmnQXgBtrAa6i33T63g3hcxUGoIC', } ], 'condition': 'checkout_chromium_fsc_test_dependencies', @@ -610,7 +610,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'c45ee22cb4f6f56a7afca1e1ce66942e77672a65', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'b156c37d0faa70c2dc8d137f198dc28f174cf237', 'condition': 'checkout_ios', }, @@ -767,7 +767,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '2x0RaVwBwxRoEqsOfKvBqGyoI_asDh5FLRC5F_o9PiYC', + 'version': '5FmojmYp53y0XBXcZuz3Mglv3JiYPGYex2LMT6kbzv8C', }, ], 'condition': 'checkout_android', @@ -1003,7 +1003,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4f3583d6d585894cc99481e7ab850c65e864f968', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '49a703f3d915b140c9f373107e1ba17f30e2487d', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1682,7 +1682,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0e8a492cf58f73346ac71ef2fceb7a94580f9b32', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f416b8e9038f7ca88ddd2c83e37f892acff4005c', 'condition': 'checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 155708e..8ef9e66d 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2583,7 +2583,6 @@ "//ui/aura:test_support", "//ui/base", "//ui/base:test_support", - "//ui/base/cursor", "//ui/base/cursor:cursor_base", "//ui/base/cursor/mojom:cursor_type", "//ui/base/dragdrop:types", @@ -2607,7 +2606,6 @@ "//ui/events/devices", "//ui/events/devices:test_support", "//ui/gfx", - "//ui/gfx:geometry_skia", "//ui/gfx:test_support", "//ui/gfx/geometry", "//ui/gl:test_support",
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc index e531a72..20b727d 100644 --- a/ash/app_list/app_list_presenter_unittest.cc +++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -1081,6 +1081,208 @@ EXPECT_EQ("Item 2", apps_grid_view_->GetItemViewAt(2)->item()->id()); } +// Tests that app list item drag gets canceled if the dragged app list item gets +// deleted. +TEST_P(PopulatedAppListTest, CancelItemDragOnDragItemDeletion) { + InitializeAppsGrid(); + app_list_test_model_->PopulateApps(4); + + // Start dragging a view. + AppListItemView* const dragged_view = apps_grid_view_->GetItemViewAt(0); + ui::test::EventGenerator* event_generator = GetEventGenerator(); + event_generator->MoveMouseTo(dragged_view->GetBoundsInScreen().CenterPoint()); + event_generator->PressLeftButton(); + dragged_view->FireMouseDragTimerForTest(); + event_generator->MoveMouseTo( + apps_grid_view_->GetItemViewAt(2)->GetBoundsInScreen().left_center()); + EXPECT_TRUE(apps_grid_view_->IsDragging()); + + // Delete the dragged item. + app_list_test_model_->DeleteUninstalledItem(dragged_view->item()->id()); + EXPECT_FALSE(apps_grid_view_->IsDragging()); + + // Verify that mouse drag has been canceled. + EXPECT_FALSE(apps_grid_view_->IsDragging()); + + EXPECT_EQ("Item 1", apps_grid_view_->GetItemViewAt(0)->item()->id()); + EXPECT_EQ("Item 2", apps_grid_view_->GetItemViewAt(1)->item()->id()); + EXPECT_EQ("Item 3", apps_grid_view_->GetItemViewAt(2)->item()->id()); + + // Hide and show the app list again to verify checks done when resetting the + // apps grid for show pass (e.g. verification that size of the app list views + // model matches the size of app list data model). + AppListTestHelper* helper = GetAppListTestHelper(); + helper->ShowAndRunLoop(GetPrimaryDisplay().id()); + helper->DismissAndRunLoop(); +} + +// Tests that app list item drag in folder gets canceled if the dragged app list +// item gets deleted. +TEST_P(PopulatedAppListTest, CancelFolderItemDragOnDragItemDeletion) { + InitializeAppsGrid(); + app_list_test_model_->PopulateApps(2); + AppListFolderItem* folder = + app_list_test_model_->CreateAndPopulateFolderWithApps(3); + app_list_test_model_->PopulateApps(3); + + // Tap the folder item to show it. + ui::test::EventGenerator* event_generator = GetEventGenerator(); + event_generator->GestureTapAt( + apps_grid_view_->GetItemViewAt(2)->GetBoundsInScreen().CenterPoint()); + ASSERT_TRUE(AppListIsInFolderView()); + + // Start dragging the first item in the active folder. + AppListItemView* const dragged_view = + folder_view()->items_grid_view()->GetItemViewAt(0); + event_generator->MoveTouch(dragged_view->GetBoundsInScreen().CenterPoint()); + event_generator->PressTouch(); + ASSERT_TRUE(dragged_view->FireTouchDragTimerForTest()); + event_generator->MoveTouchBy(10, 10); + + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_TRUE(folder_view()->items_grid_view()->IsDragging()); + + // Delete the dragged item. + app_list_test_model_->DeleteUninstalledItem(dragged_view->item()->id()); + + // Verify that drag has been canceled. + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_FALSE(folder_view()->items_grid_view()->IsDragging()); + + EXPECT_EQ("Item 0", apps_grid_view_->GetItemViewAt(0)->item()->id()); + EXPECT_EQ("Item 1", apps_grid_view_->GetItemViewAt(1)->item()->id()); + EXPECT_EQ(folder->id(), apps_grid_view_->GetItemViewAt(2)->item()->id()); + EXPECT_EQ("Item 3", + folder_view()->items_grid_view()->GetItemViewAt(0)->item()->id()); + + // Hide and show the app list again to verify checks done when resetting the + // apps grid for show pass (e.g. verification that size of the app list views + // model matches the size of app list data model). + AppListTestHelper* helper = GetAppListTestHelper(); + helper->ShowAndRunLoop(GetPrimaryDisplay().id()); + helper->DismissAndRunLoop(); +} + +// Tests that app list item drag from folder to root apps grid gets canceled if +// the dragged app list item gets deleted. +TEST_P(PopulatedAppListTest, CancelFolderItemReparentDragOnDragItemDeletion) { + InitializeAppsGrid(); + app_list_test_model_->PopulateApps(2); + AppListFolderItem* folder = + app_list_test_model_->CreateAndPopulateFolderWithApps(3); + app_list_test_model_->PopulateApps(3); + + // Tap the folder item to show it. + ui::test::EventGenerator* event_generator = GetEventGenerator(); + event_generator->GestureTapAt( + apps_grid_view_->GetItemViewAt(2)->GetBoundsInScreen().CenterPoint()); + ASSERT_TRUE(AppListIsInFolderView()); + + // Start dragging the first item in the active folder. + AppListItemView* const dragged_view = + folder_view()->items_grid_view()->GetItemViewAt(0); + event_generator->MoveTouch(dragged_view->GetBoundsInScreen().CenterPoint()); + event_generator->PressTouch(); + ASSERT_TRUE(dragged_view->FireTouchDragTimerForTest()); + event_generator->MoveTouchBy(10, 10); + + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_TRUE(folder_view()->items_grid_view()->IsDragging()); + + // Drag the item outside the folder bounds. + event_generator->MoveTouch( + apps_grid_view_->GetItemViewAt(1)->GetBoundsInScreen().CenterPoint()); + event_generator->MoveTouchBy(2, 2); + + // Fire reparenting timer. + EXPECT_TRUE( + folder_view()->items_grid_view()->FireFolderItemReparentTimerForTest()); + EXPECT_FALSE(AppListIsInFolderView()); + event_generator->MoveTouch( + apps_grid_view_->GetItemViewAt(3)->GetBoundsInScreen().CenterPoint()); + + EXPECT_TRUE(apps_grid_view_->IsDragging()); + EXPECT_TRUE(folder_view()->items_grid_view()->IsDragging()); + + // Delete the dragged item. + app_list_test_model_->DeleteUninstalledItem(dragged_view->item()->id()); + + // Verify that drag has been canceled. + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_FALSE(folder_view()->items_grid_view()->IsDragging()); + + EXPECT_EQ("Item 0", apps_grid_view_->GetItemViewAt(0)->item()->id()); + EXPECT_EQ("Item 1", apps_grid_view_->GetItemViewAt(1)->item()->id()); + EXPECT_EQ(folder->id(), apps_grid_view_->GetItemViewAt(2)->item()->id()); + EXPECT_EQ("Item 5", apps_grid_view_->GetItemViewAt(3)->item()->id()); + + // Hide and show the app list again to verify checks done when resetting the + // apps grid for show pass (e.g. verification that size of the app list views + // model matches the size of app list data model). + AppListTestHelper* helper = GetAppListTestHelper(); + helper->ShowAndRunLoop(GetPrimaryDisplay().id()); + helper->DismissAndRunLoop(); +} + +TEST_P(PopulatedAppListTest, + CancelFolderItemReparentDragOnDragItemAndFolderDeletion) { + InitializeAppsGrid(); + app_list_test_model_->PopulateApps(2); + app_list_test_model_->CreateAndPopulateFolderWithApps(2); + app_list_test_model_->PopulateApps(3); + + // Tap the folder item to show it. + ui::test::EventGenerator* event_generator = GetEventGenerator(); + event_generator->GestureTapAt( + apps_grid_view_->GetItemViewAt(2)->GetBoundsInScreen().CenterPoint()); + ASSERT_TRUE(AppListIsInFolderView()); + + // Start dragging the first item in the active folder. + AppListItemView* const dragged_view = + folder_view()->items_grid_view()->GetItemViewAt(0); + event_generator->MoveTouch(dragged_view->GetBoundsInScreen().CenterPoint()); + event_generator->PressTouch(); + ASSERT_TRUE(dragged_view->FireTouchDragTimerForTest()); + event_generator->MoveTouchBy(10, 10); + + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_TRUE(folder_view()->items_grid_view()->IsDragging()); + + // Drag the item outside the folder bounds. + event_generator->MoveTouch( + apps_grid_view_->GetItemViewAt(1)->GetBoundsInScreen().CenterPoint()); + event_generator->MoveTouchBy(2, 2); + + // Fire reparenting timer. + EXPECT_TRUE( + folder_view()->items_grid_view()->FireFolderItemReparentTimerForTest()); + EXPECT_FALSE(AppListIsInFolderView()); + event_generator->MoveTouch( + apps_grid_view_->GetItemViewAt(3)->GetBoundsInScreen().CenterPoint()); + + EXPECT_TRUE(apps_grid_view_->IsDragging()); + EXPECT_TRUE(folder_view()->items_grid_view()->IsDragging()); + + // Delete the dragged item. + app_list_test_model_->DeleteUninstalledItem(dragged_view->item()->id()); + + // Verify that drag has been canceled. + EXPECT_FALSE(apps_grid_view_->IsDragging()); + EXPECT_FALSE(folder_view()->items_grid_view()->IsDragging()); + + EXPECT_EQ("Item 0", apps_grid_view_->GetItemViewAt(0)->item()->id()); + EXPECT_EQ("Item 1", apps_grid_view_->GetItemViewAt(1)->item()->id()); + EXPECT_EQ("Item 3", apps_grid_view_->GetItemViewAt(2)->item()->id()); + EXPECT_EQ("Item 4", apps_grid_view_->GetItemViewAt(3)->item()->id()); + + // Hide and show the app list again to verify checks done when resetting the + // apps grid for show pass (e.g. verification that size of the app list views + // model matches the size of app list data model). + AppListTestHelper* helper = GetAppListTestHelper(); + helper->ShowAndRunLoop(GetPrimaryDisplay().id()); + helper->DismissAndRunLoop(); +} + // Tests that apps grid item layers are not destroyed immediately after item // drag ends. TEST_P(PopulatedAppListTest,
diff --git a/ash/app_list/model/app_list_item_list.cc b/ash/app_list/model/app_list_item_list.cc index a5e6df4..f8aadaa 100644 --- a/ash/app_list/model/app_list_item_list.cc +++ b/ash/app_list/model/app_list_item_list.cc
@@ -178,6 +178,8 @@ << item_count() << " add index " << index; app_list_items_.insert(app_list_items_.begin() + index, std::move(page_break_item)); + for (auto& observer : observers_) + observer.OnListItemAdded(index, item); return item; }
diff --git a/ash/app_list/paged_view_structure.cc b/ash/app_list/paged_view_structure.cc index 43b22ec..9dbb8c63 100644 --- a/ash/app_list/paged_view_structure.cc +++ b/ash/app_list/paged_view_structure.cc
@@ -303,7 +303,7 @@ } int PagedViewStructure::GetTargetModelIndexForMove( - AppListItemView* moved_view, + AppListItem* moved_item, const GridIndex& index) const { if (mode_ == Mode::kSinglePage || mode_ == Mode::kFullPages) return GetModelIndexFromIndex(index); @@ -317,8 +317,12 @@ // Skip the item view to be moved in the page if found. // Decrement |target_model_index| if |moved_view| is in this page because it // is represented by a placeholder. - auto iter = std::find(page.begin(), page.end(), moved_view); - if (iter != page.end()) + auto it = + std::find_if(page.begin(), page.end(), [&](AppListItemView* item_view) { + return item_view->item() == moved_item; + }); + + if (it != page.end()) --target_model_index; } @@ -329,7 +333,7 @@ } int PagedViewStructure::GetTargetItemListIndexForMove( - AppListItemView* moved_view, + AppListItem* moved_item, const GridIndex& index) const { if (mode_ == Mode::kFullPages) return GetModelIndexFromIndex(index); @@ -371,7 +375,7 @@ while (current_item_index < item_list->item_count() && !item_list->item_at(current_item_index)->is_page_break() && current_index != index) { - if (moved_view->item() == item_list->item_at(current_item_index) && + if (moved_item && moved_item == item_list->item_at(current_item_index) && current_index.page < index.page) { // If the item view is moved to a following page, we need to skip the // item view. If the view is moved to the same page, do not skip the
diff --git a/ash/app_list/paged_view_structure.h b/ash/app_list/paged_view_structure.h index 1d69505..b3f0426 100644 --- a/ash/app_list/paged_view_structure.h +++ b/ash/app_list/paged_view_structure.h
@@ -15,6 +15,7 @@ namespace ash { class AppsGridView; +class AppListItem; class AppListItemView; struct GridIndex; @@ -102,12 +103,12 @@ // Returns the target model index if moving the item view to specified target // visual index. - int GetTargetModelIndexForMove(AppListItemView* moved_view, + int GetTargetModelIndexForMove(AppListItem* moved_item, const GridIndex& index) const; // Returns the target `AppsGridView::item_list_` index if moving the item view // to specified target visual index. - int GetTargetItemListIndexForMove(AppListItemView* moved_view, + int GetTargetItemListIndexForMove(AppListItem* moved_item, const GridIndex& index) const; // Returns true if the visual index is valid position to which an item view
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index b971ad0..078d06dc 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -248,8 +248,7 @@ const AppListItem* top_item = folder_view_->folder_item()->item_list()->item_at(i); if (top_item->GetIcon(folder_view_->GetAppListConfig().type()).isNull() || - (folder_view_->items_grid_view()->drag_view() && - top_item == folder_view_->items_grid_view()->drag_view()->item())) { + top_item == folder_view_->items_grid_view()->drag_item()) { // The item being dragged should be excluded. continue; }
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 264977e..d69c0e23 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -1096,6 +1096,10 @@ DCHECK(item_weak_); item_weak_->RemoveObserver(this); item_weak_ = nullptr; + + // `EndDrag()` may delete this. + if (drag_state_ != DragState::kNone) + grid_delegate_->EndDrag(/*cancel=*/true); } int AppListItemView::GetPreviewCircleRadius() const {
diff --git a/ash/app_list/views/app_list_main_view_unittest.cc b/ash/app_list/views/app_list_main_view_unittest.cc index fe034c98..f34e90e 100644 --- a/ash/app_list/views/app_list_main_view_unittest.cc +++ b/ash/app_list/views/app_list_main_view_unittest.cc
@@ -377,19 +377,19 @@ AppListItemView* dragged = StartDragForReparent(0); // Now add an item to the model, not in any folder, e.g., as if by Sync. - EXPECT_TRUE(GetRootGridView()->has_dragged_view()); - EXPECT_TRUE(GetFolderGridView()->has_dragged_view()); + EXPECT_TRUE(GetRootGridView()->has_dragged_item()); + EXPECT_TRUE(GetFolderGridView()->has_dragged_item()); delegate_->GetTestModel()->CreateAndAddItem("Extra"); // The drag operation should get canceled. - EXPECT_FALSE(GetRootGridView()->has_dragged_view()); - EXPECT_FALSE(GetFolderGridView()->has_dragged_view()); + EXPECT_FALSE(GetRootGridView()->has_dragged_item()); + EXPECT_FALSE(GetFolderGridView()->has_dragged_item()); // Additional mouse move operations should be ignored. gfx::Point point(1, 1); SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged, point); - EXPECT_FALSE(GetRootGridView()->has_dragged_view()); - EXPECT_FALSE(GetFolderGridView()->has_dragged_view()); + EXPECT_FALSE(GetRootGridView()->has_dragged_item()); + EXPECT_FALSE(GetFolderGridView()->has_dragged_item()); } // Test that dragging an app out of a single item folder and reparenting it
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 27c066a..34ed200e 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -150,28 +150,6 @@ DISALLOW_COPY_AND_ASSIGN(RowMoveAnimationDelegate); }; -// ItemRemoveAnimationDelegate is used to show animation for removing an item. -// This happens when user drags an item into a folder. The dragged item will -// be removed from the original list after it is dropped into the folder. -class ItemRemoveAnimationDelegate : public views::AnimationDelegateViews { - public: - explicit ItemRemoveAnimationDelegate(views::View* view) - : views::AnimationDelegateViews(view), view_(view) {} - - ~ItemRemoveAnimationDelegate() override = default; - - // views::AnimationDelegateViews: - void AnimationProgressed(const gfx::Animation* animation) override { - view_->layer()->SetOpacity(1 - animation->GetCurrentValue()); - view_->layer()->ScheduleDraw(); - } - - private: - std::unique_ptr<views::View> view_; - - DISALLOW_COPY_AND_ASSIGN(ItemRemoveAnimationDelegate); -}; - bool IsOEMFolderItem(AppListItem* item) { return IsFolderItem(item) && (static_cast<AppListFolderItem*>(item))->folder_type() == @@ -274,6 +252,28 @@ this}; }; +// Class used by AppsGridView to track whether app list model is being updated +// by the AppsGridView (by setting `updating_model_`). While this is in scope, +// app list model changes will not cancel in progress drag, and will delay +// `view_structure_` sanitization until the app list model update finishes. +class AppsGridView::ScopedModelUpdate { + public: + explicit ScopedModelUpdate(AppsGridView* apps_grid_view) + : apps_grid_view_(apps_grid_view) { + apps_grid_view_->updating_model_ = true; + view_structure_sanitize_lock_ = + apps_grid_view_->view_structure_.GetSanitizeLock(); + } + ScopedModelUpdate(const ScopedModelUpdate&) = delete; + ScopedModelUpdate& operator=(const ScopedModelUpdate&) = delete; + ~ScopedModelUpdate() { apps_grid_view_->updating_model_ = false; } + + private: + AppsGridView* const apps_grid_view_; + std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> + view_structure_sanitize_lock_; +}; + AppsGridView::AppsGridView(ContentsView* contents_view, AppListA11yAnnouncer* a11y_announcer, AppListViewDelegate* app_list_view_delegate, @@ -312,8 +312,8 @@ // Coming here |drag_view_| should already be canceled since otherwise the // drag would disappear after the app list got animated away and closed, // which would look odd. - DCHECK(!drag_view_); - if (drag_view_) + DCHECK(!drag_item_); + if (drag_item_) EndDrag(true); if (model_) @@ -454,7 +454,7 @@ base::OnceClosure drag_start_callback, base::OnceClosure drag_end_callback) { DCHECK(view); - if (drag_view_ || pulsing_blocks_model_.view_size()) + if (drag_item_ || pulsing_blocks_model_.view_size()) return false; DVLOG(1) << "Initiate drag"; @@ -470,6 +470,7 @@ for (const auto& entry : view_model_.entries()) static_cast<AppListItemView*>(entry.view)->EnsureLayer(); drag_view_ = view; + drag_item_ = view->item(); // Dragged view should have focus. This also fixed the issue // https://crbug.com/834682. @@ -487,13 +488,10 @@ void AppsGridView::TryStartDragAndDropHostDrag(Pointer pointer) { // Stopping the animation may have invalidated our drag view due to the // view hierarchy changing. - if (!drag_view_) + if (!drag_item_) return; drag_pointer_ = pointer; - // Move the view to the front so that it appears on top of other views. - items_container_->ReorderChildView(drag_view_, -1); - bounds_animator_->StopAnimatingView(drag_view_); if (!dragging_for_reparent_item_) StartDragAndDropHostDrag(); @@ -504,7 +502,7 @@ bool AppsGridView::UpdateDragFromItem(bool is_touch, const ui::LocatedEvent& event) { - if (!drag_view_) + if (!drag_item_) return false; // Drag canceled. gfx::Point drag_point_in_grid_view; @@ -530,7 +528,7 @@ if (folder_delegate_) UpdateDragStateInsideFolder(pointer, point); - if (!drag_view_) + if (!drag_item_) return; // Drag canceled. gfx::Vector2d drag_vector(point - drag_start_grid_view_); @@ -597,7 +595,7 @@ DVLOG(1) << __func__; // EndDrag was called before if |drag_view_| is nullptr. - if (!drag_view_) + if (!drag_item_) return; // Coming here a drag and drop was in progress. @@ -610,7 +608,7 @@ // This is the folder view to drop an item into. Cache the |drag_view_|'s item // and its bounds for later use in folder dropping animation. AppListItemView* folder_item_view = nullptr; - AppListItem* drag_item = drag_view_->item(); + AppListItem* drag_item = drag_item_; if (forward_events_to_drag_and_drop_host_) { DCHECK(!IsDraggingForReparentInRootLevelGridView()); @@ -623,11 +621,6 @@ folder_delegate_->DispatchEndDragEventForReparent( true /* events_forwarded_to_drag_drop_host */, cancel /* cancel_drag */, std::move(drag_icon_proxy_)); - } else { - // |drag_view_| is reordered when initiating the drag. In addition, the - // icon's location in AppsGridView does not alter after being dragged to - // Shelf. So recover the order when drag ends. - MoveItemInModel(drag_view_, drag_view_init_index_); } } else { if (IsDraggingForReparentInHiddenGridView()) { @@ -653,16 +646,12 @@ if (drop_target_region_ == ON_ITEM && DraggedItemCanEnterFolder() && DropTargetIsValidFolder()) { MaybeCreateFolderDroppingAccessibilityEvent(); - folder_item_view = MoveItemToFolder(drag_view_, drop_target_); - // If the view that the folder is replacing had a layer, ensure the new - // folder view has one too. - if (drag_view_ && drag_view_->layer()) - folder_item_view->EnsureLayer(); + folder_item_view = MoveItemToFolder(drag_item_, drop_target_); reparented_into_folder = true; } else if (IsValidReorderTargetIndex(drop_target_)) { // Ensure reorder event has already been announced by the end of drag. MaybeCreateDragReorderAccessibilityEvent(); - MoveItemInModel(drag_view_, drop_target_); + MoveItemInModel(drag_item_, drop_target_); RecordAppMovingTypeMetrics(folder_delegate_ ? kReorderByDragInFolder : kReorderByDragInTopLevel); } @@ -686,13 +675,6 @@ SetAsFolderDroppingTarget(drop_target_, false); - // Keep track of the |drag_view| after it is released to ensure that it does - // not have a visible title until its animation to ideal bounds is complete. - // Do not cache the drag view if it's reparented into folder, as it's - // scheduled to be removed from the view hierarchy. - AppListItemView* released_drag_view = - !reparented_into_folder ? drag_view_ : nullptr; - ClearDragState(); UpdatePaging(); if (GetWidget()) { @@ -730,8 +712,8 @@ StopAutoScroll(); SetFocusAfterEndDrag(); // Maybe focus the search box. - AnimateDragIconToTargetPosition(reparented_into_folder, released_drag_view, - drag_item, folder_item_view); + AnimateDragIconToTargetPosition(reparented_into_folder, drag_item, + folder_item_view); } AppListItemView* AppsGridView::GetItemViewAt(int index) const { @@ -750,25 +732,11 @@ // entire apps grid. reorder_placeholder_ = view_structure_.GetLastTargetIndex(); - // Create a new AppListItemView to duplicate the original_drag_view in the - // folder's grid view. - auto view = CreateViewForItem(original_drag_view->item()); items_need_layer_for_drag_ = true; - auto* view_ptr = items_container_->AddChildView(std::move(view)); for (const auto& entry : view_model_.entries()) static_cast<AppListItemView*>(entry.view)->EnsureLayer(); - view_ptr->EnsureLayer(); - drag_view_ = view_ptr; - // Dragged view should have focus. This also fixed the issue - // https://crbug.com/834682. - drag_view_->RequestFocus(); - drag_view_hider_ = std::make_unique<DragViewHider>(drag_view_); - - // Add drag_view_ to the end of the view_model_. - view_model_.Add(drag_view_, view_model_.view_size()); - view_structure_.Add(drag_view_, view_structure_.GetLastTargetIndex()); - + drag_item_ = original_drag_view->item(); drag_start_grid_view_ = drag_point; // Set the flag in root level grid view. dragging_for_reparent_item_ = true; @@ -781,7 +749,7 @@ // Note that if a cancel ocurrs while reparenting, the |drag_view_| in both // root and folder grid views is cleared, so the check in UpdateDragFromItem() // for |drag_view_| being nullptr (in the folder grid) is sufficient. - DCHECK(drag_view_); + DCHECK(drag_item_); DCHECK(IsDraggingForReparentInRootLevelGridView()); UpdateDrag(pointer, drag_point); @@ -792,7 +760,7 @@ } bool AppsGridView::IsDraggedView(const AppListItemView* view) const { - return drag_view_ == view; + return drag_item_ == view->item(); } void AppsGridView::ClearDragState() { @@ -812,15 +780,8 @@ if (folder_item_reparent_timer_.IsRunning()) folder_item_reparent_timer_.Stop(); - if (drag_view_) { - if (IsDraggingForReparentInRootLevelGridView()) { - const int drag_view_index = view_model_.GetIndexOfView(drag_view_); - CHECK_EQ(view_model_.view_size() - 1, drag_view_index); - DeleteItemViewAtIndex(drag_view_index); - } - } drag_view_ = nullptr; - + drag_item_ = nullptr; drag_out_of_folder_container_ = false; dragging_for_reparent_item_ = false; extra_page_opened_ = false; @@ -907,9 +868,6 @@ if (activated_folder_item_view_ == details.child) activated_folder_item_view_ = nullptr; - if (drag_view_ == details.child) - EndDrag(true); - if (app_list_features::IsAppGridGhostEnabled()) { if (current_ghost_view_ == details.child) current_ghost_view_ = nullptr; @@ -1003,20 +961,18 @@ } } -std::unique_ptr<AppListItemView> AppsGridView::CreateViewForItem( - AppListItem* item) { - std::unique_ptr<AppListItemView> view = - std::make_unique<AppListItemView>(this, item, app_list_view_delegate_); - return view; -} - std::unique_ptr<AppListItemView> AppsGridView::CreateViewForItemAtIndex( size_t index) { // The |drag_view_| might be pending for deletion, therefore |view_model_| // may have one more item than |item_list_|. DCHECK_LE(index, item_list_->item_count()); - auto* item = item_list_->item_at(index); - return CreateViewForItem(item); + auto view = std::make_unique<AppListItemView>( + this, item_list_->item_at(index), app_list_view_delegate_); + if (items_need_layer_for_drag_) + view->EnsureLayer(); + if (cardified_state_) + view->EnterCardifyState(); + return view; } void AppsGridView::EnsureViewVisible(const GridIndex& index) { @@ -1144,9 +1100,6 @@ CalculateIdealBoundsForFolder(); for (int i = 0; i < view_model_.view_size(); ++i) { AppListItemView* view = GetItemViewAt(i); - if (view == drag_view_) - continue; - const gfx::Rect& target = view_model_.ideal_bounds(i); if (bounds_animator_->GetTargetBounds(view) == target) continue; @@ -1154,7 +1107,8 @@ const gfx::Rect& current = view->bounds(); const bool current_visible = visible_bounds.Intersects(current); const bool target_visible = visible_bounds.Intersects(target); - const bool visible = current_visible || target_visible; + const bool visible = + !IsViewHiddenForDrag(view) && (current_visible || target_visible); const int y_diff = target.y() - current.y(); if (visible && y_diff && y_diff % GetTotalTileSize().height() == 0) { @@ -1233,7 +1187,7 @@ } void AppsGridView::UpdateDropTargetRegion() { - DCHECK(drag_view_); + DCHECK(drag_item_); gfx::Point point = last_drag_point_; point.set_x(GetMirroredXInView(point.x())); @@ -1308,7 +1262,6 @@ void AppsGridView::AnimateDragIconToTargetPosition( bool dropping_into_folder, - AppListItemView* drag_view, AppListItem* drag_item, AppListItemView* target_folder_view) { // If drag icon proxy had not been created, just reshow the drag view. @@ -1320,19 +1273,24 @@ // Calculate target item bounds. gfx::Rect drag_icon_drop_bounds; if (!dropping_into_folder) { - DCHECK(drag_view); + // Find the view for drag item, and use its ideal bounds to calculate target + // drop bounds. + for (int i = 0; i < view_model_.view_size(); ++i) { + if (view_model_.view_at(i)->item() != drag_item) + continue; - // Get icon bounds in the drag view coordinates. - drag_icon_drop_bounds = drag_view->GetIconBounds(); + auto* drag_view = view_model_.view_at(i); + // Get icon bounds in the drag view coordinates. + drag_icon_drop_bounds = drag_view->GetIconBounds(); - // Get the expected drag item view location. - const int drag_view_model_index = view_model_.GetIndexOfView(drag_view); - const gfx::Rect drag_view_ideal_bounds = - view_model_.ideal_bounds(drag_view_model_index); + // Get the expected drag item view location. + const gfx::Rect drag_view_ideal_bounds = view_model_.ideal_bounds(i); - // Position target icon bounds relative to the ideal drag view bounds. - drag_icon_drop_bounds.Offset(drag_view_ideal_bounds.x(), - drag_view_ideal_bounds.y()); + // Position target icon bounds relative to the ideal drag view bounds. + drag_icon_drop_bounds.Offset(drag_view_ideal_bounds.x(), + drag_view_ideal_bounds.y()); + break; + } } else if (target_folder_view) { // Calculate target bounds of dragged item. drag_icon_drop_bounds = @@ -1363,7 +1321,7 @@ } bool AppsGridView::DraggedItemCanEnterFolder() { - if (!IsFolderItem(drag_view_->item()) && !folder_delegate_) + if (!IsFolderItem(drag_item_) && !folder_delegate_) return true; return false; } @@ -1419,7 +1377,7 @@ } bool AppsGridView::DragIsCloseToItem(const gfx::Point& point) { - DCHECK(drag_view_); + DCHECK(drag_item_); GridIndex nearest_tile_index = GetNearestTileIndexForPoint(point); if (nearest_tile_index == reorder_placeholder_) @@ -1555,7 +1513,8 @@ const std::u16string target_view_title = target_view->title()->GetText(); const bool target_view_is_folder = target_view->is_folder(); - AppListItemView* folder_item = MoveItemToFolder(selected_view_, target_index); + AppListItemView* folder_item = + MoveItemToFolder(selected_view_->item(), target_index); a11y_announcer_->AnnounceKeyboardFoldering( moving_view_title, target_view_title, target_view_is_folder); DCHECK(folder_item->is_folder()); @@ -1683,7 +1642,7 @@ bool cancel_drag, std::unique_ptr<AppDragIconProxy> drag_icon_proxy) { // EndDrag was called before if |drag_view_| is nullptr. - if (!drag_view_) + if (!drag_item_) return; drag_icon_proxy_ = std::move(drag_icon_proxy); @@ -1698,12 +1657,13 @@ // This is the folder view to drop an item into. Cache the |drag_view_|'s item // and its bounds for later use in folder dropping animation. AppListItemView* folder_item_view = nullptr; + AppListItem* drag_item = drag_item_; if (!events_forwarded_to_drag_drop_host && !cancel_reparent) { UpdateDropTargetRegion(); if (drop_target_region_ == ON_ITEM && DropTargetIsValidFolder() && DraggedItemCanEnterFolder()) { - cancel_reparent = !ReparentItemToAnotherFolder(drag_view_, drop_target_); + cancel_reparent = !ReparentItemToAnotherFolder(drag_item, drop_target_); // Announce folder dropping event before end of drag of reparented item. MaybeCreateFolderDroppingAccessibilityEvent(); if (!cancel_reparent) { @@ -1714,7 +1674,7 @@ } } else if (drop_target_region_ != NO_TARGET && IsValidReorderTargetIndex(drop_target_)) { - ReparentItemForReorder(drag_view_, drop_target_); + ReparentItemForReorder(drag_item, drop_target_); RecordAppMovingTypeMetrics(kMoveByDragOutOfFolder); // Announce accessibility event before the end of drag for reparented // item. @@ -1726,25 +1686,12 @@ SetAsFolderDroppingTarget(drop_target_, false); - // ClearDragState will delete the drag view if reparent is canceled - cache - // the target app list item, as it is needed to calculate target icon drop - // bounds. - AppListItem* drag_item = drag_view_->item(); - // Hide the drag item icon from the target folder icon. if (folder_item_view) { folder_icon_item_hider_ = std::make_unique<FolderIconItemHider>( static_cast<AppListFolderItem*>(folder_item_view->item()), drag_item); } - AppListItemView* released_drag_view = nullptr; - if (!cancel_reparent) { - // By setting |drag_view_| to nullptr here, we prevent ClearDragState() from - // cleaning up the newly created AppListItemView, effectively claiming - // ownership of the newly created drag view. - released_drag_view = drag_view_; - drag_view_ = nullptr; - } UpdatePaging(); ClearDragState(); @@ -1753,7 +1700,8 @@ else AnimateToIdealBounds(); - view_structure_.SaveToMetadata(); + if (!cancel_reparent) + view_structure_.SaveToMetadata(); // Hide the |current_ghost_view_| after completed drag from within // folder to |apps_grid_view_|. @@ -1763,8 +1711,8 @@ SetFocusAfterEndDrag(); // Maybe focus the search box. AnimateDragIconToTargetPosition( - /*dropping_into_folder=*/cancel_reparent || folder_item_view, - released_drag_view, drag_item, folder_item_view); + /*dropping_into_folder=*/cancel_reparent || folder_item_view, drag_item, + folder_item_view); } void AppsGridView::EndDragForReparentInHiddenFolderGridView() { @@ -1793,19 +1741,13 @@ DCHECK(!folder_delegate_); DCHECK(activated_folder_item_view_); - auto* reparented_view_in_root_grid = items_container_->AddChildView( - CreateViewForItem(reparented_view->item())); - view_model_.Add(reparented_view_in_root_grid, view_model_.view_size()); - view_structure_.Add(reparented_view_in_root_grid, - view_structure_.GetLastTargetIndex()); - // Set |activated_folder_item_view_| selected so |target_index| will be // computed relative to the open folder. SetSelectedView(activated_folder_item_view_); const GridIndex target_index = GetTargetGridIndexForKeyboardReparent(key_code); AnnounceReorder(target_index); - ReparentItemForReorder(reparented_view_in_root_grid, target_index); + ReparentItemForReorder(reparented_view->item(), target_index); GetViewAtIndex(target_index)->RequestFocus(); Layout(); @@ -1964,44 +1906,43 @@ } } -void AppsGridView::MoveItemInModel(AppListItemView* item_view, - const GridIndex& target) { - int current_model_index = view_model_.GetIndexOfView(item_view); - CHECK_GE(current_model_index, 0); +void AppsGridView::MoveItemInModel(AppListItem* item, const GridIndex& target) { + const std::string item_id = item->id(); + size_t current_item_list_index = 0; - bool found = item_list_->FindItemIndex(item_view->item()->id(), - ¤t_item_list_index); + bool found = item_list_->FindItemIndex(item_id, ¤t_item_list_index); CHECK(found); - int target_model_index = - view_structure_.GetTargetModelIndexForMove(item_view, target); size_t target_item_list_index = - view_structure_.GetTargetItemListIndexForMove(item_view, target); - // The same item index does not guarantee the same visual index, so move the - // item visual index here. - view_structure_.Move(item_view, target); + view_structure_.GetTargetItemListIndexForMove(item, target); - DVLOG(1) << "MoveItemInModel: view model: " << current_model_index << " -> " - << target_model_index << ", item list: " << current_item_list_index - << " -> " << target_item_list_index; + const bool moving_to_new_page = + !item->IsInFolder() && + (target.page == pagination_model_.total_pages() || + (target.page == pagination_model_.total_pages() - 1 && + view_structure_.GetLastTargetIndexOfPage(target.page).slot == 0)); - // Reorder the app list item views in accordance with |view_model_|. - items_container_->ReorderChildView(item_view, target_model_index); - items_container_->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, - true /* send_native_event */); + { + ScopedModelUpdate update(this); + item_list_->MoveItem(current_item_list_index, target_item_list_index); - if (target_item_list_index == current_item_list_index) - return; - - item_list_->RemoveObserver(this); - item_list_->MoveItem(current_item_list_index, target_item_list_index); - view_model_.Move(current_model_index, target_model_index); - item_list_->AddObserver(this); + // If the item is being moved to a new page, ensure that it's preceded by a + // page break. + if (moving_to_new_page) { + size_t final_item_list_index = 0; + if (item_list_->FindItemIndex(item_id, &final_item_list_index) && + final_item_list_index > 0 && + !item_list_->item_at(final_item_list_index - 1)->is_page_break()) { + item_list_->AddPageBreakItemAfter( + item_list_->item_at(final_item_list_index - 1)); + } + } + } } -AppListItemView* AppsGridView::MoveItemToFolder(AppListItemView* item_view, +AppListItemView* AppsGridView::MoveItemToFolder(AppListItem* item, const GridIndex& target) { - const std::string& source_item_id = item_view->item()->id(); + const std::string& source_item_id = item->id(); AppListItemView* target_view = GetViewDisplayedAtSlotOnCurrentPage(target.slot); DCHECK(target_view); @@ -2012,139 +1953,54 @@ // item (e.g., if a folder drop does not clean up properly). DCHECK_NE(source_item_id, target_view_item_id); + const bool is_dragged_view = drag_item_ == item; // Make change to data model. - item_list_->RemoveObserver(this); - std::string folder_item_id = - model_->MergeItems(target_view_item_id, source_item_id); - item_list_->AddObserver(this); + std::string folder_item_id; + + { + ScopedModelUpdate update(this); + folder_item_id = model_->MergeItems(target_view_item_id, source_item_id); + } + if (folder_item_id.empty()) { LOG(ERROR) << "Unable to merge into item id: " << target_view_item_id; return nullptr; } - if (folder_item_id != target_view_item_id) { - // New folder was created, change the view model to replace the old target - // view with the new folder item view. - size_t folder_item_index; - if (item_list_->FindItemIndex(folder_item_id, &folder_item_index)) { - // Paged view structure may get updated in two steps: - // 1. Item view deletion. - // 2. Addition of the new target view. - // Make sure the view structure is not sanitized between those two steps. - std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> sanitize_lock = - view_structure_.GetSanitizeLock(); - int target_model_index = view_model_.GetIndexOfView(target_view); - GridIndex target_index = GetIndexOfView(target_view); - gfx::Rect target_view_bounds = target_view->bounds(); - DeleteItemViewAtIndex(target_model_index); - std::unique_ptr<AppListItemView> new_target_view = - CreateViewForItemAtIndex(folder_item_index); - new_target_view->SetBoundsRect(target_view_bounds); - view_model_.Add(new_target_view.get(), target_model_index); - view_structure_.Add(new_target_view.get(), target_index); - - // If drag view is in front of the position where it will be moved to, we - // should skip it. - const int offset = (drag_view_ && view_model_.GetIndexOfView(drag_view_) < - target_model_index) - ? 1 - : 0; - target_view = items_container_->AddChildViewAt( - std::move(new_target_view), target_model_index - offset); - } else { - LOG(ERROR) << "Folder no longer in item_list: " << folder_item_id; - } + const AppListItem* const folder_item = item_list_->FindItem(folder_item_id); + if (!folder_item) { + LOG(ERROR) << "Unable to find target folder item " << folder_item_id; + return nullptr; } - FadeOutItemViewAndDelete(item_view); - if (drag_view_ == item_view) + if (is_dragged_view) RecordAppMovingTypeMetrics(kMoveByDragIntoFolder); - return target_view; + return GetItemViewAt(GetModelIndexOfItem(folder_item)); } -void AppsGridView::FadeOutItemViewAndDelete(AppListItemView* item_view) { - const int model_index = view_model_.GetIndexOfView(item_view); - - view_model_.Remove(model_index); - view_structure_.Remove(item_view); - item_view->title()->SetVisible(false); - bounds_animator_->AnimateViewTo(item_view, item_view->bounds()); - bounds_animator_->SetAnimationDelegate( - item_view, std::unique_ptr<gfx::AnimationDelegate>( - new ItemRemoveAnimationDelegate(item_view))); -} - -void AppsGridView::ReparentItemForReorder(AppListItemView* item_view, +void AppsGridView::ReparentItemForReorder(AppListItem* item, const GridIndex& target) { - item_list_->RemoveObserver(this); - model_->RemoveObserver(this); + DCHECK(item->IsInFolder()); - AppListItem* reparent_item = item_view->item(); - DCHECK(reparent_item->IsInFolder()); - const std::string source_folder_id = reparent_item->folder_id(); - AppListFolderItem* source_folder = - static_cast<AppListFolderItem*>(item_list_->FindItem(source_folder_id)); - - int target_model_index = - view_structure_.GetTargetModelIndexForMove(item_view, target); + const std::string source_folder_id = item->folder_id(); int target_item_index = - view_structure_.GetTargetItemListIndexForMove(item_view, target); - - // Paged view structure may get updated in two steps: - // 1. (Folder) item view deletion. - // 2. Item move to a new position. - // Make sure the view structure is not sanitized between those two steps. - std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> sanitize_lock = - view_structure_.GetSanitizeLock(); - - // Remove the source folder view if there is only 1 item in it, since the - // source folder will be deleted after its only child item removed from it. - GridIndex target_override = target; - if (source_folder->ChildItemCount() == 1u) { - const int deleted_folder_index = - view_model_.GetIndexOfView(activated_folder_item_view_); - const GridIndex deleted_folder_grid_index = - GetIndexOfView(activated_folder_item_view_); - DeleteItemViewAtIndex(deleted_folder_index); - - // Adjust |target_model_index| if it is beyond the deleted folder index. - if (target_model_index > deleted_folder_index) { - --target_model_index; - - // Do not decrement |target_item_index| since the folder item has not been - // removed from the item list yet. - } - - // Adjust |target_override| if it is beyond the deleted folder grid index in - // the same page. - if (!folder_delegate_ && target.page == deleted_folder_grid_index.page && - target.slot > deleted_folder_grid_index.slot) { - --target_override.slot; - } - } + view_structure_.GetTargetItemListIndexForMove(item, target); // Move the item from its parent folder to top level item list. - // Must move to target_model_index, the location we expect the target item - // to be, not the item location we want to insert before. - int current_model_index = view_model_.GetIndexOfView(item_view); syncer::StringOrdinal target_position; if (target_item_index < static_cast<int>(item_list_->item_count())) target_position = item_list_->item_at(target_item_index)->position(); - model_->MoveItemToFolderAt(reparent_item, "", target_position); - view_model_.Move(current_model_index, target_model_index); - view_structure_.Move(item_view, target_override); - items_container_->ReorderChildView(item_view, target_model_index); - items_container_->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, - true /* send_native_event */); + + { + ScopedModelUpdate update(this); + model_->MoveItemToFolderAt(item, "", target_position); + } RemoveLastItemFromReparentItemFolderIfNecessary(source_folder_id); - - item_list_->AddObserver(this); - model_->AddObserver(this); } -bool AppsGridView::ReparentItemToAnotherFolder(AppListItemView* item_view, +bool AppsGridView::ReparentItemToAnotherFolder(AppListItem* item, const GridIndex& target) { DCHECK(IsDraggingForReparentInRootLevelGridView()); @@ -2153,88 +2009,29 @@ if (!target_view) return false; - AppListItem* reparent_item = item_view->item(); - DCHECK(reparent_item->IsInFolder()); - const std::string source_folder_id = reparent_item->folder_id(); - AppListFolderItem* source_folder = - static_cast<AppListFolderItem*>(item_list_->FindItem(source_folder_id)); + CHECK(item->IsInFolder()); + const std::string source_folder_id = item->folder_id(); AppListItem* target_item = target_view->item(); // An app is being reparented to its original folder. Just cancel the // reparent. - if (target_item->id() == reparent_item->folder_id()) + if (target_item->id() == item->folder_id()) return false; - // Make change to data model. - item_list_->RemoveObserver(this); - - // Paged view structure may get updated in several steps: - // 1. (Folder) item view deletion (if the folder has no items left). - // 2. Deletion of item view on which the drag view was dropped (if a new - // folder was created). - // 3. Addition of a new folder view (if a new folder was created). - // 4. Removal of the last item from the source folder (if only one item was - // left). - // 5. Removal of the drag view. - // Make sure the view structure is not sanitized between those steps. - std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> sanitize_lock = - view_structure_.GetSanitizeLock(); - - // Remove the source folder view if there is only 1 item in it, since the - // source folder will be deleted after its only child item merged into the - // target item. - if (source_folder->ChildItemCount() == 1u) { - DeleteItemViewAtIndex( - view_model_.GetIndexOfView(activated_folder_item_view())); + std::string target_id_after_merge; + { + ScopedModelUpdate update(this); + target_id_after_merge = model_->MergeItems(target_item->id(), item->id()); } - // Move item to the target folder. - std::string target_id_after_merge = - model_->MergeItems(target_item->id(), reparent_item->id()); if (target_id_after_merge.empty()) { LOG(ERROR) << "Unable to reparent to item id: " << target_item->id(); - item_list_->AddObserver(this); return false; } - if (target_id_after_merge != target_item->id()) { - // New folder was created, change the view model to replace the old target - // view with the new folder item view. - const std::string& new_folder_id = reparent_item->folder_id(); - size_t new_folder_index; - if (item_list_->FindItemIndex(new_folder_id, &new_folder_index)) { - // Save the target view's bounds before deletion, which will be used as - // new folder view's bounds. - gfx::Rect target_rect = target_view->bounds(); - int target_model_index = view_model_.GetIndexOfView(target_view); - GridIndex target_index = GetIndexOfView(target_view); - DeleteItemViewAtIndex(target_model_index); - std::unique_ptr<AppListItemView> new_folder_view = - CreateViewForItemAtIndex(new_folder_index); - new_folder_view->SetBoundsRect(target_rect); - view_model_.Add(new_folder_view.get(), target_model_index); - view_structure_.Add(new_folder_view.get(), target_index); - items_container_->AddChildViewAt(std::move(new_folder_view), - target_model_index); - } else { - LOG(ERROR) << "Folder no longer in item_list: " << new_folder_id; - } - } - RemoveLastItemFromReparentItemFolderIfNecessary(source_folder_id); - item_list_->AddObserver(this); - - // Fade out the drag_view_ and delete it when animation ends. - int drag_model_index = view_model_.GetIndexOfView(drag_view_); - view_model_.Remove(drag_model_index); - view_structure_.Remove(drag_view_); - bounds_animator_->AnimateViewTo(drag_view_, drag_view_->bounds()); - bounds_animator_->SetAnimationDelegate( - drag_view_, std::unique_ptr<gfx::AnimationDelegate>( - new ItemRemoveAnimationDelegate(drag_view_))); - RecordAppMovingTypeMetrics(kMoveIntoAnotherFolder); return true; } @@ -2250,25 +2047,6 @@ if (!source_folder || (source_folder && !source_folder->ShouldAutoRemove())) return; - // Save the folder item view's bounds before deletion, which will be used as - // last item view's bounds. - gfx::Rect folder_rect = activated_folder_item_view()->bounds(); - const GridIndex target_index = GetIndexOfView(activated_folder_item_view()); - const int target_model_index = - view_model_.GetIndexOfView(activated_folder_item_view()); - - // Removing last item from the folder may require several paged view - // structure updates: - // 1. Delete the folder view. - // 2. Add an item view for the last folder item to the root level grid. - // Ensure the view structure is not sanitized between those steps. - std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> sanitize_lock = - view_structure_.GetSanitizeLock(); - - // Delete view associated with the folder item to be removed. - DeleteItemViewAtIndex( - view_model_.GetIndexOfView(activated_folder_item_view())); - // For single-app folders (which can exist for system-managed folders, see // crbug.com/925052) there will not be a "last item" so we can ignore the // rest. @@ -2277,22 +2055,8 @@ // Now make the data change to remove the folder item in model. AppListItem* last_item = source_folder->item_list()->item_at(0); + ScopedModelUpdate update(this); model_->MoveItemToFolderAt(last_item, "", source_folder->position()); - - // Create a new item view for the last item in folder. - size_t last_item_index; - if (!item_list_->FindItemIndex(last_item->id(), &last_item_index) || - last_item_index > item_list_->item_count()) { - NOTREACHED(); - return; - } - std::unique_ptr<AppListItemView> last_item_view = - CreateViewForItemAtIndex(last_item_index); - last_item_view->SetBoundsRect(folder_rect); - view_model_.Add(last_item_view.get(), target_model_index); - view_structure_.Add(last_item_view.get(), target_index); - items_container_->AddChildViewAt(std::move(last_item_view), - target_model_index); } void AppsGridView::CancelContextMenusOnCurrentPage() { @@ -2321,41 +2085,59 @@ } void AppsGridView::OnListItemAdded(size_t index, AppListItem* item) { - EndDrag(true); + if (!updating_model_) + EndDrag(true); if (!item->is_page_break()) { std::unique_ptr<AppListItemView> view = CreateViewForItemAtIndex(index); + if (view->item() == drag_item_) { + drag_view_ = view.get(); + drag_view_->RequestFocus(); + drag_view_hider_ = std::make_unique<DragViewHider>(drag_view_); + } int model_index = GetTargetModelIndexFromItemIndex(index); view_model_.Add(view.get(), model_index); items_container_->AddChildViewAt(std::move(view), model_index); } view_structure_.LoadFromMetadata(); - UpdateColsAndRowsForFolder(); - UpdatePaging(); - UpdatePulsingBlockViews(); + + // If model update is in progress, paging should be updated when the operation + // that caused the model update completes. + if (!updating_model_) { + UpdatePaging(); + UpdateColsAndRowsForFolder(); + UpdatePulsingBlockViews(); + } + Layout(); - SchedulePaint(); } void AppsGridView::OnListItemRemoved(size_t index, AppListItem* item) { - EndDrag(true); + if (!updating_model_) + EndDrag(true); if (!item->is_page_break()) DeleteItemViewAtIndex(GetModelIndexOfItem(item)); view_structure_.LoadFromMetadata(); - UpdateColsAndRowsForFolder(); - UpdatePaging(); - UpdatePulsingBlockViews(); + + // If model update is in progress, paging should be updated when the operation + // that caused the model update completes. + if (!updating_model_) { + UpdatePaging(); + UpdateColsAndRowsForFolder(); + UpdatePulsingBlockViews(); + } + Layout(); - SchedulePaint(); } void AppsGridView::OnListItemMoved(size_t from_index, size_t to_index, AppListItem* item) { - EndDrag(true); + if (!updating_model_) + EndDrag(true); if (item->is_page_break()) { LOG(ERROR) << "Page break item is moved: " << item->id(); @@ -2373,9 +2155,16 @@ } view_structure_.LoadFromMetadata(); - UpdateColsAndRowsForFolder(); - UpdatePaging(); - if (GetWidget() && GetWidget()->IsVisible()) + + // If model update is in progress, paging should be updated when the operation + // that caused the model update completes. + if (!updating_model_) { + UpdatePaging(); + UpdateColsAndRowsForFolder(); + UpdatePulsingBlockViews(); + } + + if (!updating_model_ && GetWidget() && GetWidget()->IsVisible()) AnimateToIdealBounds(); else Layout(); @@ -2391,7 +2180,7 @@ } void AppsGridView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { - if (drag_view_ || drag_icon_proxy_) + if (drag_item_ || drag_icon_proxy_) return; if (bounds_animation_for_cardified_state_in_progress_ || @@ -2618,9 +2407,6 @@ handling_keyboard_move_ = true; - if (target_index.page == pagination_model_.total_pages()) - view_structure_.AppendPage(); - AppListItemView* original_selected_view = selected_view_; const GridIndex original_selected_view_index = GetIndexOfView(original_selected_view); @@ -2638,11 +2424,10 @@ // a full page results in the last item being pushed to the next page. std::unique_ptr<PagedViewStructure::ScopedSanitizeLock> sanitize_lock = view_structure_.GetSanitizeLock(); - MoveItemInModel(selected_view_, target_index); - view_structure_.SaveToMetadata(); + MoveItemInModel(selected_view_->item(), target_index); if (swap_items) { DCHECK(target_view); - MoveItemInModel(target_view, original_selected_view_index); + MoveItemInModel(target_view->item(), original_selected_view_index); } } @@ -2803,8 +2588,10 @@ } void AppsGridView::MaybeCreateFolderDroppingAccessibilityEvent() { + if (!drag_item_ || !drag_view_) + return; if (drop_target_region_ != ON_ITEM || !DropTargetIsValidFolder() || - IsFolderItem(drag_view_->item()) || folder_delegate_ || + IsFolderItem(drag_item_) || folder_delegate_ || drop_target_ == last_folder_dropping_a11y_event_location_) { return; }
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h index ad705301..b999f39 100644 --- a/ash/app_list/views/apps_grid_view.h +++ b/ash/app_list/views/apps_grid_view.h
@@ -170,9 +170,11 @@ bool has_selected_view() const { return selected_view_ != nullptr; } AppListItemView* selected_view() const { return selected_view_; } - bool has_dragged_view() const { return drag_view_ != nullptr; } const AppListItemView* drag_view() const { return drag_view_; } + bool has_dragged_item() const { return drag_item_ != nullptr; } + const AppListItem* drag_item() const { return drag_item_; } + // Gets the PaginationModel used for the grid view. PaginationModel* pagination_model() { return &pagination_model_; } @@ -439,6 +441,11 @@ // drag state is cleared complete. bool items_need_layer_for_drag_ = false; + // The `AppListItemView` that is being dragged within the apps grid (i.e. the + // AppListItemView for `drag_item_`) if the drag item is currently part of the + // item list shown in the apps grid. `drag_view_` may be nullptr during item + // reparent drag while being handled in the root app list grid (the drag item + // will be added to target item list only when the drag ends). // Subclasses need non-const access. AppListItemView* drag_view_ = nullptr; @@ -502,8 +509,6 @@ // number of apps. void UpdatePulsingBlockViews(); - std::unique_ptr<AppListItemView> CreateViewForItem(AppListItem* item); - std::unique_ptr<AppListItemView> CreateViewForItemAtIndex(size_t index); // Ensures the view is visible. Note that if there is a running page @@ -568,34 +573,29 @@ void DispatchDragEventToDragAndDropHost( const gfx::Point& location_in_screen_coordinates); - // Updates |model_| to move item represented by |item_view| to |target| slot. - // Pushes all items from |item_view|'s GridIndex + 1 to |target| back by 1 - // GridIndex slot. - void MoveItemInModel(AppListItemView* item_view, const GridIndex& target); + // Updates `model_` to move `item` to `target` slot. + void MoveItemInModel(AppListItem* item, const GridIndex& target); - // Updates |model_| to move item represented by |item_view| into a folder - // containing item located at |target| slot, also update |view_model_| for - // the related view changes. Returns the preexisting or created folder as a - // result of the move, or nullptr if the move fails. - AppListItemView* MoveItemToFolder(AppListItemView* item_view, - const GridIndex& target); + // Updates `model_` to move `item` into a folder containing item located at + // `target` slot. Returns the preexisting or created folder view as a result + // of the move, or nullptr if the move fails. + AppListItemView* MoveItemToFolder(AppListItem* item, const GridIndex& target); - // Sets up |item_view| to fade out and delete on animation end. - void FadeOutItemViewAndDelete(AppListItemView* item_view); + // Updates data model for re-parenting a folder item to a new position in top + // level item list. The view model is will get updated in response to the data + // model changes. + void ReparentItemForReorder(AppListItem* item, const GridIndex& target); - // Updates both data model and view_model_ for re-parenting a folder item to a - // new position in top level item list. - void ReparentItemForReorder(AppListItemView* item_view, - const GridIndex& target); - - // Updates both data model and view_model_ for re-parenting a folder item - // to anther folder target. Returns whether the reparent succeeded. - bool ReparentItemToAnotherFolder(AppListItemView* item_view, + // Updates both data model for re-parenting a folder item + // to anther folder target. The view model will get updated in response to the + // data model changes. + // Returns whether the reparent succeeded. + bool ReparentItemToAnotherFolder(AppListItem* item_view, const GridIndex& target); // If there is only 1 item left in the source folder after reparenting an item - // from it, updates both data model and view_model_ for removing last item - // from the source folder and removes the source folder. + // from it, updates data model to remove last item from the source folder and + // remove the source folder. void RemoveLastItemFromReparentItemFolderIfNecessary( const std::string& source_folder_id); @@ -622,14 +622,10 @@ // set. // `dropping_into_folder` - Whether the drag item icon should be dropped // into a folder view. - // `drag_view` - The view showing the drag item. Used to calculate target - // bounds when the item is dropped into the root apps grid. Can be nullptr - // otherwise. // `drag_item` - The dragged item. // `target_folder_view` - If the item needs to be dropped into a folder, the // target folder view. void AnimateDragIconToTargetPosition(bool dropping_into_folder, - AppListItemView* drag_view, AppListItem* drag_item, AppListItemView* target_folder_view); @@ -755,6 +751,8 @@ // Invoked when |host_drag_start_timer_| fires. void OnHostDragStartTimerFired(); + class ScopedModelUpdate; + AppListModel* model_ = nullptr; // Owned by AppListView. AppListItemList* item_list_ = nullptr; // Not owned. @@ -782,6 +780,11 @@ AppListItemView* selected_view_ = nullptr; + // Set while the AppsGridView is handling drag operation for an app list item. + // It's set to the drag item that is being dragged in the UI. If `drag_view_` + // is set, it should have the same value as `drag_view_->item()`. + AppListItem* drag_item_ = nullptr; + // The index of the drag_view_ when the drag starts. GridIndex drag_view_init_index_; @@ -790,6 +793,9 @@ Pointer drag_pointer_ = NONE; + // Whether the apps grid is currently updating the app list model. + bool updating_model_ = false; + // Object that while in scope hides the drag view from the UI during the drag // operation. Note that this may remain set even after ClearDragState(), while // the drag icon proxy animation is in progress. @@ -849,9 +855,6 @@ // True if the drag_view_ item is a folder item being dragged for reparenting. bool dragging_for_reparent_item_ = false; - // True if it is the end gesture from shelf dragging. - bool is_end_gesture_ = false; - // The drop location of the most recent reorder related accessibility event. GridIndex last_reorder_a11y_event_location_;
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc index 917a59d9..8eedd9c 100644 --- a/ash/app_list/views/apps_grid_view_unittest.cc +++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -408,7 +408,7 @@ // Calls the private method. void MoveItemInModel(AppListItemView* item_view, const GridIndex& target) { - apps_grid_view_->MoveItemInModel(item_view, target); + apps_grid_view_->MoveItemInModel(item_view->item(), target); } TestAppListColorProvider color_provider_; // Needed by AppListView. @@ -2017,6 +2017,8 @@ TEST_F(AppsGridViewTest, ControlArrowSwapsBetweenFullPages) { const int kPages = 3; model_->PopulateApps(kPages * GetTilesPerPage()); + apps_grid_view_->UpdatePagedViewStructure(); + // For every item in the first row, ensure an upward move results in the item // swapping places with the item directly above it. for (int i = 0; i < apps_grid_view_->cols(); ++i) {
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc index 109b586..86dd864 100644 --- a/ash/app_list/views/contents_view.cc +++ b/ash/app_list/views/contents_view.cc
@@ -176,11 +176,11 @@ } void ContentsView::CancelDrag() { - if (apps_container_view_->apps_grid_view()->has_dragged_view()) + if (apps_container_view_->apps_grid_view()->has_dragged_item()) apps_container_view_->apps_grid_view()->EndDrag(true); if (apps_container_view_->app_list_folder_view() ->items_grid_view() - ->has_dragged_view()) { + ->has_dragged_item()) { apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag( true); }
diff --git a/ash/app_list/views/paged_apps_grid_view.cc b/ash/app_list/views/paged_apps_grid_view.cc index 6c665ff..9308937 100644 --- a/ash/app_list/views/paged_apps_grid_view.cc +++ b/ash/app_list/views/paged_apps_grid_view.cc
@@ -629,8 +629,6 @@ int new_selected) { items_container()->layer()->SetTransform(gfx::Transform()); if (IsDragging()) { - drag_view_->layer()->SetTransform(gfx::Transform()); - // Sets the transform to locate the scrolled content. gfx::Size grid_size = GetTileGridSize(); gfx::Vector2d update; @@ -971,10 +969,7 @@ RecenterItemsContainer(); // Drag view can be nullptr or moved from the model by EndDrag. - const bool model_contains_drag_view = - drag_view_ && (view_model()->GetIndexOfView(drag_view_) != -1); - const int number_of_views_to_animate = - view_model()->view_size() - (model_contains_drag_view ? 1 : 0); + const int number_of_views_to_animate = view_model()->view_size(); base::RepeatingClosure on_bounds_animator_callback; if (number_of_views_to_animate > 0) { @@ -989,9 +984,6 @@ 0, start_position.y() - items_container()->origin().y()); for (int i = 0; i < view_model()->view_size(); ++i) { AppListItemView* entry_view = view_model()->view_at(i); - // We don't animate bounds for the dragged view. - if (entry_view == drag_view_) - continue; // Reposition view bounds to compensate for the translation offset. gfx::Rect current_bounds = entry_view->bounds(); current_bounds.Offset(translate_offset); @@ -1006,6 +998,11 @@ gfx::Rect target_bounds(view_model()->ideal_bounds(i)); entry_view->SetBoundsRect(target_bounds); + if (IsViewHiddenForDrag(entry_view)) { + on_bounds_animator_callback.Run(); + continue; + } + // View bounds are currently |target_bounds|. Transform the view so it // appears in |current_bounds|. Note that bounds are flipped by views in // RTL UI direction, which is not taken into account by
diff --git a/ash/app_list/views/scrollable_apps_grid_view.cc b/ash/app_list/views/scrollable_apps_grid_view.cc index ac1559c..83b0ba3 100644 --- a/ash/app_list/views/scrollable_apps_grid_view.cc +++ b/ash/app_list/views/scrollable_apps_grid_view.cc
@@ -81,14 +81,7 @@ CalculateIdealBoundsForFolder(); for (int i = 0; i < view_model()->view_size(); ++i) { AppListItemView* view = GetItemViewAt(i); - if (view != drag_view()) { - view->SetBoundsRect(view_model()->ideal_bounds(i)); - } else { - // If the drag view size changes, make sure it has the same center. - gfx::Rect bounds = view->bounds(); - bounds.ClampToCenteredSize(GetTileViewSize()); - view->SetBoundsRect(bounds); - } + view->SetBoundsRect(view_model()->ideal_bounds(i)); } views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model()); }
diff --git a/ash/components/power/dark_resume_controller.cc b/ash/components/power/dark_resume_controller.cc index 3c2d6fc..247a0c5 100644 --- a/ash/components/power/dark_resume_controller.cc +++ b/ash/components/power/dark_resume_controller.cc
@@ -9,7 +9,7 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h" -namespace chromeos { +namespace ash { namespace system { namespace { @@ -149,4 +149,4 @@ } } // namespace system -} // namespace chromeos +} // namespace ash
diff --git a/ash/components/power/dark_resume_controller.h b/ash/components/power/dark_resume_controller.h index 2272afd..468fcfc 100644 --- a/ash/components/power/dark_resume_controller.h +++ b/ash/components/power/dark_resume_controller.h
@@ -17,7 +17,7 @@ #include "services/device/public/mojom/wake_lock.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h" -namespace chromeos { +namespace ash { namespace system { // This class listens to dark resume events from the power manager and makes @@ -132,6 +132,13 @@ }; } // namespace system +} // namespace ash + +// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done. +namespace chromeos { +namespace system { +using ::ash::system::DarkResumeController; +} // namespace system } // namespace chromeos #endif // ASH_COMPONENTS_POWER_DARK_RESUME_CONTROLLER_H_
diff --git a/ash/components/power/dark_resume_controller_unittest.cc b/ash/components/power/dark_resume_controller_unittest.cc index 9409705..17050c2 100644 --- a/ash/components/power/dark_resume_controller_unittest.cc +++ b/ash/components/power/dark_resume_controller_unittest.cc
@@ -15,16 +15,16 @@ #include "services/device/public/cpp/test/test_wake_lock_provider.h" #include "testing/gtest/include/gtest/gtest.h" -namespace chromeos { +namespace ash { namespace system { namespace { +using device::mojom::WakeLockType; + constexpr char kWakeLockDescription[] = "DarkResumeTest"; -} - -using device::mojom::WakeLockType; +} // namespace class DarkResumeControllerTest : public testing::Test { public: @@ -188,4 +188,4 @@ } } // namespace system -} // namespace chromeos +} // namespace ash
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc index dd3d3dc..b79ee77f 100644 --- a/ash/display/cursor_window_controller.cc +++ b/ash/display/cursor_window_controller.cc
@@ -4,8 +4,6 @@ #include "ash/display/cursor_window_controller.h" -#include <utility> - #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h" #include "ash/capture_mode/capture_mode_controller.h" #include "ash/capture_mode/capture_mode_session.h" @@ -323,16 +321,23 @@ if (!is_cursor_compositing_enabled_) return; - // This scale has the UI zoom applied. - float ui_scale = display_.device_scale_factor(); - float cursor_scale = cursor_.image_scale_factor(); + // Use the original device scale factor instead of the display's, which + // might have been adjusted for the UI scale. + const float original_scale = Shell::Get() + ->display_manager() + ->GetDisplayInfo(display_.id()) + .device_scale_factor(); + // And use the nearest resource scale factor. + float cursor_scale = ui::GetScaleForResourceScaleFactor( + ui::GetSupportedResourceScaleFactor(original_scale)); + gfx::ImageSkia image; gfx::Point hot_point_in_physical_pixels; if (cursor_.type() == ui::mojom::CursorType::kCustom) { const SkBitmap& bitmap = cursor_.custom_bitmap(); if (bitmap.isNull()) return; - image = gfx::ImageSkia::CreateFromBitmap(bitmap, cursor_scale); + image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); hot_point_in_physical_pixels = cursor_.custom_hotspot(); } else { int resource_id; @@ -344,31 +349,27 @@ *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); } - // The accessibility large cursor size is specified in dips, with respect to - // the original device scale factor. - if (cursor_size_ == ui::CursorSize::kLarge) { - const float dsf = Shell::Get() - ->display_manager() - ->GetDisplayInfo(display_.id()) - .device_scale_factor(); - cursor_scale = dsf; - if (large_cursor_size_in_dip_ != image.size().width()) { - const float rescale = static_cast<float>(large_cursor_size_in_dip_) / - static_cast<float>(image.size().width()); - cursor_scale *= rescale; - hot_point_in_physical_pixels = - gfx::ScaleToCeiledPoint(hot_point_in_physical_pixels, rescale); - } + gfx::ImageSkia resized = image; + + // Rescale cursor size. This is used with the combination of accessibility + // large cursor. We don't need to care about the case where cursor + // compositing is disabled as we always use cursor compositing if + // accessibility large cursor is enabled. + if (cursor_size_ == ui::CursorSize::kLarge && + large_cursor_size_in_dip_ != image.size().width()) { + float rescale = static_cast<float>(large_cursor_size_in_dip_) / + static_cast<float>(image.size().width()); + resized = gfx::ImageSkiaOperations::CreateResizedImage( + image, skia::ImageOperations::ResizeMethod::RESIZE_GOOD, + gfx::ScaleToCeiledSize(image.size(), rescale)); + hot_point_in_physical_pixels = + gfx::ScaleToCeiledPoint(hot_point_in_physical_pixels, rescale); } - // Make sure the cursor image isn't scaled by creating an ImageSkia with the - // target size for the UI scale. - const gfx::Size ui_size = - ScaleToRoundedSize(image.size(), cursor_scale / ui_scale); - const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(cursor_scale); - delegate_->SetCursorImage( - ui_size, - gfx::ImageSkia::CreateFromBitmap(GetAdjustedBitmap(image_rep), ui_scale)); + const gfx::ImageSkiaRep& image_rep = resized.GetRepresentation(cursor_scale); + delegate_->SetCursorImage(resized.size(), + gfx::ImageSkia::CreateFromBitmap( + GetAdjustedBitmap(image_rep), cursor_scale)); // TODO(danakj): Should this be rounded? Or kept as a floating point? hot_point_ = gfx::ToFlooredPoint( gfx::ConvertPointToDips(hot_point_in_physical_pixels, cursor_scale));
diff --git a/ash/display/cursor_window_controller_unittest.cc b/ash/display/cursor_window_controller_unittest.cc index e43f66f..ec2a481 100644 --- a/ash/display/cursor_window_controller_unittest.cc +++ b/ash/display/cursor_window_controller_unittest.cc
@@ -4,8 +4,6 @@ #include "ash/display/cursor_window_controller.h" -#include <string> - #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/constants/ash_constants.h" #include "ash/constants/ash_pref_names.h" @@ -15,25 +13,16 @@ #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/command_line.h" -#include "base/strings/stringprintf.h" #include "components/prefs/pref_service.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/base/cursor/cursor.h" -#include "ui/base/cursor/cursor_lookup.h" -#include "ui/base/cursor/cursor_size.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" -#include "ui/base/layout.h" -#include "ui/base/resource/scale_factor.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/display/test/display_manager_test_api.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/color_utils.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/image/image_skia_rep.h" -#include "ui/gfx/skia_util.h" #include "ui/wm/core/coordinate_conversion.h" namespace ash { @@ -75,15 +64,6 @@ return cursor_window_controller_->display_.id(); } - void SetCursorSize(ui::CursorSize size) { - cursor_window_controller_->SetCursorSize(size); - } - - void SetLargeCursorSizeInDip(int large_cursor_size_in_dip) { - cursor_window_controller_->SetLargeCursorSizeInDip( - large_cursor_size_in_dip); - } - void SetCursorCompositionEnabled(bool enabled) { // Cursor compositing will be enabled when high contrast mode is turned on. // Cursor compositing will be disabled when high contrast mode is the only @@ -189,50 +169,25 @@ EXPECT_TRUE(GetCursorWindow()->IsVisible()); } -// Test that the composited cursor matches the native cursor in size. -TEST_F(CursorWindowControllerTest, CursorSize) { - for (int dsf : {1, 2}) { - std::string display_specs = base::StringPrintf("1000x500*%d", dsf); - UpdateDisplay(display_specs); - int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); - display::test::ScopedSetInternalDisplayId set_internal(display_manager(), - primary_id); - for (float zoom_factor : {0.5f, 1.0f, 1.5f, 2.0f}) { - display_manager()->UpdateZoomFactor(primary_id, zoom_factor); - auto display = display::Screen::GetScreen()->GetPrimaryDisplay(); - const float ui_scale = display.device_scale_factor(); +// Make sure that composition cursor stays big even when +// the DSF becomes 1x as a result of zooming out. +TEST_F(CursorWindowControllerTest, DSF) { + UpdateDisplay("1000x500*2"); + int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); - ui::Cursor cursor(ui::mojom::CursorType::kPointer); - // This would be done by NativeCursorManagerAsh::SetCursor(). - cursor.set_image_scale_factor(ui::GetScaleForResourceScaleFactor( - ui::GetSupportedResourceScaleFactor(ui_scale))); + display::test::ScopedSetInternalDisplayId set_internal(display_manager(), + primary_id); + SetCursorCompositionEnabled(true); + ASSERT_EQ( + 2.0f, + display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor()); + EXPECT_TRUE(GetCursorImage().HasRepresentation(2.0f)); - // Normal size. - SetCursorSize(ui::CursorSize::kNormal); - - // Both checks are needed. To ensure that the cursor isn't scaled, besides - // checking that its size isn't changed, the image needs to be available - // for the current display scale. - EXPECT_EQ(GetCursorImage().GetRepresentation(ui_scale).pixel_size(), - gfx::SkISizeToSize(ui::GetCursorBitmap(cursor).dimensions())); - EXPECT_TRUE(GetCursorImage().HasRepresentation(ui_scale)); - - // Large size. - SetCursorSize(ui::CursorSize::kLarge); - for (const auto kLargeSizeInDips : - {kDefaultLargeCursorSize / 2, kDefaultLargeCursorSize}) { - SetLargeCursorSizeInDip(kLargeSizeInDips); - EXPECT_EQ( - GetCursorImage().GetRepresentation(ui_scale).pixel_size().width(), - kLargeSizeInDips * dsf); - EXPECT_TRUE(GetCursorImage().HasRepresentation(ui_scale)); - } - - // TODO(https://crbug.com/1149906): test custom cursors when - // WebCursor::GetNativeCursor() is moved to CursorLoader, as ash cannot - // depend on //content. - } - } + display_manager()->UpdateZoomFactor(primary_id, 0.5f); + ASSERT_EQ( + 1.0f, + display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor()); + EXPECT_TRUE(GetCursorImage().HasRepresentation(2.0f)); } // Test that cursor compositing is enabled if at least one of the features that
diff --git a/ash/quick_answers/ui/quick_answers_view.cc b/ash/quick_answers/ui/quick_answers_view.cc index 6d81e58..2c68a63c 100644 --- a/ash/quick_answers/ui/quick_answers_view.cc +++ b/ash/quick_answers/ui/quick_answers_view.cc
@@ -87,13 +87,11 @@ constexpr int kSettingsButtonMarginDip = 8; constexpr int kSettingsButtonSizeDip = 14; constexpr SkColor kSettingsButtonColor = gfx::kGoogleGrey500; -constexpr SkColor kSettingsButtonInkDropColor = gfx::kGoogleGrey500; // Phonetics audio button. constexpr int kPhoneticsAudioButtonMarginDip = 4; constexpr int kPhoneticsAudioButtonSizeDip = 14; constexpr SkColor kPhoneticsAudioButtonColor = gfx::kGoogleBlue600; -constexpr SkColor kPhoneticsAudioButtonInkDropColor = gfx::kGoogleGrey500; // ReportQueryView. constexpr char kGoogleSansFont[] = "Google Sans"; @@ -481,12 +479,6 @@ kSettingsButtonColor)); settings_button_->SetTooltipText(l10n_util::GetStringUTF16( IDS_ASH_QUICK_ANSWERS_SETTINGS_BUTTON_TOOLTIP_TEXT)); - - views::InkDropHost* const ink_drop = views::InkDrop::Get(settings_button_); - ink_drop->SetBaseColor(kSettingsButtonInkDropColor); - ink_drop->SetMode(views::InkDropHost::InkDropMode::ON); - settings_button_->SetHasInkDropActionOnClick(true); - views::InstallCircleHighlightPathGenerator(settings_button_); } void QuickAnswersView::AddPhoneticsAudioButton(const GURL& phonetics_audio, @@ -515,13 +507,6 @@ gfx::CreateVectorIcon(kSystemMenuVolumeHighIcon, kPhoneticsAudioButtonSizeDip, kPhoneticsAudioButtonColor)); - - views::InkDropHost* const ink_drop = - views::InkDrop::Get(phonetics_audio_button_); - ink_drop->SetBaseColor(kPhoneticsAudioButtonInkDropColor); - ink_drop->SetMode(views::InkDropHost::InkDropMode::ON); - phonetics_audio_button_->SetHasInkDropActionOnClick(true); - views::InstallCircleHighlightPathGenerator(phonetics_audio_button_); } void QuickAnswersView::AddAssistantIcon() { @@ -658,8 +643,14 @@ // retry-label, and so is not included when this is the case. if (!retry_label_) focusable_views.push_back(this); + if (settings_button_ && settings_button_->GetVisible()) + focusable_views.push_back(settings_button_); + if (phonetics_audio_button_ && phonetics_audio_button_->GetVisible()) + focusable_views.push_back(phonetics_audio_button_); if (retry_label_ && retry_label_->GetVisible()) focusable_views.push_back(retry_label_); + if (report_query_view_ && report_query_view_->GetVisible()) + focusable_views.push_back(report_query_view_); if (dogfood_button_ && dogfood_button_->GetVisible()) focusable_views.push_back(dogfood_button_); return focusable_views;
diff --git a/ash/services/recording/public/mojom/BUILD.gn b/ash/services/recording/public/mojom/BUILD.gn index 9962692..eca8eead 100644 --- a/ash/services/recording/public/mojom/BUILD.gn +++ b/ash/services/recording/public/mojom/BUILD.gn
@@ -7,6 +7,8 @@ mojom("mojom") { sources = [ "recording_service.mojom" ] + public_deps = [ "//sandbox/policy/mojom" ] + deps = [ "//media/mojo/mojom", "//services/viz/privileged/mojom/compositing",
diff --git a/ash/services/recording/public/mojom/recording_service.mojom b/ash/services/recording/public/mojom/recording_service.mojom index 4e968aaa..8fdc4e4 100644 --- a/ash/services/recording/public/mojom/recording_service.mojom +++ b/ash/services/recording/public/mojom/recording_service.mojom
@@ -7,6 +7,7 @@ import "media/mojo/mojom/audio_stream_factory.mojom"; import "mojo/public/mojom/base/big_string.mojom"; import "mojo/public/mojom/base/file_path.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; import "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom"; import "services/viz/public/mojom/compositing/frame_sink_id.mojom"; import "services/viz/public/mojom/compositing/subtree_capture_id.mojom"; @@ -58,6 +59,8 @@ // video frames, and writes the WebM muxed video chunks to directly to a file // whose path was given to the Record*() functions. // Note that a maximum of one screen recording can be done at any time. +// TODO(https://crbug.com/1147991) Explore alternative sandboxing. +[ServiceSandbox=sandbox.mojom.Sandbox.kVideoCapture] interface RecordingService { // All the below Record*() interfaces, take a pending remote to a client (e.g. // Ash) which will be notified when recording finishes and all the webm
diff --git a/ash/webui/scanning/mojom/scanning.mojom b/ash/webui/scanning/mojom/scanning.mojom index aabc8ca..fb037c1 100644 --- a/ash/webui/scanning/mojom/scanning.mojom +++ b/ash/webui/scanning/mojom/scanning.mojom
@@ -187,7 +187,11 @@ // Scans the next page in a multi-page scan session. |success| indicates // whether the scan started successfully. ScanNextPage(mojo_base.mojom.UnguessableToken scanner_id, - ScanSettings settings) => (bool success); + ScanSettings settings) => (bool success); + + // Removes a scanned image from an ongoing multi-page scan session at the + // specified |page_index|. |page_index| is zero-based. + RemovePage(uint32 page_index); // Ends a multi-page scan session and saves the scan to disk. CompleteMultiPageScan();
diff --git a/base/BUILD.gn b/base/BUILD.gn index ea830bff..7f1d68d 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2616,6 +2616,7 @@ "task/thread_pool/thread_pool_perftest.cc", "threading/counter_perftest.cc", "threading/thread_local_storage_perftest.cc", + "vlog_perftest.cc", # "test/run_all_unittests.cc", "json/json_perftest.cc",
diff --git a/base/barrier_callback.h b/base/barrier_callback.h index 37ae6f0..aa898ef9 100644 --- a/base/barrier_callback.h +++ b/base/barrier_callback.h
@@ -12,17 +12,18 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/synchronization/lock.h" +#include "base/template_util.h" #include "base/thread_annotations.h" namespace base { namespace internal { -template <typename T> +template <typename T, typename DoneArg> class BarrierCallbackInfo { public: BarrierCallbackInfo(size_t num_callbacks, - OnceCallback<void(std::vector<T>)> done_callback) + OnceCallback<void(DoneArg)> done_callback) : num_callbacks_left_(num_callbacks), done_callback_(std::move(done_callback)) { results_.reserve(num_callbacks); @@ -35,7 +36,7 @@ --num_callbacks_left_; if (num_callbacks_left_ == 0) { - std::vector<T> results = std::move(results_); + std::vector<base::remove_cvref_t<T>> results = std::move(results_); lock.Release(); std::move(done_callback_).Run(std::move(results)); } @@ -44,8 +45,8 @@ private: Lock mutex_; size_t num_callbacks_left_ GUARDED_BY(mutex_); - std::vector<T> results_ GUARDED_BY(mutex_); - OnceCallback<void(std::vector<T>)> done_callback_; + std::vector<base::remove_cvref_t<T>> results_ GUARDED_BY(mutex_); + OnceCallback<void(DoneArg)> done_callback_; }; template <typename T> @@ -61,8 +62,16 @@ // the vector of `T`s as an argument. (The ordering of the vector is // unspecified.) // +// `T`s that are movable are moved into the callback's storage; otherwise the T +// is copied. (BarrierCallback does not support `T`s that are neither movable +// nor copyable.) If T is a reference, the reference is removed, and the +// callback moves or copies the underlying value per the previously stated rule. +// // If `num_callbacks` is 0, `done_callback` is executed immediately. // +// `done_callback` may accept a `std::vector<T>`, `const std::vector<T>`, or +// `const std::vector<T>&`. +// // BarrierCallback is thread-safe - the internals are protected by a // `base::Lock`. `done_callback` will be run on the thread that calls the final // Run() on the returned callbacks, or the thread that constructed the @@ -70,18 +79,27 @@ // // `done_callback` is also cleared on the thread that runs it (by virtue of // being a OnceCallback). -template <typename T> +template <typename T, + typename RawArg = base::remove_cvref_t<T>, + typename DoneArg = std::vector<RawArg>, + template <typename> + class CallbackType, + typename std::enable_if<std::is_same< + std::vector<RawArg>, + base::remove_cvref_t<DoneArg>>::value>::type* = nullptr, + typename = base::EnableIfIsBaseCallback<CallbackType>> RepeatingCallback<void(T)> BarrierCallback( size_t num_callbacks, - OnceCallback<void(std::vector<T>)> done_callback) { + CallbackType<void(DoneArg)> done_callback) { if (num_callbacks == 0) { std::move(done_callback).Run({}); return BindRepeating(&internal::ShouldNeverRun<T>); } - return BindRepeating(&internal::BarrierCallbackInfo<T>::Run, - std::make_unique<internal::BarrierCallbackInfo<T>>( - num_callbacks, std::move(done_callback))); + return BindRepeating( + &internal::BarrierCallbackInfo<T, DoneArg>::Run, + std::make_unique<internal::BarrierCallbackInfo<T, DoneArg>>( + num_callbacks, std::move(done_callback))); } } // namespace base
diff --git a/base/barrier_callback_unittest.cc b/base/barrier_callback_unittest.cc index 32f5342c..055b4e85 100644 --- a/base/barrier_callback_unittest.cc +++ b/base/barrier_callback_unittest.cc
@@ -25,7 +25,8 @@ } TEST(BarrierCallbackTest, ErrorToCallCallbackWithZeroCallbacks) { - auto barrier_callback = base::BarrierCallback<int>(0, base::DoNothing()); + auto barrier_callback = + base::BarrierCallback<int>(0, base::DoNothing::Once<std::vector<int>>()); EXPECT_FALSE(barrier_callback.is_null()); EXPECT_CHECK_DEATH(barrier_callback.Run(3)); @@ -68,7 +69,7 @@ TEST(BarrierCallbackTest, ReleasesDoneCallbackWhenDone) { bool done_destructed = false; - auto barrier_callback = base::BarrierCallback( + auto barrier_callback = base::BarrierCallback<bool>( 1, base::BindOnce(&DestructionIndicator<std::vector<bool>>::DoNothing, std::make_unique<DestructionIndicator<std::vector<bool>>>( @@ -107,8 +108,37 @@ // No need to assert anything here, since if BarrierCallback didn't work with // move-only types, this wouldn't compile. - auto barrier_callback = base::BarrierCallback<MoveOnly>(1, base::DoNothing()); + auto barrier_callback = base::BarrierCallback<MoveOnly>( + 1, base::DoNothing::Once<std::vector<MoveOnly>>()); barrier_callback.Run(MoveOnly()); + + auto barrier_callback2 = base::BarrierCallback<MoveOnly>( + 1, base::DoNothing::Once<const std::vector<MoveOnly>&>()); + barrier_callback2.Run(MoveOnly()); +} + +TEST(BarrierCallbackTest, SupportsConstRefResults) { + auto barrier_callback = base::BarrierCallback<int>( + 1, base::DoNothing::Once<const std::vector<int>&>()); + + barrier_callback.Run(1); +} + +TEST(BarrierCallbackTest, SupportsReferenceTypes) { + class Referenceable { + // Must be copyable. + }; + Referenceable ref; + + // No need to assert anything here, since if BarrierCallback didn't work with + // by-reference args, this wouldn't compile. + auto barrier_callback = base::BarrierCallback<const Referenceable&>( + 1, base::DoNothing::Once<std::vector<Referenceable>>()); + barrier_callback.Run(ref); + + auto barrier_callback2 = base::BarrierCallback<const Referenceable&>( + 1, base::DoNothing::Once<const std::vector<Referenceable>&>()); + barrier_callback2.Run(ref); } } // namespace
diff --git a/base/vlog.cc b/base/vlog.cc index cdc30c3..a973b317 100644 --- a/base/vlog.cc +++ b/base/vlog.cc
@@ -5,11 +5,11 @@ #include "base/vlog.h" #include <stddef.h> - +#include <algorithm> +#include <limits> #include <ostream> #include <utility> -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -24,17 +24,16 @@ explicit VmodulePattern(const std::string& pattern); - VmodulePattern(); + VmodulePattern() = default; std::string pattern; - int vlog_level; - MatchTarget match_target; + int vlog_level = VlogInfo::kDefaultVlogLevel; + MatchTarget match_target = MATCH_MODULE; + size_t score = 0; }; VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern) - : pattern(pattern), - vlog_level(VlogInfo::kDefaultVlogLevel), - match_target(MATCH_MODULE) { + : pattern(pattern) { // If the pattern contains a {forward,back} slash, we assume that // it's meant to be tested against the entire __FILE__ string. std::string::size_type first_slash = pattern.find_first_of("\\/"); @@ -42,10 +41,6 @@ match_target = MATCH_FILE; } -VlogInfo::VmodulePattern::VmodulePattern() - : vlog_level(VlogInfo::kDefaultVlogLevel), - match_target(MATCH_MODULE) {} - VlogInfo::VlogInfo(const std::string& v_switch, const std::string& vmodule_switch, int* min_log_level) @@ -86,31 +81,59 @@ // Given a path, returns the basename with the extension chopped off // (and any -inl suffix). We avoid using FilePath to minimize the // number of dependencies the logging system has. -base::StringPiece GetModule(const base::StringPiece& file) { - base::StringPiece module(file); - base::StringPiece::size_type last_slash_pos = - module.find_last_of("\\/"); - if (last_slash_pos != base::StringPiece::npos) - module.remove_prefix(last_slash_pos + 1); +base::StringPiece GetModule(base::StringPiece file) { + base::StringPiece module = file; + + // Chop off the file extension. base::StringPiece::size_type extension_start = module.rfind('.'); module = module.substr(0, extension_start); - static const char kInlSuffix[] = "-inl"; - static const int kInlSuffixLen = base::size(kInlSuffix) - 1; + + // Chop off the -inl suffix. + static constexpr base::StringPiece kInlSuffix("-inl"); if (base::EndsWith(module, kInlSuffix)) - module.remove_suffix(kInlSuffixLen); + module.remove_suffix(kInlSuffix.size()); + + // Chop off the path up to the start of the file name. Using single-character + // overload of `base::StringPiece::find_last_of` for speed; this overload does + // not build a lookup table. + base::StringPiece::size_type last_slash_pos = module.find_last_of('/'); + if (last_slash_pos != base::StringPiece::npos) { + module.remove_prefix(last_slash_pos + 1); + return module; + } + last_slash_pos = module.find_last_of('\\'); + if (last_slash_pos != base::StringPiece::npos) + module.remove_prefix(last_slash_pos + 1); return module; } } // namespace -int VlogInfo::GetVlogLevel(const base::StringPiece& file) const { +int VlogInfo::GetVlogLevel(base::StringPiece file) { + base::AutoLock lock(vmodule_levels_lock_); if (!vmodule_levels_.empty()) { base::StringPiece module(GetModule(file)); - for (const auto& it : vmodule_levels_) { - base::StringPiece target( - (it.match_target == VmodulePattern::MATCH_FILE) ? file : module); - if (MatchVlogPattern(target, it.pattern)) - return it.vlog_level; + for (size_t i = 0; i < vmodule_levels_.size(); i++) { + VmodulePattern& it = vmodule_levels_[i]; + + const bool kUseFile = it.match_target == VmodulePattern::MATCH_FILE; + if (!MatchVlogPattern(kUseFile ? file : module, it.pattern)) { + continue; + } + const int ret = it.vlog_level; + + // Since `it` matched, increase its score because we believe it has a + // higher probability of winning next time. + if (it.score == std::numeric_limits<size_t>::max()) { + for (VmodulePattern& pattern : vmodule_levels_) { + pattern.score = 0; + } + } + ++it.score; + if (i > 0 && it.score > vmodule_levels_[i - 1].score) + std::swap(it, vmodule_levels_[i - 1]); + + return ret; } } return GetMaxVlogLevel(); @@ -125,23 +148,20 @@ return -*min_log_level_; } -bool MatchVlogPattern(const base::StringPiece& string, - const base::StringPiece& vlog_pattern) { - base::StringPiece pat(vlog_pattern); - base::StringPiece str(string); - +bool MatchVlogPattern(base::StringPiece string, + base::StringPiece vlog_pattern) { // The code implements the glob matching using a greedy approach described in // https://research.swtch.com/glob. size_t s = 0, nexts = 0; size_t p = 0, nextp = 0; - size_t slen = str.size(), plen = pat.size(); + const size_t slen = string.size(), plen = vlog_pattern.size(); while (s < slen || p < plen) { if (p < plen) { - switch (pat[p]) { + switch (vlog_pattern[p]) { // A slash (forward or back) must match a slash (forward or back). case '/': case '\\': - if (s < slen && (str[s] == '/' || str[s] == '\\')) { + if (s < slen && (string[s] == '/' || string[s] == '\\')) { p++, s++; continue; } @@ -160,7 +180,7 @@ continue; // Anything else must match literally. default: - if (s < slen && str[s] == pat[p]) { + if (s < slen && string[s] == vlog_pattern[p]) { p++, s++; continue; }
diff --git a/base/vlog.h b/base/vlog.h index 201daab..fd6d7397 100644 --- a/base/vlog.h +++ b/base/vlog.h
@@ -10,6 +10,8 @@ #include "base/base_export.h" #include "base/strings/string_piece.h" +#include "base/synchronization/lock.h" +#include "base/thread_annotations.h" namespace logging { @@ -45,7 +47,7 @@ // Returns the vlog level for a given file (usually taken from // __FILE__). - int GetVlogLevel(const base::StringPiece& file) const; + int GetVlogLevel(base::StringPiece file); private: void SetMaxVlogLevel(int level); @@ -54,7 +56,8 @@ // VmodulePattern holds all the information for each pattern parsed // from |vmodule_switch|. struct VmodulePattern; - std::vector<VmodulePattern> vmodule_levels_; + base::Lock vmodule_levels_lock_; + std::vector<VmodulePattern> vmodule_levels_ GUARDED_BY(vmodule_levels_lock_); int* min_log_level_; }; @@ -68,8 +71,8 @@ // "kh*n" matches "khn", "khan", or even "khaaaaan" // "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar" // (disregarding C escaping rules) -BASE_EXPORT bool MatchVlogPattern(const base::StringPiece& string, - const base::StringPiece& vlog_pattern); +BASE_EXPORT bool MatchVlogPattern(base::StringPiece string, + base::StringPiece vlog_pattern); } // namespace logging
diff --git a/base/vlog_perftest.cc b/base/vlog_perftest.cc new file mode 100644 index 0000000..edabe1c --- /dev/null +++ b/base/vlog_perftest.cc
@@ -0,0 +1,57 @@ +// Copyright (c) 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/vlog.h" + +#include "base/logging.h" +#include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_result_reporter.h" + +namespace logging { + +TEST(VlogPerfTest, GetVlogLevel) { + const std::string kMetricThroughput = "throughput"; + perf_test::PerfResultReporter reporter(/*metric_basename=*/"Vlog", + /*story_name=*/"GetVlogLevel"); + reporter.RegisterImportantMetric(/*metric_suffix=*/kMetricThroughput, + /*units=*/"gets/microsecond"); + + const base::TimeTicks job_run_start(base::TimeTicks::Now()); + + const char kVModuleSwitch[] = + "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4"; + + constexpr size_t kNumFilenames = 3; + const char* const kFileNames[kNumFilenames] = {"baz/x/qux.cc", "foo/bar", + "x/y-inl.h"}; + int min_log_level = 0; + VlogInfo vlog_info(std::string(), kVModuleSwitch, &min_log_level); + + constexpr size_t kNumSets = 1 << 21; + constexpr size_t kNumReps = 3; + + for (size_t set = 0; set < kNumSets; set++) { + const char* kFileName = kFileNames[set % kNumFilenames]; + for (size_t rep = 0; rep < kNumReps; rep++) { + int res = vlog_info.GetVlogLevel(kFileName); + ASSERT_GE(res, min_log_level); + ASSERT_LE(res, 4); + } + } + + const base::TimeDelta kDuration = base::TimeTicks::Now() - job_run_start; + const int64_t kDurationUs = kDuration.InMicroseconds(); + ASSERT_NE(kDurationUs, 0) << "Too fast, would divide by zero."; + + base::CheckedNumeric<size_t> gets_per_us_checked = kNumSets; + gets_per_us_checked *= kNumReps; + gets_per_us_checked /= kDurationUs; + + const size_t kGetsPerUs = gets_per_us_checked.ValueOrDie(); + reporter.AddResult(kMetricThroughput, kGetsPerUs); +} +} // namespace logging
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn index b6b1b2d..3803fd4f 100644 --- a/build/config/android/BUILD.gn +++ b/build/config/android/BUILD.gn
@@ -59,9 +59,6 @@ cflags += [ "--rtlib=libgcc" ] if (arm_control_flow_integrity == "standard") { cflags += [ "-mbranch-protection=standard" ] - } else { - assert(arm_control_flow_integrity == "none", - "Invalid branch protection option") } }
diff --git a/build/config/arm.gni b/build/config/arm.gni index 0473118c..0185dd73 100644 --- a/build/config/arm.gni +++ b/build/config/arm.gni
@@ -125,8 +125,12 @@ arm_use_neon = true declare_args() { # Enables the new Armv8 branch protection features. Valid strings are: - # - "standard": Enables both Pointer Authentication Code (featured in Armv8.3) and Branch Target Identification (featured in Armv8.5). + # - "standard": Enables both Pointer Authentication Code (featured in + # Armv8.3) and Branch Target Identification (Armv8.5). # - "none": No branch protection. arm_control_flow_integrity = "none" } + assert(arm_control_flow_integrity == "none" || + arm_control_flow_integrity == "standard", + "Invalid branch protection option") }
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn index 08471742..8e42cf9 100644 --- a/build/config/linux/BUILD.gn +++ b/build/config/linux/BUILD.gn
@@ -22,9 +22,6 @@ if (arm_control_flow_integrity == "standard") { cflags += [ "-mbranch-protection=standard" ] asmflags += [ "-mbranch-protection=standard" ] - } else { - assert(arm_control_flow_integrity == "none", - "Invalid branch protection option") } } }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 59108a1..bca2f1f 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -6.20210810.0.1 +6.20210810.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 59108a1..bca2f1f 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -6.20210810.0.1 +6.20210810.1.1
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index e4895ee..cf54a36 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -1016,7 +1016,7 @@ SetNeedsUpdateLayers(); } - scroll_tree.NotifyDidScroll(id, new_offset, snap_target_ids); + scroll_tree.NotifyDidCompositorScroll(id, new_offset, snap_target_ids); } else if (Layer* layer = LayerByElementId(id)) { layer->SetScrollOffsetFromImplSide(layer->scroll_offset() + delta); SetNeedsUpdateLayers();
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 6cb642e..ee9668d 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3579,10 +3579,10 @@ void AfterTest() override { EXPECT_TRUE(sent_gesture_); } // ScrollCallbacks - void DidScroll(ElementId element_id, - const gfx::ScrollOffset& scroll_offset, - const absl::optional<TargetSnapAreaElementIds>& - snap_target_ids) override { + void DidCompositorScroll(ElementId element_id, + const gfx::ScrollOffset& scroll_offset, + const absl::optional<TargetSnapAreaElementIds>& + snap_target_ids) override { last_scrolled_element_id_ = element_id; last_scrolled_offset_ = scroll_offset; }
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index b0d0479..3a4ecfab 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -87,10 +87,10 @@ } // ScrollCallbacks - void DidScroll(ElementId element_id, - const gfx::ScrollOffset& scroll_offset, - const absl::optional<TargetSnapAreaElementIds>& - snap_target_ids) override { + void DidCompositorScroll(ElementId element_id, + const gfx::ScrollOffset& scroll_offset, + const absl::optional<TargetSnapAreaElementIds>& + snap_target_ids) override { // Simulates cc client (e.g Blink) behavior when handling impl-side scrolls. SetScrollOffsetFromImplSide(layer_tree_host()->LayerByElementId(element_id), scroll_offset); @@ -621,11 +621,12 @@ } } - void DidScroll(ElementId element_id, - const gfx::ScrollOffset& offset, - const absl::optional<TargetSnapAreaElementIds>& - snap_target_ids) override { - LayerTreeHostScrollTest::DidScroll(element_id, offset, snap_target_ids); + void DidCompositorScroll(ElementId element_id, + const gfx::ScrollOffset& offset, + const absl::optional<TargetSnapAreaElementIds>& + snap_target_ids) override { + LayerTreeHostScrollTest::DidCompositorScroll(element_id, offset, + snap_target_ids); if (element_id == expected_scroll_layer_->element_id()) { final_scroll_offset_ = CurrentScrollOffset(expected_scroll_layer_); EXPECT_EQ(offset, final_scroll_offset_); @@ -1841,9 +1842,10 @@ } } - void DidScroll(ElementId element_id, - const gfx::ScrollOffset&, - const absl::optional<TargetSnapAreaElementIds>&) override { + void DidCompositorScroll( + ElementId element_id, + const gfx::ScrollOffset&, + const absl::optional<TargetSnapAreaElementIds>&) override { if (scroll_destroy_whole_tree_) { layer_tree_host()->SetRootLayer(nullptr); layer_tree_host()->property_trees()->clear();
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index 91436f3..0767972 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -1720,13 +1720,15 @@ callbacks_ = std::move(callbacks); } -void ScrollTree::NotifyDidScroll( +void ScrollTree::NotifyDidCompositorScroll( ElementId scroll_element_id, const gfx::ScrollOffset& scroll_offset, const absl::optional<TargetSnapAreaElementIds>& snap_target_ids) { DCHECK(property_trees()->is_main_thread); - if (callbacks_) - callbacks_->DidScroll(scroll_element_id, scroll_offset, snap_target_ids); + if (callbacks_) { + callbacks_->DidCompositorScroll(scroll_element_id, scroll_offset, + snap_target_ids); + } } void ScrollTree::NotifyDidChangeScrollbarsHidden(ElementId scroll_element_id,
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index e745252..3ac68f86 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -381,9 +381,10 @@ class ScrollCallbacks { public: // Called after the composited scroll offset changed. - virtual void DidScroll(ElementId scroll_element_id, - const gfx::ScrollOffset&, - const absl::optional<TargetSnapAreaElementIds>&) = 0; + virtual void DidCompositorScroll( + ElementId scroll_element_id, + const gfx::ScrollOffset&, + const absl::optional<TargetSnapAreaElementIds>&) = 0; // Called after the hidden status of composited scrollbars changed. Note that // |scroll_element_id| is the element id of the scroll not of the scrollbars. virtual void DidChangeScrollbarsHidden(ElementId scroll_element_id, @@ -500,7 +501,7 @@ void SetScrollCallbacks(base::WeakPtr<ScrollCallbacks> callbacks); - void NotifyDidScroll( + void NotifyDidCompositorScroll( ElementId scroll_element_id, const gfx::ScrollOffset& scroll_offset, const absl::optional<TargetSnapAreaElementIds>& snap_target_ids);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSwipeRefreshLayout.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSwipeRefreshLayout.java index c1e47af9a..1ce58944 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSwipeRefreshLayout.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSwipeRefreshLayout.java
@@ -98,7 +98,9 @@ public void showIPH(UserEducationHelper helper) { ViewGroup contentContainer = mActivity.findViewById(android.R.id.content); if (contentContainer == null) return; - View toolbarView = contentContainer.findViewById(org.chromium.chrome.R.id.toolbar); + // Only toolbar_container view appears in both NTP and start surface. + View toolbarView = + contentContainer.findViewById(org.chromium.chrome.R.id.toolbar_container); if (toolbarView == null) return; helper.requestShowIPH(new IPHCommandBuilder(getContext().getResources(), FeatureConstants.FEED_SWIPE_REFRESH_FEATURE, R.string.feed_swipe_refresh_iph,
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/RefreshIphScrollListener.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/RefreshIphScrollListener.java index 7d99577..0f01be17 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/RefreshIphScrollListener.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/RefreshIphScrollListener.java
@@ -51,7 +51,9 @@ } @Override - public void onHeaderOffsetChanged(int verticalOffset) {} + public void onHeaderOffsetChanged(int verticalOffset) { + maybeTriggerIPH(); + } private void maybeTriggerIPH() { final String featureForIph = FeatureConstants.FEED_SWIPE_REFRESH_FEATURE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java index 772641d0..73b145b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -47,8 +47,6 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper; import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations; -import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; -import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.share.ShareUtils; @@ -375,9 +373,7 @@ * is present for restoration. */ private int getInstanceCount() { - return SharedPreferencesManager.getInstance() - .readIntsWithPrefix(ChromePreferenceKeys.MULTI_INSTANCE_URL) - .size(); + return mMultiWindowModeStateDispatcher.getInstanceCount(); } private void prepareCommonMenuItems(Menu menu, @MenuGroup int menuGroup, boolean isIncognito) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java index 6fe2cd24..8fb16f64 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -49,7 +49,8 @@ class MultiInstanceManagerApi31 extends MultiInstanceManager { public static final int INVALID_INSTANCE_ID = MultiWindowUtils.INVALID_INSTANCE_ID; - public static final int INVALID_TASK_ID = -1; // Defined in android.app.ActivityTaskManager. + public static final int INVALID_TASK_ID = MultiWindowUtils.INVALID_TASK_ID; + private static final String EMPTY_DATA = ""; @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @@ -87,14 +88,17 @@ @Override public boolean handleMenuOrKeyboardAction(int id, boolean fromMenu) { + // clang-format off if (id == org.chromium.chrome.R.id.manage_all_windows_menu_id) { + List<InstanceInfo> info = getInstanceInfo(); InstanceSwitcherCoordinator.showDialog(mActivity, mModalDialogManagerSupplier.get(), new LargeIconBridge(getProfile()), - (item) - -> openInstance(item.instanceId, item.taskId), - (item) -> closeInstance(item.instanceId, item.taskId), getInstanceInfo()); + (item) -> openInstance(item.instanceId, item.taskId), + (item) -> closeInstance(item.instanceId, item.taskId), + this::openNewWindow, info.size() < MultiWindowUtils.getMaxInstances(), info); return true; } + // clang-format on return super.handleMenuOrKeyboardAction(id, fromMenu); } @@ -157,7 +161,7 @@ @Override public List<InstanceInfo> getInstanceInfo() { - removeInvalidEntriesFromTaskMap(); + removeInvalidInstanceData(); List<InstanceInfo> result = new ArrayList<>(); int currentItemPos = -1; for (int i = 0; i < mMaxInstances; ++i) { @@ -177,7 +181,6 @@ } } - // TODO: Remove unrecoverable incognito tab-only instance entries. int taskId = getTaskFromMap(i); result.add(new InstanceInfo(i, taskId, type, url, readTitle(i), readTabCount(i), readIncognitoTabCount(i), readIncognitoSelected(i))); @@ -198,7 +201,7 @@ @Override public int allocInstanceId(int windowId, int taskId, boolean preferNew) { - removeInvalidEntriesFromTaskMap(); + removeInvalidInstanceData(); // Explicitly specified window ID should be preferred. This comes from user selecting // a certain instance on UI. This method would never be called if there were an instance @@ -241,7 +244,7 @@ @Override public void initialize(int instanceId, int taskId) { mInstanceId = instanceId; - SharedPreferencesManager.getInstance().writeInt(taskMapKey(instanceId), taskId); + updateTaskMap(instanceId, taskId); installTabModelObserver(); } @@ -291,7 +294,6 @@ }; } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) static int getTaskFromMap(int index) { return SharedPreferencesManager.getInstance().readInt(taskMapKey(index), INVALID_TASK_ID); } @@ -300,8 +302,13 @@ return ChromePreferenceKeys.MULTI_INSTANCE_TASK_MAP.createKey(String.valueOf(index)); } - private void removeInvalidEntriesFromTaskMap() { - // Remove tasks that do not exist any more. + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void updateTaskMap(int instanceId, int taskId) { + SharedPreferencesManager.getInstance().writeInt(taskMapKey(instanceId), taskId); + } + + private void removeInvalidInstanceData() { + // Remove tasks that do not exist any more from the task map Set<Integer> validTasks = getAllChromeTasks(); Map<String, Integer> taskMap = SharedPreferencesManager.getInstance().readIntsWithPrefix( ChromePreferenceKeys.MULTI_INSTANCE_TASK_MAP); @@ -310,6 +317,13 @@ SharedPreferencesManager.getInstance().removeKey(entry.getKey()); } } + + // Remove persistent data for unrecoverable instances. + for (int i = 0; i < mMaxInstances; ++i) { + if (readUrl(i) != null && !MultiWindowUtils.isRestorableInstance(i)) { + removeInstanceInfo(i); + } + } } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @@ -351,7 +365,13 @@ return false; } - protected static void writeIncognitoSelected(int index, Tab tab) { + private static String incognitoSelectedKey(int index) { + return ChromePreferenceKeys.MULTI_INSTANCE_IS_INCOGNITO_SELECTED.createKey( + String.valueOf(index)); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void writeIncognitoSelected(int index, Tab tab) { SharedPreferencesManager.getInstance().writeBoolean( incognitoSelectedKey(index), tab.isIncognito()); } @@ -366,26 +386,19 @@ return ChromePreferenceKeys.MULTI_INSTANCE_URL.createKey(String.valueOf(index)); } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) static String readUrl(int index) { return SharedPreferencesManager.getInstance().readString(urlKey(index), null); } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - protected static void writeUrl(int index, String url) { + static void writeUrl(int index, String url) { SharedPreferencesManager.getInstance().writeString(urlKey(index), url); } - protected static void writeUrl(int index, Tab tab) { + private static void writeUrl(int index, Tab tab) { assert !tab.isIncognito(); writeUrl(index, tab.getOriginalUrl().getSpec()); } - private static String incognitoSelectedKey(int index) { - return ChromePreferenceKeys.MULTI_INSTANCE_IS_INCOGNITO_SELECTED.createKey( - String.valueOf(index)); - } - private static String titleKey(int index) { return ChromePreferenceKeys.MULTI_INSTANCE_TITLE.createKey(String.valueOf(index)); } @@ -404,11 +417,11 @@ SharedPreferencesManager.getInstance().writeString(titleKey(index), title); } - private static String tabCountKey(int index) { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static String tabCountKey(int index) { return ChromePreferenceKeys.MULTI_INSTANCE_TAB_COUNT.createKey(String.valueOf(index)); } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) static int readTabCount(int index) { return SharedPreferencesManager.getInstance().readInt(tabCountKey(index)); } @@ -423,7 +436,7 @@ return SharedPreferencesManager.getInstance().readInt(incognitoTabCountKey(index)); } - private static void writeTabCount(int index, TabModelSelector selector) { + static void writeTabCount(int index, TabModelSelector selector) { SharedPreferencesManager prefs = SharedPreferencesManager.getInstance(); int tabCount = selector.getModel(false).getCount(); prefs.writeInt(tabCountKey(index), tabCount);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcher.java index f3cc6575..0a666f0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcher.java
@@ -89,4 +89,9 @@ * @return The ActivityOptions needed to open the content in another display. */ Bundle getOpenInOtherWindowActivityOptions(); + + /** + * @return The number of Chrome instances that can switch to or launch. + */ + int getInstanceCount(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcherImpl.java index f3d9ebe..3aa81eab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcherImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowModeStateDispatcherImpl.java
@@ -91,4 +91,9 @@ public Bundle getOpenInOtherWindowActivityOptions() { return MultiWindowUtils.getOpenInOtherWindowActivityOptions(mActivity); } + + @Override + public int getInstanceCount() { + return MultiWindowUtils.getInstanceCount(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java index c4c47a9..314065f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -57,6 +57,7 @@ */ public class MultiWindowUtils implements ActivityStateListener { public static final int INVALID_INSTANCE_ID = TabWindowManager.INVALID_WINDOW_INDEX; + public static final int INVALID_TASK_ID = -1; // Defined in android.app.ActivityTaskManager. private static MultiWindowUtils sInstance = new MultiWindowUtils(); @@ -305,6 +306,22 @@ return Display.INVALID_DISPLAY; } + /** + * @return The number of Chrome instances that can switch to or launch. + */ + public static int getInstanceCount() { + int count = 0; + for (int i = 0; i < getMaxInstances(); ++i) { + if (MultiInstanceManagerApi31.readUrl(i) != null && isRestorableInstance(i)) count++; + } + return count; + } + + static boolean isRestorableInstance(int index) { + return MultiInstanceManagerApi31.readTabCount(index) != 0 + || MultiInstanceManagerApi31.getTaskFromMap(index) != INVALID_TASK_ID; + } + @Override public void onActivityStateChange(Activity activity, int newState) { if (newState == ActivityState.RESUMED && activity instanceof ChromeTabbedActivity) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 99b1f9e..3be9f86c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -668,9 +668,12 @@ rBar1.put("title", "Selection Related 1"); JSONObject rBar2 = new JSONObject(); rBar2.put("title", "Selection Related 2"); + JSONObject rBar3 = new JSONObject(); + rBar3.put("title", "Selection Related 3"); JSONArray selectionSearches = new JSONArray(); selectionSearches.put(rBar1); selectionSearches.put(rBar2); + selectionSearches.put(rBar3); suggestions.put("selection", selectionSearches); ResolvedSearchTerm intelligenceWithRelatedSearches =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index c81d9112..3e3e97e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -3973,7 +3973,6 @@ @SmallTest @Feature({"ContextualSearch"}) public void testRelatedSearchesItemNotSelected() throws Exception { - FeatureList.setTestFeatures(ENABLE_RELATED_SEARCHES_IN_PANEL); mPolicy.overrideAllowSendingPageUrlForTesting(true); FakeResolveSearch fakeSearch = simulateResolveSearch("intelligence"); Assert.assertFalse("Related Searches should have been requested but were not!", @@ -3994,7 +3993,6 @@ @Feature({"ContextualSearch"}) @DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.O, message = "crbug.com/1182040") public void testRelatedSearchesItemSelected() throws Exception { - FeatureList.setTestFeatures(ENABLE_RELATED_SEARCHES_IN_PANEL); mFakeServer.reset(); FakeResolveSearch fakeSearch = simulateResolveSearch("intelligence"); ResolvedSearchTerm resolvedSearchTerm = fakeSearch.getResolvedSearchTerm(); @@ -4004,12 +4002,12 @@ tapPeekingBarToExpandAndAssert(); // Select a Related Searches suggestion. - RelatedSearchesControl relatedSearchesControl = mPanel.getRelatedSearchesInContentControl(); + RelatedSearchesControl relatedSearchesControl = mPanel.getRelatedSearchesInBarControl(); final int chipToSelect = 2; TestThreadUtils.runOnUiThreadBlocking( () -> relatedSearchesControl.selectChipForTest(chipToSelect)); Assert.assertEquals("The Related Searches query was not shown in the Bar!", - "Related Search 3", mPanel.getSearchBarControl().getSearchTerm()); + "Selection Related 3", mPanel.getSearchBarControl().getSearchTerm()); // Collapse the panel back to the peeking state peekPanel();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java index 23fc7ae..ab169e43 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java
@@ -19,6 +19,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.homepage.HomepageTestRule; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; @@ -34,11 +35,14 @@ public class NewTabPageNavigationTest { @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + @Rule + public HomepageTestRule mHomepageTestRule = new HomepageTestRule(); private EmbeddedTestServer mTestServer; @Before public void setUp() { + mHomepageTestRule.useChromeNTPForTest(); mActivityTestRule.startMainActivityWithURL(null); mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java index 35a1b05..9e2004f4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
@@ -629,9 +629,15 @@ activity, null, null, index); if (pair == null) return INVALID_INSTANCE_ID; - mMultiInstanceManager.createInstance(pair.first, activity); - mMultiInstanceManager.initialize(pair.first, activity.getTaskId()); - return pair.first; + int instanceId = pair.first; + mMultiInstanceManager.createInstance(instanceId, activity); + mMultiInstanceManager.initialize(instanceId, activity.getTaskId()); + + // Store minimal data to get the instance recognized. + MultiInstanceManagerApi31.writeUrl(instanceId, "url" + instanceId); + SharedPreferencesManager.getInstance().writeInt( + MultiInstanceManagerApi31.tabCountKey(index), 1); + return instanceId; } // Assert that the given task is new, and not in the task map.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java index bfc595f..e0de1b4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.multiwindow; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; @@ -12,14 +13,28 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; /** * Unit tests for {@link MultiWindowUtilsUnit}. */ @RunWith(BaseRobolectricTestRunner.class) public class MultiWindowUtilsUnitTest { + private static final int INSTANCE_ID_0 = 0; + private static final int INSTANCE_ID_1 = 1; + private static final int INSTANCE_ID_2 = 2; + private static final int TASK_ID_5 = 5; + private static final int TASK_ID_6 = 6; + private static final int TASK_ID_7 = 7; + private static final String URL_1 = "url1"; + private static final String URL_2 = "url2"; + private static final String URL_3 = "url3"; + private MultiWindowUtils mUtils; private boolean mIsInMultiWindowMode; private boolean mIsInMultiDisplayMode; @@ -27,8 +42,16 @@ private boolean mIsAutosplitSupported; private boolean mCustomMultiWindowSupported; + @Mock + TabModelSelector mTabModelSelector; + @Mock + TabModel mNormalTabModel; + @Mock + TabModel mIncognitoTabModel; + @Before public void setUp() { + MockitoAnnotations.initMocks(this); mUtils = new MultiWindowUtils() { @Override public boolean isInMultiWindowMode(Activity activity) { @@ -97,4 +120,31 @@ openInOtherWindow, mUtils.isOpenInOtherWindowSupported(null)); } } + + @Test + public void testGetInstanceCount() { + when(mTabModelSelector.getModel(false)).thenReturn(mNormalTabModel); + when(mTabModelSelector.getModel(true)).thenReturn(mIncognitoTabModel); + + // Instance with no tabs (ID_1) still counts as long as it is alive. + writeInstanceInfo(INSTANCE_ID_0, URL_1, /*tabCount=*/3, /*incognitoTabCount=*/2, TASK_ID_5); + writeInstanceInfo(INSTANCE_ID_1, URL_2, /*tabCount=*/0, /*incognitoTabCount=*/0, TASK_ID_6); + writeInstanceInfo(INSTANCE_ID_2, URL_3, /*tabCount=*/6, /*incognitoTabCount=*/2, TASK_ID_7); + assertEquals(3, MultiWindowUtils.getInstanceCount()); + + // Instance with no running task is not taken into account if there is no normal tab, + // regardless of the # of incognito tabs. + writeInstanceInfo(INSTANCE_ID_1, URL_2, /*tabCount=*/0, /*incognitoTabCount=*/2, + MultiWindowUtils.INVALID_TASK_ID); + assertEquals(2, MultiWindowUtils.getInstanceCount()); + } + + private void writeInstanceInfo( + int instanceId, String url, int tabCount, int incognitoTabCount, int taskId) { + MultiInstanceManagerApi31.writeUrl(instanceId, url); + when(mNormalTabModel.getCount()).thenReturn(tabCount); + when(mIncognitoTabModel.getCount()).thenReturn(incognitoTabCount); + MultiInstanceManagerApi31.writeTabCount(instanceId, mTabModelSelector); + MultiInstanceManagerApi31.updateTaskMap(instanceId, taskId); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java index 153cbef..65f7737b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -215,6 +215,8 @@ mBookmarkBridgeSupplier, mFeedLauncher, mDialogManager, mSnackbarManager)); SharedPreferencesManager.getInstance().removeKeysWithPrefix( ChromePreferenceKeys.MULTI_INSTANCE_URL); + SharedPreferencesManager.getInstance().removeKeysWithPrefix( + ChromePreferenceKeys.MULTI_INSTANCE_TAB_COUNT); } @Test @@ -298,12 +300,14 @@ mIsNewWindowMenuFeatureEnabled = true; doReturn(true).when(mTabbedAppMenuPropertiesDelegate).instanceSwitcherEnabled(); - writeUrl(0, "https://url0"); + createInstance(0, "https://url0"); Menu menu = createMenuForMultiWindow(); assertTrue(isMenuVisible(menu, R.id.new_window_menu_id)); - for (int i = 0; i < MultiWindowUtils.getMaxInstances(); ++i) writeUrl(i, "https://url" + i); + for (int i = 0; i < MultiWindowUtils.getMaxInstances(); ++i) { + createInstance(i, "https://url" + i); + } Menu menu2 = createMenuForMultiWindow(); assertFalse(isMenuVisible(menu2, R.id.new_window_menu_id)); @@ -315,14 +319,16 @@ mIsNewWindowMenuFeatureEnabled = true; doReturn(true).when(mTabbedAppMenuPropertiesDelegate).instanceSwitcherEnabled(); - writeUrl(0, "https://url0"); + createInstance(0, "https://url0"); Menu menu = createMenuForMultiWindow(); + assertEquals(1, mMultiWindowModeStateDispatcher.getInstanceCount()); assertFalse(isMenuVisible(menu, R.id.move_to_other_window_menu_id)); - writeUrl(1, "https://url1"); + createInstance(1, "https://url1"); Menu menu2 = createMenuForMultiWindow(); + assertEquals(2, mMultiWindowModeStateDispatcher.getInstanceCount()); assertTrue(isMenuVisible(menu2, R.id.move_to_other_window_menu_id)); } @@ -332,12 +338,12 @@ mIsNewWindowMenuFeatureEnabled = true; doReturn(true).when(mTabbedAppMenuPropertiesDelegate).instanceSwitcherEnabled(); - writeUrl(0, "https://url0"); + createInstance(0, "https://url0"); Menu menu = createMenuForMultiWindow(); assertFalse(isMenuVisible(menu, R.id.manage_all_windows_menu_id)); - writeUrl(1, "https://url1"); + createInstance(1, "https://url1"); Menu menu2 = createMenuForMultiWindow(); assertTrue(isMenuVisible(menu2, R.id.manage_all_windows_menu_id)); @@ -473,6 +479,9 @@ doReturn(mIsNewWindowMenuFeatureEnabled) .when(mTabbedAppMenuPropertiesDelegate) .isNewWindowMenuFeatureEnabled(); + doReturn(MultiWindowUtils.getInstanceCount()) + .when(mMultiWindowModeStateDispatcher) + .getInstanceCount(); Menu menu = createTestMenu(); mTabbedAppMenuPropertiesDelegate.prepareMenu(menu, null); return menu; @@ -602,11 +611,11 @@ return items.toString(); } - private static void writeUrl(int index, String url) { - SharedPreferencesManager.getInstance().writeString(urlKey(index), url); - } - - private static String urlKey(int index) { - return ChromePreferenceKeys.MULTI_INSTANCE_URL.createKey(String.valueOf(index)); + private static void createInstance(int index, String url) { + String urlKey = ChromePreferenceKeys.MULTI_INSTANCE_URL.createKey(String.valueOf(index)); + SharedPreferencesManager.getInstance().writeString(urlKey, url); + String tabCountKey = + ChromePreferenceKeys.MULTI_INSTANCE_TAB_COUNT.createKey(String.valueOf(index)); + SharedPreferencesManager.getInstance().writeInt(tabCountKey, 1); } }
diff --git a/chrome/app/DEPS b/chrome/app/DEPS index e0c78d90..5ea568c926 100644 --- a/chrome/app/DEPS +++ b/chrome/app/DEPS
@@ -39,6 +39,7 @@ "+content/public/common", "+extensions/common/constants.h", "+headless/public", + "+media/base/media_switches.h", "+native_client/src/trusted/service_runtime/osx", "+pdf/pdf_ppapi.h", "+sandbox",
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 9c12fe0..73d78a39 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -185,6 +185,7 @@ #include "chromeos/crosapi/mojom/crosapi.mojom.h" // nogncheck #include "chromeos/lacros/lacros_dbus_helper.h" #include "chromeos/lacros/lacros_service.h" +#include "media/base/media_switches.h" #endif base::LazyInstance<ChromeContentGpuClient>::DestructorAtExit @@ -563,6 +564,29 @@ init_params->default_paths->downloads, drivefs); } + // This lives here rather than in ChromeBrowserMainExtraPartsLacros due to + // timing constraints. If we relocate it, then the flags aren't propagated + // to the GPU process. + if (init_params->build_flags.has_value()) { + for (auto flag : init_params->build_flags.value()) { + switch (flag) { + case crosapi::mojom::BuildFlag::kUnknown: + break; + case crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc: + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kLacrosEnablePlatformEncryptedHevc); + break; + case crosapi::mojom::BuildFlag::kEnablePlatformHevc: + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kLacrosEnablePlatformHevc); + break; + case crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia: + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kLacrosUseChromeosProtectedMedia); + break; + } + } + } } #endif
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 92d0fefe..70c62469 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -9498,9 +9498,6 @@ <message name="IDS_HISTORY_CLOSED_RESTORE_WINDOW_MAC" desc="The Mac menu item for restoring all the tabs of a recently closed window."> Restore All Tabs </message> - <message name="IDS_HISTORY_INCOGNITO_DISCLAIMER_MAC" desc="The Mac menu item for the Incognito disclaimer text."> - History isn’t saved in Incognito - </message> <!-- Window menu --> <message name="IDS_MINIMIZE_WINDOW_MAC" desc="The Mac menu item for minimize the window menu."
diff --git a/chrome/app/generated_resources_grd/IDS_HISTORY_INCOGNITO_DISCLAIMER_MAC.png.sha1 b/chrome/app/generated_resources_grd/IDS_HISTORY_INCOGNITO_DISCLAIMER_MAC.png.sha1 deleted file mode 100644 index 0a688c0..0000000 --- a/chrome/app/generated_resources_grd/IDS_HISTORY_INCOGNITO_DISCLAIMER_MAC.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c19f7b46f8031b8d97f541b1d0bfa8fdb59ca89a \ No newline at end of file
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc index df48011..f5481d5 100644 --- a/chrome/browser/ash/crosapi/browser_manager.cc +++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -27,6 +27,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/posix/eintr_wrapper.h" @@ -56,6 +57,7 @@ #include "chrome/browser/notifications/system_notification_helper.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" +#include "chrome/common/channel_info.h" #include "chromeos/crosapi/cpp/crosapi_constants.h" #include "chromeos/startup/startup_switches.h" #include "components/policy/proto/device_management_backend.pb.h" @@ -77,6 +79,21 @@ namespace { +// The actual Lacros launch mode. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class LacrosLaunchMode { + // Indicates that Lacros is disabled. + kLacrosDisabled = 0, + // Indicates that Lacros and Ash are both enabled and accessible by the user. + kSideBySide = 1, + // Similar to kSideBySide but Lacros is the primary browser. + kLacrosPrimary = 2, + // Lacros is the only browser and Ash is disabled. + kLacrosOnly = 3, + kMaxValue = kLacrosOnly +}; + using LaunchParamsFromBackground = BrowserManager::LaunchParamsFromBackground; // Pointer to the global instance of BrowserManager. @@ -723,6 +740,9 @@ void BrowserManager::OnSessionStateChanged() { DCHECK_EQ(state_, State::NOT_INITIALIZED); + // Perform the UMA recording for the current Lacros mode of operation. + RecordLacrosLaunchMode(); + // Wait for session to become active. auto* session_manager = session_manager::SessionManager::Get(); if (session_manager->session_state() != @@ -871,4 +891,23 @@ // TODO(https://crbug.com/1194187): Implement this. } +void BrowserManager::RecordLacrosLaunchMode() { + LacrosLaunchMode lacros_mode; + if (!browser_util::IsAshWebBrowserEnabled(chrome::GetChannel())) { + // As Ash is disabled, Lacros is the only available browser. + lacros_mode = LacrosLaunchMode::kLacrosOnly; + } else if (browser_util::IsLacrosPrimaryBrowser()) { + // Lacros is the primary browser - but Ash is still available. + lacros_mode = LacrosLaunchMode::kLacrosPrimary; + } else if (browser_util::IsLacrosEnabled()) { + // If Lacros is enabled but not primary or the only browser, the + // side by side mode is active. + lacros_mode = LacrosLaunchMode::kSideBySide; + } else { + lacros_mode = LacrosLaunchMode::kLacrosDisabled; + } + + UMA_HISTOGRAM_ENUMERATION("ChromeOS.Ash.Lacros.Launch.Mode", lacros_mode); +} + } // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_manager.h b/chrome/browser/ash/crosapi/browser_manager.h index ae57805a..14054431 100644 --- a/chrome/browser/ash/crosapi/browser_manager.h +++ b/chrome/browser/ash/crosapi/browser_manager.h
@@ -196,6 +196,9 @@ private: FRIEND_TEST_ALL_PREFIXES(BrowserManagerTest, LacrosKeepAlive); + // Remember the launch mode of Lacros. + void RecordLacrosLaunchMode(); + // These ash features are allowed to request that Lacros stay running in the // background. enum class Feature {
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc index 8b22dc3..5716a4d4 100644 --- a/chrome/browser/ash/crosapi/browser_util.cc +++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -86,6 +86,7 @@ #include "components/version_info/version_info.h" #include "google_apis/gaia/gaia_auth_util.h" #include "media/capture/mojom/video_capture.mojom.h" +#include "media/media_buildflags.h" #include "mojo/public/cpp/platform/platform_channel.h" #include "mojo/public/cpp/system/invitation.h" #include "services/device/public/mojom/hid.mojom.h" @@ -698,6 +699,21 @@ } } + // Add any BUILDFLAGs we use to pass our per-platform/ build configuration to + // lacros for runtime handling instead. + std::vector<crosapi::mojom::BuildFlag> build_flags; +#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC) + build_flags.emplace_back( + crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc); +#endif // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC) +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) + build_flags.emplace_back(crosapi::mojom::BuildFlag::kEnablePlatformHevc); +#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) +#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) + build_flags.emplace_back( + crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia); +#endif // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) + params->build_flags = std::move(build_flags); return params; }
diff --git a/chrome/browser/ash/events/event_rewriter_delegate_impl.cc b/chrome/browser/ash/events/event_rewriter_delegate_impl.cc index 1709100..5157167 100644 --- a/chrome/browser/ash/events/event_rewriter_delegate_impl.cc +++ b/chrome/browser/ash/events/event_rewriter_delegate_impl.cc
@@ -17,19 +17,18 @@ #include "ui/aura/client/aura_constants.h" #include "ui/message_center/message_center.h" -namespace chromeos { +namespace ash { EventRewriterDelegateImpl::EventRewriterDelegateImpl( wm::ActivationClient* activation_client) : EventRewriterDelegateImpl( activation_client, - std::make_unique<ash::DeprecationNotificationController>( + std::make_unique<DeprecationNotificationController>( message_center::MessageCenter::Get())) {} EventRewriterDelegateImpl::EventRewriterDelegateImpl( wm::ActivationClient* activation_client, - std::unique_ptr<ash::DeprecationNotificationController> - deprecation_controller) + std::unique_ptr<DeprecationNotificationController> deprecation_controller) : pref_service_for_testing_(nullptr), activation_client_(activation_client), deprecation_controller_(std::move(deprecation_controller)) {} @@ -115,7 +114,7 @@ aura::Window* active_window = activation_client_->GetActiveWindow(); return active_window && - active_window->GetProperty(ash::kSearchKeyAcceleratorReservedKey); + active_window->GetProperty(kSearchKeyAcceleratorReservedKey); } bool EventRewriterDelegateImpl::NotifyDeprecatedRightClickRewrite() { @@ -138,4 +137,4 @@ return profile ? profile->GetPrefs() : nullptr; } -} // namespace chromeos +} // namespace ash
diff --git a/chrome/browser/ash/events/event_rewriter_delegate_impl.h b/chrome/browser/ash/events/event_rewriter_delegate_impl.h index 056adb7d..a33a434 100644 --- a/chrome/browser/ash/events/event_rewriter_delegate_impl.h +++ b/chrome/browser/ash/events/event_rewriter_delegate_impl.h
@@ -12,18 +12,15 @@ class PrefService; namespace ash { -class DeprecationNotificationController; -} -namespace chromeos { +class DeprecationNotificationController; class EventRewriterDelegateImpl : public ui::EventRewriterChromeOS::Delegate { public: explicit EventRewriterDelegateImpl(wm::ActivationClient* activation_client); - EventRewriterDelegateImpl( - wm::ActivationClient* activation_client, - std::unique_ptr<ash::DeprecationNotificationController> - deprecation_controller); + EventRewriterDelegateImpl(wm::ActivationClient* activation_client, + std::unique_ptr<DeprecationNotificationController> + deprecation_controller); ~EventRewriterDelegateImpl() override; void set_pref_service_for_testing(const PrefService* pref_service) { @@ -50,12 +47,16 @@ wm::ActivationClient* activation_client_; // Handles showing notifications when deprecated event rewrites occur. - std::unique_ptr<ash::DeprecationNotificationController> - deprecation_controller_; + std::unique_ptr<DeprecationNotificationController> deprecation_controller_; DISALLOW_COPY_AND_ASSIGN(EventRewriterDelegateImpl); }; +} // namespace ash + +// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done. +namespace chromeos { +using ::ash::EventRewriterDelegateImpl; } // namespace chromeos #endif // CHROME_BROWSER_ASH_EVENTS_EVENT_REWRITER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc index acbac35..9f1c229 100644 --- a/chrome/browser/ash/events/event_rewriter_unittest.cc +++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -169,7 +169,7 @@ } // namespace -namespace chromeos { +namespace ash { class EventRewriterTest : public ChromeAshTestBase { public: @@ -183,8 +183,7 @@ input_method::InitializeForTesting( input_method_manager_mock_); // pass ownership auto deprecation_controller = - std::make_unique<ash::DeprecationNotificationController>( - &message_center_); + std::make_unique<DeprecationNotificationController>(&message_center_); deprecation_controller_ = deprecation_controller.get(); delegate_ = std::make_unique<EventRewriterDelegateImpl>( nullptr, std::move(deprecation_controller)); @@ -366,8 +365,7 @@ std::unique_ptr<EventRewriterDelegateImpl> delegate_; chromeos::input_method::FakeImeKeyboard fake_ime_keyboard_; std::unique_ptr<ui::EventRewriterChromeOS> rewriter_; - ash::DeprecationNotificationController* - deprecation_controller_; // Not owned. + DeprecationNotificationController* deprecation_controller_; // Not owned. message_center::FakeMessageCenter message_center_; }; @@ -3812,7 +3810,7 @@ void SetUp() override { ChromeAshTestBase::SetUp(); - sticky_keys_controller_ = ash::Shell::Get()->sticky_keys_controller(); + sticky_keys_controller_ = Shell::Get()->sticky_keys_controller(); delegate_ = std::make_unique<EventRewriterDelegateImpl>(nullptr); delegate_->set_pref_service_for_testing(prefs()); rewriter_ = std::make_unique<ui::EventRewriterChromeOS>( @@ -3828,7 +3826,7 @@ } protected: - ash::StickyKeysController* sticky_keys_controller_; + StickyKeysController* sticky_keys_controller_; private: std::unique_ptr<EventRewriterDelegateImpl> delegate_; @@ -4025,7 +4023,7 @@ TEST_F(EventRewriterTest, DontRewriteIfNotRewritten_SearchClickIsRightClick) { scoped_feature_list_.InitAndEnableFeature( - chromeos::features::kUseSearchClickForRightClick); + features::kUseSearchClickForRightClick); DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN); EXPECT_EQ(message_center_.NotificationCount(), 0); } @@ -4392,34 +4390,34 @@ ASSERT_TRUE(overlay_); } - ash::StickyKeysOverlay* overlay_; + StickyKeysOverlay* overlay_; }; TEST_F(StickyKeysOverlayTest, OneModifierEnabled) { EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); // Pressing modifier key should show overlay. SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::DomKey::CONTROL); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); // Pressing a normal key should hide overlay. SendActivateStickyKeyPattern(ui::VKEY_T, ui::DomCode::US_T, ui::DomKey::Constant<'t'>::Character); EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); } TEST_F(StickyKeysOverlayTest, TwoModifiersEnabled) { EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); // Pressing two modifiers should show overlay. @@ -4428,24 +4426,24 @@ SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::DomKey::CONTROL); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); // Pressing a normal key should hide overlay. SendActivateStickyKeyPattern(ui::VKEY_N, ui::DomCode::US_N, ui::DomKey::Constant<'n'>::Character); EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); } TEST_F(StickyKeysOverlayTest, LockedModifier) { EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); // Pressing a modifier key twice should lock modifier and show overlay. @@ -4454,22 +4452,22 @@ SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT, ui::DomKey::ALT); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); // Pressing a normal key should not hide overlay. SendActivateStickyKeyPattern(ui::VKEY_D, ui::DomCode::US_D, ui::DomKey::Constant<'d'>::Character); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); } TEST_F(StickyKeysOverlayTest, LockedAndNormalModifier) { EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); // Pressing a modifier key twice should lock modifier and show overlay. @@ -4478,37 +4476,37 @@ SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::DomKey::CONTROL); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); // Pressing another modifier key should still show overlay. SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT, ui::DomKey::SHIFT); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); // Pressing a normal key should not hide overlay but disable normal modifier. SendActivateStickyKeyPattern(ui::VKEY_D, ui::DomCode::US_D, ui::DomKey::Constant<'d'>::Character); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); } TEST_F(StickyKeysOverlayTest, ModifiersDisabled) { EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN)); // Enable modifiers. @@ -4526,13 +4524,13 @@ ui::DomKey::META); EXPECT_TRUE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED, + EXPECT_EQ(STICKY_KEY_STATE_ENABLED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED, + EXPECT_EQ(STICKY_KEY_STATE_LOCKED, overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN)); // Disable modifiers and overlay should be hidden. @@ -4550,13 +4548,13 @@ ui::DomKey::META); EXPECT_FALSE(overlay_->is_visible()); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_ALT_DOWN)); - EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED, + EXPECT_EQ(STICKY_KEY_STATE_DISABLED, overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN)); } @@ -4740,4 +4738,4 @@ ui::DomKey::Constant<'1'>::Character}}); } -} // namespace chromeos +} // namespace ash
diff --git a/chrome/browser/ash/input_method/ime_service_connector.cc b/chrome/browser/ash/input_method/ime_service_connector.cc index 81be41b..3e1a9226 100644 --- a/chrome/browser/ash/input_method/ime_service_connector.cc +++ b/chrome/browser/ash/input_method/ime_service_connector.cc
@@ -8,8 +8,8 @@ #include <utility> #include "base/files/file_util.h" -#include "chrome/browser/chromeos/service_sandbox_type.h" #include "chromeos/services/ime/constants.h" +#include "chromeos/services/ime/public/mojom/ime_service.mojom.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "content/public/browser/service_process_host.h" #include "net/base/load_flags.h"
diff --git a/chrome/browser/ash/scanning/scan_service.cc b/chrome/browser/ash/scanning/scan_service.cc index 1a3862d..1ab74286 100644 --- a/chrome/browser/ash/scanning/scan_service.cc +++ b/chrome/browser/ash/scanning/scan_service.cc
@@ -296,6 +296,26 @@ weak_ptr_factory_.GetWeakPtr()))); } +void ScanService::RemovePage(uint32_t page_index) { + // TODO: Update RemovePage() to allow removing with only one scanned image + // once the UI supports it. + if (scanned_images_.size() <= 1) { + mojo::ReportBadMessage( + "Invalid call to ScanService::RemovePage(), 1 or less scanned images " + "available"); + return; + } + + if (page_index >= scanned_images_.size()) { + mojo::ReportBadMessage( + "Invalid page_index passed to ScanService::RemovePage()"); + return; + } + + scanned_images_.erase(scanned_images_.begin() + page_index); + --num_pages_scanned_; +} + void ScanService::CompleteMultiPageScan() { OnScanCompleted(lorgnette::SCAN_FAILURE_MODE_NO_FAILURE); multi_page_controller_receiver_.reset();
diff --git a/chrome/browser/ash/scanning/scan_service.h b/chrome/browser/ash/scanning/scan_service.h index 8d85a659..9f7252f 100644 --- a/chrome/browser/ash/scanning/scan_service.h +++ b/chrome/browser/ash/scanning/scan_service.h
@@ -72,6 +72,7 @@ void ScanNextPage(const base::UnguessableToken& scanner_id, scanning::mojom::ScanSettingsPtr settings, ScanNextPageCallback callback) override; + void RemovePage(uint32_t page_index) override; void CompleteMultiPageScan() override; // Binds receiver_ by consuming |pending_receiver|.
diff --git a/chrome/browser/ash/scanning/scan_service_unittest.cc b/chrome/browser/ash/scanning/scan_service_unittest.cc index e2cddda..58e8b63f 100644 --- a/chrome/browser/ash/scanning/scan_service_unittest.cc +++ b/chrome/browser/ash/scanning/scan_service_unittest.cc
@@ -366,6 +366,11 @@ task_environment_.RunUntilIdle(); } + void RemovePage(const int page_number) { + multi_page_scan_controller_remote_->RemovePage(page_number); + task_environment_.RunUntilIdle(); + } + protected: // A `BrowserTaskEnvironment` allows the test to create a `TestingProfile`. content::BrowserTaskEnvironment task_environment_{ @@ -881,4 +886,96 @@ EXPECT_FALSE(StartMultiPageScan(scanners[0]->id, settings.Clone())); } +// Test that a page can be removed from a multi-page scan with two scanned +// images. +TEST_F(ScanServiceTest, MultiPageScanRemoveWithTwoPages) { + base::HistogramTester histogram_tester; + scoped_feature_list_.InitWithFeatures( + {chromeos::features::kScanAppMultiPageScan}, {}); + + fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( + {kFirstTestScannerName}); + const std::vector<std::string> scan_data = {CreatePng()}; + fake_lorgnette_scanner_manager_.SetScanResponse(scan_data); + auto scanners = GetScanners(); + ASSERT_EQ(scanners.size(), 1u); + + mojo_ipc::ScanSettings settings = CreateScanSettings( + scanned_files_mount_->GetRootPath(), mojo_ipc::FileType::kPdf); + + // Scan two pages without completing the scan. + EXPECT_TRUE(StartMultiPageScan(scanners[0]->id, settings.Clone())); + EXPECT_TRUE(ScanNextPage(scanners[0]->id, settings.Clone())); + + // Delete the first page. + RemovePage(0); + + CompleteMultiPageScan(); + + // Expect 1 record of the Scanning.NumPagesScanned metric in the 1 pages + // scanned bucket. + histogram_tester.ExpectUniqueSample("Scanning.NumPagesScanned", 1, 1); +} + +// Test that a page can be removed from a multi-page scan with three scanned +// images. +TEST_F(ScanServiceTest, MultiPageScanRemoveWithThreePages) { + base::HistogramTester histogram_tester; + scoped_feature_list_.InitWithFeatures( + {chromeos::features::kScanAppMultiPageScan}, {}); + + fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( + {kFirstTestScannerName}); + const std::vector<std::string> scan_data = {CreatePng()}; + fake_lorgnette_scanner_manager_.SetScanResponse(scan_data); + auto scanners = GetScanners(); + ASSERT_EQ(scanners.size(), 1u); + + mojo_ipc::ScanSettings settings = CreateScanSettings( + scanned_files_mount_->GetRootPath(), mojo_ipc::FileType::kPdf); + + // Scan three pages without completing the scan. + EXPECT_TRUE(StartMultiPageScan(scanners[0]->id, settings.Clone())); + EXPECT_TRUE(ScanNextPage(scanners[0]->id, settings.Clone())); + EXPECT_TRUE(ScanNextPage(scanners[0]->id, settings.Clone())); + + // Delete the second page. + RemovePage(1); + + CompleteMultiPageScan(); + + // Expect 1 record of the Scanning.NumPagesScanned metric in the 2 pages + // scanned bucket. + histogram_tester.ExpectUniqueSample("Scanning.NumPagesScanned", 2, 1); +} + +// Test that if there's only one page available, it can't be removed during a +// multi-page scan session. +TEST_F(ScanServiceTest, MultiPageScanCantRemoveOnePage) { + base::HistogramTester histogram_tester; + scoped_feature_list_.InitWithFeatures( + {chromeos::features::kScanAppMultiPageScan}, {}); + + fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( + {kFirstTestScannerName}); + const std::vector<std::string> scan_data = {CreatePng()}; + fake_lorgnette_scanner_manager_.SetScanResponse(scan_data); + auto scanners = GetScanners(); + ASSERT_EQ(scanners.size(), 1u); + + mojo_ipc::ScanSettings settings = CreateScanSettings( + scanned_files_mount_->GetRootPath(), mojo_ipc::FileType::kPdf); + + // Scan four pages without completing the scan. + EXPECT_TRUE(StartMultiPageScan(scanners[0]->id, settings.Clone())); + + // The attempt to delete the only page should do nothing. + RemovePage(0); + CompleteMultiPageScan(); + + // Expect 1 record of the Scanning.NumPagesScanned metric in the 1 page + // scanned bucket. + histogram_tester.ExpectUniqueSample("Scanning.NumPagesScanned", 1, 1); +} + } // namespace ash
diff --git a/chrome/browser/browsing_data/access_context_audit_service_factory.cc b/chrome/browser/browsing_data/access_context_audit_service_factory.cc index 12a1aa3..fc5f0b9 100644 --- a/chrome/browser/browsing_data/access_context_audit_service_factory.cc +++ b/chrome/browser/browsing_data/access_context_audit_service_factory.cc
@@ -47,8 +47,8 @@ // cookies. DCHECK(profile->ShouldPersistSessionCookies()); - std::unique_ptr<AccessContextAuditService> context_audit_service( - new AccessContextAuditService(profile)); + auto context_audit_service = + std::make_unique<AccessContextAuditService>(profile); if (!context_audit_service->Init( context->GetPath(), context->GetDefaultStoragePartition()
diff --git a/chrome/browser/browsing_data/access_context_audit_service_unittest.cc b/chrome/browser/browsing_data/access_context_audit_service_unittest.cc index b7a8c5b..5aedec0 100644 --- a/chrome/browser/browsing_data/access_context_audit_service_unittest.cc +++ b/chrome/browser/browsing_data/access_context_audit_service_unittest.cc
@@ -98,8 +98,8 @@ std::unique_ptr<KeyedService> BuildTestContextAuditService( content::BrowserContext* context) { - std::unique_ptr<AccessContextAuditService> service( - new AccessContextAuditService(static_cast<Profile*>(context))); + auto service = std::make_unique<AccessContextAuditService>( + static_cast<Profile*>(context)); service->SetTaskRunnerForTesting(task_runner_); service->Init(temp_directory_.GetPath(), cookie_manager(), history_service(), storage_partition());
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper.h b/chrome/browser/browsing_data/browsing_data_quota_helper.h index 9a84c3a..4b63601 100644 --- a/chrome/browser/browsing_data/browsing_data_quota_helper.h +++ b/chrome/browser/browsing_data/browsing_data_quota_helper.h
@@ -61,7 +61,7 @@ using QuotaInfoArray = std::list<QuotaInfo>; using FetchResultCallback = base::OnceCallback<void(const QuotaInfoArray&)>; - static BrowsingDataQuotaHelper* Create(Profile* profile); + static scoped_refptr<BrowsingDataQuotaHelper> Create(Profile* profile); virtual void StartFetching(FetchResultCallback callback) = 0;
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_impl.cc b/chrome/browser/browsing_data/browsing_data_quota_helper_impl.cc index 07fd1ac..9aab27e 100644 --- a/chrome/browser/browsing_data/browsing_data_quota_helper_impl.cc +++ b/chrome/browser/browsing_data/browsing_data_quota_helper_impl.cc
@@ -29,8 +29,9 @@ using content::BrowserContext; // static -BrowsingDataQuotaHelper* BrowsingDataQuotaHelper::Create(Profile* profile) { - return new BrowsingDataQuotaHelperImpl( +scoped_refptr<BrowsingDataQuotaHelper> BrowsingDataQuotaHelper::Create( + Profile* profile) { + return base::MakeRefCounted<BrowsingDataQuotaHelperImpl>( profile->GetDefaultStoragePartition()->GetQuotaManager()); }
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_impl.h b/chrome/browser/browsing_data/browsing_data_quota_helper_impl.h index 6d648c1..e0f77695 100644 --- a/chrome/browser/browsing_data/browsing_data_quota_helper_impl.h +++ b/chrome/browser/browsing_data/browsing_data_quota_helper_impl.h
@@ -13,8 +13,8 @@ #include <utility> #include "base/callback_forward.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/browsing_data/browsing_data_quota_helper.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom-forward.h" @@ -35,12 +35,17 @@ void StartFetching(FetchResultCallback callback) override; void RevokeHostQuota(const std::string& host) override; + explicit BrowsingDataQuotaHelperImpl(storage::QuotaManager* quota_manager); + + BrowsingDataQuotaHelperImpl(const BrowsingDataQuotaHelperImpl&) = delete; + BrowsingDataQuotaHelperImpl& operator=(const BrowsingDataQuotaHelperImpl&) = + delete; + private: using PendingHosts = std::set<std::pair<std::string, blink::mojom::StorageType>>; using QuotaInfoMap = std::map<std::string, QuotaInfo>; - explicit BrowsingDataQuotaHelperImpl(storage::QuotaManager* quota_manager); ~BrowsingDataQuotaHelperImpl() override; // Calls QuotaManager::GetStorageKeysModifiedBetween for each storage type. @@ -75,10 +80,6 @@ base::WeakPtrFactory<BrowsingDataQuotaHelperImpl> weak_factory_{this}; - friend class BrowsingDataQuotaHelper; - friend class BrowsingDataQuotaHelperTest; - - DISALLOW_COPY_AND_ASSIGN(BrowsingDataQuotaHelperImpl); }; #endif // CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_QUOTA_HELPER_IMPL_H_
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc index 01e198b..a129255 100644 --- a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
@@ -43,8 +43,8 @@ content::GetIOThreadTaskRunner({}).get(), /*quota_change_callback=*/base::DoNothing(), /*special_storage_policy=*/nullptr, storage::GetQuotaSettingsFunc()); - helper_ = base::WrapRefCounted( - new BrowsingDataQuotaHelperImpl(quota_manager_.get())); + helper_ = + base::MakeRefCounted<BrowsingDataQuotaHelperImpl>(quota_manager_.get()); } void TearDown() override {
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest_base.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest_base.cc index 859a894..43cb8c43 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_browsertest_base.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest_base.cc
@@ -183,10 +183,9 @@ // Start a download. content::DownloadManager* download_manager = GetBrowser()->profile()->GetDownloadManager(); - std::unique_ptr<content::DownloadTestObserver> observer( - new content::DownloadTestObserverTerminal( - download_manager, 1, - content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT)); + auto observer = std::make_unique<content::DownloadTestObserverTerminal>( + download_manager, 1, + content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT); GURL download_url = ui_test_utils::GetTestUrl(base::FilePath().AppendASCII("downloads"), @@ -363,23 +362,26 @@ content::NativeIOContext* native_io_context = storage_partition->GetNativeIOContext(); auto container = std::make_unique<LocalDataContainer>( - new browsing_data::CookieHelper( + base::MakeRefCounted<browsing_data::CookieHelper>( storage_partition, CookiesTreeModel::GetCookieDeletionDisabledCallback(profile)), - new browsing_data::DatabaseHelper(profile), - new browsing_data::LocalStorageHelper(profile), + base::MakeRefCounted<browsing_data::DatabaseHelper>(profile), + base::MakeRefCounted<browsing_data::LocalStorageHelper>(profile), /*session_storage_helper=*/nullptr, - new browsing_data::AppCacheHelper( + base::MakeRefCounted<browsing_data::AppCacheHelper>( storage_partition->GetAppCacheService()), - new browsing_data::IndexedDBHelper(storage_partition), + base::MakeRefCounted<browsing_data::IndexedDBHelper>(storage_partition), base::MakeRefCounted<browsing_data::FileSystemHelper>( file_system_context, browsing_data_file_system_util::GetAdditionalFileSystemTypes(), native_io_context), BrowsingDataQuotaHelper::Create(profile), - new browsing_data::ServiceWorkerHelper(service_worker_context), - new browsing_data::SharedWorkerHelper(storage_partition), - new browsing_data::CacheStorageHelper(storage_partition), + base::MakeRefCounted<browsing_data::ServiceWorkerHelper>( + service_worker_context), + base::MakeRefCounted<browsing_data::SharedWorkerHelper>( + storage_partition), + base::MakeRefCounted<browsing_data::CacheStorageHelper>( + storage_partition), BrowsingDataMediaLicenseHelper::Create(file_system_context)); base::RunLoop run_loop; CookiesTreeObserver observer(run_loop.QuitClosure());
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index c2bfbfb..bee9618 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -281,7 +281,7 @@ : profile_(Profile::FromBrowserContext(browser_context)) #if defined(OS_ANDROID) , - webapp_registry_(new WebappRegistry()) + webapp_registry_(std::make_unique<WebappRegistry>()) #endif { domain_reliability_clearer_ = base::BindRepeating(
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index df7145b8..522320974 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1132,9 +1132,10 @@ FaviconServiceFactory::GetDefaultFactory()); profile_builder.AddTestingFactory( SpellcheckServiceFactory::GetInstance(), - base::BindRepeating([](content::BrowserContext* profile) { - return std::unique_ptr<KeyedService>( - new SpellcheckService(static_cast<Profile*>(profile))); + base::BindRepeating([](content::BrowserContext* profile) + -> std::unique_ptr<KeyedService> { + return std::make_unique<SpellcheckService>( + static_cast<Profile*>(profile)); })); profile_builder.AddTestingFactory(SyncServiceFactory::GetInstance(), SyncServiceFactory::GetDefaultFactory());
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc index a5a824d..d7047043 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.cc +++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -1205,16 +1205,18 @@ CookieTreeCookiesNode* CookieTreeHostNode::GetOrCreateCookiesNode() { if (cookies_child_) return cookies_child_; - cookies_child_ = new CookieTreeCookiesNode; - AddChildSortedByTitle(base::WrapUnique(cookies_child_)); + auto cookies_node = std::make_unique<CookieTreeCookiesNode>(); + cookies_child_ = cookies_node.get(); + AddChildSortedByTitle(std::move(cookies_node)); return cookies_child_; } CookieTreeDatabasesNode* CookieTreeHostNode::GetOrCreateDatabasesNode() { if (databases_child_) return databases_child_; - databases_child_ = new CookieTreeDatabasesNode; - AddChildSortedByTitle(base::WrapUnique(databases_child_)); + auto databases_node = std::make_unique<CookieTreeDatabasesNode>(); + databases_child_ = databases_node.get(); + AddChildSortedByTitle(std::move(databases_node)); return databases_child_; } @@ -1222,8 +1224,9 @@ CookieTreeHostNode::GetOrCreateLocalStoragesNode() { if (local_storages_child_) return local_storages_child_; - local_storages_child_ = new CookieTreeLocalStoragesNode; - AddChildSortedByTitle(base::WrapUnique(local_storages_child_)); + auto local_storages_node = std::make_unique<CookieTreeLocalStoragesNode>(); + local_storages_child_ = local_storages_node.get(); + AddChildSortedByTitle(std::move(local_storages_node)); return local_storages_child_; } @@ -1231,32 +1234,37 @@ CookieTreeHostNode::GetOrCreateSessionStoragesNode() { if (session_storages_child_) return session_storages_child_; - session_storages_child_ = new CookieTreeSessionStoragesNode; - AddChildSortedByTitle(base::WrapUnique(session_storages_child_)); + auto session_storages_node = + std::make_unique<CookieTreeSessionStoragesNode>(); + session_storages_child_ = session_storages_node.get(); + AddChildSortedByTitle(std::move(session_storages_node)); return session_storages_child_; } CookieTreeAppCachesNode* CookieTreeHostNode::GetOrCreateAppCachesNode() { if (appcaches_child_) return appcaches_child_; - appcaches_child_ = new CookieTreeAppCachesNode; - AddChildSortedByTitle(base::WrapUnique(appcaches_child_)); + auto appcaches_node = std::make_unique<CookieTreeAppCachesNode>(); + appcaches_child_ = appcaches_node.get(); + AddChildSortedByTitle(std::move(appcaches_node)); return appcaches_child_; } CookieTreeIndexedDBsNode* CookieTreeHostNode::GetOrCreateIndexedDBsNode() { if (indexed_dbs_child_) return indexed_dbs_child_; - indexed_dbs_child_ = new CookieTreeIndexedDBsNode; - AddChildSortedByTitle(base::WrapUnique(indexed_dbs_child_)); + auto indexed_dbs_node = std::make_unique<CookieTreeIndexedDBsNode>(); + indexed_dbs_child_ = indexed_dbs_node.get(); + AddChildSortedByTitle(std::move(indexed_dbs_node)); return indexed_dbs_child_; } CookieTreeFileSystemsNode* CookieTreeHostNode::GetOrCreateFileSystemsNode() { if (file_systems_child_) return file_systems_child_; - file_systems_child_ = new CookieTreeFileSystemsNode; - AddChildSortedByTitle(base::WrapUnique(file_systems_child_)); + auto file_systems_node = std::make_unique<CookieTreeFileSystemsNode>(); + file_systems_child_ = file_systems_node.get(); + AddChildSortedByTitle(std::move(file_systems_node)); return file_systems_child_; } @@ -1264,8 +1272,9 @@ std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info) { if (quota_child_) return quota_child_; - quota_child_ = new CookieTreeQuotaNode(quota_info); - AddChildSortedByTitle(base::WrapUnique(quota_child_)); + auto quota_node = std::make_unique<CookieTreeQuotaNode>(quota_info); + quota_child_ = quota_node.get(); + AddChildSortedByTitle(std::move(quota_node)); return quota_child_; } @@ -1273,8 +1282,9 @@ CookieTreeHostNode::GetOrCreateServiceWorkersNode() { if (service_workers_child_) return service_workers_child_; - service_workers_child_ = new CookieTreeServiceWorkersNode; - AddChildSortedByTitle(base::WrapUnique(service_workers_child_)); + auto service_workers_node = std::make_unique<CookieTreeServiceWorkersNode>(); + service_workers_child_ = service_workers_node.get(); + AddChildSortedByTitle(std::move(service_workers_node)); return service_workers_child_; } @@ -1282,8 +1292,9 @@ CookieTreeHostNode::GetOrCreateSharedWorkersNode() { if (shared_workers_child_) return shared_workers_child_; - shared_workers_child_ = new CookieTreeSharedWorkersNode; - AddChildSortedByTitle(base::WrapUnique(shared_workers_child_)); + auto shared_workers_node = std::make_unique<CookieTreeSharedWorkersNode>(); + shared_workers_child_ = shared_workers_node.get(); + AddChildSortedByTitle(std::move(shared_workers_node)); return shared_workers_child_; } @@ -1291,8 +1302,9 @@ CookieTreeHostNode::GetOrCreateCacheStoragesNode() { if (cache_storages_child_) return cache_storages_child_; - cache_storages_child_ = new CookieTreeCacheStoragesNode; - AddChildSortedByTitle(base::WrapUnique(cache_storages_child_)); + auto cache_storages_node = std::make_unique<CookieTreeCacheStoragesNode>(); + cache_storages_child_ = cache_storages_node.get(); + AddChildSortedByTitle(std::move(cache_storages_node)); return cache_storages_child_; } @@ -1300,8 +1312,9 @@ CookieTreeHostNode::GetOrCreateMediaLicensesNode() { if (media_licenses_child_) return media_licenses_child_; - media_licenses_child_ = new CookieTreeMediaLicensesNode(); - AddChildSortedByTitle(base::WrapUnique(media_licenses_child_)); + auto media_licenses_node = std::make_unique<CookieTreeMediaLicensesNode>(); + media_licenses_child_ = media_licenses_node.get(); + AddChildSortedByTitle(std::move(media_licenses_node)); return media_licenses_child_; } @@ -1946,23 +1959,25 @@ auto* native_io_context = storage_partition->GetNativeIOContext(); auto container = std::make_unique<LocalDataContainer>( - new browsing_data::CookieHelper( + base::MakeRefCounted<browsing_data::CookieHelper>( storage_partition, GetCookieDeletionDisabledCallback(profile)), - new browsing_data::DatabaseHelper(profile), - new browsing_data::LocalStorageHelper(profile), + base::MakeRefCounted<browsing_data::DatabaseHelper>(profile), + base::MakeRefCounted<browsing_data::LocalStorageHelper>(profile), /*session_storage_helper=*/nullptr, - new browsing_data::AppCacheHelper( + base::MakeRefCounted<browsing_data::AppCacheHelper>( storage_partition->GetAppCacheService()), - new browsing_data::IndexedDBHelper(storage_partition), + base::MakeRefCounted<browsing_data::IndexedDBHelper>(storage_partition), base::MakeRefCounted<browsing_data::FileSystemHelper>( file_system_context, browsing_data_file_system_util::GetAdditionalFileSystemTypes(), native_io_context), BrowsingDataQuotaHelper::Create(profile), - new browsing_data::ServiceWorkerHelper( + base::MakeRefCounted<browsing_data::ServiceWorkerHelper>( storage_partition->GetServiceWorkerContext()), - new browsing_data::SharedWorkerHelper(storage_partition), - new browsing_data::CacheStorageHelper(storage_partition), + base::MakeRefCounted<browsing_data::SharedWorkerHelper>( + storage_partition), + base::MakeRefCounted<browsing_data::CacheStorageHelper>( + storage_partition), BrowsingDataMediaLicenseHelper::Create(file_system_context)); return std::make_unique<CookiesTreeModel>(
diff --git a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc index 7fe4d62..f75a5f1 100644 --- a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc +++ b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
@@ -9,6 +9,7 @@ #include <utility> #include "base/memory/ptr_util.h" +#include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -64,39 +65,48 @@ void SetUp() override { profile_ = std::make_unique<TestingProfile>(); mock_browsing_data_cookie_helper_ = - new browsing_data::MockCookieHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockCookieHelper>(profile_.get()); mock_browsing_data_database_helper_ = - new browsing_data::MockDatabaseHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockDatabaseHelper>(profile_.get()); mock_browsing_data_local_storage_helper_ = - new browsing_data::MockLocalStorageHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockLocalStorageHelper>( + profile_.get()); mock_browsing_data_session_storage_helper_ = - new browsing_data::MockLocalStorageHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockLocalStorageHelper>( + profile_.get()); mock_browsing_data_appcache_helper_ = - new browsing_data::MockAppCacheHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockAppCacheHelper>(profile_.get()); mock_browsing_data_indexed_db_helper_ = - new browsing_data::MockIndexedDBHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockIndexedDBHelper>( + profile_.get()); mock_browsing_data_file_system_helper_ = - new browsing_data::MockFileSystemHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockFileSystemHelper>( + profile_.get()); mock_browsing_data_quota_helper_ = - new MockBrowsingDataQuotaHelper(profile_.get()); + base::MakeRefCounted<MockBrowsingDataQuotaHelper>(profile_.get()); mock_browsing_data_service_worker_helper_ = - new browsing_data::MockServiceWorkerHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockServiceWorkerHelper>( + profile_.get()); mock_browsing_data_shared_worker_helper_ = - new browsing_data::MockSharedWorkerHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockSharedWorkerHelper>( + profile_.get()); mock_browsing_data_cache_storage_helper_ = - new browsing_data::MockCacheStorageHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockCacheStorageHelper>( + profile_.get()); mock_browsing_data_media_license_helper_ = - new MockBrowsingDataMediaLicenseHelper(profile_.get()); + base::MakeRefCounted<MockBrowsingDataMediaLicenseHelper>( + profile_.get()); const char kExtensionScheme[] = "extensionscheme"; - scoped_refptr<content_settings::CookieSettings> cookie_settings = - new content_settings::CookieSettings( + auto cookie_settings = + base::MakeRefCounted<content_settings::CookieSettings>( HostContentSettingsMapFactory::GetForProfile(profile_.get()), profile_->GetPrefs(), profile_->IsIncognitoProfile(), kExtensionScheme); #if BUILDFLAG(ENABLE_EXTENSIONS) special_storage_policy_ = - new ExtensionSpecialStoragePolicy(cookie_settings.get()); + base::MakeRefCounted<ExtensionSpecialStoragePolicy>( + cookie_settings.get()); #endif }
diff --git a/chrome/browser/browsing_data/site_data_size_collector_unittest.cc b/chrome/browser/browsing_data/site_data_size_collector_unittest.cc index f27bc877..b0ef6cd5 100644 --- a/chrome/browser/browsing_data/site_data_size_collector_unittest.cc +++ b/chrome/browser/browsing_data/site_data_size_collector_unittest.cc
@@ -38,21 +38,26 @@ void SetUp() override { profile_ = std::make_unique<TestingProfile>(); mock_browsing_data_cookie_helper_ = - new browsing_data::MockCookieHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockCookieHelper>(profile_.get()); mock_browsing_data_database_helper_ = - new browsing_data::MockDatabaseHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockDatabaseHelper>(profile_.get()); mock_browsing_data_local_storage_helper_ = - new browsing_data::MockLocalStorageHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockLocalStorageHelper>( + profile_.get()); mock_browsing_data_appcache_helper_ = - new browsing_data::MockAppCacheHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockAppCacheHelper>(profile_.get()); mock_browsing_data_indexed_db_helper_ = - new browsing_data::MockIndexedDBHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockIndexedDBHelper>( + profile_.get()); mock_browsing_data_file_system_helper_ = - new browsing_data::MockFileSystemHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockFileSystemHelper>( + profile_.get()); mock_browsing_data_service_worker_helper_ = - new browsing_data::MockServiceWorkerHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockServiceWorkerHelper>( + profile_.get()); mock_browsing_data_cache_storage_helper_ = - new browsing_data::MockCacheStorageHelper(profile_.get()); + base::MakeRefCounted<browsing_data::MockCacheStorageHelper>( + profile_.get()); base::WriteFile(profile_->GetPath().Append(chrome::kCookieFilename), kCookieFileData, base::size(kCookieFileData));
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 0da8ea6..e07aca8 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -1593,13 +1593,6 @@ CloudPrintProxyServiceFactory::GetForProfile(profile_); #endif - // Two different types of hang detection cannot attempt to upload crashes at - // the same time or they would interfere with each other. - if (!base::HangWatcher::IsCrashReportingEnabled()) { - // Start watching all browser threads for responsiveness. - ThreadWatcherList::StartWatchingAll(parsed_command_line()); - } - // This has to come before the first GetInstance() call. PreBrowserStart() // seems like a reasonable place to put this, except on Android, // OfflinePageInfoHandler::Register() below calls GetInstance(). @@ -1607,10 +1600,6 @@ sessions::ContentSerializedNavigationDriver::SetInstance( ChromeSerializedNavigationDriver::GetInstance()); -#if defined(OS_ANDROID) - ThreadWatcherAndroid::RegisterApplicationStatusListener(); -#endif // defined(OS_ANDROID) - #if BUILDFLAG(ENABLE_OFFLINE_PAGES) offline_pages::OfflinePageInfoHandler::Register(); #endif @@ -1827,9 +1816,6 @@ if (notify_result_ == ProcessSingleton::PROCESS_NONE) process_singleton_->Cleanup(); - // Stop all tasks that might run on WatchDogThread. - ThreadWatcherList::StopWatchingAll(); - browser_process_->metrics_service()->Stop(); restart_last_session_ = browser_shutdown::ShutdownPreThreadsStop();
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 56c871a..c09a8d1d 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -3158,7 +3158,6 @@ "secure_channel/secure_channel_client_provider.h", "secure_channel/util/histogram_util.cc", "secure_channel/util/histogram_util.h", - "service_sandbox_type.h", "session_length_limiter.cc", "session_length_limiter.h", "set_time_dialog.cc",
diff --git a/chrome/browser/chromeos/OWNERS b/chrome/browser/chromeos/OWNERS index 5439524..078bbe0 100644 --- a/chrome/browser/chromeos/OWNERS +++ b/chrome/browser/chromeos/OWNERS
@@ -11,7 +11,3 @@ xiyuan@chromium.org per-file *active_directory*=file://chrome/browser/ash/authpolicy/OWNERS per-file tpm_firmware_update*=mnissler@chromium.org - -# Sandbox selection needs security review -per-file service_sandbox_type.h=set noparent -per-file service_sandbox_type.h=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index 38db7c05..43d7b66 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -7,6 +7,8 @@ #include <memory> +// TODO(https://crbug.com/1164001): remove and use forward declaration. +#include "ash/components/power/dark_resume_controller.h" #include "base/macros.h" #include "base/task/cancelable_task_tracker.h" // TODO(https://crbug.com/1164001): remove and use forward declaration. @@ -14,6 +16,8 @@ // TODO(https://crbug.com/1164001): remove and use forward declaration. #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" // TODO(https://crbug.com/1164001): remove and use forward declaration. +#include "chrome/browser/ash/events/event_rewriter_delegate_impl.h" +// TODO(https://crbug.com/1164001): remove and use forward declaration. #include "chrome/browser/ash/login/demo_mode/demo_mode_resources_remover.h" // TODO(https://crbug.com/1164001): remove and use forward declaration. #include "chrome/browser/ash/notifications/gnubby_notification.h" @@ -86,7 +90,6 @@ class BulkPrintersCalculatorFactory; class DebugdNotificationHandler; -class EventRewriterDelegateImpl; class FastTransitionObserver; class LoginScreenExtensionsLifetimeManager; class LoginScreenExtensionsStorageCleaner; @@ -109,10 +112,6 @@ class KeyPermissionsManager; } -namespace system { -class DarkResumeController; -} // namespace system - // ChromeBrowserMainParts implementation for chromeos specific code. // NOTE: Chromeos UI (Ash) support should be added to // ChromeBrowserMainExtraPartsAsh instead. This class should not depend on
diff --git a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc index b52762a..653dd8d 100644 --- a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc +++ b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc
@@ -68,18 +68,53 @@ SystemNotificationManager::CreateNotification( const std::string& notification_id, const std::u16string& title, - const std::u16string& message) { + const std::u16string& message, + const base::RepeatingClosure& click_callback) { return ash::CreateSystemNotification( message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title, message, std::u16string(), GURL(), message_center::NotifierId(), message_center::RichNotificationData(), - new message_center::HandleNotificationClickDelegate( - base::BindRepeating(&SystemNotificationManager::Dismiss, - weak_ptr_factory_.GetWeakPtr(), notification_id)), + new message_center::HandleNotificationClickDelegate(click_callback), kNotificationGoogleIcon, message_center::SystemNotificationWarningLevel::NORMAL); } +std::unique_ptr<message_center::Notification> +SystemNotificationManager::CreateNotification( + const std::string& notification_id, + const std::u16string& title, + const std::u16string& message) { + return CreateNotification( + notification_id, title, message, + base::BindRepeating(&SystemNotificationManager::Dismiss, + weak_ptr_factory_.GetWeakPtr(), notification_id)); +} + +std::unique_ptr<message_center::Notification> +SystemNotificationManager::CreateNotification( + const std::string& notification_id, + int title_id, + int message_id) { + std::u16string title = l10n_util::GetStringUTF16(title_id); + std::u16string message = l10n_util::GetStringUTF16(message_id); + return CreateNotification(notification_id, title, message); +} + +std::unique_ptr<message_center::Notification> +SystemNotificationManager::CreateNotification( + const std::string& notification_id, + int title_id, + int message_id, + const scoped_refptr<message_center::NotificationDelegate>& delegate) { + std::u16string title = l10n_util::GetStringUTF16(title_id); + std::u16string message = l10n_util::GetStringUTF16(message_id); + return ash::CreateSystemNotification( + message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title, message, + std::u16string(), GURL(), message_center::NotifierId(), + message_center::RichNotificationData(), delegate, kNotificationGoogleIcon, + message_center::SystemNotificationWarningLevel::NORMAL); +} + void SystemNotificationManager::HandleProgressClick( const std::string& notification_id, absl::optional<int> button_index) { @@ -117,23 +152,6 @@ message_center::SystemNotificationWarningLevel::NORMAL); } -std::unique_ptr<message_center::Notification> -SystemNotificationManager::CreateNotification( - const std::string& notification_id, - int title_id, - int message_id) { - return ash::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, - l10n_util::GetStringUTF16(title_id), - l10n_util::GetStringUTF16(message_id), std::u16string(), GURL(), - message_center::NotifierId(), message_center::RichNotificationData(), - new message_center::HandleNotificationClickDelegate( - base::BindRepeating(&SystemNotificationManager::Dismiss, - weak_ptr_factory_.GetWeakPtr(), notification_id)), - kNotificationGoogleIcon, - message_center::SystemNotificationWarningLevel::NORMAL); -} - void SystemNotificationManager::Dismiss(const std::string& notification_id) { GetNotificationDisplayService()->Close(NotificationHandler::Type::TRANSIENT, notification_id); @@ -295,17 +313,13 @@ event_arguments[0], &dialog_event)) { std::vector<message_center::ButtonInfo> notification_buttons; id = file_manager_private::ToString(dialog_event.type); - notification = ash::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, kDriveDialogId, - l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL), - l10n_util::GetStringUTF16(IDS_FILE_BROWSER_OFFLINE_ENABLE_MESSAGE), - std::u16string(), GURL(), message_center::NotifierId(), - message_center::RichNotificationData(), + scoped_refptr<message_center::NotificationDelegate> delegate = new message_center::HandleNotificationClickDelegate(base::BindRepeating( &SystemNotificationManager::HandleDriveDialogClick, - weak_ptr_factory_.GetWeakPtr())), - kNotificationGoogleIcon, - message_center::SystemNotificationWarningLevel::NORMAL); + weak_ptr_factory_.GetWeakPtr())); + notification = CreateNotification( + kDriveDialogId, IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL, + IDS_FILE_BROWSER_OFFLINE_ENABLE_MESSAGE, delegate); notification_buttons.push_back(message_center::ButtonInfo( l10n_util::GetStringUTF16(IDS_FILE_BROWSER_OFFLINE_ENABLE_REJECT))); @@ -448,27 +462,49 @@ } std::unique_ptr<message_center::Notification> +SystemNotificationManager::MakeMountErrorNotification( + file_manager_private::MountCompletedEvent& event, + const Volume& volume) { + std::unique_ptr<message_center::Notification> notification; + scoped_refptr<message_center::NotificationDelegate> delegate = + new message_center::HandleNotificationClickDelegate(base::BindRepeating( + &SystemNotificationManager::HandleRemovableNotificationClick, + weak_ptr_factory_.GetWeakPtr(), volume.mount_path().value())); + switch (event.status) { + case file_manager_private:: + MOUNT_COMPLETED_STATUS_ERROR_UNSUPPORTED_FILESYSTEM: + notification = CreateNotification( + kRemovableNotificationId, IDS_REMOVABLE_DEVICE_DETECTION_TITLE, + IDS_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE, delegate); + break; + default: + DLOG(WARNING) << "Unhandled mount error for " << event.status; + break; + } + return notification; +} + +std::unique_ptr<message_center::Notification> SystemNotificationManager::MakeRemovableNotification( file_manager_private::MountCompletedEvent& event, const Volume& volume) { + if (event.status != file_manager_private::MOUNT_COMPLETED_STATUS_SUCCESS) { + return MakeMountErrorNotification(event, volume); + } int message_id; if (volume.is_read_only() && !volume.is_read_only_removable_device()) { message_id = IDS_REMOVABLE_DEVICE_NAVIGATION_MESSAGE_READONLY_POLICY; } else { message_id = IDS_REMOVABLE_DEVICE_NAVIGATION_MESSAGE; } + scoped_refptr<message_center::NotificationDelegate> delegate = + new message_center::HandleNotificationClickDelegate(base::BindRepeating( + &SystemNotificationManager::HandleRemovableNotificationClick, + weak_ptr_factory_.GetWeakPtr(), volume.mount_path().value())); std::unique_ptr<message_center::Notification> notification = - ash::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, kRemovableNotificationId, - l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_DETECTION_TITLE), - l10n_util::GetStringUTF16(message_id), std::u16string(), GURL(), - message_center::NotifierId(), message_center::RichNotificationData(), - new message_center::HandleNotificationClickDelegate( - base::BindRepeating( - &SystemNotificationManager::HandleRemovableNotificationClick, - weak_ptr_factory_.GetWeakPtr(), volume.mount_path().value())), - kNotificationGoogleIcon, - message_center::SystemNotificationWarningLevel::NORMAL); + CreateNotification(kRemovableNotificationId, + IDS_REMOVABLE_DEVICE_DETECTION_TITLE, message_id, + delegate); std::vector<message_center::ButtonInfo> notification_buttons; notification_buttons.push_back(message_center::ButtonInfo(
diff --git a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h index e1cd039..22c108ee 100644 --- a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h +++ b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h
@@ -43,6 +43,25 @@ void HandleDeviceEvent(const file_manager_private::DeviceEvent& event); /** + * Returns an instance of an 'ash' Notification with a bound click callback. + */ + std::unique_ptr<message_center::Notification> CreateNotification( + const std::string& notification_id, + const std::u16string& title, + const std::u16string& message, + const base::RepeatingClosure& click_callback); + + /** + * Returns an instance of an 'ash' Notification with title and message + * specified by string ID values (for 110n) with a bound click delegate. + */ + std::unique_ptr<message_center::Notification> CreateNotification( + const std::string& notification_id, + int title_id, + int message_id, + const scoped_refptr<message_center::NotificationDelegate>& delegate); + + /** * Returns an instance of an 'ash' Notification. */ std::unique_ptr<message_center::Notification> CreateNotification( @@ -135,6 +154,13 @@ absl::optional<int> button_index); /** + * Makes a notification instance for mount errors. + */ + std::unique_ptr<message_center::Notification> MakeMountErrorNotification( + file_manager_private::MountCompletedEvent& event, + const Volume& volume); + + /** * Makes a notification instance for removable devices. */ std::unique_ptr<message_center::Notification> MakeRemovableNotification(
diff --git a/chrome/browser/chromeos/service_sandbox_type.h b/chrome/browser/chromeos/service_sandbox_type.h deleted file mode 100644 index c92d707..0000000 --- a/chrome/browser/chromeos/service_sandbox_type.h +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_SERVICE_SANDBOX_TYPE_H_ -#define CHROME_BROWSER_CHROMEOS_SERVICE_SANDBOX_TYPE_H_ - -#include "build/chromeos_buildflags.h" -#include "chromeos/assistant/buildflags.h" -#include "content/public/browser/service_process_host.h" -#include "sandbox/policy/sandbox_type.h" - -// This file maps service classes to sandbox types. See -// ServiceProcessHost::Launch() for how these templates are consumed. - -// chromeos::ime::mojom::ImeService -namespace chromeos { -namespace ime { -namespace mojom { -class ImeService; -} // namespace mojom -} // namespace ime -} // namespace chromeos - -template <> -inline sandbox::policy::SandboxType -content::GetServiceSandboxType<chromeos::ime::mojom::ImeService>() { - return sandbox::policy::SandboxType::kIme; -} - -// chromeos::tts::mojom::TtsService -namespace chromeos { -namespace tts { -namespace mojom { -class TtsService; -} // namespace mojom -} // namespace tts -} // namespace chromeos - -template <> -inline sandbox::policy::SandboxType -content::GetServiceSandboxType<chromeos::tts::mojom::TtsService>() { - return sandbox::policy::SandboxType::kTts; -} - -#if BUILDFLAG(IS_CHROMEOS_ASH) -// recording::mojom::RecordingService -namespace recording { -namespace mojom { -class RecordingService; -} // namespace mojom -} // namespace recording - -// This is needed to prevent the service from crashing on a sandbox seccomp-bpf -// failure when the audio capturer tries to open a stream. -// TODO(https://crbug.com/1147991): Explore alternatives if any. -template <> -inline sandbox::policy::SandboxType -content::GetServiceSandboxType<recording::mojom::RecordingService>() { - return sandbox::policy::SandboxType::kVideoCapture; -} - -// chromeos::assistant::mojom::AssistantAudioDecoderFactory -namespace chromeos { -namespace assistant { -namespace mojom { -class AssistantAudioDecoderFactory; -} // namespace mojom -} // namespace assistant -} // namespace chromeos - -template <> -inline sandbox::policy::SandboxType content::GetServiceSandboxType< - chromeos::assistant::mojom::AssistantAudioDecoderFactory>() { - return sandbox::policy::SandboxType::kUtility; -} - -#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) -// chromeos::libassistant::mojom::LibassistantService -namespace chromeos { -namespace libassistant { -namespace mojom { -class LibassistantService; -} // namespace mojom -} // namespace libassistant -} // namespace chromeos - -template <> -inline sandbox::policy::SandboxType content::GetServiceSandboxType< - chromeos::libassistant::mojom::LibassistantService>() { - return sandbox::policy::SandboxType::kLibassistant; -} -#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - -#endif // CHROME_BROWSER_CHROMEOS_SERVICE_SANDBOX_TYPE_H_
diff --git a/chrome/browser/download/internal/android/java/res/layout/download_manager_section_header.xml b/chrome/browser/download/internal/android/java/res/layout/download_manager_section_header.xml index 348feba..7dd2bbe 100644 --- a/chrome/browser/download/internal/android/java/res/layout/download_manager_section_header.xml +++ b/chrome/browser/download/internal/android/java/res/layout/download_manager_section_header.xml
@@ -8,16 +8,12 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> - <Space - android:id="@+id/top_space" - android:layout_width="match_parent" - android:layout_height="@dimen/download_manager_section_title_padding_top" /> - <TextView android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/top_space" + android:layout_marginTop="@dimen/download_manager_section_title_top_margin" + android:layout_marginBottom="@dimen/download_manager_section_title_bottom_margin" android:paddingStart="@dimen/list_item_default_margin" android:maxLines="1" android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
diff --git a/chrome/browser/download/internal/android/java/res/values-v17/dimens.xml b/chrome/browser/download/internal/android/java/res/values-v17/dimens.xml index 144d25e..bb4fcce 100644 --- a/chrome/browser/download/internal/android/java/res/values-v17/dimens.xml +++ b/chrome/browser/download/internal/android/java/res/values-v17/dimens.xml
@@ -11,7 +11,9 @@ <dimen name="download_manager_max_image_item_width_wide_screen">300dp</dimen> <dimen name="download_manager_prefetch_vertical_margin">12dp</dimen> <dimen name="download_manager_recycler_view_min_padding_wide_screen">16dp</dimen> - <dimen name="download_manager_section_title_padding_top">16dp</dimen> + <dimen name="download_manager_section_title_top_margin">16dp</dimen> + <dimen name="download_manager_section_title_bottom_margin">8dp</dimen> + <dimen name="download_manager_vertical_margin_between_download_types">8dp</dimen> <!-- The corner radius is calculated by subtracting the hairline border width from the background card corner radius. --> <dimen name="download_manager_thumbnail_corner_radius">7dp</dimen>
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java index d6ee183d..112bc69 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.download.home.DownloadManagerUiConfig; import org.chromium.chrome.browser.download.home.list.DateOrderedListCoordinator.DateOrderedListObserver; +import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem; import org.chromium.chrome.browser.download.home.list.holder.ListItemViewHolder; import org.chromium.chrome.browser.download.internal.R; import org.chromium.components.browser_ui.widget.displaystyle.HorizontalDisplayStyle; @@ -41,6 +42,7 @@ private final int mInterImagePaddingPx; private final int mPrefetchVerticalPaddingPx; private final int mHorizontalPaddingPx; + private final int mVerticalPaddingPx; private final int mMaxWidthImageItemPx; private final RecyclerView mView; @@ -61,6 +63,8 @@ R.dimen.download_manager_horizontal_margin); mPrefetchVerticalPaddingPx = context.getResources().getDimensionPixelSize( R.dimen.download_manager_prefetch_vertical_margin); + mVerticalPaddingPx = context.getResources().getDimensionPixelSize( + R.dimen.download_manager_vertical_margin_between_download_types); mMaxWidthImageItemPx = context.getResources().getDimensionPixelSize( R.dimen.download_manager_max_image_item_width_wide_screen); @@ -242,6 +246,11 @@ == HorizontalDisplayStyle.WIDE) { outRect.right += Math.max(getAvailableViewWidth() - mMaxWidthImageItemPx, 0); } + + if (item instanceof ListItem.OfflineItemListItem + && ((OfflineItemListItem) item).isLastOfDownloadTypeInSection) { + outRect.bottom += mVerticalPaddingPx; + } } private void computeItemDecoration(int position, Rect outRect) {
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java index 9fcbf06..93a33de 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java
@@ -174,6 +174,7 @@ public OfflineItem item; public boolean spanFullWidth; public boolean isGrouped; + public boolean isLastOfDownloadTypeInSection; /** Creates an {@link OfflineItemListItem} wrapping {@code item}. */ public OfflineItemListItem(OfflineItem item) {
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/mutator/ListItemPropertySetter.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/mutator/ListItemPropertySetter.java index 874ad42..b96766f5 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/mutator/ListItemPropertySetter.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/mutator/ListItemPropertySetter.java
@@ -15,6 +15,7 @@ * Post processes the items in the list and sets properties for UI as appropriate. The properties * being set are: * - Image item span width. + * - Margins between {@link OfflineItemFilter} types (image, document, etc.). */ public class ListItemPropertySetter implements ListConsumer { private final DownloadManagerUiConfig mConfig; @@ -40,6 +41,7 @@ /** Sets properties for items in the given list. */ private void setProperties(List<ListItem> sortedList) { setWidthForImageItems(sortedList); + setMarginsBetweenDifferentItemTypes(sortedList); } private void setWidthForImageItems(List<ListItem> listItems) { @@ -63,4 +65,25 @@ } } } + + private void setMarginsBetweenDifferentItemTypes(List<ListItem> listItems) { + for (int i = 0; i < listItems.size(); i++) { + ListItem currentItem = listItems.get(i); + + // Margins should only be added to OfflineItems + if (!(currentItem instanceof OfflineItemListItem)) { + continue; + } + + ListItem nextItem = i >= listItems.size() - 1 ? null : listItems.get(i + 1); + boolean nextItemIsDifferentType = nextItem instanceof OfflineItemListItem + && ((OfflineItemListItem) currentItem).item.filter + != ((OfflineItemListItem) nextItem).item.filter; + boolean nextItemIsNotOfflineItem = !(nextItem instanceof OfflineItemListItem); + + if (nextItemIsDifferentType || nextItemIsNotOfflineItem) { + ((OfflineItemListItem) currentItem).isLastOfDownloadTypeInSection = true; + } + } + } }
diff --git a/chrome/browser/enterprise/connectors/file_system/box_captured_sites_interactive_uitest.cc b/chrome/browser/enterprise/connectors/file_system/box_captured_sites_interactive_uitest.cc index 378a1e2..66f8bf23 100644 --- a/chrome/browser/enterprise/connectors/file_system/box_captured_sites_interactive_uitest.cc +++ b/chrome/browser/enterprise/connectors/file_system/box_captured_sites_interactive_uitest.cc
@@ -450,7 +450,6 @@ void CancelBoxSignInConfirmation() { signin_confirmation_dlg_->Cancel(); - WaitForSignInDialogToShow(); } // Bypass Single-Factor-Authentication sign in and authorize @@ -1029,6 +1028,42 @@ download_item_observer.upload_observer()->GetFileUrl()); } +IN_PROC_BROWSER_TEST_F(BoxCapturedSitesInteractiveTest, EnterpriseIdMismatch) { + SetCloudFSCPolicy(GetAllAllowedTestPolicy("123456789")); + StartWprUsingFSCCaptureDir("box.com.ent.id.mismatch.wpr"); + + StartDownloadByNavigatingToEmbeddedServerUrl( + "/enterprise/connectors/file_system/downloads/cipd/" + "direct_download_gibben.epub"); + BoxDownloadItemObserver download_item_observer( + download_manager_observer()->GetLatestDownloadItem()); + + download_item_observer.WaitForSignInConfirmationDialog(); + download_item_observer.sign_in_observer()->AcceptBoxSigninConfirmation(); + + // Bypass the Box signin and authorize dialog. + download_item_observer.sign_in_observer()->AuthorizeWithUserAndPasswordSFA( + GetBoxAccountUserName(), GetBoxAccountPassword()); + EXPECT_FALSE( + download_item_observer.fetch_access_token_observer()->WaitForFetch()); + + // The sign in confirmation dialog will relaunch after the enterprise ID + // mismatch error. Close the confirmation dialog. + download_item_observer.WaitForSignInConfirmationDialog(); + download_item_observer.sign_in_observer()->CancelBoxSignInConfirmation(); + + download_manager_observer()->WaitForDownloadToFinish(); + EXPECT_TRUE( + download_item_observer.upload_observer()->WaitForTmpFileDeletion()); + + // Check that the download shelf is displaying the expected "upload + // cancelled" text. + EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); + DownloadItemView* item_view = GetItemViewForLastDownload(); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED), + item_view->GetStatusTextForTesting()); +} + IN_PROC_BROWSER_TEST_F(BoxCapturedSitesInteractiveTest, CancelSignInConfirmation) { SetCloudFSCPolicy(GetAllAllowedTestPolicy("797972721"));
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index 07e39eb..9a546676 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -427,13 +427,7 @@ << message_; } -// TODO(http://crbug.com/1213987): flaky on ChromeOS. -#if defined(OS_CHROMEOS) -#define MAYBE_DesktopInitialFocus DISABLED_DesktopInitialFocus -#else -#define MAYBE_DesktopInitialFocus DesktopInitialFocus -#endif -IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_DesktopInitialFocus) { +IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopInitialFocus) { ASSERT_TRUE(RunExtensionTest("automation/tests/desktop", {.page_url = "initial_focus.html"})) << message_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index ba692bca..f8df6a9 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2041,11 +2041,6 @@ "expiry_milestone": 100 }, { - "name": "enable-ios-managed-settings-ui", - "owners": [ "tinazwang", "rohitrao", "bling-flags@google.com" ], - "expiry_milestone": 90 - }, - { "name": "enable-javascript-harmony", "owners": [ "adamk", "hablich" ], // This flag is used by web developers to test upcoming javascript features. @@ -4370,7 +4365,7 @@ // TODO(b/172341945): Fix this asap. "name": "overscroll-history-navigation", "owners": [ "mohsen", "jinsukkim" ], - "expiry_milestone": 93 + "expiry_milestone": 105 }, { "name": "page-info-discoverability", @@ -5215,8 +5210,8 @@ }, { "name": "split-settings-sync", - "owners": [ "jamescook", "cros-system-services@google.com" ], - "expiry_milestone": 92 + "owners": [ "rsorokin", "cros-oac@google.com" ], + "expiry_milestone": 98 }, { "name": "start-surface",
diff --git a/chrome/browser/image_editor/screenshot_flow.cc b/chrome/browser/image_editor/screenshot_flow.cc index fce9bf8..810c6a2 100644 --- a/chrome/browser/image_editor/screenshot_flow.cc +++ b/chrome/browser/image_editor/screenshot_flow.cc
@@ -22,6 +22,11 @@ #include "ui/snapshot/snapshot.h" #include "ui/views/background.h" +#if defined(OS_MAC) +#include "content/public/browser/render_view_host.h" +#include "ui/views/widget/widget.h" +#endif + #if defined(USE_AURA) #include "ui/aura/window.h" #include "ui/wm/core/window_util.h" @@ -62,29 +67,39 @@ if (screen_capture_layer_) return; -#if defined(OS_MAC) - return; -#else - const gfx::NativeWindow& native_window = web_contents_->GetNativeView(); - screen_capture_layer_ = std::make_unique<ui::Layer>(ui::LayerType::LAYER_TEXTURED); screen_capture_layer_->SetName("ScreenshotRegionSelectionLayer"); screen_capture_layer_->SetFillsBoundsOpaquely(true); screen_capture_layer_->set_delegate(this); +#if defined(OS_MAC) + gfx::Rect bounds = web_contents_->GetViewBounds(); + const gfx::NativeView web_contents_view = + web_contents_->GetContentNativeView(); + views::Widget* widget = + views::Widget::GetWidgetForNativeView(web_contents_view); + ui::Layer* content_layer = widget->GetLayer(); + const gfx::Rect offset_bounds = widget->GetWindowBoundsInScreen(); + bounds.Offset(-offset_bounds.x(), -offset_bounds.y()); - ui::Layer* native_window_layer = native_window->layer(); - native_window_layer->Add(screen_capture_layer_.get()); - native_window_layer->StackAtTop(screen_capture_layer_.get()); - - screen_capture_layer_->SetBounds(native_window->bounds()); - screen_capture_layer_->SetVisible(true); - + views::Widget* top_widget = + views::Widget::GetTopLevelWidgetForNativeView(web_contents_view); + views::View* root_view = top_widget->GetRootView(); + root_view->AddPreTargetHandler(this); +#else + const gfx::NativeWindow& native_window = web_contents_->GetNativeView(); + ui::Layer* content_layer = native_window->layer(); + const gfx::Rect bounds = native_window->bounds(); // Capture mouse down and drag events on our window. // TODO(skare): We should exit from this mode when moving between tabs, // clicking on browser chrome, etc. native_window->AddPreTargetHandler(this); #endif + + content_layer->Add(screen_capture_layer_.get()); + content_layer->StackAtTop(screen_capture_layer_.get()); + screen_capture_layer_->SetBounds(bounds); + screen_capture_layer_->SetVisible(true); } void ScreenshotFlow::RemoveUIOverlay() { @@ -92,31 +107,42 @@ return; #if defined(OS_MAC) - return; + views::Widget* widget = views::Widget::GetWidgetForNativeView( + web_contents_->GetContentNativeView()); + ui::Layer* content_layer = widget->GetLayer(); + views::View* root_view = widget->GetRootView(); + root_view->RemovePreTargetHandler(this); #else // TODO(skare): Fix case of web_contents_ going away. // Otherwise we can crash on shutdown while the capture mode is active. const gfx::NativeWindow& native_window = web_contents_->GetNativeView(); native_window->RemovePreTargetHandler(this); + ui::Layer* content_layer = native_window->layer(); +#endif - ui::Layer* native_window_layer = native_window->layer(); - native_window_layer->Remove(screen_capture_layer_.get()); + content_layer->Remove(screen_capture_layer_.get()); + screen_capture_layer_->set_delegate(nullptr); screen_capture_layer_.reset(); -#endif } void ScreenshotFlow::Start(ScreenshotCaptureCallback flow_callback) { -#if defined(OS_MAC) - return; -#else flow_callback_ = std::move(flow_callback); +#if defined(OS_MAC) + const gfx::NativeView& native_view = web_contents_->GetContentNativeView(); + gfx::Image img; + bool rval = ui::GrabViewSnapshot(native_view, + gfx::Rect(web_contents_->GetSize()), &img); + // If |img| is empty, clients should treat it as a canceled action, but + // we have a DCHECK for development as we expected this call to succeed. + DCHECK(rval); + OnSnapshotComplete(img); +#else // Start the capture process by capturing the entire window, then allow // the user to drag out a selection mask. ui::GrabWindowSnapshotAsyncCallback screenshot_callback = base::BindOnce(&ScreenshotFlow::OnSnapshotComplete, weak_this_); const gfx::NativeWindow& native_window = web_contents_->GetNativeView(); - native_window->GetRootWindow(); // TODO(skare): Evaluate against other screenshot capture methods. // The synchronous variant mentions support is different between platforms // and another library might be better if there is a browser process. @@ -180,6 +206,7 @@ canvas.DrawImageInt(image_foreground_, region.x(), region.y(), w, h, 0, 0, w, h, false); result.image = gfx::Image::CreateFrom1xBitmap(canvas.GetBitmap()); + result.screen_bounds = screen_capture_layer_->bounds(); } RemoveUIOverlay();
diff --git a/chrome/browser/image_editor/screenshot_flow.h b/chrome/browser/image_editor/screenshot_flow.h index 719ea7d..2a9ef46 100644 --- a/chrome/browser/image_editor/screenshot_flow.h +++ b/chrome/browser/image_editor/screenshot_flow.h
@@ -34,6 +34,8 @@ struct ScreenshotCaptureResult { // The image obtained from capture. Empty on failure. gfx::Image image; + // The bounds of the screen during which capture took place. Empty on failure. + gfx::Rect screen_bounds; }; // Callback for obtaining image data.
diff --git a/chrome/browser/lacros/download_controller_client_lacros.cc b/chrome/browser/lacros/download_controller_client_lacros.cc index b7ea0b36..02c050387 100644 --- a/chrome/browser/lacros/download_controller_client_lacros.cc +++ b/chrome/browser/lacros/download_controller_client_lacros.cc
@@ -6,12 +6,13 @@ #include "base/bind.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chromeos/crosapi/mojom/download_controller.mojom.h" #include "chromeos/lacros/lacros_service.h" #include "components/download/public/common/download_item.h" +#include "components/download/public/common/simple_download_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/download_item_utils.h" -#include "content/public/browser/download_manager.h" #include "mojo/public/cpp/bindings/pending_remote.h" namespace { @@ -58,124 +59,6 @@ } // namespace -// A wrapper for `base::ScopedObservation` and `DownloadManageObserver` that -// allows us to keep the manager associated with its `OnManagerInitialized()` -// event. This prevents us from having to check every manager and profile when -// a single manager is updated, since `OnManagerInitialized()` does not pass a -// pointer to the relevant `content::DownloadManager`. -class DownloadControllerClientLacros::ObservableDownloadManager - : public content::DownloadManager::Observer, - public download::DownloadItem::Observer { - public: - ObservableDownloadManager(DownloadControllerClientLacros* controller_client, - content::DownloadManager* manager) - : controller_client_(controller_client), manager_(manager) { - download_manager_observer_.Observe(manager); - if (manager->IsManagerInitialized()) - OnManagerInitialized(); - } - - ~ObservableDownloadManager() override = default; - - // Returns all downloads, no matter the type or state. - std::vector<download::DownloadItem*> GetAllDownloads() { - download::SimpleDownloadManager::DownloadVector downloads; - if (manager_->IsManagerInitialized()) - manager_->GetAllDownloads(&downloads); - return downloads; - } - - // Pauses the download associated with the specified `download_guid`. - void Pause(const std::string& download_guid) { - auto* download = manager_->GetDownloadByGuid(download_guid); - if (download) - download->Pause(); - } - - // Resumes the download associated with the specified `download_guid`. If - // `user_resume` is `true`, it signifies that this invocation was triggered by - // an explicit user action. - void Resume(const std::string& download_guid, bool user_resume) { - auto* download = manager_->GetDownloadByGuid(download_guid); - if (download) - download->Resume(user_resume); - } - - // Cancels the download associated with the specified `download_guid`. If - // `user_cancel` is `true`, it signifies that this invocation was triggered by - // an explicit user action. - void Cancel(const std::string& download_guid, bool user_cancel) { - auto* download = manager_->GetDownloadByGuid(download_guid); - if (download) - download->Cancel(user_cancel); - } - - // Marks the download associated with the specified `download_guid` to be - // `open_when_complete`. - void SetOpenWhenComplete(const std::string& download_guid, - bool open_when_complete) { - auto* download = manager_->GetDownloadByGuid(download_guid); - if (download) - download->SetOpenWhenComplete(open_when_complete); - } - - private: - // content::DownloadManager::Observer: - void OnManagerInitialized() override { - download::SimpleDownloadManager::DownloadVector downloads; - manager_->GetAllDownloads(&downloads); - - for (auto* download : downloads) { - download_item_observer_.AddObservation(download); - controller_client_->OnDownloadCreated(download); - } - } - - void ManagerGoingDown(content::DownloadManager* manager) override { - download_manager_observer_.Reset(); - // Manually call the destroyed event for each download, because this - // `ObservableDownloadManager` will be destroyed before we receive them. - download::SimpleDownloadManager::DownloadVector downloads; - manager->GetAllDownloads(&downloads); - - for (auto* download : downloads) - OnDownloadDestroyed(download); - - controller_client_->OnManagerGoingDown(this); - } - - void OnDownloadCreated(content::DownloadManager* manager, - download::DownloadItem* item) override { - if (!manager->IsManagerInitialized()) - return; - download_item_observer_.AddObservation(item); - controller_client_->OnDownloadCreated(item); - } - - // download::DownloadItem::Observer: - void OnDownloadUpdated(download::DownloadItem* item) override { - controller_client_->OnDownloadUpdated(item); - } - - void OnDownloadDestroyed(download::DownloadItem* item) override { - if (download_item_observer_.IsObservingSource(item)) - download_item_observer_.RemoveObservation(item); - controller_client_->OnDownloadDestroyed(item); - } - - DownloadControllerClientLacros* const controller_client_; - - content::DownloadManager* const manager_; - - base::ScopedMultiSourceObservation<download::DownloadItem, - download::DownloadItem::Observer> - download_item_observer_{this}; - - base::ScopedObservation<content::DownloadManager, - content::DownloadManager::Observer> - download_manager_observer_{this}; -}; - DownloadControllerClientLacros::DownloadControllerClientLacros() { g_browser_process->profile_manager()->AddObserver(this); auto profiles = g_browser_process->profile_manager()->GetLoadedProfiles(); @@ -209,10 +92,8 @@ std::vector<crosapi::mojom::DownloadItemPtr> downloads; // Aggregate all downloads. - for (auto& observable_download_manager : observable_download_managers_) { - for (auto* download : observable_download_manager->GetAllDownloads()) - downloads.push_back(ConvertToMojoDownloadItem(download)); - } + for (auto* download : download_notifier_.GetAllDownloads()) + downloads.push_back(ConvertToMojoDownloadItem(download)); // Sort chronologically by start time. std::sort(downloads.begin(), downloads.end(), @@ -225,56 +106,55 @@ } void DownloadControllerClientLacros::Pause(const std::string& download_guid) { - for (auto& observable_download_manager : observable_download_managers_) - observable_download_manager->Pause(download_guid); + auto* download = download_notifier_.GetDownloadByGuid(download_guid); + if (download) + download->Pause(); } void DownloadControllerClientLacros::Resume(const std::string& download_guid, bool user_resume) { - for (auto& observable_download_manager : observable_download_managers_) - observable_download_manager->Resume(download_guid, user_resume); + auto* download = download_notifier_.GetDownloadByGuid(download_guid); + if (download) + download->Resume(user_resume); } void DownloadControllerClientLacros::Cancel(const std::string& download_guid, bool user_cancel) { - for (auto& observable_download_manager : observable_download_managers_) - observable_download_manager->Cancel(download_guid, user_cancel); + auto* download = download_notifier_.GetDownloadByGuid(download_guid); + if (download) + download->Cancel(user_cancel); } void DownloadControllerClientLacros::SetOpenWhenComplete( const std::string& download_guid, bool open_when_complete) { - for (auto& observable_download_manager : observable_download_managers_) { - observable_download_manager->SetOpenWhenComplete(download_guid, - open_when_complete); - } + auto* download = download_notifier_.GetDownloadByGuid(download_guid); + if (download) + download->SetOpenWhenComplete(open_when_complete); } void DownloadControllerClientLacros::OnProfileAdded(Profile* profile) { - profile_observer_.AddObservation(profile); - auto* manager = profile->GetDownloadManager(); - observable_download_managers_.emplace( - std::make_unique<ObservableDownloadManager>(this, manager)); + download_notifier_.AddProfile(profile); } -void DownloadControllerClientLacros::OnOffTheRecordProfileCreated( - Profile* off_the_record) { - OnProfileAdded(off_the_record); -} - -void DownloadControllerClientLacros::OnProfileWillBeDestroyed( - Profile* profile) { - profile_observer_.RemoveObservation(profile); +void DownloadControllerClientLacros::OnManagerInitialized( + content::DownloadManager* manager) { + download::SimpleDownloadManager::DownloadVector downloads; + manager->GetAllDownloads(&downloads); + for (auto* download : downloads) + OnDownloadCreated(manager, download); } void DownloadControllerClientLacros::OnManagerGoingDown( - ObservableDownloadManager* observable_manager) { - auto it = observable_download_managers_.find(observable_manager); - DCHECK_NE(it->get(), observable_download_managers_.end()->get()); - observable_download_managers_.erase(it); + content::DownloadManager* manager) { + download::SimpleDownloadManager::DownloadVector downloads; + manager->GetAllDownloads(&downloads); + for (auto* download : downloads) + OnDownloadDestroyed(manager, download); } void DownloadControllerClientLacros::OnDownloadCreated( + content::DownloadManager* manager, download::DownloadItem* item) { auto* service = chromeos::LacrosService::Get(); if (!service->IsAvailable<crosapi::mojom::DownloadController>()) @@ -285,6 +165,7 @@ } void DownloadControllerClientLacros::OnDownloadUpdated( + content::DownloadManager* manager, download::DownloadItem* item) { auto* service = chromeos::LacrosService::Get(); if (!service->IsAvailable<crosapi::mojom::DownloadController>()) @@ -295,6 +176,7 @@ } void DownloadControllerClientLacros::OnDownloadDestroyed( + content::DownloadManager* manager, download::DownloadItem* item) { auto* service = chromeos::LacrosService::Get(); if (!service->IsAvailable<crosapi::mojom::DownloadController>())
diff --git a/chrome/browser/lacros/download_controller_client_lacros.h b/chrome/browser/lacros/download_controller_client_lacros.h index 52cae56..6bf7174 100644 --- a/chrome/browser/lacros/download_controller_client_lacros.h +++ b/chrome/browser/lacros/download_controller_client_lacros.h
@@ -5,20 +5,18 @@ #ifndef CHROME_BROWSER_LACROS_DOWNLOAD_CONTROLLER_CLIENT_LACROS_H_ #define CHROME_BROWSER_LACROS_DOWNLOAD_CONTROLLER_CLIENT_LACROS_H_ -#include <memory> -#include <set> #include <string> -#include "base/containers/unique_ptr_adapters.h" -#include "base/scoped_multi_source_observation.h" -#include "base/scoped_observation.h" +#include "chrome/browser/download/notification/multi_profile_download_notifier.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager_observer.h" -#include "chrome/browser/profiles/profile_observer.h" #include "chromeos/crosapi/mojom/download_controller.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" +namespace content { +class DownloadManager; +} // namespace content + namespace download { class DownloadItem; } // namespace download @@ -28,8 +26,8 @@ // calls to pause, cancel, and resume downloads from ash-chrome, hence the name. class DownloadControllerClientLacros : public crosapi::mojom::DownloadControllerClient, - public ProfileManagerObserver, - public ProfileObserver { + public MultiProfileDownloadNotifier::Client, + public ProfileManagerObserver { public: DownloadControllerClientLacros(); DownloadControllerClientLacros(const DownloadControllerClientLacros&) = @@ -39,8 +37,6 @@ ~DownloadControllerClientLacros() override; private: - class ObservableDownloadManager; - // crosapi::mojom::DownloadControllerClient: void GetAllDownloads( crosapi::mojom::DownloadControllerClient::GetAllDownloadsCallback @@ -54,24 +50,20 @@ // ProfileManagerObserver: void OnProfileAdded(Profile* profile) override; - // ProfileObserver: - void OnOffTheRecordProfileCreated(Profile* off_the_record) override; - void OnProfileWillBeDestroyed(Profile* profile) override; - - void OnManagerGoingDown(ObservableDownloadManager* observable_manager); - void OnDownloadCreated(download::DownloadItem* item); - void OnDownloadUpdated(download::DownloadItem* item); - void OnDownloadDestroyed(download::DownloadItem* item); - - std::set<std::unique_ptr<ObservableDownloadManager>, - base::UniquePtrComparator> - observable_download_managers_; - - base::ScopedMultiSourceObservation<Profile, ProfileObserver> - profile_observer_{this}; + // MultiProfileDownloadNotifier::Client: + void OnManagerInitialized(content::DownloadManager* manager) override; + void OnManagerGoingDown(content::DownloadManager* manager) override; + void OnDownloadCreated(content::DownloadManager* manager, + download::DownloadItem* item) override; + void OnDownloadUpdated(content::DownloadManager* manager, + download::DownloadItem* item) override; + void OnDownloadDestroyed(content::DownloadManager* manager, + download::DownloadItem* item) override; mojo::Receiver<crosapi::mojom::DownloadControllerClient> client_receiver_{ this}; + MultiProfileDownloadNotifier download_notifier_{ + this, /*wait_for_manager_initialization=*/true}; }; #endif // CHROME_BROWSER_LACROS_DOWNLOAD_CONTROLLER_CLIENT_LACROS_H_
diff --git a/chrome/browser/lens/metrics/lens_metrics.h b/chrome/browser/lens/metrics/lens_metrics.h index b7b3980..b6787c29 100644 --- a/chrome/browser/lens/metrics/lens_metrics.h +++ b/chrome/browser/lens/metrics/lens_metrics.h
@@ -7,11 +7,22 @@ namespace lens { +// Histogram for recording the capture result of Lens Region Search. See enum +// below for types of results. constexpr char kLensRegionSearchCaptureResultHistogramName[] = "Search.RegionsSearch.Lens.Result"; -// This should be kept in sync with the LensRegionSearchCaptureResult enum in -// tools/metrics/histograms/enums.xml. +// Histogram for recording the viewport proportion in relation to region +// selected for the Lens Region Search feature. +constexpr char kLensRegionSearchRegionViewportProportionHistogramName[] = + "Search.RegionSearch.Lens.RegionViewportProportion"; + +// Histogram for recording the aspect ratio of the captured region. +constexpr char kLensRegionSearchRegionAspectRatioHistogramName[] = + "Search.RegionSearch.Lens.RegionAspectRatio"; + +// This should be kept in sync with the LensRegionSearchCaptureResult enum +// in tools/metrics/histograms/enums.xml. enum class LensRegionSearchCaptureResult { SUCCESS = 0, FAILED_TO_OPEN_TAB = 1, @@ -19,6 +30,23 @@ kMaxValue = ERROR_CAPTURING_REGION }; +// This should be kept in sync with the LensRegionSearchAspectRatio enum +// in tools/metrics/histograms/enums.xml. The aspect ratios are defined as: +// SQUARE: [0.8, 1.2] +// WIDE: (1.2, 1.7] +// VERY_WIDE: (1.7, infinity) +// TALL: [0.3, 0.8) +// VERY_TALL: [0, 0.3) +enum class LensRegionSearchAspectRatio { + UNDEFINED = 0, + SQUARE = 1, + WIDE = 2, + VERY_WIDE = 3, + TALL = 4, + VERY_TALL = 5, + kMaxValue = VERY_TALL +}; + } // namespace lens #endif // CHROME_BROWSER_LENS_METRICS_LENS_METRICS_H_
diff --git a/chrome/browser/lens/region_search/lens_region_search_controller.cc b/chrome/browser/lens/region_search/lens_region_search_controller.cc index ff8b309..f2d6ece4 100644 --- a/chrome/browser/lens/region_search/lens_region_search_controller.cc +++ b/chrome/browser/lens/region_search/lens_region_search_controller.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/lens/region_search/lens_region_search_controller.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "chrome/browser/image_editor/screenshot_flow.h" #include "chrome/browser/lens/metrics/lens_metrics.h" @@ -52,6 +53,77 @@ result); } +int LensRegionSearchController::CalculateViewportProportionFromAreas( + int screen_height, + int screen_width, + int image_width, + int image_height) { + // To get the region proportion of the screen, we must calculate the areas of + // the screen and captured region. Then, we must divide the area of the region + // by the area of the screen to get the percentage. Multiply by 100 to make it + // an integer. Returns -1 if screen_area is 0 to prevent undefined values. + double screen_area = screen_width * screen_height; + if (screen_area <= 0) { + return -1; + } + double region_area = image_width * image_height; + double region_proportion = region_area / screen_area; + int region_proportion_int = region_proportion * 100; + return region_proportion_int; +} + +lens::LensRegionSearchAspectRatio +LensRegionSearchController::GetAspectRatioFromSize(int image_height, + int image_width) { + // Convert to double to prevent integer division. + double width = image_width; + double height = image_height; + + // To record region aspect ratio, we must divide the region's width by height. + // Should never be zero, but check to prevent any crashes or undefined + // recordings. + if (height > 0) { + double aspect_ratio = width / height; + if (aspect_ratio <= 1.2 && aspect_ratio >= 0.8) { + return lens::LensRegionSearchAspectRatio::SQUARE; + } else if (aspect_ratio < 0.8 && aspect_ratio >= 0.3) { + return lens::LensRegionSearchAspectRatio::TALL; + } else if (aspect_ratio < 0.3) { + return lens::LensRegionSearchAspectRatio::VERY_TALL; + } else if (aspect_ratio > 1.2 && aspect_ratio <= 1.7) { + return lens::LensRegionSearchAspectRatio::WIDE; + } else if (aspect_ratio > 1.7) { + return lens::LensRegionSearchAspectRatio::VERY_WIDE; + } + } + return lens::LensRegionSearchAspectRatio::UNDEFINED; +} + +void LensRegionSearchController::RecordRegionSizeRelatedMetrics( + gfx::Rect screen_bounds, + gfx::Size image_size) { + // If any of the rects are empty, it means the area is zero. In this case, + // return. + if (screen_bounds.IsEmpty() || image_size.IsEmpty()) + return; + double region_width = image_size.width(); + double region_height = image_size.height(); + + int region_proportion = CalculateViewportProportionFromAreas( + screen_bounds.height(), screen_bounds.width(), region_width, + region_height); + if (region_proportion >= 0) { + base::UmaHistogramPercentage( + lens::kLensRegionSearchRegionViewportProportionHistogramName, + region_proportion); + } + + // To record region aspect ratio, we must divide the region's width by height. + base::UmaHistogramEnumeration( + lens::kLensRegionSearchRegionAspectRatioHistogramName, + GetAspectRatioFromSize(region_height, region_width)); +} + void LensRegionSearchController::OnCaptureCompleted( const image_editor::ScreenshotCaptureResult& result) { const gfx::Image& captured_image = result.image; @@ -62,6 +134,9 @@ return; } + // Record region size related UMA histograms according to region and screen. + RecordRegionSizeRelatedMetrics(result.screen_bounds, captured_image.Size()); + const gfx::Image& image = ResizeImageIfNecessary(captured_image); CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(source_web_contents_); @@ -71,7 +146,8 @@ return; } core_tab_helper->SearchWithLensInNewTab( - image, lens::EntryPoint::CHROME_REGION_SEARCH_MENU_ITEM); + image, captured_image.Size(), + lens::EntryPoint::CHROME_REGION_SEARCH_MENU_ITEM); RecordCaptureResult(lens::LensRegionSearchCaptureResult::SUCCESS); }
diff --git a/chrome/browser/lens/region_search/lens_region_search_controller.h b/chrome/browser/lens/region_search/lens_region_search_controller.h index 72866c1..bbd6ca5 100644 --- a/chrome/browser/lens/region_search/lens_region_search_controller.h +++ b/chrome/browser/lens/region_search/lens_region_search_controller.h
@@ -7,6 +7,7 @@ #include "chrome/browser/image_editor/screenshot_flow.h" #include "chrome/browser/lens/metrics/lens_metrics.h" #include "content/public/browser/web_contents.h" + namespace lens { class LensRegionSearchController { @@ -19,9 +20,22 @@ // around the web contents. When finished with selection, the region is // converted into a PNG and sent to Lens. void Start(); + // Calculates the percentage that the image area takes up in the screen area. + // This value is calculated as double and then floored to the nearest integer. + static int CalculateViewportProportionFromAreas(int screen_height, + int screen_width, + int image_width, + int image_height); + // Returns an enum representing the aspect ratio of the image as defined in + // lens_metrics.h. + static lens::LensRegionSearchAspectRatio GetAspectRatioFromSize( + int image_height, + int image_width); private: void RecordCaptureResult(lens::LensRegionSearchCaptureResult result); + void RecordRegionSizeRelatedMetrics(gfx::Rect screen_bounds, + gfx::Size region_size); void OnCaptureCompleted(const image_editor::ScreenshotCaptureResult& result); gfx::Image ResizeImageIfNecessary(const gfx::Image& image);
diff --git a/chrome/browser/lens/region_search/lens_region_search_controller_unittest.cc b/chrome/browser/lens/region_search/lens_region_search_controller_unittest.cc new file mode 100644 index 0000000..6900fbcc --- /dev/null +++ b/chrome/browser/lens/region_search/lens_region_search_controller_unittest.cc
@@ -0,0 +1,73 @@ +// Copyright 2021 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/lens/region_search/lens_region_search_controller.h" + +#include "chrome/browser/lens/metrics/lens_metrics.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace lens { + +TEST(LensRegionSearchControllerTest, UndefinedAspectRatioTest) { + int height = 0; + int width = 100; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::UNDEFINED); +} + +TEST(LensRegionSearchControllerTest, SquareAspectRatioTest) { + int height = 100; + int width = 100; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::SQUARE); +} + +TEST(LensRegionSearchControllerTest, WideAspectRatioTest) { + int height = 100; + int width = 170; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::WIDE); +} + +TEST(LensRegionSearchControllerTest, VeryWideAspectRatioTest) { + int height = 100; + int width = 10000; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::VERY_WIDE); +} + +TEST(LensRegionSearchControllerTest, TallAspectRatioTest) { + int height = 170; + int width = 100; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::TALL); +} + +TEST(LensRegionSearchControllerTest, VeryTallAspectRatioTest) { + int height = 10000; + int width = 100; + EXPECT_EQ(LensRegionSearchController::GetAspectRatioFromSize(height, width), + LensRegionSearchAspectRatio::VERY_TALL); +} + +TEST(LensRegionSearchControllerTest, AccurateViewportProportionTest) { + int screen_height = 1000; + int screen_width = 1000; + int image_height = 100; + int image_width = 100; + EXPECT_EQ(LensRegionSearchController::CalculateViewportProportionFromAreas( + screen_height, screen_width, image_width, image_height), + 1); +} + +TEST(LensRegionSearchControllerTest, UndefinedViewportProportionTest) { + int screen_height = 0; + int screen_width = 0; + int image_height = 100; + int image_width = 100; + EXPECT_EQ(LensRegionSearchController::CalculateViewportProportionFromAreas( + screen_height, screen_width, image_width, image_height), + -1); +} + +} // namespace lens
diff --git a/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc b/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc index 2d853e13..a4f02cc 100644 --- a/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc +++ b/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc
@@ -10,6 +10,7 @@ #include "base/json/json_reader.h" #include "base/memory/ptr_util.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "chrome/browser/policy/messaging_layer/upload/record_upload_request_builder.h" #include "components/reporting/proto/record.pb.h" #include "components/reporting/proto/record_constants.pb.h"
diff --git a/chrome/browser/renderer_context_menu/context_menu_content_type_unittest.cc b/chrome/browser/renderer_context_menu/context_menu_content_type_unittest.cc index 134ed17..02dc0ed 100644 --- a/chrome/browser/renderer_context_menu/context_menu_content_type_unittest.cc +++ b/chrome/browser/renderer_context_menu/context_menu_content_type_unittest.cc
@@ -118,10 +118,10 @@ ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)); EXPECT_TRUE(content_type->SupportsGroup( ContextMenuContentType::ITEM_GROUP_PRINT)); - EXPECT_TRUE(content_type->SupportsGroup( - ContextMenuContentType::ITEM_GROUP_LENS_REGION_SEARCH)); EXPECT_FALSE(content_type->SupportsGroup( + ContextMenuContentType::ITEM_GROUP_LENS_REGION_SEARCH)); + EXPECT_FALSE(content_type->SupportsGroup( ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)); EXPECT_FALSE(content_type->SupportsGroup( ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO));
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 6da0c74..9e358b1c 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -875,10 +875,8 @@ if (media_image) AppendImageItems(); - // Do not show image search menu items if Lens Region Search will be shown. if (content_type_->SupportsGroup( - ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE) && - !IsLensRegionSearchEnabled()) { + ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) { if (base::FeatureList::IsEnabled(lens::features::kLensStandalone) && search::DefaultSearchProviderIsGoogle(GetProfile())) { AppendSearchLensForImageItems();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc index 050fc24..46cc12af 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -734,6 +734,22 @@ EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH)); } + +// Verify that the Lens Region Search menu item is disabled when the user +// clicks on an image. +TEST_F(RenderViewContextMenuPrefsTest, LensRegionSearchDisabledOnImage) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(lens::features::kLensRegionSearch); + SetUserSelectedDefaultSearchProvider("https://www.google.com"); + content::ContextMenuParams params = CreateParams(MenuItem::IMAGE); + params.has_image_contents = true; + auto menu = std::make_unique<TestRenderViewContextMenu>( + web_contents()->GetMainFrame(), params); + AppendImageItems(menu.get()); + + EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH)); +} + // Verify that the Lens Region Search menu item is disabled when the user's // default browser is not Google. TEST_F(RenderViewContextMenuPrefsTest,
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn index 2ec88747..3a2601b8 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
@@ -115,6 +115,7 @@ "nodes/group_node_test.js", "nodes/tab_node_test.js", "point_scan_manager_test.js", + "saatlite/gen/saatlite_tests.js", "switch_access_predicate_test.js", "switch_access_test.js", "text_navigation_manager_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compile_saatlite_tests.py b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compile_saatlite_tests.py new file mode 100755 index 0000000..cf71533 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compile_saatlite_tests.py
@@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# Copyright 2021 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. +'''Compiles all tests in the tests/ directory from Switch Access Automated +Testing Language into a js2gtest.''' + +import os +import sys + +def main() -> None: + SAATL_dir = os.path.dirname(__file__) + compiler_dir = os.path.abspath(os.path.join(SAATL_dir, 'compiler/')) + test_dir = os.path.abspath(os.path.join(SAATL_dir, 'tests/')) + '/' + out_file = os.path.abspath(os.path.join(SAATL_dir, 'gen/saatlite_tests.js')) + + initial_dir = os.getcwd() + os.chdir(compiler_dir) + + args = ['node', + 'compiler.js', + test_dir, + out_file] + + os.system(' '.join(args)) + os.chdir(initial_dir) + +if __name__ == '__main__': + main()
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/Makefile b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/Makefile new file mode 100644 index 0000000..5ebd129 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/Makefile
@@ -0,0 +1,6 @@ +parser: parser.jison lexer.jisonlex + npx jison-gho parser.jison lexer.jisonlex -o parser.js + ./format_parser.sh + +clean: + rm -f parser.js
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/README b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/README new file mode 100644 index 0000000..56d459f --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/README
@@ -0,0 +1,10 @@ +# Instructions to Rebuild the Parser + +After making changes to the parser.jison or lexer.jisonlex files, follow the +below instructions to rebuild the parser.js module. + +1. Install node (`apt install nodejs`) +2. Install npm (`apt install npm`) +3. Install npx (`npm install npx`) +4. (Optional) Ensure the old parser is removed (`make clean`) +5. Build the parser (`make parser`)
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/compiler.js b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/compiler.js new file mode 100644 index 0000000..5144cc6 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/compiler.js
@@ -0,0 +1,62 @@ +// Copyright 2021 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. + +/* + * Main entry point for the SAATLite compiler. It handles reading the .saatl + * in files, calling the parser, and writing the .js out files. + */ + +const parse = require('./parser').parse; +const fs = require('fs'); + +const preamble = `// Copyright 2021 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. + +GEN_INCLUDE(['../../switch_access_e2e_test_base.js', '../../test_utility.js']); + +/** Test fixture for the SAATLite generated tests. */ +SwitchAccessSAATLiteTest = class extends SwitchAccessE2ETest { + /** @override */ + setUp() { + const runTest = this.deferRunTest(WhenTestDone.EXPECT); + (async () => { + await TestUtility.setup(); + runTest(); + })(); + } +}; + +`; + +const args = process.argv.slice(2); +const testDir = args[0]; +const outFile = args[1]; + +if (typeof testDir !== 'string' || typeof outFile !== 'string') { + throw new Error( + 'Error: compiler needs two string arguments: ' + + 'the test dir and the out file.'); +} + +// Delete the output file if it already exists. +if (fs.existsSync(outFile)) { + fs.unlinkSync(outFile); +} + +const stream = fs.createWriteStream(outFile); +stream.on('error', console.error); +stream.on('open', () => { + stream.write(preamble); + + // Read all the files in the tests/ directory. + const filenames = fs.readdirSync(testDir); + filenames.forEach((filename) => { + console.log('Compiling file: ', filename); + const contents = fs.readFileSync(testDir + filename, {encoding: 'utf8'}); + stream.write(parse(contents).output + '\n'); + }); + + stream.end(); +});
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/format_parser.sh b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/format_parser.sh new file mode 100755 index 0000000..c5b010a --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/format_parser.sh
@@ -0,0 +1,57 @@ +#!/bin/bash +# Copyright 2021 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. + +# This file formats the auto-generated parser.js so it passes presubmit checks. + +if ! grep -q 'Copyright' parser.js; then + sed -i '0,/\//{s|/|// Copyright 2021 The Chromium Authors. Al#\n/|}' parser.js + sed -i '0,/#/{s|#|l rights reserved.\n// Use of this source code#|}' parser.js + sed -i '0,/#/{s|#| is governed by a BSD-style license that can b#|}' parser.js + sed -i '0,/#/{s|#|e\n// found in the LICENSE file.\n|}' parser.js +fi + +sed -i 's/show_input_position == undefined/!show_input_position/g' parser.js +sed -i "s|[ \t\n]*// can't ever have more input lines than this![ \t\n]*| |g" \ + parser.js + +sed -i "s/recovery approach availabl/recovery approach '+'availabl/g" parser.js +sed -i "s/the lexer is of/the '+'lexer is of/g" parser.js +sed -i "s/persuasion (options./persuasion '+'(options./g" parser.js +sed -i "s/non-existing condition/non-existing '+'condition/g" parser.js +sed -i "s/the application programmer/the '+'application programmer/g" parser.js + +sed -i 's/preceeding/preceding/g' parser.js + +sed -i 's/sharedState_yy/sharedStateYy/g' parser.js +sed -i 's/this_production/thisProduction/g' parser.js +sed -i 's/pretty_src/prettySrc/g' parser.js +sed -i 's/pos_str/posStr/g' parser.js +sed -i 's/lineno_msg/linenoMsg/g' parser.js +sed -i 's/rule_re/ruleRe/g' parser.js +sed -i 's/rule_ids/ruleIds/g' parser.js +sed -i 's/rule_regexes/ruleRegexes/g' parser.js +sed -i 's/rule_new_ids/ruleNewIds/g' parser.js +sed -i 's/slice_len/sliceLen/g' parser.js +sed -i 's/pre_lines/preLines/g' parser.js +sed -i 's/lineno_display_width/linenoDisplayWidth/g' parser.js +sed -i 's/ws_prefix/wsPrefix/g' parser.js +sed -i 's/nonempty_line_indexes/nonemptyLineIndexes/g' parser.js +sed -i 's/lno_pfx/lnoPfx/g' parser.js +sed -i 's/clip_start/clipStart/g' parser.js +sed -i 's/clip_end/clipEnd/g' parser.js +sed -i 's/intermediate_line/intermediateLine/g' parser.js +sed -i 's/yy_/yY/g' parser.js +sed -i 's/MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT/MIN_VIS_LINE/g' parser.js + +git cl format --js parser.js + +node_dir='../../../../../../../../third_party/node' + +${node_dir}/linux/node-linux-x64/bin/node \ + ${node_dir}/node_modules/eslint/bin/eslint \ + --resolve-plugins-relative-to ${node_dir}/node_modules \ + --ignore-pattern .eslintrc.js parser.js --fix + +git cl format --js parser.js
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/lexer.jisonlex b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/lexer.jisonlex new file mode 100644 index 0000000..0429201 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/lexer.jisonlex
@@ -0,0 +1,33 @@ +// Copyright 2021 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. + +%options case-insensitive + +%% +[<][^\n]+ return 'HTML_SNIPPET'; +chrome[:][/][/][^\n]* return 'CHROME_URL'; +\"[^"]*\" return 'STRING_LITERAL'; + +\n return 'EOL'; +[0-9]+ return 'NUMBER'; +[(] return 'LEFT_PARENS'; +[)] return 'RIGHT_PARENS'; +[,] return 'COMMA'; + +expect return 'EXPECT'; +focus return 'FOCUS'; +load[ ]page return 'LOAD_PAGE'; +next return 'NEXT'; +on return 'ON'; +previous return 'PREVIOUS'; +select return 'SELECT'; + +button return 'ROLE'; +slider return 'ROLE'; +spinButton return 'ROLE'; +textField return 'ROLE'; +textFieldWithComboBox return 'ROLE'; + +<<EOF>> return 'EOF'; +\s /* Ignore whitespace */;
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/package.json b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/package.json new file mode 100644 index 0000000..e6b892a3 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/package.json
@@ -0,0 +1,11 @@ +{ + "name": "saatlite_compiler", + "version": "1.0.0", + "description": "Compiles SAATLite simple declarative tests into extension js2gtest format.", + "main": "compiler.js", + "scripts": { + "compiler.js": "node compiler.js" + }, + "author": "The Chromium Authors", + "license": "Copyright 2021 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." +}
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.jison b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.jison new file mode 100644 index 0000000..9b5a6b6 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.jison
@@ -0,0 +1,212 @@ +// Copyright 2021 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. + +/* This file compiles SAATLite tests into JS tests. */ + +// Preamble: +%{ + let page, point, objectToMatch; + + let indent = ''; + const increaseIndent = () => indent = indent + ' '; + const decreaseIndent = () => indent = indent.substring(2); + + let buffer = ''; + const addToBuffer = (text) => buffer += indent + text + '\n'; + const flushBuffer = () => { + const result = buffer; + buffer = ''; + return result; + } + + function addAllStatements(statements) { + if (statements.find(statement => !statement.output)) { + throw new Error('Compiler error: statement not converted to Javascript'); + } + statements.forEach(statement => addToBuffer(statement.output)); + return flushBuffer(); + } + + // Initialize test before anything else. + const initTest = (page = `''`) => { + addToBuffer(`TEST_F('SwitchAccessSAATLiteTest', 'Demo', function() {`); + increaseIndent(); + addToBuffer(`this.runWithLoadedTree(${page.output}, async (rootWebArea) => {`); + increaseIndent(); + addToBuffer('TestUtility.startFocusInside(rootWebArea);'); + return flushBuffer(); + } + + const finishTest = (opt_url) => { + decreaseIndent(); + if (opt_url) { + addToBuffer(`}, {url: ${opt_url.output}});`); + } else { + addToBuffer(`});`); + } + decreaseIndent(); + addToBuffer(`});`); + + return flushBuffer(); + } +%} + +%start test + +%% + +test + : load_expression statements EOF { + $$ = {}; + if ($1.page.type === 'HTML') { + $$.output = initTest($1.page); + } else { + $$.output = initTest(); + } + + $$.output += addAllStatements($2); + + if ($1.page.type === 'ChromeURL') { + $$.output += finishTest($1.page); + } else { + $$.output += finishTest(); + } + + $2.unshift($1); + $$.ast = $2; + return $$; + } + | statements EOF { + $$ = {ast: $1}; + $$.output = initTest(); + $$.output += addAllStatements($1); + $$.output += finishTest(); + + return $$; + } + ; + +load_expression + : LOAD_PAGE page_expression { + $$ = {command: 'Load', page: $2}; + } + | LOAD_PAGE EOL page_expression { + $$ = {command: 'Load', page: $3}; + } + ; + +statements + // Expect a new line between statements. + : statements EOL statement { + $$ = $1; + $$.push($3); + } + // Allow arbitrary empty lines. + | statements EOL { + $$ = $1; + } + | statement { + $$ = [$1]; + } + | /* Empty */ { + $$ = []; + } + ; + +statement + : NEXT { + $$ = {command: 'Next'}; + $$.output = 'TestUtility.pressNextSwitch();'; + } + | PREVIOUS { + $$ = {command: 'Previous'}; + $$.output = 'TestUtility.pressPreviousSwitch();'; + } + | SELECT point_expression { + $$ = {command: 'Select'}; + // A point_expression is only expected when point_scan is enabled. + if ($2) { + $$.point = $2; + point = $$.point.output; + $$.output = `TestUtility.simulatePointScanSelect(${point});`; + } else { + $$.output = 'TestUtility.pressSelectSwitch();'; + } + } + | EXPECT expectation_expression { + $$ = {command: 'Expect', expectation: $2}; + $$.output = $2.output; + } + ; + +page_expression + : html_page { + $$ = {type: 'HTML', value: $1}; + page = $$.value; + $$.output = `'` + page + `'`; + } + | CHROME_URL { + $$ = {type: 'ChromeURL', value: $1}; + page = $$.value; + $$.output = `'` + page + `'`; + } + ; + +html_page + : html_page HTML_SNIPPET { + $$ = $1 + '\n' + $2; + } + | HTML_SNIPPET { + $$ = $1; + } + ; + +point_expression + : LEFT_PARENS NUMBER COMMA NUMBER RIGHT_PARENS { + $$ = {x: $2, y: $4}; + point = $$; + $$.output = `{x: ${point.x}, y: ${point.y}}`; + } + | /* Empty */ { + $$ = null; + } + ; + +expectation_expression + : FOCUS ON focusable_expression { + $$ = {type: 'Focus', matches: $3}; + objectToMatch = $$.matches.output; + $$.output = `await TestUtility.expectFocusOn(${objectToMatch});`; + } + ; + +focusable_expression + : ROLE string_literal { + $$ = {role: $1, name: $2}; + objectToMatch = $$; + $$.output = `{role: '${objectToMatch.role}', name: '${objectToMatch.name}'}`; + } + | string_literal ROLE { + $$ = {role: $2, name: $1}; + objectToMatch = $$; + $$.output = `{role: '${objectToMatch.role}', name: '${objectToMatch.name}'}`; + } + | ROLE { + $$ = {role: $1}; + objectToMatch = $$; + $$.output = `{role: '${objectToMatch.role}'}`; + } + | string_literal { + $$ = {name: $1}; + objectToMatch = $$; + $$.output = `{name: '${objectToMatch.name}'}`; + } + ; + +string_literal + : STRING_LITERAL { + // Remove the quotes from the string. + $$ = $1.substring(1, $1.length - 1); + } + ;
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.js b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.js new file mode 100644 index 0000000..460598654 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/compiler/parser.js
@@ -0,0 +1,3582 @@ + +// Copyright 2021 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. + +/* parser generated by jison 0.6.1-215 */ + +/* + * Returns a Parser object of the following structure: + * + * Parser: { + * yy: {} The so-called "shared state" or rather the *source* of it; + * the real "shared state" `yy` passed around to + * the rule actions, etc. is a derivative/copy of this one, + * not a direct reference! + * } + * + * Parser.prototype: { + * yy: {}, + * EOF: 1, + * TERROR: 2, + * + * trace: function(errorMessage, ...), + * + * JisonParserError: function(msg, hash), + * + * quoteName: function(name), + * Helper function which can be overridden by user code later on: + * put suitable quotes around literal IDs in a description string. + * + * originalQuoteName: function(name), + * The basic quoteName handler provided by JISON. + * `cleanupAfterParse()` will clean up and reset `quoteName()` to + * reference this function at the end of the `parse()`. + * + * describeSymbol: function(symbol), + * Return a more-or-less human-readable description of the given + * symbol, when available, or the symbol itself, serving as its own + * 'description' for lack of something better to serve up. + * + * Return NULL when the symbol is unknown to the parser. + * + * symbols_: {associative list: name ==> number}, + * terminals_: {associative list: number ==> name}, + * nonterminals: {associative list: rule-name ==> {associative list: number + * ==> rule-alt}}, terminal_descriptions_: (if there are any) {associative list: + * number ==> description}, productions_: [...], + * + * performAction: function parser__performAction(yytext, yyleng, yylineno, + * yyloc, yystate, yysp, yyvstack, yylstack, yystack, yysstack), + * + * The function parameters and `this` have the following + * value/meaning: + * - `this` : reference to the `yyval` internal object, which + * has members (`$` and `_$`) to store/reference the rule value `$$` and + * location info `@$`. + * + * One important thing to note about `this` a.k.a. `yyval`: + * every *reduce* action gets to see the same object via the `this` reference, + * i.e. if you wish to carry custom data from one reduce action through to the + * next within a single parse run, then you may get nasty and use `yyval` a.k.a. + * `this` for storing you own semi-permanent data. + * + * `this.yy` is a direct reference to the `yy` shared state + * object. + * + * `%parse-param`-specified additional `parse()` arguments have + * been added to this `yy` object at `parse()` start and are therefore available + * to the action code via the same named `yy.xxxx` attributes (where `xxxx` + * represents a identifier name from the %parse-param` list. + * + * - `yytext` : reference to the lexer value which belongs to the + * last lexer token used to match this rule. This is *not* the look-ahead token, + * but the last token that's actually part of this rule. + * + * Formulated another way, `yytext` is the value of the token + * immediately preceding the current look-ahead token. Caveats apply for rules + * which don't require look-ahead, such as epsilon rules. + * + * - `yyleng` : ditto as `yytext`, only now for the lexer.yyleng + * value. + * + * - `yylineno`: ditto as `yytext`, only now for the + * lexer.yylineno value. + * + * - `yyloc` : ditto as `yytext`, only now for the lexer.yylloc + * lexer token location info. + * + * WARNING: since jison 0.4.18-186 this entry may + * be NULL/UNDEFINED instead of an empty object when no suitable location info + * can be provided. + * + * - `yystate` : the current parser state number, used internally + * for dispatching and executing the action code chunk matching the rule + * currently being reduced. + * + * - `yysp` : the current state stack position (a.k.a. 'stack + * pointer') + * + * This one comes in handy when you are going to do advanced + * things to the parser stacks, all of which are accessible from your action + * code (see the next entries below). + * + * Also note that you can access this and other stack index + * values using the new double-hash syntax, i.e. `##$ === ##0 === yysp`, while + * `##1` is the stack index for all things related to the first rule term, just + * like you have `$1`, `@1` and `#1`. This is made available to write very + * advanced grammar action rules, e.g. when you want to investigate the parse + * state stack in your action code, which would, for example, be relevant when + * you wish to implement error diagnostics and reporting schemes similar to the + * work described here: + * + * + Pottier, F., 2016. Reachability and error diagnosis in + * LR(1) automata. In Journées Francophones des Languages Applicatifs. + * + * + Jeffery, C.L., 2003. Generating LR syntax error messages + * from examples. ACM Transactions on Programming Languages and Systems + * (TOPLAS), 25(5), pp.631–640. + * + * - `yyrulelength`: the current rule's term count, i.e. the + * number of entries occupied on the stack. + * + * This one comes in handy when you are going to do advanced + * things to the parser stacks, all of which are accessible from your action + * code (see the next entries below). + * + * - `yyvstack`: reference to the parser value stack. Also + * accessed via the `$1` etc. constructs. + * + * - `yylstack`: reference to the parser token location stack. + * Also accessed via the `@1` etc. constructs. + * + * WARNING: since jison 0.4.18-186 this array MAY + * contain slots which are UNDEFINED rather than an empty (location) object, + * when the lexer/parser action code did not provide a suitable location info + * object when such a slot was filled! + * + * - `yystack` : reference to the parser token id stack. Also + * accessed via the + * `#1` etc. constructs. + * + * Note: this is a bit of a **white lie** as we can statically + * decode any `#n` reference to its numeric token id value, hence that code + * wouldn't need the `yystack` but *you* might want access this array for your + * own purposes, such as error analysis as mentioned above! + * + * Note that this stack stores the current stack of *tokens*, + * that is the sequence of already parsed=reduced *nonterminals* (tokens + * representing rules) and *terminals* (lexer tokens *shifted* onto the stack + * until the rule they belong to is found and *reduced*. + * + * - `yysstack`: reference to the parser state stack. This one + * carries the internal parser *states* such as the one in `yystate`, which are + * used to represent the parser state machine in the *parse table*. *Very* + * *internal* stuff, what can I say? If you access this one, you're clearly + * doing wicked things + * + * - `...` : the extra arguments you specified in the + * `%parse-param` statement in your grammar definition file. + * + * table: [...], + * State transition table + * ---------------------- + * + * index levels are: + * - `state` --> hash table + * - `symbol` --> action (number or array) + * + * If the `action` is an array, these are the elements' meaning: + * - index [0]: 1 = shift, 2 = reduce, 3 = accept + * - index [1]: GOTO `state` + * + * If the `action` is a number, it is the GOTO `state` + * + * defaultActions: {...}, + * + * parseError: function(str, hash, ExceptionClass), + * yyError: function(str, ...), + * yyRecovering: function(), + * yyErrOk: function(), + * yyClearIn: function(), + * + * constructParseErrorInfo: function(error_message, exception_object, + * expected_token_set, is_recoverable), Helper function **which will be set up + * during the first invocation of the `parse()` method**. Produces a new + * errorInfo 'hash object' which can be passed into `parseError()`. See it's use + * in this parser kernel in many places; example usage: + * + * var infoObj = parser.constructParseErrorInfo('fail!', null, + * parser.collect_expected_token_set(state), + * true); var retVal = parser.parseError(infoObj.errStr, infoObj, + * parser.JisonParserError); + * + * originalParseError: function(str, hash, ExceptionClass), + * The basic `parseError` handler provided by JISON. + * `cleanupAfterParse()` will clean up and reset `parseError()` to + * reference this function at the end of the `parse()`. + * + * options: { ... parser %options ... }, + * + * parse: function(input[, args...]), + * Parse the given `input` and return the parsed value (or `true` + * when none was provided by the root action, in which case the parser is acting + * as a *matcher*). You MAY use the additional `args...` parameters as per + * `%parse-param` spec of this grammar: these extra `args...` are added verbatim + * to the `yy` object reference as member variables. + * + * WARNING: + * Parser's additional `args...` parameters (via `%parse-param`) + * MAY conflict with any attributes already added to `yy` by the jison run-time; + * when such a collision is detected an exception is thrown to + * prevent the generated run-time from silently accepting this confusing and + * potentially hazardous situation! + * + * The lexer MAY add its own set of additional parameters (via the + * `%parse-param` line in the lexer section of the grammar spec): these will be + * inserted in the `yy` shared state object and any collision with those will be + * reported by the lexer via a thrown exception. + * + * cleanupAfterParse: function(resultValue, invoke_post_methods, + * do_not_nuke_errorinfos), Helper function **which will be set up during the + * first invocation of the `parse()` method**. This helper API is invoked at the + * end of the `parse()` call, unless an exception was thrown and `%options + * no-try-catch` has been defined for this grammar: in that case this helper MAY + * be invoked by calling user code to ensure the `post_parse` + * callbacks are invoked and the internal parser gets properly garbage collected + * under these particular circumstances. + * + * yyMergeLocationInfo: function(first_index, last_index, first_yylloc, + * last_yylloc, dont_look_back), Helper function **which will be set up during + * the first invocation of the `parse()` method**. This helper API can be + * invoked to calculate a spanning `yylloc` location info object. + * + * Note: %epsilon rules MAY specify no `first_index` and + * `first_yylloc`, in which case this function will attempt to obtain a suitable + * location marker by inspecting the location stack backwards. + * + * For more info see the documentation comment further below, + * immediately above this function's implementation. + * + * lexer: { + * yy: {...}, A reference to the so-called "shared state" `yy` + * once received via a call to the `.setInput(input, yy)` lexer API. EOF: 1, + * ERROR: 2, + * JisonLexerError: function(msg, hash), + * parseError: function(str, hash, ExceptionClass), + * setInput: function(input, [yy]), + * input: function(), + * unput: function(str), + * more: function(), + * reject: function(), + * less: function(n), + * pastInput: function(n), + * upcomingInput: function(n), + * showPosition: function(), + * test_match: function(regex_match_array, rule_index, ...), + * next: function(...), + * lex: function(...), + * begin: function(condition), + * pushState: function(condition), + * popState: function(), + * topState: function(), + * _currentRules: function(), + * stateStackSize: function(), + * cleanupAfterLex: function() + * + * options: { ... lexer %options ... }, + * + * performAction: function(yy, yY, $avoiding_name_collisions, YY_START, + * ...), rules: [...], conditions: {associative list: name ==> set}, + * } + * } + * + * + * token location info (@$, _$, etc.): { + * first_line: n, + * last_line: n, + * first_column: n, + * last_column: n, + * range: [start_number, end_number] + * (where the numbers are indexes into the input string, + * zero-based) + * } + * + * --- + * + * The `parseError` function receives a 'hash' object with these members for + * lexer and parser errors: + * + * { + * text: (matched text) + * token: (the produced terminal token, if any) + * token_id: (the produced terminal token numeric ID, if any) + * line: (yylineno) + * loc: (yylloc) + * } + * + * parser (grammar) errors will also provide these additional members: + * + * { + * expected: (array describing the set of expected tokens; + * may be UNDEFINED when we cannot easily produce such a set) + * state: (integer (or array when the table includes grammar + * collisions); represents the current internal state of the parser kernel. can, + * for example, be used to pass to the `collect_expected_token_set()` API to + * obtain the expected token set) action: (integer; represents the current + * internal action which will be executed) new_state: (integer; represents the + * next/planned internal state, once the current action has executed) + * recoverable: (boolean: TRUE when the parser MAY have an error recovery + * rule available for this particular error) state_stack: (array: the current + * parser LALR/LR internal state stack; this can be used, for instance, for + * advanced error analysis and reporting) value_stack: (array: the current + * parser LALR/LR internal `$$` value stack; this can be used, for instance, for + * advanced error analysis and reporting) location_stack: (array: the current + * parser LALR/LR internal location stack; this can be used, for instance, for + * advanced error analysis and reporting) yy: (object: the current + * parser internal "shared state" `yy` as is also available in the rule actions; + * this can be used, for instance, for advanced error analysis and reporting) + * lexer: (reference to the current lexer instance used by the parser) + * parser: (reference to the current parser instance) + * } + * + * while `this` will reference the current parser instance. + * + * When `parseError` is invoked by the lexer, `this` will still reference the + * related *parser* instance, while these additional `hash` fields will also be + * provided: + * + * { + * lexer: (reference to the current lexer instance which reported the + * error) + * } + * + * When `parseError` is invoked by the parser due to a **JavaScript exception** + * being fired from either the parser or lexer, `this` will still reference the + * related *parser* instance, while these additional `hash` fields will also be + * provided: + * + * { + * exception: (reference to the exception thrown) + * } + * + * Please do note that in the latter situation, the `expected` field will be + * omitted as this type of failure is assumed not to be due to *parse errors* + * but rather due to user action code in either parser or lexer failing + * unexpectedly. + * + * --- + * + * You can specify parser options by setting / modifying the `.yy` object of + * your Parser instance. These options are available: + * + * ### options which are global for all parser instances + * + * Parser.pre_parse: function(yy) + * optional: you can specify a pre_parse() function in the chunk + * following the grammar, i.e. after the last `%%`. Parser.post_parse: + * function(yy, retval, parseInfo) { return retval; } optional: you can specify + * a post_parse() function in the chunk following the grammar, i.e. after the + * last `%%`. When it does not return any value, the parser will return the + * original `retval`. + * + * ### options which can be set up per parser instance + * + * yy: { + * pre_parse: function(yy) + * optional: is invoked before the parse cycle starts (and + * before the first invocation of `lex()`) but immediately after the invocation + * of `parser.pre_parse()`). post_parse: function(yy, retval, parseInfo) { + * return retval; } optional: is invoked when the parse terminates due to + * success ('accept') or failure (even when exceptions are thrown). `retval` + * contains the return value to be produced by `Parser.parse()`; this function + * can override the return value by returning another. When it does not return + * any value, the parser will return the original `retval`. This function is + * invoked immediately before `parser.post_parse()`. + * + * parseError: function(str, hash, ExceptionClass) + * optional: overrides the default `parseError` function. + * quoteName: function(name), + * optional: overrides the default `quoteName` function. + * } + * + * parser.lexer.options: { + * pre_lex: function() + * optional: is invoked before the lexer is invoked to produce + * another token. `this` refers to the Lexer object. post_lex: function(token) { + * return token; } optional: is invoked when the lexer has produced a token + * `token`; this function can override the returned token value by returning + * another. When it does not return any (truthy) value, the lexer will return + * the original `token`. + * `this` refers to the Lexer object. + * + * ranges: boolean + * optional: `true` ==> token location info will include a + * .range[] member. flex: boolean optional: `true` ==> flex-like lexing + * behaviour where the rules are tested exhaustively to find the longest match. + * backtrack_lexer: boolean + * optional: `true` ==> lexer regexes are tested in order and + * for invoked; the lexer terminates the scan when a token is returned by the + * action code. xregexp: boolean optional: `true` ==> lexer rule regexes are + * "extended regex format" requiring the `XRegExp` library. When this `%option` + * has not been specified at compile time, all lexer rule regexes have been + * written as standard JavaScript RegExp expressions. + * } + */ + + + +var parser = (function() { + // See also: + // http://stackoverflow.com/questions/1382107/whats-a-good-way-to-extend-error-in-javascript/#35881508 + // but we keep the prototype.constructor and prototype.name assignment lines + // too for compatibility with userland code which might access the derived + // class in a 'classic' way. + function JisonParserError(msg, hash) { + Object.defineProperty( + this, 'name', + {enumerable: false, writable: false, value: 'JisonParserError'}); + + if (msg == null) { + msg = '???'; + } + + Object.defineProperty( + this, 'message', {enumerable: false, writable: true, value: msg}); + + this.hash = hash; + + var stacktrace; + if (hash && hash.exception instanceof Error) { + var ex2 = hash.exception; + this.message = ex2.message || msg; + stacktrace = ex2.stack; + } + if (!stacktrace) { + if (Error.hasOwnProperty('captureStackTrace')) { // V8/Chrome engine + Error.captureStackTrace(this, this.constructor); + } else { + stacktrace = (new Error(msg)).stack; + } + } + if (stacktrace) { + Object.defineProperty( + this, 'stack', + {enumerable: false, writable: false, value: stacktrace}); + } + } + + if (typeof Object.setPrototypeOf === 'function') { + Object.setPrototypeOf(JisonParserError.prototype, Error.prototype); + } else { + JisonParserError.prototype = Object.create(Error.prototype); + } + JisonParserError.prototype.constructor = JisonParserError; + JisonParserError.prototype.name = 'JisonParserError'; + + + + // helper: reconstruct the productions[] table + function bp(s) { + var rv = []; + var p = s.pop; + var r = s.rule; + for (var i = 0, l = p.length; i < l; i++) { + rv.push([p[i], r[i]]); + } + return rv; + } + + + + // helper: reconstruct the defaultActions[] table + function bda(s) { + var rv = {}; + var d = s.idx; + var g = s.goto; + for (var i = 0, l = d.length; i < l; i++) { + var j = d[i]; + rv[j] = g[i]; + } + return rv; + } + + + + // helper: reconstruct the 'goto' table + function bt(s) { + var rv = []; + var d = s.len; + var y = s.symbol; + var t = s.type; + var a = s.state; + var m = s.mode; + var g = s.goto; + for (var i = 0, l = d.length; i < l; i++) { + var n = d[i]; + var q = {}; + for (var j = 0; j < n; j++) { + var z = y.shift(); + switch (t.shift()) { + case 2: + q[z] = [m.shift(), g.shift()]; + break; + + case 0: + q[z] = a.shift(); + break; + + default: + // type === 1: accept + q[z] = [3]; + } + } + rv.push(q); + } + return rv; + } + + + + // helper: runlength encoding with increment step: code, length: step (default + // step = 0) `this` references an array + function s(c, l, a) { + a = a || 0; + for (var i = 0; i < l; i++) { + this.push(c); + c += a; + } + } + + // helper: duplicate sequence from *relative* offset and length. + // `this` references an array + function c(i, l) { + i = this.length - i; + for (l += i; i < l; i++) { + this.push(this[i]); + } + } + + // helper: unpack an array using helpers and data, all passed in an array + // argument 'a'. + function u(a) { + var rv = []; + for (var i = 0, l = a.length; i < l; i++) { + var e = a[i]; + // Is this entry a helper function? + if (typeof e === 'function') { + i++; + e.apply(rv, a[i]); + } else { + rv.push(e); + } + } + return rv; + } + + + var parser = { + // Code Generator Information Report + // --------------------------------- + // + // Options: + // + // default action mode: ............. ["classic","merge"] + // test-compile action mode: ........ "parser:*,lexer:*" + // try..catch: ...................... true + // default resolve on conflict: ..... true + // on-demand look-ahead: ............ false + // error recovery token skip maximum: 3 + // yyerror in parse actions is: ..... NOT recoverable, + // yyerror in lexer actions and other non-fatal lexer are: + // .................................. NOT recoverable, + // debug grammar/output: ............ false + // has partial LR conflict upgrade: true + // rudimentary token-stack support: false + // parser table compression mode: ... 2 + // export debug tables: ............. false + // export *all* tables: ............. false + // module type: ..................... commonjs + // parser engine type: .............. lalr + // output main() in the module: ..... true + // has user-specified main(): ....... false + // has user-specified require()/import modules for main(): + // .................................. false + // number of expected conflicts: .... 0 + // + // + // Parser Analysis flags: + // + // no significant actions (parser is a language matcher only): + // .................................. false + // uses yyleng: ..................... false + // uses yylineno: ................... false + // uses yytext: ..................... false + // uses yylloc: ..................... false + // uses ParseError API: ............. false + // uses YYERROR: .................... false + // uses YYRECOVERING: ............... false + // uses YYERROK: .................... false + // uses YYCLEARIN: .................. false + // tracks rule values: .............. true + // assigns rule values: ............. true + // uses location tracking: .......... false + // assigns location: ................ false + // uses yystack: .................... false + // uses yysstack: ................... false + // uses yysp: ....................... true + // uses yyrulelength: ............... false + // uses yyMergeLocationInfo API: .... false + // has error recovery: .............. false + // has error reporting: ............. false + // + // --------- END OF REPORT ----------- + + trace: function no_op_trace() {}, + JisonParserError, + yy: {}, + options: { + type: 'lalr', + hasPartialLrUpgradeOnConflict: true, + errorRecoveryTokenDiscardCount: 3 + }, + symbols_: { + '$accept': 0, + '$end': 1, + 'CHROME_URL': 9, + 'COMMA': 13, + 'EOF': 1, + 'EOL': 4, + 'EXPECT': 8, + 'FOCUS': 15, + 'HTML_SNIPPET': 10, + 'LEFT_PARENS': 11, + 'LOAD_PAGE': 3, + 'NEXT': 5, + 'NUMBER': 12, + 'ON': 16, + 'PREVIOUS': 6, + 'RIGHT_PARENS': 14, + 'ROLE': 17, + 'SELECT': 7, + 'STRING_LITERAL': 18, + 'error': 2, + 'expectation_expression': 26, + 'focusable_expression': 27, + 'html_page': 24, + 'load_expression': 20, + 'page_expression': 23, + 'point_expression': 25, + 'statement': 22, + 'statements': 21, + 'string_literal': 28, + 'test': 19 + }, + terminals_: { + 1: 'EOF', + 2: 'error', + 3: 'LOAD_PAGE', + 4: 'EOL', + 5: 'NEXT', + 6: 'PREVIOUS', + 7: 'SELECT', + 8: 'EXPECT', + 9: 'CHROME_URL', + 10: 'HTML_SNIPPET', + 11: 'LEFT_PARENS', + 12: 'NUMBER', + 13: 'COMMA', + 14: 'RIGHT_PARENS', + 15: 'FOCUS', + 16: 'ON', + 17: 'ROLE', + 18: 'STRING_LITERAL' + }, + TERROR: 2, + EOF: 1, + + // internals: defined here so the object *structure* doesn't get modified by + // parse() et al, + // thus helping JIT compilers like Chrome V8. + originalQuoteName: null, + originalParseError: null, + cleanupAfterParse: null, + constructParseErrorInfo: null, + yyMergeLocationInfo: null, + + __reentrant_call_depth: 0, // INTERNAL USE ONLY + __error_infos: [], // INTERNAL USE ONLY: the set of parseErrorInfo objects + // created since the last cleanup + __error_recovery_infos: [], // INTERNAL USE ONLY: the set of parseErrorInfo + // objects created since the last cleanup + + // APIs which will be set up depending on user action code analysis: + // yyRecovering: 0, + // yyErrOk: 0, + // yyClearIn: 0, + + // Helper APIs + // ----------- + + // Helper function which can be overridden by user code later on: put + // suitable quotes around + // literal IDs in a description string. + quoteName: function parser_quoteName(id_str) { + return '"' + id_str + '"'; + }, + + // Return the name of the given symbol (terminal or non-terminal) as a + // string, when available. + // + // Return NULL when the symbol is unknown to the parser. + getSymbolName: function parser_getSymbolName(symbol) { + if (this.terminals_[symbol]) { + return this.terminals_[symbol]; + } + + // Otherwise... this might refer to a RULE token i.e. a non-terminal: see + // if we can dig that one up. + // + // An example of this may be where a rule's action code contains a call + // like this: + // + // parser.getSymbolName(#$) + // + // to obtain a human-readable name of the current grammar rule. + var s = this.symbols_; + for (var key in s) { + if (s[key] === symbol) { + return key; + } + } + return null; + }, + + // Return a more-or-less human-readable description of the given symbol, + // when available, + // or the symbol itself, serving as its own 'description' for lack of + // something better to serve up. + // + // Return NULL when the symbol is unknown to the parser. + describeSymbol: function parser_describeSymbol(symbol) { + if (symbol !== this.EOF && this.terminal_descriptions_ && + this.terminal_descriptions_[symbol]) { + return this.terminal_descriptions_[symbol]; + } else if (symbol === this.EOF) { + return 'end of input'; + } + var id = this.getSymbolName(symbol); + if (id) { + return this.quoteName(id); + } + return null; + }, + + // Produce a (more or less) human-readable list of expected tokens at the + // point of failure. + // + // The produced list may contain token or token set descriptions instead of + // the tokens + // themselves to help turning this output into something that easier to read + // by humans + // unless `do_not_describe` parameter is set, in which case a list of the + // raw, *numeric*, + // expected terminals and nonterminals is produced. + // + // The returned list (array) will not contain any duplicate entries. + collect_expected_token_set: function parser_collect_expected_token_set( + state, do_not_describe) { + var TERROR = this.TERROR; + var tokenset = []; + var check = {}; + // Has this (error?) state been outfitted with a custom expectations + // description text for human consumption? If so, use that one instead of + // the less palatable token set. + if (!do_not_describe && this.state_descriptions_ && + this.state_descriptions_[state]) { + return [this.state_descriptions_[state]]; + } + for (var p in this.table[state]) { + p = +p; + if (p !== TERROR) { + var d = do_not_describe ? p : this.describeSymbol(p); + if (d && !check[d]) { + tokenset.push(d); + check[d] = + true; // Mark this token description as already mentioned to + // prevent outputting duplicate entries. + } + } + } + return tokenset; + }, + productions_: bp({ + pop: u([ + 19, 19, 20, 20, s, [21, 4], s, [22, 4], 23, 23, 24, 24, 25, 25, 26, s, + [27, 4], 28 + ]), + rule: u([ + 3, 2, 2, 3, s, [3, 4, -1], 1, 1, 2, 2, c, [4, 3], 1, 5, 0, c, [18, 3], + s, [1, 3] + ]) + }), + performAction: function parser__PerformAction( + yystate /* action[1] */, yysp, yyvstack) { + /* this == yyval */ + + // the JS engine itself can go and remove these statements when `yy` turns + // out to be unused in any action code! + var yy = this.yy; + var yyparser = yy.parser; + var yylexer = yy.lexer; + + + + switch (yystate) { + case 0: + /*! Production:: $accept : test $end */ + + // default action (generated by JISON mode classic/merge :: + // 1,VT,VA,-,-,-,-,-,-): + this.$ = yyvstack[yysp - 1]; + // END of default action (generated by JISON mode classic/merge :: + // 1,VT,VA,-,-,-,-,-,-) + break; + + case 1: + /*! Production:: test : load_expression statements EOF */ + + this.$ = {}; + if (yyvstack[yysp - 2].page.type === 'HTML') { + this.$.output = initTest(yyvstack[yysp - 2].page); + } else { + this.$.output = initTest(); + } + + this.$.output += addAllStatements(yyvstack[yysp - 1]); + + if (yyvstack[yysp - 2].page.type === 'ChromeURL') { + this.$.output += finishTest(yyvstack[yysp - 2].page); + } else { + this.$.output += finishTest(); + } + + yyvstack[yysp - 1].unshift(yyvstack[yysp - 2]); + this.$.ast = yyvstack[yysp - 1]; + return this.$; + break; + + case 2: + /*! Production:: test : statements EOF */ + + this.$ = {ast: yyvstack[yysp - 1]}; + this.$.output = initTest(); + this.$.output += addAllStatements(yyvstack[yysp - 1]); + this.$.output += finishTest(); + + return this.$; + break; + + case 3: + /*! Production:: load_expression : LOAD_PAGE page_expression */ + case 4: + /*! Production:: load_expression : LOAD_PAGE EOL page_expression */ + + this.$ = {command: 'Load', page: yyvstack[yysp]}; + break; + + case 5: + /*! Production:: statements : statements EOL statement */ + + this.$ = yyvstack[yysp - 2]; + this.$.push(yyvstack[yysp]); + break; + + case 6: + /*! Production:: statements : statements EOL */ + + this.$ = yyvstack[yysp - 1]; + break; + + case 7: + /*! Production:: statements : statement */ + + this.$ = [yyvstack[yysp]]; + break; + + case 8: + /*! Production:: statements : %epsilon */ + + this.$ = []; + break; + + case 9: + /*! Production:: statement : NEXT */ + + this.$ = {command: 'Next'}; + this.$.output = 'TestUtility.pressNextSwitch();'; + break; + + case 10: + /*! Production:: statement : PREVIOUS */ + + this.$ = {command: 'Previous'}; + this.$.output = 'TestUtility.pressPreviousSwitch();'; + break; + + case 11: + /*! Production:: statement : SELECT point_expression */ + + this.$ = {command: 'Select'}; + // A point_expression is only expected when point_scan is enabled. + if (yyvstack[yysp]) { + this.$.point = yyvstack[yysp]; + point = this.$.point.output; + this.$.output = `TestUtility.simulatePointScanSelect(${point});`; + } else { + this.$.output = 'TestUtility.pressSelectSwitch();'; + } + break; + + case 12: + /*! Production:: statement : EXPECT expectation_expression */ + + this.$ = {command: 'Expect', expectation: yyvstack[yysp]}; + this.$.output = yyvstack[yysp].output; + break; + + case 13: + /*! Production:: page_expression : html_page */ + + this.$ = {type: 'HTML', value: yyvstack[yysp]}; + page = this.$.value; + this.$.output = `'` + page + `'`; + break; + + case 14: + /*! Production:: page_expression : CHROME_URL */ + + this.$ = {type: 'ChromeURL', value: yyvstack[yysp]}; + page = this.$.value; + this.$.output = `'` + page + `'`; + break; + + case 15: + /*! Production:: html_page : html_page HTML_SNIPPET */ + + this.$ = yyvstack[yysp - 1] + '\n' + yyvstack[yysp]; + break; + + case 16: + /*! Production:: html_page : HTML_SNIPPET */ + + this.$ = yyvstack[yysp]; + break; + + case 17: + /*! Production:: point_expression : LEFT_PARENS NUMBER COMMA NUMBER + * RIGHT_PARENS */ + + this.$ = {x: yyvstack[yysp - 3], y: yyvstack[yysp - 1]}; + point = this.$; + this.$.output = `{x: ${point.x}, y: ${point.y}}`; + break; + + case 18: + /*! Production:: point_expression : %epsilon */ + + this.$ = null; + break; + + case 19: + /*! Production:: expectation_expression : FOCUS ON + * focusable_expression */ + + this.$ = {type: 'Focus', matches: yyvstack[yysp]}; + objectToMatch = this.$.matches.output; + this.$.output = `await TestUtility.expectFocusOn(${objectToMatch});`; + break; + + case 20: + /*! Production:: focusable_expression : ROLE string_literal */ + + this.$ = {role: yyvstack[yysp - 1], name: yyvstack[yysp]}; + objectToMatch = this.$; + this.$.output = + `{role: '${objectToMatch.role}', name: '${objectToMatch.name}'}`; + break; + + case 21: + /*! Production:: focusable_expression : string_literal ROLE */ + + this.$ = {role: yyvstack[yysp], name: yyvstack[yysp - 1]}; + objectToMatch = this.$; + this.$.output = + `{role: '${objectToMatch.role}', name: '${objectToMatch.name}'}`; + break; + + case 22: + /*! Production:: focusable_expression : ROLE */ + + this.$ = {role: yyvstack[yysp]}; + objectToMatch = this.$; + this.$.output = `{role: '${objectToMatch.role}'}`; + break; + + case 23: + /*! Production:: focusable_expression : string_literal */ + + this.$ = {name: yyvstack[yysp]}; + objectToMatch = this.$; + this.$.output = `{name: '${objectToMatch.name}'}`; + break; + + case 24: + /*! Production:: string_literal : STRING_LITERAL */ + + // Remove the quotes from the string. + this.$ = yyvstack[yysp].substring(1, yyvstack[yysp].length - 1); + break; + } + }, + table: bt({ + len: u([ + 11, 1, 8, 2, 5, s, [0, 3], 4, 2, 2, 0, 7, 0, 4, 7, + s, [0, 3], 1, 0, 1, s, [0, 4], 1, 4, 1, 0, 4, 3, c, [12, 5] + ]), + symbol: u([ + 1, s, [3, 6, 1], s, [19, 4, 1], 1, 1, c, [11, 5], + c, [9, 3], 4, 4, 9, 10, 23, 24, 1, + 4, 11, 25, 15, 26, 1, 4, c, [23, 6], + 22, c, [19, 6], c, [11, 4], 10, 12, 16, 13, + 17, 18, 27, 28, 12, 1, 4, 18, 28, + 1, 4, 17, 14 + ]), + type: u([ + s, [2, 7], s, [0, 4], 1, c, [11, 8], c, + [7, 10], 0, 2, c, [13, 6], c, [11, 5], c, + [26, 8], c, [51, 9], c, [23, 7], 2, 2 + ]), + state: u([1, 2, 3, 5, 10, 5, 13, 15, 18, 20, 23, 24, 15, 29, 31, 34]), + mode: u([ + 2, 1, 2, s, [1, 4], 2, c, [6, 5], s, [1, 5], + c, [11, 6], c, [17, 8], s, [2, 6], c, [27, 10], c, [12, 4] + ]), + goto: u([ + 8, 4, 8, s, [6, 4, 1], 8, c, [6, 5], 11, 12, + 14, 16, 17, 18, 18, 19, 21, 22, 12, s, + [6, 3], c, [17, 3], 16, 17, s, [13, 6], s, [25, 4, 1], 30, + 32, 33, 22, 22, 32, 23, 23, 35, 36 + ]) + }), + defaultActions: bda({ + idx: u( + [5, 6, 7, 11, 13, 16, 17, 18, 20, s, [22, 4, 1], 29, 32, 34, 35, 36]), + goto: u([7, 9, 10, 2, 3, 14, 16, 11, 12, 1, 5, 4, 15, 19, 24, 20, 21, 17]) + }), + parseError: function parseError(str, hash, ExceptionClass) { + if (hash.recoverable) { + if (typeof this.trace === 'function') { + this.trace(str); + } + hash.destroy(); // destroy... well, *almost*! + } else { + if (typeof this.trace === 'function') { + this.trace(str); + } + if (!ExceptionClass) { + ExceptionClass = this.JisonParserError; + } + throw new ExceptionClass(str, hash); + } + }, + parse: function parse(input) { + var self = this; + var stack = new Array(128); // token stack: stores token which leads to + // state at the same index (column storage) + var sstack = + new Array(128); // state stack: stores states (column storage) + + var vstack = new Array(128); // semantic value stack + + var table = this.table; + var sp = 0; // 'stack pointer': index into the stacks + + + + var symbol = 0; + + + + var TERROR = this.TERROR; + var EOF = this.EOF; + var ERROR_RECOVERY_TOKEN_DISCARD_COUNT = + (this.options.errorRecoveryTokenDiscardCount | 0) || 3; + var NO_ACTION = [ + 0, 37 /* === table.length :: ensures that anyone using this new state + will fail dramatically! */ + ]; + + var lexer; + if (this.__lexer__) { + lexer = this.__lexer__; + } else { + lexer = this.__lexer__ = Object.create(this.lexer); + } + + var sharedStateYy = { + parseError: undefined, + quoteName: undefined, + lexer: undefined, + parser: undefined, + pre_parse: undefined, + post_parse: undefined, + pre_lex: undefined, + post_lex: + undefined // WARNING: must be written this way for the code + // expanders to work correctly in both ES5 and ES6 modes! + }; + + var ASSERT; + if (typeof assert !== 'function') { + ASSERT = function JisonAssert(cond, msg) { + if (!cond) { + throw new Error('assertion failed: ' + (msg || '***')); + } + }; + } else { + ASSERT = assert; + } + + this.yyGetSharedState = function yyGetSharedState() { + return sharedStateYy; + }; + + + + function shallow_copy_noclobber(dst, src) { + for (var k in src) { + if (typeof dst[k] === 'undefined' && + Object.prototype.hasOwnProperty.call(src, k)) { + dst[k] = src[k]; + } + } + } + + // copy state + shallow_copy_noclobber(sharedStateYy, this.yy); + + sharedStateYy.lexer = lexer; + sharedStateYy.parser = this; + + + + // Does the shared state override the default `parseError` that already + // comes with this instance? + if (typeof sharedStateYy.parseError === 'function') { + this.parseError = function parseErrorAlt(str, hash, ExceptionClass) { + if (!ExceptionClass) { + ExceptionClass = this.JisonParserError; + } + return sharedStateYy.parseError.call(this, str, hash, ExceptionClass); + }; + } else { + this.parseError = this.originalParseError; + } + + // Does the shared state override the default `quoteName` that already + // comes with this instance? + if (typeof sharedStateYy.quoteName === 'function') { + this.quoteName = function quoteNameAlt(id_str) { + return sharedStateYy.quoteName.call(this, id_str); + }; + } else { + this.quoteName = this.originalQuoteName; + } + + // set up the cleanup function; make it an API so that external code can + // re-use this one in case of calamities or when the `%options + // no-try-catch` option has been specified for the grammar, in which case + // this parse() API method doesn't come with a `finally { ... }` block any + // more! + // + // NOTE: as this API uses parse() as a closure, it MUST be set again on + // every parse() invocation, + // or else your `sharedState`, etc. references will be *wrong*! + this.cleanupAfterParse = function parser_cleanupAfterParse( + resultValue, invoke_post_methods, do_not_nuke_errorinfos) { + var rv; + + if (invoke_post_methods) { + var hash; + + if (sharedStateYy.post_parse || this.post_parse) { + // create an error hash info instance: we re-use this API in a + // **non-error situation** as this one delivers all parser internals + // ready for access by userland code. + hash = this.constructParseErrorInfo( + null /* no error! */, null /* no exception! */, null, false); + } + + if (sharedStateYy.post_parse) { + rv = sharedStateYy.post_parse.call( + this, sharedStateYy, resultValue, hash); + if (typeof rv !== 'undefined') { + resultValue = rv; + } + } + if (this.post_parse) { + rv = this.post_parse.call(this, sharedStateYy, resultValue, hash); + if (typeof rv !== 'undefined') { + resultValue = rv; + } + } + + // cleanup: + if (hash && hash.destroy) { + hash.destroy(); + } + } + + if (this.__reentrant_call_depth > 1) { + return resultValue; + } // do not (yet) kill the sharedState when this is + // a reentrant run. + + // clean up the lingering lexer structures as well: + if (lexer.cleanupAfterLex) { + lexer.cleanupAfterLex(do_not_nuke_errorinfos); + } + + // prevent lingering circular references from causing memory leaks: + if (sharedStateYy) { + sharedStateYy.lexer = undefined; + sharedStateYy.parser = undefined; + if (lexer.yy === sharedStateYy) { + lexer.yy = undefined; + } + } + sharedStateYy = undefined; + this.parseError = this.originalParseError; + this.quoteName = this.originalQuoteName; + + // nuke the vstack[] array at least as that one will still reference + // obsoleted user values. To be safe, we nuke the other internal stack + // columns as well... + stack.length = + 0; // fastest way to nuke an array without overly bothering the GC + sstack.length = 0; + + vstack.length = 0; + sp = 0; + + // nuke the error hash info instances created during this run. + // Userland code must COPY any data/references + // in the error hash instance(s) it is more permanently interested in. + if (!do_not_nuke_errorinfos) { + for (var i = this.__error_infos.length - 1; i >= 0; i--) { + var el = this.__error_infos[i]; + if (el && typeof el.destroy === 'function') { + el.destroy(); + } + } + this.__error_infos.length = 0; + } + + return resultValue; + }; + + + + // NOTE: as this API uses parse() as a closure, it MUST be set again on + // every parse() invocation, + // or else your `lexer`, `sharedState`, etc. references will be + // *wrong*! + this.constructParseErrorInfo = function parser_constructParseErrorInfo( + msg, ex, expected, recoverable) { + var pei = { + errStr: msg, + exception: ex, + text: lexer.match, + value: lexer.yytext, + token: this.describeSymbol(symbol) || symbol, + token_id: symbol, + line: lexer.yylineno, + + expected, + recoverable, + state, + action, + new_state: newState, + symbol_stack: stack, + state_stack: sstack, + value_stack: vstack, + + stack_pointer: sp, + yy: sharedStateYy, + lexer, + parser: this, + + // and make sure the error info doesn't stay due to potential + // ref cycle via userland code manipulations. + // These would otherwise all be memory leak opportunities! + // + // Note that only array and object references are nuked as those + // constitute the set of elements which can produce a cyclic ref. + // The rest of the members is kept intact as they are harmless. + destroy: function destructParseErrorInfo() { + // remove cyclic references added to error info: + // info.yy = null; + // info.lexer = null; + // info.value = null; + // info.value_stack = null; + // ... + var rec = !!this.recoverable; + for (var key in this) { + if (this.hasOwnProperty(key) && typeof key === 'object') { + this[key] = undefined; + } + } + this.recoverable = rec; + } + }; + // track this instance so we can `destroy()` it once we deem it + // superfluous and ready for garbage collection! + this.__error_infos.push(pei); + return pei; + }; + + + + function getNonTerminalFromCode(symbol) { + var tokenName = self.getSymbolName(symbol); + if (!tokenName) { + tokenName = symbol; + } + return tokenName; + } + + + function stdLex() { + var token = lexer.lex(); + // if token isn't its numeric value, convert + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + + return token || EOF; + } + + function fastLex() { + var token = lexer.fastLex(); + // if token isn't its numeric value, convert + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + + return token || EOF; + } + + var lex = stdLex; + + + var state, action, r, t; + var yyval = {$: true, _$: undefined, yy: sharedStateYy}; + var p; + var yyrulelen; + var thisProduction; + var newState; + var retval = false; + + + try { + this.__reentrant_call_depth++; + + lexer.setInput(input, sharedStateYy); + + // NOTE: we *assume* no lexer pre/post handlers are set up *after* + // this initial `setInput()` call: hence we can now check and decide + // whether we'll go with the standard, slower, lex() API or the + // `fast_lex()` one: + if (typeof lexer.canIUse === 'function') { + var lexerInfo = lexer.canIUse(); + if (lexerInfo.fastLex && typeof fastLex === 'function') { + lex = fastLex; + } + } + + + + vstack[sp] = null; + sstack[sp] = 0; + stack[sp] = 0; + ++sp; + + + + if (this.pre_parse) { + this.pre_parse.call(this, sharedStateYy); + } + if (sharedStateYy.pre_parse) { + sharedStateYy.pre_parse.call(this, sharedStateYy); + } + + newState = sstack[sp - 1]; + for (;;) { + // retrieve state number from top of stack + state = newState; // sstack[sp - 1]; + + // use default actions if available + if (this.defaultActions[state]) { + action = 2; + newState = this.defaultActions[state]; + } else { + // The single `==` condition below covers both these `===` + // comparisons in a single operation: + // + // if (symbol === null || typeof symbol === 'undefined') ... + if (!symbol) { + symbol = lex(); + } + // read action for current state and first input + t = (table[state] && table[state][symbol]) || NO_ACTION; + newState = t[1]; + action = t[0]; + + + + // handle parse error + if (!action) { + var errStr; + var errSymbolDescr = (this.describeSymbol(symbol) || symbol); + var expected = this.collect_expected_token_set(state); + + // Report error + if (typeof lexer.yylineno === 'number') { + errStr = 'Parse error on line ' + (lexer.yylineno + 1) + ': '; + } else { + errStr = 'Parse error: '; + } + if (typeof lexer.showPosition === 'function') { + errStr += '\n' + lexer.showPosition(79 - 10, 10) + '\n'; + } + if (expected.length) { + errStr += 'Expecting ' + expected.join(', ') + + ', got unexpected ' + errSymbolDescr; + } else { + errStr += 'Unexpected ' + errSymbolDescr; + } + // we cannot recover from the error! + p = this.constructParseErrorInfo(errStr, null, expected, false); + r = this.parseError(p.errStr, p, this.JisonParserError); + if (typeof r !== 'undefined') { + retval = r; + } + break; + } + } + + + + switch (action) { + // catch misc. parse failures: + default: + // this shouldn't happen, unless resolve defaults are off + if (action instanceof Array) { + p = this.constructParseErrorInfo( + 'Parse Error: multiple actions possible at state: ' + + state + ', token: ' + symbol, + null, null, false); + r = this.parseError(p.errStr, p, this.JisonParserError); + if (typeof r !== 'undefined') { + retval = r; + } + break; + } + // Another case of better safe than sorry: in case state + // transitions come out of another error recovery process or a + // buggy LUT (LookUp Table): + p = this.constructParseErrorInfo( + 'Parsing halted. No viable error recovery approach ' + + 'available due to internal system failure.', + null, null, false); + r = this.parseError(p.errStr, p, this.JisonParserError); + if (typeof r !== 'undefined') { + retval = r; + } + break; + + // shift: + case 1: + stack[sp] = symbol; + vstack[sp] = lexer.yytext; + + sstack[sp] = newState; // push state + + ++sp; + symbol = 0; + + + + // Pick up the lexer details for the current symbol as that one is + // not 'look-ahead' any more: + + + + continue; + + // reduce: + case 2: + + + + thisProduction = + this.productions_[newState - 1]; // `this.productions_[]` is + // zero-based indexed while + // states start from 1 + // upwards... + yyrulelen = thisProduction[1]; + + + + r = this.performAction.call(yyval, newState, sp - 1, vstack); + + if (typeof r !== 'undefined') { + retval = r; + break; + } + + // pop off stack + sp -= yyrulelen; + + // don't overwrite the `symbol` variable: use a local var to speed + // things up: + var ntsymbol = thisProduction[0]; // push nonterminal (reduce) + stack[sp] = ntsymbol; + vstack[sp] = yyval.$; + + // goto new state = table[STATE][NONTERMINAL] + newState = table[sstack[sp - 1]][ntsymbol]; + sstack[sp] = newState; + ++sp; + + + + continue; + + // accept: + case 3: + if (sp !== -2) { + retval = true; + // Return the `$accept` rule's `$$` result, if available. + // + // Also note that JISON always adds this top-most `$accept` rule + // (with implicit, default, action): + // + // $accept: <startSymbol> $end + // %{ $$ = $1; @$ = @1; %} + // + // which, combined with the parse kernel's `$accept` state + // behaviour coded below, will produce the `$$` value output of + // the <startSymbol> rule as the parse result, IFF that result + // is *not* `undefined`. (See also the parser kernel code.) + // + // In code: + // + // %{ + // @$ = @1; // if location + // tracking support is included if (typeof + // $1 !== 'undefined') + // return $1; + // else + // return true; // the + // default parse result if the rule + // actions don't produce anything + // %} + sp--; + if (typeof vstack[sp] !== 'undefined') { + retval = vstack[sp]; + } + } + break; + } + + // break out of loop: we accept or fail with error + break; + } + } catch (ex) { + // report exceptions through the parseError callback too, but keep the + // exception intact if it is a known parser or lexer error which has + // been thrown by parseError() already: + if (ex instanceof this.JisonParserError) { + throw ex; + } else if ( + lexer && typeof lexer.JisonLexerError === 'function' && + ex instanceof lexer.JisonLexerError) { + throw ex; + } + + p = this.constructParseErrorInfo( + 'Parsing aborted due to exception.', ex, null, false); + retval = false; + r = this.parseError(p.errStr, p, this.JisonParserError); + if (typeof r !== 'undefined') { + retval = r; + } + } finally { + retval = this.cleanupAfterParse(retval, true, true); + this.__reentrant_call_depth--; + } // /finally + + return retval; + } + }; + parser.originalParseError = parser.parseError; + parser.originalQuoteName = parser.quoteName; + /* lexer generated by jison-lex 0.6.1-215 */ + + /* + * Returns a Lexer object of the following structure: + * + * Lexer: { + * yy: {} The so-called "shared state" or rather the *source* of it; + * the real "shared state" `yy` passed around to + * the rule actions, etc. is a direct reference! + * + * This "shared context" object was passed to the lexer by way + * of the `lexer.setInput(str, yy)` API before you may use it. + * + * This "shared context" object is passed to the lexer action + * code in `performAction()` so userland code in the lexer actions may + * communicate with the outside world and/or other lexer rules' actions in + * more or less complex ways. + * + * } + * + * Lexer.prototype: { + * EOF: 1, + * ERROR: 2, + * + * yy: The overall "shared context" object reference. + * + * JisonLexerError: function(msg, hash), + * + * performAction: function lexer__performAction(yy, yyrulenumber, + * YY_START), + * + * The function parameters and `this` have the following + * value/meaning: + * - `this` : reference to the `lexer` instance. + * `yY` is an alias for `this` lexer instance + * reference used internally. + * + * - `yy` : a reference to the `yy` "shared state" object + * which was passed to the lexer by way of the `lexer.setInput(str, yy)` API + * before. + * + * Note: + * The extra arguments you specified in the + * `%parse-param` statement in your + * **parser** grammar definition file are passed + * to the lexer via this object reference as member variables. + * + * - `yyrulenumber` : index of the matched lexer rule (regex), + * used internally. + * + * - `YY_START`: the current lexer "start condition" state. + * + * parseError: function(str, hash, ExceptionClass), + * + * constructLexErrorInfo: function(error_message, is_recoverable), + * Helper function. + * Produces a new errorInfo 'hash object' which can be passed + * into `parseError()`. See it's use in this lexer kernel in many places; + * example usage: + * + * var infoObj = lexer.constructParseErrorInfo('fail!', + * true); var retVal = lexer.parseError(infoObj.errStr, infoObj, + * lexer.JisonLexerError); + * + * options: { ... lexer %options ... }, + * + * lex: function(), + * Produce one token of lexed input, which was passed in earlier + * via the `lexer.setInput()` API. You MAY use the additional `args...` + * parameters as per `%parse-param` spec of the **lexer** grammar: these extra + * `args...` are added verbatim to the `yy` object reference as member + * variables. + * + * WARNING: + * Lexer's additional `args...` parameters (via lexer's + * `%parse-param`) MAY conflict with any attributes already added to `yy` by + * the **parser** or the jison run-time; when such a collision is detected an + * exception is thrown to prevent the generated run-time from silently + * accepting this confusing and potentially hazardous situation! + * + * cleanupAfterLex: function(do_not_nuke_errorinfos), + * Helper function. + * + * This helper API is invoked when the **parse process** has + * completed: it is the responsibility of the **parser** (or the calling + * userland code) to invoke this method once cleanup is desired. + * + * This helper may be invoked by user code to ensure the + * internal lexer gets properly garbage collected. + * + * setInput: function(input, [yy]), + * + * + * input: function(), + * + * + * unput: function(str), + * + * + * more: function(), + * + * + * reject: function(), + * + * + * less: function(n), + * + * + * pastInput: function(n), + * + * + * upcomingInput: function(n), + * + * + * showPosition: function(), + * + * + * test_match: function(regex_match_array, rule_index), + * + * + * next: function(), + * + * + * begin: function(condition), + * + * + * pushState: function(condition), + * + * + * popState: function(), + * + * + * topState: function(), + * + * + * _currentRules: function(), + * + * + * stateStackSize: function(), + * + * + * performAction: function(yy, yY, yyrulenumber, YY_START), + * + * + * rules: [...], + * + * + * conditions: {associative list: name ==> set}, + * } + * + * + * token location info (`yylloc`): { + * first_line: n, + * last_line: n, + * first_column: n, + * last_column: n, + * range: [start_number, end_number] + * (where the numbers are indexes into the input string, + * zero-based) + * } + * + * --- + * + * The `parseError` function receives a 'hash' object with these members for + * lexer errors: + * + * { + * text: (matched text) + * token: (the produced terminal token, if any) + * token_id: (the produced terminal token numeric ID, if any) + * line: (yylineno) + * loc: (yylloc) + * recoverable: (boolean: TRUE when the parser MAY have an error recovery + * rule available for this particular error) yy: (object: the current + * parser internal "shared state" `yy` as is also available in the rule + * actions; this can be used, for instance, for advanced error analysis and + * reporting) lexer: (reference to the current lexer instance used by + * the parser) + * } + * + * while `this` will reference the current lexer instance. + * + * When `parseError` is invoked by the lexer, the default implementation will + * attempt to invoke `yy.parser.parseError()`; when this callback is not + * provided it will try to invoke `yy.parseError()` instead. When that + * callback is also not provided, a `JisonLexerError` exception will be thrown + * containing the error message and `hash`, as constructed by the + * `constructLexErrorInfo()` API. + * + * Note that the lexer's `JisonLexerError` error class is passed via the + * `ExceptionClass` argument, which is invoked to construct the exception + * instance to be thrown, so technically `parseError` will throw the object + * produced by the `new ExceptionClass(str, hash)` JavaScript expression. + * + * --- + * + * You can specify lexer options by setting / modifying the `.options` object + * of your Lexer instance. These options are available: + * + * (Options are permanent.) + * + * yy: { + * parseError: function(str, hash, ExceptionClass) + * optional: overrides the default `parseError` function. + * } + * + * lexer.options: { + * pre_lex: function() + * optional: is invoked before the lexer is invoked to produce + * another token. `this` refers to the Lexer object. post_lex: + * function(token) { return token; } optional: is invoked when the lexer has + * produced a token `token`; this function can override the returned token + * value by returning another. When it does not return any (truthy) value, the + * lexer will return the original `token`. `this` refers to the Lexer object. + * + * WARNING: the next set of options are not meant to be changed. They echo the + * abilities of the lexer as per when it was compiled! + * + * ranges: boolean + * optional: `true` ==> token location info will include a + * .range[] member. flex: boolean optional: `true` ==> flex-like lexing + * behaviour where the rules are tested exhaustively to find the longest + * match. backtrack_lexer: boolean optional: `true` ==> lexer regexes are + * tested in order and for invoked; the lexer terminates the scan when a token + * is returned by the action code. xregexp: boolean optional: `true` ==> lexer + * rule regexes are "extended regex format" requiring the `XRegExp` library. + * When this %option has not been specified at compile time, all lexer rule + * regexes have been written as standard JavaScript RegExp expressions. + * } + */ + + + var lexer = function() { + /** + * See also: + * http://stackoverflow.com/questions/1382107/whats-a-good-way-to-extend-error-in-javascript/#35881508 + * but we keep the prototype.constructor and prototype.name assignment lines + * too for compatibility with userland code which might access the derived + * class in a 'classic' way. + * + * @public + * @constructor + * @nocollapse + */ + function JisonLexerError(msg, hash) { + Object.defineProperty( + this, 'name', + {enumerable: false, writable: false, value: 'JisonLexerError'}); + + if (msg == null) { + msg = '???'; + } + + Object.defineProperty( + this, 'message', {enumerable: false, writable: true, value: msg}); + + this.hash = hash; + var stacktrace; + + if (hash && hash.exception instanceof Error) { + var ex2 = hash.exception; + this.message = ex2.message || msg; + stacktrace = ex2.stack; + } + + if (!stacktrace) { + if (Error.hasOwnProperty('captureStackTrace')) { + // V8 + Error.captureStackTrace(this, this.constructor); + } else { + stacktrace = new Error(msg).stack; + } + } + + if (stacktrace) { + Object.defineProperty( + this, 'stack', + {enumerable: false, writable: false, value: stacktrace}); + } + } + + if (typeof Object.setPrototypeOf === 'function') { + Object.setPrototypeOf(JisonLexerError.prototype, Error.prototype); + } else { + JisonLexerError.prototype = Object.create(Error.prototype); + } + + JisonLexerError.prototype.constructor = JisonLexerError; + JisonLexerError.prototype.name = 'JisonLexerError'; + + var lexer = { + + // Code Generator Information Report + // --------------------------------- + // + // Options: + // + // backtracking: .................... false + // location.ranges: ................. false + // location line+column tracking: ... true + // + // + // Forwarded Parser Analysis flags: + // + // uses yyleng: ..................... false + // uses yylineno: ................... false + // uses yytext: ..................... false + // uses yylloc: ..................... false + // uses lexer values: ............... true / true + // location tracking: ............... false + // location assignment: ............. false + // + // + // Lexer Analysis flags: + // + // uses yyleng: ..................... ??? + // uses yylineno: ................... ??? + // uses yytext: ..................... ??? + // uses yylloc: ..................... ??? + // uses ParseError API: ............. ??? + // uses yyerror: .................... ??? + // uses location tracking & editing: ??? + // uses more() API: ................. ??? + // uses unput() API: ................ ??? + // uses reject() API: ............... ??? + // uses less() API: ................. ??? + // uses display APIs pastInput(), upcomingInput(), showPosition(): + // ............................. ??? + // uses describeYYLLOC() API: ....... ??? + // + // --------- END OF REPORT ----------- + + EOF: 1, + ERROR: 2, + + // JisonLexerError: JisonLexerError, /// <-- injected by the code + // generator + + // options: {}, /// <-- injected by the code + // generator + + // yy: ..., /// <-- injected by setInput() + + __currentRuleSet__: null, /// INTERNAL USE ONLY: internal rule set cache + /// for the current lexer state + + __error_infos: [], /// INTERNAL USE ONLY: the set of lexErrorInfo objects + /// created since the last cleanup + __decompressed: + false, /// INTERNAL USE ONLY: mark whether the lexer instance has + /// been 'unfolded' completely and is now ready for use + done: false, /// INTERNAL USE ONLY + _backtrack: false, /// INTERNAL USE ONLY + _input: '', /// INTERNAL USE ONLY + _more: false, /// INTERNAL USE ONLY + _signaled_error_token: false, /// INTERNAL USE ONLY + conditionStack: [], /// INTERNAL USE ONLY; managed via `pushState()`, + /// `popState()`, `topState()` and `stateStackSize()` + match: + '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks input + /// which has been matched so far for the lexer token under + /// construction. `match` is identical to `yytext` except that + /// this one still contains the matched input string after + /// `lexer.performAction()` has been invoked, where userland code + /// MAY have changed/replaced the `yytext` value entirely! + matched: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks + /// entire input which has been matched so far + matches: false, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks + /// RE match result for last (successful) match attempt + yytext: '', /// ADVANCED USE ONLY: tracks input which has been matched so + /// far for the lexer token under construction; this value is + /// transferred to the parser as the 'token value' when the + /// parser consumes the lexer token produced through a call + /// to the `lex()` API. + offset: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks the + /// 'cursor position' in the input string, i.e. the number of + /// characters matched so far + yyleng: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: length of + /// matched input for the token under construction (`yytext`) + yylineno: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: 'line + /// number' at which the token under construction is located + yylloc: null, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks + /// location info (lines + columns) for the token under + /// construction + + /** + * INTERNAL USE: construct a suitable error info hash object instance for + * `parseError`. + * + * @public + * @this {RegExpLexer} + */ + constructLexErrorInfo: function lexer_constructLexErrorInfo( + msg, recoverable, show_input_position) { + msg = '' + msg; + + // heuristic to determine if the error message already contains a + // (partial) source code dump as produced by either `showPosition()` or + // `prettyPrintRange()`: + if (!show_input_position) { + show_input_position = + !(msg.indexOf('\n') > 0 && msg.indexOf('^') > 0); + } + + if (this.yylloc && show_input_position) { + if (typeof this.prettyPrintRange === 'function') { + var prettySrc = this.prettyPrintRange(this.yylloc); + + if (!/\n\s*$/.test(msg)) { + msg += '\n'; + } + + msg += '\n Erroneous area:\n' + this.prettyPrintRange(this.yylloc); + } else if (typeof this.showPosition === 'function') { + var posStr = this.showPosition(); + + if (posStr) { + if (msg.length && msg[msg.length - 1] !== '\n' && + posStr[0] !== '\n') { + msg += '\n' + posStr; + } else { + msg += posStr; + } + } + } + } + + /** @constructor */ + var pei = { + errStr: msg, + recoverable: !!recoverable, + text: this.match, // This one MAY be empty; userland code should use + // the `upcomingInput` API to obtain more text + // which follows the 'lexer cursor position'... + token: null, + line: this.yylineno, + loc: this.yylloc, + yy: this.yy, + lexer: this, + + /** + * and make sure the error info doesn't stay due to potential + * ref cycle via userland code manipulations. + * These would otherwise all be memory leak opportunities! + * + * Note that only array and object references are nuked as those + * constitute the set of elements which can produce a cyclic ref. + * The rest of the members is kept intact as they are harmless. + * + * @public + * @this {LexErrorInfo} + */ + destroy: function destructLexErrorInfo() { + // remove cyclic references added to error info: + // info.yy = null; + // info.lexer = null; + // ... + var rec = !!this.recoverable; + + for (var key in this) { + if (this.hasOwnProperty(key) && typeof key === 'object') { + this[key] = undefined; + } + } + + this.recoverable = rec; + } + }; + + // track this instance so we can `destroy()` it once we deem it + // superfluous and ready for garbage collection! + this.__error_infos.push(pei); + + return pei; + }, + + /** + * handler which is invoked when a lexer error occurs. + * + * @public + * @this {RegExpLexer} + */ + parseError: function lexer_parseError(str, hash, ExceptionClass) { + if (!ExceptionClass) { + ExceptionClass = this.JisonLexerError; + } + + if (this.yy) { + if (this.yy.parser && + typeof this.yy.parser.parseError === 'function') { + return this.yy.parser.parseError.call( + this, str, hash, ExceptionClass) || + this.ERROR; + } else if (typeof this.yy.parseError === 'function') { + return this.yy.parseError.call(this, str, hash, ExceptionClass) || + this.ERROR; + } + } + + throw new ExceptionClass(str, hash); + }, + + /** + * method which implements `yyerror(str, ...args)` functionality for use + * inside lexer actions. + * + * @public + * @this {RegExpLexer} + */ + yyerror: function yyError(str /*, ...args */) { + var linenoMsg = ''; + + if (this.yylloc) { + linenoMsg = ' on line ' + (this.yylineno + 1); + } + + var p = this.constructLexErrorInfo( + 'Lexical error' + linenoMsg + ': ' + str, + this.options.lexerErrorsAreRecoverable); + + // Add any extra args to the hash under the name + // `extra_error_attributes`: + var args = Array.prototype.slice.call(arguments, 1); + + if (args.length) { + p.extra_error_attributes = args; + } + + return this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR; + }, + + /** + * final cleanup function for when we have completed lexing the input; + * make it an API so that external code can use this one once userland + * code has decided it's time to destroy any lingering lexer error + * hash object instances and the like: this function helps to clean + * up these constructs, which *may* carry cyclic references which would + * otherwise prevent the instances from being properly and timely + * garbage-collected, i.e. this function helps prevent memory leaks! + * + * @public + * @this {RegExpLexer} + */ + cleanupAfterLex: function lexer_cleanupAfterLex(do_not_nuke_errorinfos) { + // prevent lingering circular references from causing memory leaks: + this.setInput('', {}); + + // nuke the error hash info instances created during this run. + // Userland code must COPY any data/references + // in the error hash instance(s) it is more permanently interested in. + if (!do_not_nuke_errorinfos) { + for (var i = this.__error_infos.length - 1; i >= 0; i--) { + var el = this.__error_infos[i]; + + if (el && typeof el.destroy === 'function') { + el.destroy(); + } + } + + this.__error_infos.length = 0; + } + + return this; + }, + + /** + * clear the lexer token context; intended for internal use only + * + * @public + * @this {RegExpLexer} + */ + clear: function lexer_clear() { + this.yytext = ''; + this.yyleng = 0; + this.match = ''; + + // - DO NOT reset `this.matched` + this.matches = false; + + this._more = false; + this._backtrack = false; + var col = (this.yylloc ? this.yylloc.last_column : 0); + + this.yylloc = { + first_line: this.yylineno + 1, + first_column: col, + last_line: this.yylineno + 1, + last_column: col, + range: [this.offset, this.offset] + }; + }, + + /** + * resets the lexer, sets new input + * + * @public + * @this {RegExpLexer} + */ + setInput: function lexer_setInput(input, yy) { + this.yy = yy || this.yy || {}; + + // also check if we've fully initialized the lexer instance, + // including expansion work to be done to go from a loaded + // lexer to a usable lexer: + if (!this.__decompressed) { + // step 1: decompress the regex list: + var rules = this.rules; + + for (var i = 0, len = rules.length; i < len; i++) { + var ruleRe = rules[i]; + + // compression: is the RE an xref to another RE slot in the rules[] + // table? + if (typeof ruleRe === 'number') { + rules[i] = rules[ruleRe]; + } + } + + // step 2: unfold the conditions[] set to make these ready for use: + var conditions = this.conditions; + + for (var k in conditions) { + var spec = conditions[k]; + var ruleIds = spec.rules; + var len = ruleIds.length; + var ruleRegexes = + new Array(len + 1); // slot 0 is unused; we use a 1-based index + // approach here to keep the hottest code + // in `lexer_next()` fast and simple! + var ruleNewIds = new Array(len + 1); + + for (var i = 0; i < len; i++) { + var idx = ruleIds[i]; + var ruleRe = rules[idx]; + ruleRegexes[i + 1] = ruleRe; + ruleNewIds[i + 1] = idx; + } + + spec.rules = ruleNewIds; + spec.__ruleRegexes = ruleRegexes; + spec.__rule_count = len; + } + + this.__decompressed = true; + } + + this._input = input || ''; + this.clear(); + this._signaled_error_token = false; + this.done = false; + this.yylineno = 0; + this.matched = ''; + this.conditionStack = ['INITIAL']; + this.__currentRuleSet__ = null; + + this.yylloc = { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 0, + range: [0, 0] + }; + + this.offset = 0; + return this; + }, + + /** + * edit the remaining input via user-specified callback. + * This can be used to forward-adjust the input-to-parse, + * e.g. inserting macro expansions and alike in the + * input which has yet to be lexed. + * The behaviour of this API contrasts the `unput()` et al + * APIs as those act on the *consumed* input, while this + * one allows one to manipulate the future, without impacting + * the current `yyloc` cursor location or any history. + * + * Use this API to help implement C-preprocessor-like + * `#include` statements, etc. + * + * The provided callback must be synchronous and is + * expected to return the edited input (string). + * + * The `cpsArg` argument value is passed to the callback + * as-is. + * + * `callback` interface: + * `function callback(input, cpsArg)` + * + * - `input` will carry the remaining-input-to-lex string + * from the lexer. + * - `cpsArg` is `cpsArg` passed into this API. + * + * The `this` reference for the callback will be set to + * reference this lexer instance so that userland code + * in the callback can easily and quickly access any lexer + * API. + * + * When the callback returns a non-string-type falsey value, + * we assume the callback did not edit the input and we + * will using the input as-is. + * + * When the callback returns a non-string-type value, it + * is converted to a string for lexing via the `"" + retval` + * operation. (See also why: + * http://2ality.com/2012/03/converting-to-string.html + * -- that way any returned object's `toValue()` and `toString()` + * methods will be invoked in a proper/desirable order.) + * + * @public + * @this {RegExpLexer} + */ + editRemainingInput: function lexer_editRemainingInput(callback, cpsArg) { + var rv = callback.call(this, this._input, cpsArg); + + if (typeof rv !== 'string') { + if (rv) { + this._input = '' + rv; + } + // else: keep `this._input` as is. + } else { + this._input = rv; + } + + return this; + }, + + /** + * consumes and returns one char from the input + * + * @public + * @this {RegExpLexer} + */ + input: function lexer_input() { + if (!this._input) { + // this.done = true; -- don't set `done` as we want the + // lex()/next() API to be able to produce one custom EOF token match + // after this anyhow. (lexer can match special <<EOF>> tokens and + // perform user action code for a <<EOF>> match, but only does so + // *once*) + return null; + } + + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + + // Count the linenumber up when we hit the LF (or a stand-alone CR). + // On CRLF, the linenumber is incremented when you fetch the CR or the + // CRLF combo and we advance immediately past the LF as well, returning + // both together as if it was all a single 'character' only. + var sliceLen = 1; + + var lines = false; + + if (ch === '\n') { + lines = true; + } else if (ch === '\r') { + lines = true; + var ch2 = this._input[1]; + + if (ch2 === '\n') { + sliceLen++; + ch += ch2; + this.yytext += ch2; + this.yyleng++; + this.offset++; + this.match += ch2; + this.matched += ch2; + this.yylloc.range[1]++; + } + } + + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + this.yylloc.last_column = 0; + } else { + this.yylloc.last_column++; + } + + this.yylloc.range[1]++; + this._input = this._input.slice(sliceLen); + return ch; + }, + + /** + * unshifts one char (or an entire string) into the input + * + * @public + * @this {RegExpLexer} + */ + unput: function lexer_unput(ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len); + this.yyleng = this.yytext.length; + this.offset -= len; + this.match = this.match.substr(0, this.match.length - len); + this.matched = this.matched.substr(0, this.matched.length - len); + + if (lines.length > 1) { + this.yylineno -= lines.length - 1; + this.yylloc.last_line = this.yylineno + 1; + + // Get last entirely matched line into the `preLines[]` array's + // last index slot; we don't mind when other previously + // matched lines end up in the array too. + var pre = this.match; + + var preLines = pre.split(/(?:\r\n?|\n)/g); + + if (preLines.length === 1) { + pre = this.matched; + preLines = pre.split(/(?:\r\n?|\n)/g); + } + + this.yylloc.last_column = preLines[preLines.length - 1].length; + } else { + this.yylloc.last_column -= len; + } + + this.yylloc.range[1] = this.yylloc.range[0] + this.yyleng; + this.done = false; + return this; + }, + + /** + * cache matched text and append it on next action + * + * @public + * @this {RegExpLexer} + */ + more: function lexer_more() { + this._more = true; + return this; + }, + + /** + * signal the lexer that this rule fails to match the input, so the + * next matching rule (regex) should be tested instead. + * + * @public + * @this {RegExpLexer} + */ + reject: function lexer_reject() { + if (this.options.backtrack_lexer) { + this._backtrack = true; + } else { + // when the `parseError()` call returns, we MUST ensure that the error + // is registered. We accomplish this by signaling an 'error' token to + // be produced for the current + // `.lex()` run. + var linenoMsg = ''; + + if (this.yylloc) { + linenoMsg = ' on line ' + (this.yylineno + 1); + } + + var p = this.constructLexErrorInfo( + 'Lexical error' + linenoMsg + + ': You can only invoke reject() in the lexer when the ' + + 'lexer is of the backtracking persuasion ' + + '(options.backtrack_lexer = true).', + false); + + this._signaled_error_token = + this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR; + } + + return this; + }, + + /** + * retain first n characters of the match + * + * @public + * @this {RegExpLexer} + */ + less: function lexer_less(n) { + return this.unput(this.match.slice(n)); + }, + + /** + * return (part of the) already matched input, i.e. for error + * messages. + * + * Limit the returned string length to `maxSize` (default: 20). + * + * Limit the returned string to the `maxLines` number of lines of + * input (default: 1). + * + * Negative limit values equal *unlimited*. + * + * @public + * @this {RegExpLexer} + */ + pastInput: function lexer_pastInput(maxSize, maxLines) { + var past = + this.matched.substring(0, this.matched.length - this.match.length); + + if (maxSize < 0) { + maxSize = past.length; + } else if (!maxSize) { + maxSize = 20; + } + + if (maxLines < 0) { + maxLines = past.length; + } else if (!maxLines) { + maxLines = 1; + } + + // `substr` anticipation: treat \r\n as a single character and take a + // little more than necessary so that we can still properly check + // against maxSize after we've transformed and limited the newLines in + // here: + past = past.substr(-maxSize * 2 - 2); + + // now that we have a significantly reduced string to process, transform + // the newlines and chop them, then limit them: + var a = past.replace(/\r\n|\r/g, '\n').split('\n'); + + a = a.slice(-maxLines); + past = a.join('\n'); + + // When, after limiting to maxLines, we still have too much to return, + // do add an ellipsis prefix... + if (past.length > maxSize) { + past = '...' + past.substr(-maxSize); + } + + return past; + }, + + /** + * return (part of the) upcoming input, i.e. for error messages. + * + * Limit the returned string length to `maxSize` (default: 20). + * + * Limit the returned string to the `maxLines` number of lines of input + * (default: 1). + * + * Negative limit values equal *unlimited*. + * + * > ### NOTE ### + * > + * > *"upcoming input"* is defined as the whole of the both + * > the *currently lexed* input, together with any remaining input + * > following that. *"currently lexed"* input is the input + * > already recognized by the lexer but not yet returned with + * > the lexer token. This happens when you are invoking this API + * > from inside any lexer rule action code block. + * > + * + * @public + * @this {RegExpLexer} + */ + upcomingInput: function lexer_upcomingInput(maxSize, maxLines) { + var next = this.match; + + if (maxSize < 0) { + maxSize = next.length + this._input.length; + } else if (!maxSize) { + maxSize = 20; + } + + if (maxLines < 0) { + maxLines = maxSize; + } else if (!maxLines) { + maxLines = 1; + } + + // `substring` anticipation: treat \r\n as a single character and take a + // little more than necessary so that we can still properly check + // against maxSize after we've transformed and limited the newLines in + // here: + if (next.length < maxSize * 2 + 2) { + next += this._input.substring( + 0, maxSize * 2 + 2); // substring is faster on Chrome/V8 + } + + // now that we have a significantly reduced string to process, transform + // the newlines and chop them, then limit them: + var a = next.replace(/\r\n|\r/g, '\n').split('\n'); + + a = a.slice(0, maxLines); + next = a.join('\n'); + + // When, after limiting to maxLines, we still have too much to return, + // do add an ellipsis postfix... + if (next.length > maxSize) { + next = next.substring(0, maxSize) + '...'; + } + + return next; + }, + + /** + * return a string which displays the character position where the + * lexing error occurred, i.e. for error messages + * + * @public + * @this {RegExpLexer} + */ + showPosition: function lexer_showPosition(maxPrefix, maxPostfix) { + var pre = this.pastInput(maxPrefix).replace(/\s/g, ' '); + var c = new Array(pre.length + 1).join('-'); + return pre + this.upcomingInput(maxPostfix).replace(/\s/g, ' ') + '\n' + + c + '^'; + }, + + /** + * return an YYLLOC info object derived off the given context (actual, + * preceding, following, current). Use this method when the given `actual` + * location is not guaranteed to exist (i.e. when it MAY be NULL) and you + * MUST have a valid location info object anyway: then we take the given + * context of the `preceding` and `following` locations, IFF those are + * available, and reconstruct the `actual` location info from those. If + * this fails, the heuristic is to take the `current` location, IFF + * available. If this fails as well, we assume the sought location is + * at/around the current lexer position and then produce that one as a + * response. DO NOTE that these heuristic/derived location info values MAY + * be inaccurate! + * + * NOTE: `deriveLocationInfo()` ALWAYS produces a location info object + * *copy* of `actual`, not just a *reference* hence all input location + * objects can be assumed to be 'constant' (function has no side-effects). + * + * @public + * @this {RegExpLexer} + */ + deriveLocationInfo: function lexer_deriveYYLLOC( + actual, preceding, following, current) { + var loc = { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 0, + range: [0, 0] + }; + + if (actual) { + loc.first_line = actual.first_line | 0; + loc.last_line = actual.last_line | 0; + loc.first_column = actual.first_column | 0; + loc.last_column = actual.last_column | 0; + + if (actual.range) { + loc.range[0] = actual.range[0] | 0; + loc.range[1] = actual.range[1] | 0; + } + } + + if (loc.first_line <= 0 || loc.last_line < loc.first_line) { + // plan B: heuristic using preceding and following: + if (loc.first_line <= 0 && preceding) { + loc.first_line = preceding.last_line | 0; + loc.first_column = preceding.last_column | 0; + + if (preceding.range) { + loc.range[0] = actual.range[1] | 0; + } + } + + if ((loc.last_line <= 0 || loc.last_line < loc.first_line) && + following) { + loc.last_line = following.first_line | 0; + loc.last_column = following.first_column | 0; + + if (following.range) { + loc.range[1] = actual.range[0] | 0; + } + } + + // plan C?: see if the 'current' location is useful/sane too: + if (loc.first_line <= 0 && current && + (loc.last_line <= 0 || current.last_line <= loc.last_line)) { + loc.first_line = current.first_line | 0; + loc.first_column = current.first_column | 0; + + if (current.range) { + loc.range[0] = current.range[0] | 0; + } + } + + if (loc.last_line <= 0 && current && + (loc.first_line <= 0 || current.first_line >= loc.first_line)) { + loc.last_line = current.last_line | 0; + loc.last_column = current.last_column | 0; + + if (current.range) { + loc.range[1] = current.range[1] | 0; + } + } + } + + // sanitize: fix last_line BEFORE we fix first_line as we use the 'raw' + // value of the latter or plan D heuristics to produce a 'sensible' + // last_line value: + if (loc.last_line <= 0) { + if (loc.first_line <= 0) { + loc.first_line = this.yylloc.first_line; + loc.last_line = this.yylloc.last_line; + loc.first_column = this.yylloc.first_column; + loc.last_column = this.yylloc.last_column; + loc.range[0] = this.yylloc.range[0]; + loc.range[1] = this.yylloc.range[1]; + } else { + loc.last_line = this.yylloc.last_line; + loc.last_column = this.yylloc.last_column; + loc.range[1] = this.yylloc.range[1]; + } + } + + if (loc.first_line <= 0) { + loc.first_line = loc.last_line; + loc.first_column = 0; // loc.last_column; + loc.range[1] = loc.range[0]; + } + + if (loc.first_column < 0) { + loc.first_column = 0; + } + + if (loc.last_column < 0) { + loc.last_column = (loc.first_column > 0 ? loc.first_column : 80); + } + + return loc; + }, + + /** + * return a string which displays the lines & columns of input which are + * referenced by the given location info range, plus a few lines of + * context. + * + * This function pretty-prints the indicated section of the input, with + * line numbers and everything! + * + * This function is very useful to provide highly readable error reports, + * while the location range may be specified in various flexible ways: + * + * - `loc` is the location info object which references the area which + * should be displayed and 'marked up': these lines & columns of text are + * marked up by `^` characters below each character in the entire input + * range. + * + * - `context_loc` is the *optional* location info object which instructs + * this pretty-printer how much *leading* context should be displayed + * alongside the area referenced by `loc`. This can help provide context + * for the displayed error, etc. + * + * When this location info is not provided, a default context of 3 lines + * is used. + * + * - `context_loc2` is another *optional* location info object, which + * serves a similar purpose to `context_loc`: it specifies the amount of + * *trailing* context lines to display in the pretty-print output. + * + * When this location info is not provided, a default context of 1 line + * only is used. + * + * Special Notes: + * + * - when the `loc`-indicated range is very large (about 5 lines or more), + * then only the first and last few lines of this block are printed while + * a + * `...continued...` message will be printed between them. + * + * This serves the purpose of not printing a huge amount of text when + * the `loc` range happens to be huge: this way a manageable & readable + * output results for arbitrary large ranges. + * + * - this function can display lines of input which whave not yet been + * lexed. `prettyPrintRange()` can access the entire input! + * + * @public + * @this {RegExpLexer} + */ + prettyPrintRange: function lexer_prettyPrintRange( + loc, context_loc, context_loc2) { + loc = this.deriveLocationInfo(loc, context_loc, context_loc2); + const CONTEXT = 3; + const CONTEXT_TAIL = 1; + const MIN_VIS_LINE = 2; + var input = this.matched + this._input; + var lines = input.split('\n'); + var l0 = Math.max( + 1, + (context_loc ? context_loc.first_line : loc.first_line - CONTEXT)); + var l1 = Math.max( + 1, + (context_loc2 ? context_loc2.last_line : + loc.last_line + CONTEXT_TAIL)); + var linenoDisplayWidth = 1 + Math.log10(l1 | 1) | 0; + var wsPrefix = new Array(linenoDisplayWidth).join(' '); + var nonemptyLineIndexes = []; + + var rv = lines.slice(l0 - 1, l1 + 1) + .map(function injectLineNumber(line, index) { + var lno = index + l0; + var lnoPfx = + (wsPrefix + lno).substr(-linenoDisplayWidth); + var rv = lnoPfx + ': ' + line; + var errpfx = new Array(linenoDisplayWidth + 1).join('^'); + var offset = 2 + 1; + var len = 0; + + if (lno === loc.first_line) { + offset += loc.first_column; + + len = Math.max( + 2, + ((lno === loc.last_line ? loc.last_column : + line.length)) - + loc.first_column + 1); + } else if (lno === loc.last_line) { + len = Math.max(2, loc.last_column + 1); + } else if (lno > loc.first_line && lno < loc.last_line) { + len = Math.max(2, line.length + 1); + } + + if (len) { + var lead = new Array(offset).join('.'); + var mark = new Array(len).join('^'); + rv += '\n' + errpfx + lead + mark; + + if (line.trim().length > 0) { + nonemptyLineIndexes.push(index); + } + } + + rv = rv.replace(/\t/g, ' '); + return rv; + }); + + // now make sure we don't print an overly large amount of error area: + // limit it to the top and bottom line count: + if (nonemptyLineIndexes.length > 2 * MIN_VIS_LINE) { + var clipStart = nonemptyLineIndexes[MIN_VIS_LINE - 1] + 1; + var clipEnd = + nonemptyLineIndexes[nonemptyLineIndexes.length - MIN_VIS_LINE] - + 1; + var intermediateLine = new Array(linenoDisplayWidth + 1).join(' ') + + ' (...continued...)'; + intermediateLine += '\n' + + new Array(linenoDisplayWidth + 1).join('-') + + ' (---------------)'; + rv.splice(clipStart, clipEnd - clipStart + 1, intermediateLine); + } + + return rv.join('\n'); + }, + + /** + * helper function, used to produce a human readable description as a + * string, given the input `yylloc` location object. + * + * Set `display_range_too` to TRUE to include the string character index + * position(s) in the description if the `yylloc.range` is available. + * + * @public + * @this {RegExpLexer} + */ + describeYYLLOC: function lexer_describe_yylloc( + yylloc, display_range_too) { + var l1 = yylloc.first_line; + var l2 = yylloc.last_line; + var c1 = yylloc.first_column; + var c2 = yylloc.last_column; + var dl = l2 - l1; + var dc = c2 - c1; + var rv; + + if (dl === 0) { + rv = 'line ' + l1 + ', '; + + if (dc <= 1) { + rv += 'column ' + c1; + } else { + rv += 'columns ' + c1 + ' .. ' + c2; + } + } else { + rv = 'lines ' + l1 + '(column ' + c1 + ') .. ' + l2 + '(column ' + + c2 + ')'; + } + + if (yylloc.range && display_range_too) { + var r1 = yylloc.range[0]; + var r2 = yylloc.range[1] - 1; + + if (r2 <= r1) { + rv += ' {String Offset: ' + r1 + '}'; + } else { + rv += ' {String Offset range: ' + r1 + ' .. ' + r2 + '}'; + } + } + + return rv; + }, + + /** + * test the lexed token: return FALSE when not a match, otherwise return + * token. + * + * `match` is supposed to be an array coming out of a regex match, i.e. + * `match[0]` contains the actually matched text string. + * + * Also move the input cursor forward and update the match collectors: + * + * - `yytext` + * - `yyleng` + * - `match` + * - `matches` + * - `yylloc` + * - `offset` + * + * @public + * @this {RegExpLexer} + */ + test_match: function lexer_test_match(match, indexed_rule) { + var token, lines, backup, match_str, match_str_len; + + if (this.options.backtrack_lexer) { + // save context + backup = { + yylineno: this.yylineno, + + yylloc: { + first_line: this.yylloc.first_line, + last_line: this.yylloc.last_line, + first_column: this.yylloc.first_column, + last_column: this.yylloc.last_column, + range: this.yylloc.range.slice(0) + }, + + yytext: this.yytext, + match: this.match, + matches: this.matches, + matched: this.matched, + yyleng: this.yyleng, + offset: this.offset, + _more: this._more, + _input: this._input, + + //_signaled_error_token: this._signaled_error_token, + yy: this.yy, + + conditionStack: this.conditionStack.slice(0), + done: this.done + }; + } + + match_str = match[0]; + match_str_len = match_str.length; + + // if (match_str.indexOf('\n') !== -1 || match_str.indexOf('\r') !== + // -1) { + lines = match_str.split(/(?:\r\n?|\n)/g); + + if (lines.length > 1) { + this.yylineno += lines.length - 1; + this.yylloc.last_line = this.yylineno + 1; + this.yylloc.last_column = lines[lines.length - 1].length; + } else { + this.yylloc.last_column += match_str_len; + } + + // } + this.yytext += match_str; + + this.match += match_str; + this.matched += match_str; + this.matches = match; + this.yyleng = this.yytext.length; + this.yylloc.range[1] += match_str_len; + + // previous lex rules MAY have invoked the `more()` API rather than + // producing a token: those rules will already have moved this `offset` + // forward matching their match lengths, hence we must only add our own + // match length now: + this.offset += match_str_len; + + this._more = false; + this._backtrack = false; + this._input = this._input.slice(match_str_len); + + // calling this method: + // + // function lexer__performAction(yy, yyrulenumber, YY_START) {...} + token = this.performAction.call( + this, this.yy, indexed_rule, + this.conditionStack[this.conditionStack.length - 1] /* = YY_START */ + ); + + // otherwise, when the action codes are all simple return token + // statements: + // token = this.simpleCaseActionClusters[indexed_rule]; + + if (this.done && this._input) { + this.done = false; + } + + if (token) { + return token; + } else if (this._backtrack) { + // recover context + for (var k in backup) { + this[k] = backup[k]; + } + + this.__currentRuleSet__ = null; + return false; // rule action called reject() implying the next rule + // should be tested instead. + } else if (this._signaled_error_token) { + // produce one 'error' token as `.parseError()` in `reject()` + // did not guarantee a failure signal by throwing an exception! + token = this._signaled_error_token; + + this._signaled_error_token = false; + return token; + } + + return false; + }, + + /** + * return next match in input + * + * @public + * @this {RegExpLexer} + */ + next: function lexer_next() { + if (this.done) { + this.clear(); + return this.EOF; + } + + if (!this._input) { + this.done = true; + } + + var token, match, tempMatch, index; + + if (!this._more) { + this.clear(); + } + + var spec = this.__currentRuleSet__; + + if (!spec) { + // Update the ruleset cache as we apparently encountered a state + // change or just started lexing. The cache is set up for fast lookup + // -- we assume a lexer will switch states much less often than it + // will invoke the `lex()` token-producing API and related APIs, hence + // caching the set for direct access helps speed up those activities a + // tiny bit. + spec = this.__currentRuleSet__ = this._currentRules(); + + // Check whether a *sane* condition has been pushed before: this makes + // the lexer robust against user-programmer bugs such as + // https://github.com/zaach/jison-lex/issues/19 + if (!spec || !spec.rules) { + var linenoMsg = ''; + + if (this.options.trackPosition) { + linenoMsg = ' on line ' + (this.yylineno + 1); + } + + var p = this.constructLexErrorInfo( + 'Internal lexer engine error' + linenoMsg + + ': The lex grammar programmer pushed a non-existing ' + + 'condition name "' + this.topState() + + '"; this is a fatal error and should be reported to the ' + + 'application programmer team!', + false); + + // produce one 'error' token until this situation has been resolved, + // most probably by parse termination! + return this.parseError(p.errStr, p, this.JisonLexerError) || + this.ERROR; + } + } + + var ruleIds = spec.rules; + var regexes = spec.__ruleRegexes; + var len = spec.__rule_count; + + // Note: the arrays are 1-based, while `len` itself is a valid index, + // hence the non-standard less-or-equal check in the next loop + // condition! + for (var i = 1; i <= len; i++) { + tempMatch = this._input.match(regexes[i]); + + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + + if (this.options.backtrack_lexer) { + token = this.test_match(tempMatch, ruleIds[i]); + + if (token !== false) { + return token; + } else if (this._backtrack) { + match = undefined; + continue; // rule action called reject() implying a rule + // MISmatch. + } else { + // else: this is a lexer rule which consumes input without + // producing a token (e.g. whitespace) + return false; + } + } else if (!this.options.flex) { + break; + } + } + } + + if (match) { + token = this.test_match(match, ruleIds[index]); + + if (token !== false) { + return token; + } + + // else: this is a lexer rule which consumes input without producing a + // token (e.g. whitespace) + return false; + } + + if (!this._input) { + this.done = true; + this.clear(); + return this.EOF; + } else { + var linenoMsg = ''; + + if (this.options.trackPosition) { + linenoMsg = ' on line ' + (this.yylineno + 1); + } + + var p = this.constructLexErrorInfo( + 'Lexical error' + linenoMsg + ': Unrecognized text.', + this.options.lexerErrorsAreRecoverable); + + var pendingInput = this._input; + var activeCondition = this.topState(); + var conditionStackDepth = this.conditionStack.length; + token = + this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR; + + if (token === this.ERROR) { + // we can try to recover from a lexer error that `parseError()` did + // not 'recover' for us by moving forward at least one character at + // a time IFF the (user-specified?) `parseError()` has not + // consumed/modified any pending input or changed state in the error + // handler: + if (!this.matches && // and make sure the input has been + // modified/consumed ... + pendingInput === + this._input && // ...or the lexer state has been modified + // significantly enough + // to merit a non-consuming error handling action right now. + activeCondition === this.topState() && + conditionStackDepth === this.conditionStack.length) { + this.input(); + } + } + + return token; + } + }, + + /** + * return next match that has a token + * + * @public + * @this {RegExpLexer} + */ + lex: function lexer_lex() { + var r; + + // allow the PRE/POST handlers set/modify the return token for maximum + // flexibility of the generated lexer: + if (typeof this.pre_lex === 'function') { + r = this.pre_lex.call(this, 0); + } + + if (typeof this.options.pre_lex === 'function') { + // (also account for a userdef function which does not return any + // value: keep the token as is) + r = this.options.pre_lex.call(this, r) || r; + } + + if (this.yy && typeof this.yy.pre_lex === 'function') { + // (also account for a userdef function which does not return any + // value: keep the token as is) + r = this.yy.pre_lex.call(this, r) || r; + } + + while (!r) { + r = this.next(); + } + + if (this.yy && typeof this.yy.post_lex === 'function') { + // (also account for a userdef function which does not return any + // value: keep the token as is) + r = this.yy.post_lex.call(this, r) || r; + } + + if (typeof this.options.post_lex === 'function') { + // (also account for a userdef function which does not return any + // value: keep the token as is) + r = this.options.post_lex.call(this, r) || r; + } + + if (typeof this.post_lex === 'function') { + // (also account for a userdef function which does not return any + // value: keep the token as is) + r = this.post_lex.call(this, r) || r; + } + + return r; + }, + + /** + * return next match that has a token. Identical to the `lex()` API but + * does not invoke any of the `pre_lex()` nor any of the `post_lex()` + * callbacks. + * + * @public + * @this {RegExpLexer} + */ + fastLex: function lexer_fastLex() { + var r; + + while (!r) { + r = this.next(); + } + + return r; + }, + + /** + * return info about the lexer state that can help a parser or other lexer + * API user to use the most efficient means available. This API is + * provided to aid run-time performance for larger systems which employ + * this lexer. + * + * @public + * @this {RegExpLexer} + */ + canIUse: function lexer_canIUse() { + var rv = { + fastLex: !(typeof this.pre_lex === 'function' || + typeof this.options.pre_lex === 'function' || + this.yy && typeof this.yy.pre_lex === 'function' || + this.yy && typeof this.yy.post_lex === 'function' || + typeof this.options.post_lex === 'function' || + typeof this.post_lex === 'function') && + typeof this.fastLex === 'function' + }; + + return rv; + }, + + /** + * backwards compatible alias for `pushState()`; + * the latter is symmetrical with `popState()` and we advise to use + * those APIs in any modern lexer code, rather than `begin()`. + * + * @public + * @this {RegExpLexer} + */ + begin: function lexer_begin(condition) { + return this.pushState(condition); + }, + + /** + * activates a new lexer condition state (pushes the new lexer + * condition state onto the condition stack) + * + * @public + * @this {RegExpLexer} + */ + pushState: function lexer_pushState(condition) { + this.conditionStack.push(condition); + this.__currentRuleSet__ = null; + return this; + }, + + /** + * pop the previously active lexer condition state off the condition + * stack + * + * @public + * @this {RegExpLexer} + */ + popState: function lexer_popState() { + var n = this.conditionStack.length - 1; + + if (n > 0) { + this.__currentRuleSet__ = null; + return this.conditionStack.pop(); + } else { + return this.conditionStack[0]; + } + }, + + /** + * return the currently active lexer condition state; when an index + * argument is provided it produces the N-th previous condition state, + * if available + * + * @public + * @this {RegExpLexer} + */ + topState: function lexer_topState(n) { + n = this.conditionStack.length - 1 - Math.abs(n || 0); + + if (n >= 0) { + return this.conditionStack[n]; + } else { + return 'INITIAL'; + } + }, + + /** + * (internal) determine the lexer rule set which is active for the + * currently active lexer condition state + * + * @public + * @this {RegExpLexer} + */ + _currentRules: function lexer__currentRules() { + if (this.conditionStack.length && + this.conditionStack[this.conditionStack.length - 1]) { + return this + .conditions[this.conditionStack[this.conditionStack.length - 1]]; + } else { + return this.conditions['INITIAL']; + } + }, + + /** + * return the number of states currently on the stack + * + * @public + * @this {RegExpLexer} + */ + stateStackSize: function lexer_stateStackSize() { + return this.conditionStack.length; + }, + + options: {trackPosition: true, caseInsensitive: true}, + + JisonLexerError, + + performAction: function lexer__performAction(yy, yyrulenumber, YY_START) { + var yY = this; + var YYSTATE = YY_START; + + switch (yyrulenumber) { + case 21: + break; + + default: + return this.simpleCaseActionClusters[yyrulenumber]; + } + }, + + simpleCaseActionClusters: { + /*! Conditions:: INITIAL */ + /*! Rule:: [<][^\n]+ */ + 0: 10, + + /*! Conditions:: INITIAL */ + /*! Rule:: chrome[:][/][/][^\n]* */ + 1: 9, + + /*! Conditions:: INITIAL */ + /*! Rule:: "[^"]*" */ + 2: 18, + + /*! Conditions:: INITIAL */ + /*! Rule:: \n */ + 3: 4, + + /*! Conditions:: INITIAL */ + /*! Rule:: [0-9]+ */ + 4: 12, + + /*! Conditions:: INITIAL */ + /*! Rule:: [(] */ + 5: 11, + + /*! Conditions:: INITIAL */ + /*! Rule:: [)] */ + 6: 14, + + /*! Conditions:: INITIAL */ + /*! Rule:: [,] */ + 7: 13, + + /*! Conditions:: INITIAL */ + /*! Rule:: expect */ + 8: 8, + + /*! Conditions:: INITIAL */ + /*! Rule:: focus */ + 9: 15, + + /*! Conditions:: INITIAL */ + /*! Rule:: load[ ]page */ + 10: 3, + + /*! Conditions:: INITIAL */ + /*! Rule:: next */ + 11: 5, + + /*! Conditions:: INITIAL */ + /*! Rule:: on */ + 12: 16, + + /*! Conditions:: INITIAL */ + /*! Rule:: previous */ + 13: 6, + + /*! Conditions:: INITIAL */ + /*! Rule:: select */ + 14: 7, + + /*! Conditions:: INITIAL */ + /*! Rule:: button */ + 15: 17, + + /*! Conditions:: INITIAL */ + /*! Rule:: slider */ + 16: 17, + + /*! Conditions:: INITIAL */ + /*! Rule:: spinButton */ + 17: 17, + + /*! Conditions:: INITIAL */ + /*! Rule:: textField */ + 18: 17, + + /*! Conditions:: INITIAL */ + /*! Rule:: textFieldWithComboBox */ + 19: 17, + + /*! Conditions:: INITIAL */ + /*! Rule:: $ */ + 20: 1 + }, + + rules: [ + /* 0: */ /^(?:[<][^\n]+)/i, + /* 1: */ /^(?:chrome[:][/][/][^\n]*)/i, + /* 2: */ /^(?:"[^"]*")/i, + /* 3: */ /^(?:\n)/i, + /* 4: */ /^(?:\d+)/i, + /* 5: */ /^(?:[(])/i, + /* 6: */ /^(?:[)])/i, + /* 7: */ /^(?:[,])/i, + /* 8: */ /^(?:expect)/i, + /* 9: */ /^(?:focus)/i, + /* 10: */ /^(?:load[ ]page)/i, + /* 11: */ /^(?:next)/i, + /* 12: */ /^(?:on)/i, + /* 13: */ /^(?:previous)/i, + /* 14: */ /^(?:select)/i, + /* 15: */ /^(?:button)/i, + /* 16: */ /^(?:slider)/i, + /* 17: */ /^(?:spinButton)/i, + /* 18: */ /^(?:textField)/i, + /* 19: */ /^(?:textFieldWithComboBox)/i, + /* 20: */ /^(?:$)/i, + /* 21: */ /^(?:\s)/i + ], + + conditions: { + 'INITIAL': { + rules: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 + ], + + inclusive: true + } + } + }; + + return lexer; + }(); + parser.lexer = lexer; + + let page, point, objectToMatch; + + let indent = ''; + const increaseIndent = () => indent = indent + ' '; + const decreaseIndent = () => indent = indent.substring(2); + + let buffer = ''; + const addToBuffer = (text) => buffer += indent + text + '\n'; + const flushBuffer = () => { + const result = buffer; + buffer = ''; + return result; + }; + + function addAllStatements(statements) { + if (statements.find(statement => !statement.output)) { + throw new Error('Compiler error: statement not converted to Javascript'); + } + statements.forEach(statement => addToBuffer(statement.output)); + return flushBuffer(); + } + + // Initialize test before anything else. + const initTest = (page = `''`) => { + addToBuffer(`TEST_F('SwitchAccessSAATLiteTest', 'Demo', function() {`); + increaseIndent(); + addToBuffer( + `this.runWithLoadedTree(${page.output}, async (rootWebArea) => {`); + increaseIndent(); + addToBuffer('TestUtility.startFocusInside(rootWebArea);'); + return flushBuffer(); + }; + + const finishTest = (opt_url) => { + decreaseIndent(); + if (opt_url) { + addToBuffer(`}, {url: ${opt_url.output}});`); + } else { + addToBuffer(`});`); + } + decreaseIndent(); + addToBuffer(`});`); + + return flushBuffer(); + }; + + function Parser() { + this.yy = {}; + } + Parser.prototype = parser; + parser.Parser = Parser; + + return new Parser(); +})(); + + + +if (typeof require !== 'undefined' && typeof exports !== 'undefined') { + exports.parser = parser; + exports.Parser = parser.Parser; + exports.parse = function() { + return parser.parse.apply(parser, arguments); + }; +}
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/gen/saatlite_tests.js b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/gen/saatlite_tests.js new file mode 100644 index 0000000..efb57d4 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/gen/saatlite_tests.js
@@ -0,0 +1,27 @@ +// Copyright 2021 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. + +GEN_INCLUDE(['../../switch_access_e2e_test_base.js', '../../test_utility.js']); + +/** Test fixture for the SAATLite generated tests. */ +SwitchAccessSAATLiteTest = class extends SwitchAccessE2ETest { + /** @override */ + setUp() { + const runTest = this.deferRunTest(WhenTestDone.EXPECT); + (async () => { + await TestUtility.setup(); + runTest(); + })(); + } +}; + +TEST_F('SwitchAccessSAATLiteTest', 'Demo', function() { + this.runWithLoadedTree('<button>Hi</button>', async (rootWebArea) => { + TestUtility.startFocusInside(rootWebArea); + TestUtility.pressNextSwitch(); + TestUtility.pressPreviousSwitch(); + TestUtility.pressSelectSwitch(); + await TestUtility.expectFocusOn({role: 'button'}); + }); +});
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/tests/demo.saatl b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/tests/demo.saatl new file mode 100644 index 0000000..2d1945e --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/saatlite/tests/demo.saatl
@@ -0,0 +1,5 @@ +load page <button>Hi</button> +next +previous +select +expect focus on button
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js index 6287d69..b855f5b05 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js
@@ -233,7 +233,9 @@ /** @private */ dictationLocaleMenuSubtitle_: { type: String, - value: '', + computed: 'computeDictationLocaleSubtitle_(' + + 'dictationLocaleOptions_, ' + + 'prefs.settings.a11y.dictation_locale.value)', }, /** @private */ @@ -672,14 +674,15 @@ localeInfo.value === currentLocale, }; }); - this.updateDictationLocaleSubtitle_(); }, /** - * Updates the Dictation locale subtitle. + * Calculates the Dictation locale subtitle based on the current + * locale from prefs and the offline availability of that locale. + * @return {string} * @private */ - updateDictationLocaleSubtitle_() { + computeDictationLocaleSubtitle_() { const currentLocale = this.get('prefs.settings.a11y.dictation_locale.value'); const locale = this.dictationLocaleOptions_.find( @@ -687,7 +690,7 @@ if (!locale) { return ''; } - this.dictationLocaleMenuSubtitle_ = this.i18n( + return this.i18n( locale.offline ? 'dictationLocaleSubLabelOffline' : 'dictationLocaleSubLabelNetwork', locale.name); @@ -703,6 +706,5 @@ /** @private */ onChangeDictationLocalesDialogClosed_() { this.showDictationLocaleMenu_ = false; - this.updateDictationLocaleSubtitle_(); }, });
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.html b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.html index ccff110..e3d897b8 100644 --- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.html +++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.html
@@ -37,19 +37,30 @@ </div> <div class="device-lists-separator"></div> <div id="container"> - <!-- TODO(crbug.com/1010321): Populate with real data. --> - <div class="settings-box-text"> - $i18n{bluetoothDeviceListCurrentlyConnected} - </div> - <div class="device-list"> - <os-settings-paired-bluetooth-list> - </os-settings-paired-bluetooth-list> - </div> - <div class="settings-box-text"> - $i18n{bluetoothDeviceListPreviouslyConnected} - </div> - <div class="device-list"> - <os-settings-paired-bluetooth-list> - </os-settings-paired-bluetooth-list> - </div> + <template is="dom-if" + if="[[shouldShowDeviceList_(connectedDevices_, + connectedDevices_.length)]]" restamp> + <div class="settings-box-text"> + $i18n{bluetoothDeviceListCurrentlyConnected} + </div> + <div class="device-list"> + <os-settings-paired-bluetooth-list + id="connectedDeviceList" + devices="[[connectedDevices_]]"> + </os-settings-paired-bluetooth-list> + </div> + </template> + <template is="dom-if" + if="[[shouldShowDeviceList_(unconnectedDevices_, + unconnectedDevices_.length)]]" restamp> + <div class="settings-box-text"> + $i18n{bluetoothDeviceListPreviouslyConnected} + </div> + <div class="device-list"> + <os-settings-paired-bluetooth-list + id="unconnectedDeviceList" + devices="[[unconnectedDevices_]]"> + </os-settings-paired-bluetooth-list> + </div> + </template> </div> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.js b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.js index b30e191d..af61583 100644 --- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.js +++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_devices_subpage.js
@@ -55,6 +55,22 @@ type: Boolean, observer: 'onBluetoothToggleChanged_', }, + + /** + * @private {!Array<!chromeos.bluetoothConfig.mojom.PairedBluetoothDeviceProperties>} + */ + connectedDevices_: { + type: Array, + value: [], + }, + + /** + * @private {!Array<!chromeos.bluetoothConfig.mojom.PairedBluetoothDeviceProperties>} + */ + unconnectedDevices_: { + type: Array, + value: [], + } }; } @@ -67,6 +83,13 @@ mojom.BluetoothSystemState.kEnabled || this.systemProperties.systemState === mojom.BluetoothSystemState.kEnabling; + + this.connectedDevices_ = this.systemProperties.pairedDevices.filter( + device => device.deviceProperties.connectionState !== + mojom.DeviceConnectionState.kNotConnected); + this.unconnectedDevices_ = this.systemProperties.pairedDevices.filter( + device => device.deviceProperties.connectionState === + mojom.DeviceConnectionState.kNotConnected); } /** @private */ @@ -95,6 +118,16 @@ getOnOffString_(isBluetoothToggleOn, onString, offString) { return isBluetoothToggleOn ? onString : offString; } + + /** + * @param {!Array<!chromeos.bluetoothConfig.mojom.PairedBluetoothDeviceProperties>} + * devices + * @return boolean + * @private + */ + shouldShowDeviceList_(devices) { + return devices.length > 0; + } } customElements.define(
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_paired_bluetooth_list.js b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_paired_bluetooth_list.js index 3a1b55e..ee39097 100644 --- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_paired_bluetooth_list.js +++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_paired_bluetooth_list.js
@@ -36,8 +36,7 @@ static get properties() { return { /** - * TODO(crbug.com/1010321): Use actual Device objects. - * @private {Array<Object>} + * @private {!Array<!chromeos.bluetoothConfig.mojom.PairedBluetoothDeviceProperties>} */ devices: { type: Array,
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc b/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc index 4427a3f..9a2c663 100644 --- a/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc +++ b/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc
@@ -6,13 +6,13 @@ #include "base/check.h" #include "base/memory/singleton.h" -#include "chrome/browser/chromeos/service_sandbox_type.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h" #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h" #include "chrome/common/extensions/extension_constants.h" +#include "chromeos/services/tts/public/mojom/tts_service.mojom.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ui/android/multiwindow/BUILD.gn b/chrome/browser/ui/android/multiwindow/BUILD.gn index a3f8097b..2afd176 100644 --- a/chrome/browser/ui/android/multiwindow/BUILD.gn +++ b/chrome/browser/ui/android/multiwindow/BUILD.gn
@@ -36,6 +36,7 @@ android_resources("java_resources") { sources = [ "java/res/drawable/circle_green.xml", + "java/res/layout/instance_switcher_cmd_item.xml", "java/res/layout/instance_switcher_dialog.xml", "java/res/layout/instance_switcher_item.xml", "java/res/layout/instance_switcher_list.xml",
diff --git a/chrome/browser/ui/android/multiwindow/java/res/layout/instance_switcher_cmd_item.xml b/chrome/browser/ui/android/multiwindow/java/res/layout/instance_switcher_cmd_item.xml new file mode 100644 index 0000000..f0ea4407 --- /dev/null +++ b/chrome/browser/ui/android/multiwindow/java/res/layout/instance_switcher_cmd_item.xml
@@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright 2021 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/content" + style="@style/ListItemContainer" > + + <ImageView + android:id="@+id/favicon" + android:src="@drawable/ic_add" + android:layout_toEndOf="@id/current" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="48dp" + android:layout_marginEnd="8dp" + android:layout_marginVertical="8dp" + android:scaleType="fitCenter" + android:layout_gravity="center_vertical" + app:tint="@color/default_bg_color_blue" + android:importantForAccessibility="no" /> + + <FrameLayout + android:id="@+id/text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_toEndOf="@id/favicon" + android:layout_toStartOf="@id/end_button" + android:layout_alignParentEnd="true" + android:paddingEnd="@dimen/default_list_row_padding" + android:layout_gravity="center_vertical" > + + <TextView + android:id="@+id/command" + android:text="@string/menu_new_window" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:textAppearance="@style/TextAppearance.TextLarge.Primary" /> + <TextView + android:id="@+id/max_info" + android:text="@string/max_number_of_windows" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:textAppearance="@style/TextAppearance.TextMedium.Secondary" /> + </FrameLayout> +</RelativeLayout>
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java index eb90760..074898c9 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
@@ -37,6 +37,7 @@ /** * Coordinator to construct the instance switcher dialog. + * TODO: Resolve various inconsistencies that can be caused by Ui from multiple instances. */ public class InstanceSwitcherCoordinator { /** @@ -52,6 +53,7 @@ private final Context mContext; private final Callback<InstanceInfo> mOpenCallback; private final Callback<InstanceInfo> mCloseCallback; + private final Runnable mNewWindowAction; private final ModalDialogManager mModalDialogManager; private final ModelList mModelList = new ModelList(); @@ -62,6 +64,8 @@ private PropertyModel mConfirmDialog; private InstanceInfo mItemToDelete; private boolean mIsShowingConfirmationMessage; + private PropertyModel mNewWindowModel; + private boolean mNewWindowEnabled; /** * Show instance switcher modal dialog UI. @@ -70,24 +74,28 @@ * @param iconBridge An object that fetches favicons from local DB. * @param openCallback Callback to invoke to open a chosen instance. * @param closeCallback Callback to invoke to close a chosen instance. + * @param newWindowAction Runnable to invoke to open a new window. + * @param newWindowEnabled True if the "New window" command needs to be enabled. * @param instanceInfo List of {@link InstanceInfo} for available Chrome instances. */ public static void showDialog(Context context, ModalDialogManager modalDialogManager, LargeIconBridge iconBridge, Callback<InstanceInfo> openCallback, - Callback<InstanceInfo> closeCallback, List<InstanceInfo> instanceInfo) { - new InstanceSwitcherCoordinator( - context, modalDialogManager, iconBridge, openCallback, closeCallback) - .showDialog(instanceInfo); + Callback<InstanceInfo> closeCallback, Runnable newWindowAction, + boolean newWindowEnabled, List<InstanceInfo> instanceInfo) { + new InstanceSwitcherCoordinator(context, modalDialogManager, iconBridge, openCallback, + closeCallback, newWindowAction) + .showDialog(instanceInfo, newWindowEnabled); } private InstanceSwitcherCoordinator(Context context, ModalDialogManager modalDialogManager, LargeIconBridge iconBridge, Callback<InstanceInfo> openCallback, - Callback<InstanceInfo> closeCallback) { + Callback<InstanceInfo> closeCallback, Runnable newWindowAction) { mContext = context; mModalDialogManager = modalDialogManager; mOpenCallback = openCallback; mCloseCallback = closeCallback; mUiUtils = new UiUtils(mContext, iconBridge); + mNewWindowAction = newWindowAction; ModelListAdapter adapter = new ModelListAdapter(mModelList); // TODO: Extend modern_list_item_view.xml to replace instance_switcher_item.xml @@ -95,17 +103,24 @@ parentView -> LayoutInflater.from(mContext).inflate(R.layout.instance_switcher_item, null), InstanceSwitcherItemViewBinder::bind); + adapter.registerType(EntryType.COMMAND, + parentView + -> LayoutInflater.from(mContext).inflate(R.layout.instance_switcher_cmd_item, null), + InstanceSwitcherItemViewBinder::bind); mDialogView = LayoutInflater.from(context).inflate(R.layout.instance_switcher_dialog, null); ListView listView = (ListView) mDialogView.findViewById(R.id.list_view); listView.setAdapter(adapter); } - private void showDialog(List<InstanceInfo> items) { + private void showDialog(List<InstanceInfo> items, boolean newWindowEnabled) { for (int i = 0; i < items.size(); ++i) { PropertyModel itemModel = generateListItem(items.get(i)); mModelList.add(new ModelListAdapter.ListItem(EntryType.INSTANCE, itemModel)); } - // TODO: Add "+ New Window" menu item at the bottom of the list. + mNewWindowModel = new PropertyModel(InstanceSwitcherItemProperties.ALL_KEYS); + enableNewWindowCommand(newWindowEnabled); + mModelList.add(new ModelListAdapter.ListItem(EntryType.COMMAND, mNewWindowModel)); + mDialog = createDialog(mDialogView, mModelList, items); mModalDialogManager.showDialog(mDialog, ModalDialogType.APP); } @@ -165,6 +180,21 @@ return model; } + private void enableNewWindowCommand(boolean enabled) { + if (mNewWindowEnabled && enabled) return; + mNewWindowModel.set(InstanceSwitcherItemProperties.ENABLE_COMMAND, enabled); + if (enabled) { + mNewWindowModel.set( + InstanceSwitcherItemProperties.CLICK_LISTENER, this::newWindowAction); + } + mNewWindowEnabled = enabled; + } + + private void newWindowAction(View view) { + dismissDialog(DialogDismissalCause.ACTION_ON_CONTENT); + mNewWindowAction.run(); + } + private void buildMoreMenu(PropertyModel.Builder builder, InstanceInfo item) { ModelList moreMenu = new ModelList(); moreMenu.add(buildMenuListItem(R.string.instance_switcher_close_window, 0, 0)); @@ -209,6 +239,9 @@ } } mCloseCallback.onResult(item); + + // Removing an instance enables the new window item. + enableNewWindowCommand(true); } private void showConfirmationMessage(InstanceInfo item) {
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java index 2e27db8..a256ad43 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
@@ -71,9 +71,28 @@ Callback<InstanceInfo> openCallback = (item) -> itemClickCallbackHelper.notifyCalled(); TestThreadUtils.runOnUiThreadBlocking(() -> { InstanceSwitcherCoordinator.showDialog(getActivity(), mModalDialogManager, mIconBridge, - openCallback, null, Arrays.asList(instances)); + openCallback, null, null, false, Arrays.asList(instances)); }); onData(anything()).atPosition(1).perform(click()); itemClickCallbackHelper.waitForCallback(itemClickCount); } + + @Test + @SmallTest + public void testInstanceSwitcherCoordinator_newWindow() throws Exception { + InstanceInfo[] instances = new InstanceInfo[] { + new InstanceInfo(0, 57, InstanceInfo.Type.CURRENT, "url0", "title0", 1, 0, false), + new InstanceInfo(1, 58, InstanceInfo.Type.OTHER, "ur11", "title1", 2, 0, false), + new InstanceInfo(2, 59, InstanceInfo.Type.OTHER, "url2", "title2", 1, 1, false)}; + final CallbackHelper itemClickCallbackHelper = new CallbackHelper(); + final int itemClickCount = itemClickCallbackHelper.getCallCount(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + InstanceSwitcherCoordinator.showDialog(getActivity(), mModalDialogManager, mIconBridge, + null, null, itemClickCallbackHelper::notifyCalled, true, + Arrays.asList(instances)); + }); + // 0 ~ 2: instances. 3: 'new window' command. + onData(anything()).atPosition(3).perform(click()); + itemClickCallbackHelper.waitForCallback(itemClickCount); + } }
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemProperties.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemProperties.java index 798c97ff..4b6d2901 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemProperties.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemProperties.java
@@ -18,6 +18,9 @@ public static final PropertyModel.WritableBooleanPropertyKey CURRENT = new PropertyModel.WritableBooleanPropertyKey(); + public static final PropertyModel.WritableBooleanPropertyKey ENABLE_COMMAND = + new PropertyModel.WritableBooleanPropertyKey(); + public static final PropertyModel.WritableObjectPropertyKey<Drawable> FAVICON = new PropertyModel.WritableObjectPropertyKey<>(); @@ -38,5 +41,5 @@ new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyKey[] ALL_KEYS = new PropertyKey[] { - CURRENT, FAVICON, TITLE, DESC, INSTANCE_ID, CLICK_LISTENER, MORE_MENU}; + CURRENT, ENABLE_COMMAND, FAVICON, TITLE, DESC, INSTANCE_ID, CLICK_LISTENER, MORE_MENU}; }
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemViewBinder.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemViewBinder.java index 6d96d27..6ac8b62 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemViewBinder.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherItemViewBinder.java
@@ -20,12 +20,22 @@ .setImageDrawable(model.get(InstanceSwitcherItemProperties.FAVICON)); } else if (InstanceSwitcherItemProperties.TITLE == propertyKey) { - ((TextView) view.findViewById(R.id.title)) - .setText(model.get(InstanceSwitcherItemProperties.TITLE)); + TextView titleView = (TextView) view.findViewById(R.id.title); + String text = model.get(InstanceSwitcherItemProperties.TITLE); + if (text != null) { + titleView.setText(text); + } else { + titleView.setVisibility(View.GONE); + } } else if (InstanceSwitcherItemProperties.DESC == propertyKey) { - ((TextView) view.findViewById(R.id.desc)) - .setText(model.get(InstanceSwitcherItemProperties.DESC)); + TextView descView = (TextView) view.findViewById(R.id.desc); + String text = model.get(InstanceSwitcherItemProperties.DESC); + if (text != null) { + descView.setText(text); + } else { + descView.setVisibility(View.GONE); + } } else if (InstanceSwitcherItemProperties.CURRENT == propertyKey) { boolean current = model.get(InstanceSwitcherItemProperties.CURRENT); @@ -39,6 +49,15 @@ } else if (InstanceSwitcherItemProperties.MORE_MENU == propertyKey) { ListMenuButtonDelegate delegate = model.get(InstanceSwitcherItemProperties.MORE_MENU); ((ListMenuButton) view.findViewById(R.id.more)).setDelegate(delegate); + + } else if (InstanceSwitcherItemProperties.ENABLE_COMMAND == propertyKey) { + View command = view.findViewById(R.id.command); + View info = view.findViewById(R.id.max_info); + View favicon = view.findViewById(R.id.favicon); + boolean enabled = model.get(InstanceSwitcherItemProperties.ENABLE_COMMAND); + command.setVisibility(enabled ? View.VISIBLE : View.GONE); + favicon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); + info.setVisibility(enabled ? View.GONE : View.VISIBLE); } } }
diff --git a/chrome/browser/ui/ash/assistant/assistant_browser_delegate_impl.cc b/chrome/browser/ui/ash/assistant/assistant_browser_delegate_impl.cc index dc99c4e..f7785db 100644 --- a/chrome/browser/ui/ash/assistant/assistant_browser_delegate_impl.cc +++ b/chrome/browser/ui/ash/assistant/assistant_browser_delegate_impl.cc
@@ -12,7 +12,6 @@ #include "ash/public/cpp/network_config_service.h" #include "chrome/browser/ash/assistant/assistant_util.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/chromeos/service_sandbox_type.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/ash/assistant/assistant_context_util.h" @@ -21,6 +20,7 @@ #include "chrome/browser/ui/ash/assistant/conversation_starters_client_impl.h" #include "chrome/browser/ui/ash/assistant/device_actions_delegate_impl.h" #include "chromeos/services/assistant/public/cpp/features.h" +#include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h" #include "components/session_manager/core/session_manager.h" #include "content/public/browser/audio_service.h" #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/ui/ash/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/chrome_capture_mode_delegate.cc index c65eb290..58dc651 100644 --- a/chrome/browser/ui/ash/chrome_capture_mode_delegate.cc +++ b/chrome/browser/ui/ash/chrome_capture_mode_delegate.cc
@@ -14,7 +14,6 @@ #include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/ash/policy/dlp/dlp_content_manager.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/service_sandbox_type.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.h b/chrome/browser/ui/cocoa/history_menu_bridge.h index 1a81df9..9276d95 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge.h +++ b/chrome/browser/ui/cocoa/history_menu_bridge.h
@@ -116,14 +116,11 @@ enum Tags { kRecentlyClosedSeparator = 400, // Item before recently closed section. kRecentlyClosedTitle = 401, // Title of recently closed section. - kRecentlyClosed = 420, // Used for items in the recently closed section. - kVisitedSeparator = 440, // Separator before visited section. - kVisitedTitle = 441, // Title of the visited section. - kVisited = 460, // Used for all entries in the visited section. - kShowFullSeparator = 480, // Separator after the visited section. - kIncognitoDisclaimerSeparator = - 500, // Separator before Incognito disclaimer text. - kIncognitoDisclaimerLabel = 501 // Label for Incognito disclaimer text. + kRecentlyClosed = 420, // Used for items in the recently closed section. + kVisitedSeparator = 440, // Separator before visited section. + kVisitedTitle = 441, // Title of the visited section. + kVisited = 460, // Used for all entries in the visited section. + kShowFullSeparator = 480 // Separator after the visited section. }; explicit HistoryMenuBridge(Profile* profile);
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.mm b/chrome/browser/ui/cocoa/history_menu_bridge.mm index 26e3b23..ef6b867 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge.mm +++ b/chrome/browser/ui/cocoa/history_menu_bridge.mm
@@ -73,10 +73,6 @@ NSMenuItem* full_history_item = [HistoryMenu() itemWithTag:IDC_SHOW_HISTORY]; [full_history_item setImage:rb.GetNativeImageNamed(IDR_HISTORY_FAVICON).ToNSImage()]; - NSMenuItem* incognito_disclaimer_item = - [HistoryMenu() itemWithTag:kIncognitoDisclaimerLabel]; - [incognito_disclaimer_item - setImage:rb.GetNativeImageNamed(IDR_INFO_FAVICON).ToNSImage()]; // Set the visibility of menu items according to profile type. // "Recently Visited", "Recently Closed" and "Show Full History" sections @@ -577,8 +573,7 @@ bool HistoryMenuBridge::ShouldMenuItemBeVisible(NSMenuItem* item) { if (!base::FeatureList::IsEnabled( features::kUpdateHistoryEntryPointsInIncognito)) { - return [item tag] != kIncognitoDisclaimerLabel && - [item tag] != kIncognitoDisclaimerSeparator; + return true; } int tag = [item tag]; @@ -596,10 +591,6 @@ case kShowFullSeparator: case IDC_SHOW_HISTORY: return !profile_->IsOffTheRecord(); - // The incognito profile specific menu items - case kIncognitoDisclaimerSeparator: - case kIncognitoDisclaimerLabel: - return profile_->IsOffTheRecord(); } // When a new menu item is introduced, it should be added to one of the cases
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm index 008dd9a2..ea8b695 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm +++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -209,18 +209,6 @@ item.get().tag = regular_visible_items[i]; EXPECT_EQ(!is_incognito, test->ShouldMenuItemBeVisible(item)); } - - // Check visibilty of items belong to incognito mode. They should be visible - // for incognito mode, not for regular mode. - NSInteger incognito_visible_items[] = { - HistoryMenuBridge::kIncognitoDisclaimerSeparator, - HistoryMenuBridge::kIncognitoDisclaimerLabel}; - for (size_t i = 0; i < base::size(incognito_visible_items); i++) { - // Create a fake item with tag. - base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] init]); - item.get().tag = incognito_visible_items[i]; - EXPECT_EQ(is_incognito, test->ShouldMenuItemBeVisible(item)); - } } // Edge case test for clearing until the end of a menu.
diff --git a/chrome/browser/ui/cocoa/main_menu_builder.mm b/chrome/browser/ui/cocoa/main_menu_builder.mm index 7270fa1..ed29003a 100644 --- a/chrome/browser/ui/cocoa/main_menu_builder.mm +++ b/chrome/browser/ui/cocoa/main_menu_builder.mm
@@ -326,15 +326,6 @@ Item(IDS_HISTORY_SHOWFULLHISTORY_LINK) .command_id(IDC_SHOW_HISTORY) .remove_if(is_pwa), - Item() - .tag(HistoryMenuBridge::kIncognitoDisclaimerSeparator) - .is_separator() - .set_hidden(true) - .remove_if(is_pwa), - Item(IDS_HISTORY_INCOGNITO_DISCLAIMER_MAC) - .tag(HistoryMenuBridge::kIncognitoDisclaimerLabel) - .set_hidden(true) - .remove_if(is_pwa), }) .Build(); return item;
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc index 7d48a90..cab5773a 100644 --- a/chrome/browser/ui/tab_contents/core_tab_helper.cc +++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -98,6 +98,7 @@ } void CoreTabHelper::SearchWithLensInNewTab(gfx::Image image, + const gfx::Size& image_original_size, lens::EntryPoint entry_point) { Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); @@ -122,7 +123,7 @@ search_args.image_thumbnail_content.assign(image_bytes_begin, image_bytes_end); - search_args.image_original_size = image.Size(); + search_args.image_original_size = image_original_size; search_args.additional_query_params = lens::GetQueryParameterFromEntryPoint(entry_point);
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.h b/chrome/browser/ui/tab_contents/core_tab_helper.h index 64d53639..973dee97 100644 --- a/chrome/browser/ui/tab_contents/core_tab_helper.h +++ b/chrome/browser/ui/tab_contents/core_tab_helper.h
@@ -41,8 +41,11 @@ lens::EntryPoint entry_point); // Open the Lens experience for an image. Used for sending the bitmap selected - // via Lens Region Search. - void SearchWithLensInNewTab(gfx::Image image, lens::EntryPoint entry_point); + // via Lens Region Search. |image_original_size| is specified in case of + // resizing that happens prior to passing the image to CoreTabHelper. + void SearchWithLensInNewTab(gfx::Image image, + const gfx::Size& image_original_size, + lens::EntryPoint entry_point); // Perform an image search for the image that triggered the context menu. The // |src_url| is passed to the search request and is not used directly to fetch
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc index d3b85d6..e6cb0d9 100644 --- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc +++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
@@ -144,19 +144,17 @@ // The label of the overlay will now show the error in red. auto error_label = std::make_unique<views::Label>(error_message); - const SkColor warning_text_color = views::style::GetColor( - *error_label, ChromeTextContext::CONTEXT_DIALOG_BODY_TEXT_SMALL, - STYLE_RED); - error_label->SetEnabledColor(warning_text_color); + views::SetCascadingNativeThemeColor( + error_label.get(), views::kCascadingLabelEnabledColor, + ui::NativeTheme::kColorId_AlertSeverityHigh); error_label->SetMultiLine(true); // Replace the throbber with a warning icon. Since this is a permanent // error we do not intend to return to a previous state. - auto error_icon = std::make_unique<views::ImageView>(); - error_icon->SetImage(gfx::CreateVectorIcon( - kBrowserToolsErrorIcon, - GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_AlertSeverityHigh))); + auto error_icon = + std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon( + kBrowserToolsErrorIcon, + ui::NativeTheme::kColorId_AlertSeverityHigh)); layout->StartRow(1.0, 0); layout->AddView(std::move(error_icon));
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc index 120761c..3780c74 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc
@@ -16,7 +16,11 @@ #include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" #include "chrome/grit/generated_resources.h" #include "components/media_message_center/media_notification_item.h" +#include "components/media_router/browser/media_router_metrics.h" +#include "components/media_router/common/mojom/media_route_provider_id.mojom-shared.h" #include "components/media_router/common/mojom/media_router.mojom.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "media/audio/audio_device_description.h" #include "media/base/media_switches.h" #include "services/media_session/public/mojom/media_session.mojom.h" @@ -28,6 +32,8 @@ #include "ui/views/bubble/bubble_border.h" #include "ui/views/layout/box_layout.h" +using media_router::mojom::MediaRouteProviderId; + namespace { // Constants for the MediaNotificationDeviceSelectorView @@ -41,6 +47,39 @@ // devices. const int kAudioDevicesCountHistogramMax = 30; +media_router::MediaRouterDialogOpenOrigin ConvertToOrigin( + GlobalMediaControlsEntryPoint entry_point) { + switch (entry_point) { + case GlobalMediaControlsEntryPoint::kPresentation: + return media_router::MediaRouterDialogOpenOrigin::PAGE; + case GlobalMediaControlsEntryPoint::kSystemTray: + return media_router::MediaRouterDialogOpenOrigin::SYSTEM_TRAY; + case GlobalMediaControlsEntryPoint::kToolbarIcon: + return media_router::MediaRouterDialogOpenOrigin::TOOLBAR; + } +} + +void RecordCastDeviceCountMetrics(GlobalMediaControlsEntryPoint entry_point, + std::vector<CastDeviceEntryView*> entries) { + media_router::MediaRouterMetrics::RecordDeviceCount(entries.size()); + + std::map<MediaRouteProviderId, std::map<bool, int>> counts = { + {MediaRouteProviderId::CAST, {{true, 0}, {false, 0}}}, + {MediaRouteProviderId::DIAL, {{true, 0}, {false, 0}}}, + {MediaRouteProviderId::WIRED_DISPLAY, {{true, 0}, {false, 0}}}}; + for (const CastDeviceEntryView* entry : entries) { + counts.at(entry->sink().provider).at(entry->GetEnabled())++; + } + for (auto provider : {MediaRouteProviderId::CAST, MediaRouteProviderId::DIAL, + MediaRouteProviderId::WIRED_DISPLAY}) { + for (bool is_available : {true, false}) { + int count = counts.at(provider).at(is_available); + media_router::MediaRouterMetrics::RecordGmcDeviceCount( + ConvertToOrigin(entry_point), provider, is_available, count); + } + } +} + class ExpandDeviceSelectorButton : public IconLabelBubbleView { public: explicit ExpandDeviceSelectorButton(IconLabelBubbleView::Delegate* delegate); @@ -289,6 +328,7 @@ device_entry_views_container_->children().size(), kAudioDevicesCountHistogramMax); base::UmaHistogramBoolean(kDeviceSelectorOpenedHistogramName, true); + RecordCastDeviceCountAfterDelay(); have_devices_been_shown_ = true; } @@ -515,6 +555,26 @@ action); } +void MediaNotificationDeviceSelectorView::RecordCastDeviceCountAfterDelay() { + content::GetUIThreadTaskRunner({})->PostDelayedTask( + FROM_HERE, + base::BindOnce( + &MediaNotificationDeviceSelectorView::RecordCastDeviceCount, + weak_ptr_factory_.GetWeakPtr()), + media_router::MediaRouterMetrics::kDeviceCountMetricDelay); +} + +void MediaNotificationDeviceSelectorView::RecordCastDeviceCount() { + std::vector<CastDeviceEntryView*> entries; + for (views::View* view : device_entry_views_container_->children()) { + DeviceEntryUI* entry = GetDeviceEntryUI(view); + if (entry->GetType() == DeviceEntryUIType::kCast) { + entries.push_back(static_cast<CastDeviceEntryView*>(entry)); + } + } + RecordCastDeviceCountMetrics(entry_point_, entries); +} + void MediaNotificationDeviceSelectorView::RegisterAudioDeviceCallbacks() { // Get a list of the connected audio output devices. audio_device_subscription_ =
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.h b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.h index fb2bfd0..80d27d7c 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.h
@@ -19,6 +19,8 @@ class ExpandDeviceSelectorButton; const char kAudioDevicesCountHistogramName[] = "Media.GlobalMediaControls.NumberOfAvailableAudioDevices"; +const char kCastDeviceCountHistogramName[] = + "Media.GlobalMediaControls.CastDeviceCount"; const char kDeviceSelectorAvailableHistogramName[] = "Media.GlobalMediaControls.DeviceSelectorAvailable"; const char kDeviceSelectorOpenedHistogramName[] = @@ -115,6 +117,8 @@ void DoStartCastSession(const media_router::UIMediaSink& sink); void RecordStartCastingMetrics(); void RecordStopCastingMetrics(); + void RecordCastDeviceCountAfterDelay(); + void RecordCastDeviceCount(); DeviceEntryUI* GetDeviceEntryUI(views::View* view) const; void RegisterAudioDeviceCallbacks();
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc b/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc index 197d9902..ebd2727 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc
@@ -6,12 +6,16 @@ #include "base/metrics/histogram_macros.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/media_router/ui_media_sink.h" #include "chrome/common/pref_names.h" +#include "components/media_router/common/mojom/media_route_provider_id.mojom-shared.h" #include "components/media_router/common/pref_names.h" #include "components/prefs/pref_service.h" namespace media_router { +using mojom::MediaRouteProviderId; + namespace { DialogActivationLocationAndCastMode GetActivationLocationAndCastMode( @@ -91,6 +95,7 @@ // |OVERFLOW_MENU| refers to extension icons hidden in the app menu. That // mode is no longer available for the Cast toolbar icon. case MediaRouterDialogOpenOrigin::OVERFLOW_MENU: + case MediaRouterDialogOpenOrigin::SYSTEM_TRAY: case MediaRouterDialogOpenOrigin::TOTAL_COUNT: break; } @@ -164,8 +169,26 @@ MaybeRecordFirstAction(MediaRouterUserAction::CLOSE); } -void CastDialogMetrics::OnRecordSinkCount(int sink_count) { - media_router::MediaRouterMetrics::RecordDeviceCount(sink_count); +void CastDialogMetrics::OnRecordSinkCount( + std::vector<const UIMediaSink*> sinks) { + media_router::MediaRouterMetrics::RecordDeviceCount(sinks.size()); + + std::map<MediaRouteProviderId, std::map<bool, int>> counts = { + {MediaRouteProviderId::CAST, {{true, 0}, {false, 0}}}, + {MediaRouteProviderId::DIAL, {{true, 0}, {false, 0}}}, + {MediaRouteProviderId::WIRED_DISPLAY, {{true, 0}, {false, 0}}}}; + for (const UIMediaSink* sink : sinks) { + counts.at(sink->provider) + .at(sink->state != UIMediaSinkState::UNAVAILABLE)++; + } + for (auto provider : {MediaRouteProviderId::CAST, MediaRouteProviderId::DIAL, + MediaRouteProviderId::WIRED_DISPLAY}) { + for (bool is_available : {true, false}) { + int count = counts.at(provider).at(is_available); + media_router::MediaRouterMetrics::RecordCastDialogDeviceCount( + activation_location_, provider, is_available, count); + } + } } void CastDialogMetrics::MaybeRecordFirstAction(MediaRouterUserAction action) {
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics.h b/chrome/browser/ui/views/media_router/cast_dialog_metrics.h index 7b71653..db12b5c 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics.h +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "chrome/browser/ui/media_router/media_cast_mode.h" +#include "chrome/browser/ui/media_router/ui_media_sink.h" #include "components/media_router/browser/media_router_metrics.h" class Profile; @@ -52,7 +53,7 @@ void OnCloseDialog(const base::Time& close_time); // Records the number of sinks, which may be 0. - void OnRecordSinkCount(int sink_count); + void OnRecordSinkCount(std::vector<const UIMediaSink*> sinks); private: // Records the first user action if it hasn't already been recorded.
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc b/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc index 0efacc7..76751c2 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc
@@ -6,8 +6,10 @@ #include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" +#include "chrome/browser/ui/media_router/ui_media_sink.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" +#include "components/media_router/common/mojom/media_route_provider_id.mojom-shared.h" #include "components/media_router/common/pref_names.h" #include "components/prefs/pref_service.h" #include "content/public/test/browser_task_environment.h" @@ -82,10 +84,13 @@ } TEST_F(CastDialogMetricsTest, OnRecordSinkCount) { - constexpr int kSinkCount = 3; - metrics_.OnRecordSinkCount(kSinkCount); + UIMediaSink sink1{mojom::MediaRouteProviderId::CAST}; + UIMediaSink sink2{mojom::MediaRouteProviderId::CAST}; + UIMediaSink sink3{mojom::MediaRouteProviderId::DIAL}; + std::vector<const UIMediaSink*> sinks{&sink1, &sink2, &sink3}; + metrics_.OnRecordSinkCount(sinks); tester_.ExpectUniqueSample(MediaRouterMetrics::kHistogramUiDeviceCount, - kSinkCount, 1); + sinks.size(), 1); } TEST_F(CastDialogMetricsTest, RecordFirstAction) {
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_view.cc index 13a5a9ea..6605453 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_view.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
@@ -441,11 +441,15 @@ FROM_HERE, base::BindOnce(&CastDialogView::RecordSinkCount, weak_factory_.GetWeakPtr()), - base::TimeDelta::FromSeconds(3)); + MediaRouterMetrics::kDeviceCountMetricDelay); } void CastDialogView::RecordSinkCount() { - metrics_.OnRecordSinkCount(sink_buttons_.size()); + std::vector<const UIMediaSink*> sinks; + for (CastDialogSinkButton* sink_button : sink_buttons_) { + sinks.push_back(&sink_button->sink()); + } + metrics_.OnRecordSinkCount(sinks); } void CastDialogView::OnFilePickerClosed(const ui::SelectedFileInfo* file_info) {
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc index cf6b517..defd4ccc 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc +++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -25,6 +25,7 @@ #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/border.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" +#include "ui/views/cascading_property.h" #include "ui/views/controls/button/button_controller.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/style/platform_style.h" @@ -228,11 +229,8 @@ if (!GetWidget()) return; - const ui::NativeTheme* theme = GetNativeTheme(); const SkColor icon_color = - active_ ? theme->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor) - : icon_color_; + active_ ? views::GetCascadingAccentColor(this) : icon_color_; const int icon_size = delegate_->GetPageActionIconSize(); const gfx::ImageSkia image = gfx::CreateVectorIconWithBadge( GetVectorIcon(), icon_size, icon_color, GetVectorIconBadge());
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc index 2b651379..ee5f0dd6 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc
@@ -36,9 +36,11 @@ #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/label.h" #include "ui/views/event_monitor.h" -#include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/flex_layout.h" +#include "ui/views/layout/flex_layout_types.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/layout/layout_types.h" #include "ui/views/style/platform_style.h" #include "ui/views/style/typography.h" #include "ui/views/view_class_properties.h" @@ -218,29 +220,15 @@ ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_BACKGROUND); const SkColor text_color = theme_provider->GetColor( ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_TEXT); - const int text_vertical_spacing = layout_provider->GetDistanceMetric( - views::DISTANCE_RELATED_CONTROL_VERTICAL); - const int button_vertical_spacing = layout_provider->GetDistanceMetric( - views::DISTANCE_UNRELATED_CONTROL_VERTICAL); - auto box_layout = std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, kBubbleContentsInsets, - text_vertical_spacing); - box_layout->set_main_axis_alignment( - views::BoxLayout::MainAxisAlignment::kCenter); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CrossAxisAlignment::kStretch); - SetLayoutManager(std::move(box_layout)); + // Add child views. + // Add progress indicator. + views::View* progress_indicator_container = nullptr; if (params.tutorial_progress_current) { DCHECK(params.tutorial_progress_max); - views::View* progress_indicator_container = + progress_indicator_container = AddChildView(std::make_unique<views::View>()); - views::BoxLayout* const box_layout = - progress_indicator_container->SetLayoutManager( - std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal)); - box_layout->set_between_child_spacing(text_vertical_spacing); // TODO(crbug.com/1197208): surface progress information in a11y tree @@ -254,8 +242,10 @@ } } + // Add title label. + views::Label* title_label = nullptr; if (params.title_text.has_value()) { - auto* title_label = AddChildView(std::make_unique<views::Label>( + title_label = AddChildView(std::make_unique<views::Label>( std::move(*params.title_text), ChromeTextContext::CONTEXT_IPH_BUBBLE_TITLE)); title_label->SetBackgroundColor(background_color); @@ -266,6 +256,7 @@ title_label->SetMultiLine(true); } + // Add body label. auto* body_label = AddChildView( std::make_unique<views::Label>(body_text, CONTEXT_IPH_BUBBLE_BODY)); body_label->SetBackgroundColor(background_color); @@ -273,17 +264,10 @@ body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); body_label->SetMultiLine(true); + // Add buttons. + views::View* button_container = nullptr; if (!params.buttons.empty()) { - auto* button_container = AddChildView(std::make_unique<views::View>()); - auto* button_layout = - button_container->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal)); - - button_layout->set_main_axis_alignment( - views::BoxLayout::MainAxisAlignment::kEnd); - button_container->SetProperty( - views::kMarginsKey, gfx::Insets(button_vertical_spacing, 0, 0, 0)); - + button_container = AddChildView(std::make_unique<views::View>()); auto close_bubble_and_run_callback = [](FeaturePromoBubbleView* view, base::RepeatingClosure callback, const ui::Event& event) { @@ -291,10 +275,6 @@ callback.Run(); }; - const int button_spacing = layout_provider->GetDistanceMetric( - views::DISTANCE_RELATED_BUTTON_HORIZONTAL); - - bool is_first_button = true; for (ButtonParams& button_params : params.buttons) { MdIPHBubbleButton* const button = button_container->AddChildView(std::make_unique<MdIPHBubbleButton>( @@ -303,18 +283,72 @@ std::move(button_params.callback)), std::move(button_params.text), button_params.has_border)); buttons_.push_back(button); - button->SetMinSize(gfx::Size(0, 0)); button->SetCustomPadding(kBubbleButtonPadding); - - if (!is_first_button) { - button->SetProperty(views::kMarginsKey, - gfx::Insets(0, button_spacing, 0, 0)); - } - is_first_button = false; } } + // Set up layouts. This is the default vertical spacing that is also used to + // separate progress indicators for symmetry. + // TODO(dfried): consider whether we could take font ascender and descender + // height and factor them into margin calculations. + const int default_spacing = layout_provider->GetDistanceMetric( + views::DISTANCE_RELATED_CONTROL_VERTICAL); + + // Create primary layout (vertical). + SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kVertical) + .SetMainAxisAlignment(views::LayoutAlignment::kCenter) + .SetInteriorMargin(kBubbleContentsInsets) + .SetCollapseMargins(true) + .SetDefault(views::kMarginsKey, gfx::Insets(0, 0, default_spacing, 0)) + .SetIgnoreDefaultMainAxisMargins(true); + + // Set up progress container layout. + if (progress_indicator_container) { + progress_indicator_container + ->SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kHorizontal) + .SetDefault(views::kMarginsKey, gfx::Insets(0, default_spacing, 0, 0)) + .SetIgnoreDefaultMainAxisMargins(true); + } + + // Set label flex properties. This ensures that if the width of the bubble + // maxes out the text will shrink on the cross-axis and grow to multiple + // lines without getting cut off. + const views::FlexSpecification text_flex( + views::LayoutOrientation::kVertical, + views::MinimumFlexSizeRule::kPreferred, + views::MaximumFlexSizeRule::kPreferred, + /* adjust_height_for_width = */ true, + views::MinimumFlexSizeRule::kScaleToMinimum); + body_label->SetProperty(views::kFlexBehaviorKey, text_flex); + if (title_label) + title_label->SetProperty(views::kFlexBehaviorKey, text_flex); + + // Set up button container layout. + if (button_container) { + // Add in the default spacing between bubble content and bottom/buttons. + button_container->SetProperty( + views::kMarginsKey, + gfx::Insets(layout_provider->GetDistanceMetric( + views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL), + 0, 0, 0)); + + // Create button container internal layout. + button_container->SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kHorizontal) + .SetMainAxisAlignment(views::LayoutAlignment::kEnd) + .SetDefault(views::kMarginsKey, + gfx::Insets(0, + layout_provider->GetDistanceMetric( + views::DISTANCE_RELATED_BUTTON_HORIZONTAL), + 0, 0)) + .SetIgnoreDefaultMainAxisMargins(true); + } + + // Set up the bubble itself. + set_close_on_deactivate(!params.persist_on_blur); set_margins(gfx::Insets()); @@ -404,7 +438,8 @@ GetHeightForWidth(preferred_width_.value())); } - gfx::Size layout_manager_preferred_size = View::CalculatePreferredSize(); + const gfx::Size layout_manager_preferred_size = + View::CalculatePreferredSize(); // Wrap if the width is larger than |kBubbleMaxWidthDip|. if (layout_manager_preferred_size.width() > kBubbleMaxWidthDip) {
diff --git a/chrome/browser/ui/views/web_apps/README.md b/chrome/browser/ui/views/web_apps/README.md index c5cbae5..976424d 100644 --- a/chrome/browser/ui/views/web_apps/README.md +++ b/chrome/browser/ui/views/web_apps/README.md
@@ -1,56 +1,67 @@ # dPWA Integration Tests The dPWA integration tests use a special framework. Each test is defined by a -series of "testing actions", and test cases are read from a csv file. - -## Future work - -* Integrate with the tests generated by the integration testing script. (https://crbug.com/1215791) - * Create methods that match how the generated script tests use. - * Abandon the CSV file. - * Remove #if guards to have the generated tests compile & run. -* Update documentation to cover the new way tests are disabled & delete the TestExpectations file. +series of "testing actions", and test cases programmatically generated by a +python script. The script will only yield tests for which every "action" is +currently supported by the testing framework. ## Background See this [design doc](https://docs.google.com/document/d/e/2PACX-1vTFI0sXhZMvvg1B3sctYVUe64WbLVNzuXFUa6f3XyYTzKs2JnuFR8qKNyXYZsxE-rPPvsq__4ZCyrcS/pub) for background information, and the testing script [README](../../../../test/webapps/README.md) for how integration tests are generated. -### Identifying and Diagnosing Failed Tests +## Future work -Every test will log a message that will give: +* Fix how sync tests await web app quiescense. Currently, there is no waiting, + and tests will fail. - * the failing test case - * the line to add to the TestExpectations file to disable the test - * the command line argument to specify to run the given test locally +## Disabling a Test -In addition to this, every testing action will be printed to console before it -is executed, giving insight into where test failures are occurring. +Tests can be disabled in the same manner that other integration/browser tests +are disabled, using macros. See [On disabling +tests](https://chromium.googlesource.com/chromium/src/+/main/docs/testing/on_disabling_tests.md) +for more information. -### Test Input Files +## How to Contribute -Test files live in //chrome/test/data/web_apps/: - * web_app_integration_browsertest_cases.csv - * web_app_integration_browsertest_cases_sync.csv - * TestExpectations +### Adding a Testing Action -### Disabling a Test +Adding support for a new testing action in the framework is as simple as adding +a new method in `WebAppIntegrationBrowserTestBase`. In some cases, you may want +to implement actions related to profile sync, and need to call into SyncTest +helper methods. In this case, the meat of the action can be implemented in +`TwoClientWebAppsIntegrationSyncTest`. From there, you implement a method of the +same name in the base class, and have it call your sync action on the +`TestDelegate` member (ie `delegate_->SwitchProfileClients()`). -To disable a failing / crashing test, add an entry to the TestExpectations -file mentioned above. The format is as follows: -``` -crbug.com/id [ Platform ] [ Expectation ] list,of,actions,in,test -``` +The list of testing actions are maintained in +`chrome/test/webapps/data/framework_supported_actions.csv`. To add a new testing +action, add the action into that csv. Use the emojis to indicate which platforms +the action is supported on (at the time of your CL landing, rather than in the +future). -The list of supported platforms and expectations is maintained in the -TestExpectations file. This test suite requires adding an entry -per-platform that the test should be disabled on. Please create a bug for each -test case added to this file. +### Managing State + +After every state-change action, a state snapshot is constructed and stored as a +member of WebAppIntegrationBrowserTestBase, `after_state_change_action_state_`. +This is done in `ConstructStateSnapshot()`, called from +`AfterStateChangeAction()`. At the start of every state-change action, this +state snapshot gets moved into the `before_state_change_action_state_` member, +giving us the ability to compare the pre- and post-conditions of every +state-change action. + +When adding actions, it may be useful to bolt onto this state snapshot in order +to verify the results of state-change actions within state-check actions. To do +this, simply add onto the relevant state objects, and update the objects `==` +operator. Then, you need to make sure that your new state fields are updated in +`ConstructStateSnapshot()`. ## How It Works -This testing framework uses a script to generate a minimal set of -test cases that produce the maximum amount of code coverage, and reading in that -script output in these test implementations. +This testing framework uses a [script](../../../../test/webapps/README.md) to +generate a minimal set of test cases that produce the maximum amount of code +coverage. The script will output in stdout tests cases to add and remove, and +the developer then performs the instructed changes to make the testing +implementation up-to-date. This suite of tests has two main parts: @@ -62,20 +73,13 @@ ### Script See the [README](../../../../test/webapps/README.md) and [design doc](https://docs.google.com/document/d/e/2PACX-1vTFI0sXhZMvvg1B3sctYVUe64WbLVNzuXFUa6f3XyYTzKs2JnuFR8qKNyXYZsxE-rPPvsq__4ZCyrcS/pub). -### Test implementation +### Test Structure The high level flow of execution is as follows: - * Read the input file which contains the test cases - * Parse the test cases into an `std::vector<std::vector<std::string>>` - * Pass the vector of test cases to a parameterized test using - `testing::ValuesIn()`, which will run a test for each line in the input - file - * Each test will loop over the testing actions, calling - `ExecuteAction(action_string)` - * `ExecuteAction()` will switch on the string, and call the appropriate - action implementation method - * A state snapshot will be captured after non-inspection (state mutating) - actions (so inspection actions can assert various state changes) - + * Each tests lives as a regular browsertest with a specific name so the script + can determine if it exists. + * The script outputs a test where actions are method calls, and before & after + each test there is Pre and Post action method to call allow the framework to + record state, clean up, or wait as necessary. ## Components [Design @@ -84,11 +88,9 @@ ### WebAppIntegrationBrowserTestBase A helper class containing most of the test implementation, meant to be used as a private member on the test-driving classes. Contains most of the test -implementation: - * Input file parser - * ExecuteAction() - * Most action implementation methods - * Capturing state snapshots +framework implementation: + * Most action implementation methods. + * Capturing state snapshots. ### WebAppIntegrationBrowserTestBase::TestDelegate An abstract class that’s an application of the delegate interface pattern. @@ -100,14 +102,13 @@ in `TwoClientWebAppsSyncTest`, but called from the base class. ### WebAppIntegrationBrowserTest -Subclass of both `InProcessBrowserTest` and -`WebAppIntegrationBrowserTestBase::TestDelegate`. Drives the test by -calling `IN_PROC_BROWSER_TEST_P` and instantiating the parameterized -test as described above. Responsible for telling the base class where the test -input files live, handling test setup, and implementing `TestDelegate` methods -to expose protected members of `InProcessBrowserTest` to the base class. This -class owns the base class, and stores it as a private member, `helper_`, passing -it an instance of itself (as the TestDelegate) on construction. +Class that drives the tests. Subclass of both `InProcessBrowserTest` and +`WebAppIntegrationBrowserTestBase::TestDelegate`. Responsible +for telling the base class where the test input files live, handling test setup, +and implementing `TestDelegate` methods to expose protected members of +`InProcessBrowserTest` to the base class. This class owns the base class, and +stores it as a private member, `helper_`, passing it an instance of itself (as +the TestDelegate) on construction. ### TwoClientWebAppsSyncTest
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 199f1f4..9847454 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -1193,6 +1193,29 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +// Ensure that web app windows don't duplicate the app name in the title, when +// the page's title already starts with the app name. +IN_PROC_BROWSER_TEST_P(WebAppBrowserTest_PrefixInTitle, PrefixExistsInTitle) { + const GURL app_url = + https_server()->GetURL("app.com", "/web_apps/title_appname_prefix.html"); + const std::u16string app_title = u"A Web App"; + + auto web_app_info = std::make_unique<WebApplicationInfo>(); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->title = app_title; + const AppId app_id = InstallWebApp(std::move(web_app_info)); + + Browser* const app_browser = LaunchWebAppBrowser(app_id); + content::WebContents* const web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + + // The window title should not repeat "A Web App". + EXPECT_EQ(u"A Web App - funny cat video", + app_browser->GetWindowTitleForCurrentTab(false)); +} + // Ensure that web app windows with blank titles don't display the URL as a // default window title. IN_PROC_BROWSER_TEST_P(WebAppBrowserTest_PrefixInTitle,
diff --git a/chrome/common/media/cdm_registration.cc b/chrome/common/media/cdm_registration.cc index 421d7d8..28107be 100644 --- a/chrome/common/media/cdm_registration.cc +++ b/chrome/common/media/cdm_registration.cc
@@ -235,6 +235,12 @@ void AddHardwareSecureWidevine(std::vector<content::CdmInfo>* cdms) { #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia)) { + return; + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) media::CdmCapability capability; // The following audio formats are supported for decrypt-only. @@ -249,7 +255,15 @@ capability.video_codecs.emplace(media::VideoCodec::kCodecH264, kAllProfiles); #endif #if BUILDFLAG(ENABLE_PLATFORM_HEVC) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosEnablePlatformHevc)) { + capability.video_codecs.emplace(media::VideoCodec::kCodecHEVC, + kAllProfiles); + } +#else capability.video_codecs.emplace(media::VideoCodec::kCodecHEVC, kAllProfiles); +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) #endif // Both encryption schemes are supported on ChromeOS.
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc index f0e1a2d..56364b0 100644 --- a/chrome/renderer/media/chrome_key_systems.cc +++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/command_line.h" #include "base/containers/contains.h" #include "base/containers/flat_set.h" #include "base/logging.h" @@ -172,6 +173,13 @@ #if BUILDFLAG(ENABLE_PLATFORM_HEVC) SupportedCodecs GetHevcCodecs( const std::vector<media::VideoCodecProfile>& profiles) { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosEnablePlatformHevc)) { + return media::EME_CODEC_NONE; + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + // If no profiles are specified, then all are supported. if (profiles.empty()) { return media::EME_CODEC_HEVC_PROFILE_MAIN |
diff --git a/chrome/services/sharing/nearby/nearby_connections.cc b/chrome/services/sharing/nearby/nearby_connections.cc index 1677aa8..4a901b62 100644 --- a/chrome/services/sharing/nearby/nearby_connections.cc +++ b/chrome/services/sharing/nearby/nearby_connections.cc
@@ -564,7 +564,8 @@ if (!remote) return; - DCHECK_GE(info.total_bytes, 0); + // TODO(crbug.com/1237525): Investigate if OnPayloadTransferUpdate() + // should not be called if |info.total_bytes| is negative. DCHECK_GE(info.bytes_transferred, 0); remote->OnPayloadTransferUpdate( endpoint_id,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 99cfd40..d3e9a6a8 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -7576,6 +7576,13 @@ "../browser/ui/webui/management/management_ui_handler_unittest.cc", ] } + + if (is_win || is_linux || is_chromeos) { + sources += [ + "../browser/lens/region_search/lens_region_search_controller_unittest.cc", + ] + deps += [ "//chrome/browser/lens/region_search" ] + } } static_library("test_support_unit") {
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/initial_focus.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/initial_focus.js index 02e34b8..13ac37f9 100644 --- a/chrome/test/data/extensions/api_test/automation/tests/desktop/initial_focus.js +++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/initial_focus.js
@@ -10,7 +10,12 @@ rootNode.addEventListener('focus', function(event) { if (event.target.root.url == url) { chrome.automation.getFocus(function(focus) { - assertEq('textField', focus.role); + if (focus.role !== 'textField') { + // If the page is particularly slow in loading, the root may have + // focus first. Wait for subsequent focus events. + return; + } + assertEq('abc', focus.name); chrome.test.succeed(); });
diff --git a/chrome/test/data/web_apps/TestExpectations b/chrome/test/data/web_apps/TestExpectations deleted file mode 100644 index 6c52bbc..0000000 --- a/chrome/test/data/web_apps/TestExpectations +++ /dev/null
@@ -1,8 +0,0 @@ -# Format: -# crbug.com/bug_id [Platform] [Expectation] test_case -# -# Supported Platforms: ChromeOS, Linux, Mac, Win -# Supported Expectations: Skip - -# Add support for |uninstall_from_menu| on CrOS -crbug.com/1159651 [ ChromeOS ] [ Skip ] navigate_installable, install_omnibox_or_menu, launch_internal, uninstall_from_menu, navigate_browser_in_scope, check_install_icon_shown,check_launch_icon_not_shown,
diff --git a/chrome/test/data/web_apps/title_appname_prefix.html b/chrome/test/data/web_apps/title_appname_prefix.html new file mode 100644 index 0000000..7c72118 --- /dev/null +++ b/chrome/test/data/web_apps/title_appname_prefix.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> + <title>A Web App - funny cat video</title> +</head> +<body> + <h1>Content</h1> +</body> +</html>
diff --git a/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv b/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv deleted file mode 100644 index f7927945..0000000 --- a/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv +++ /dev/null
@@ -1,52 +0,0 @@ -add_policy_app_internal_tabbed_site_a, check_manifest_display_mode_browser_internal, -add_policy_app_internal_tabbed_site_a, list_apps_internal -add_policy_app_internal_tabbed_site_a, navigate_browser_in_scope_site_a, check_launch_icon_not_shown, check_install_icon_shown -add_policy_app_internal_tabbed_site_a, uninstall_policy_app, list_apps_internal, check_app_not_in_list_site_a, -add_policy_app_internal_windowed_site_a, check_manifest_display_mode_standalone_internal, -navigate_installable_site_a, check_install_icon_shown, check_launch_icon_not_shown, -navigate_installable_site_a, check_install_icon_shown, install_omnibox, check_window_created, launch_internal_site_a, close_pwa, check_no_crash, -navigate_installable_site_a, check_installable, install_omnibox, navigate_browser_in_scope_site_a, check_launch_icon_shown, check_install_icon_not_shown, -navigate_installable_site_a, install_create_shortcut_tabbed, list_apps_internal, set_open_in_window_internal_site_a, launch_internal_site_a, check_window_created, navigate_browser_in_scope_site_a, check_launch_icon_shown -navigate_installable_site_a, install_create_shortcut_tabbed, list_apps_internal, set_open_in_window_internal_site_a, list_apps_internal -navigate_installable_site_a, install_create_shortcut_tabbed, list_apps_internal, set_open_in_window_internal_site_a, navigate_browser_in_scope_site_a, check_launch_icon_shown -navigate_installable_site_a, install_create_shortcut_tabbed, set_open_in_window_internal_site_a, launch_internal_site_a, check_window_created, -navigate_installable_site_a, install_create_shortcut_tabbed, set_open_in_window_internal_site_a, launch_internal_site_a, check_window_created, navigate_browser_in_scope_site_a, check_launch_icon_shown -navigate_installable_site_a, install_create_shortcut_tabbed, set_open_in_window_internal_site_a, list_apps_internal -navigate_installable_site_a, install_create_shortcut_tabbed, set_open_in_window_internal_site_a, navigate_browser_in_scope_site_a, check_launch_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, launch_internal_site_a, check_window_created, navigate_browser_in_scope_site_a, check_install_icon_not_shown, check_launch_icon_shown, close_pwa, check_no_crash -navigate_installable_site_a, install_internal_windowed_site_a, list_apps_internal, set_open_in_tab_internal_site_a, launch_internal_site_a, check_tab_created, check_install_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, list_apps_internal, set_open_in_tab_internal_site_a, list_apps_internal -navigate_installable_site_a, install_internal_windowed_site_a, list_apps_internal, set_open_in_tab_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, navigate_browser_in_scope_site_a, check_install_icon_not_shown, check_launch_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, set_open_in_tab_internal_site_a, launch_internal_site_a, check_tab_created, check_install_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, set_open_in_tab_internal_site_a, list_apps_internal -navigate_installable_site_a, install_internal_windowed_site_a, set_open_in_tab_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -Linux, Mac, Win | navigate_installable_site_a, install_internal_windowed_site_a, uninstall_from_menu, list_apps_internal, check_app_not_in_list_site_a -ChromeOS | navigate_installable_site_a, install_internal_windowed_site_a, uninstall_internal_site_a, list_apps_internal, check_app_not_in_list_site_a -Linux, Mac, Win | navigate_installable_site_a, install_internal_windowed_site_a, uninstall_from_menu, navigate_browser_in_scope_site_a, check_install_icon_shown -ChromeOS | navigate_installable_site_a, install_internal_windowed_site_a, uninstall_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_internal_windowed_site_a, uninstall_internal_site_a, list_apps_internal, check_app_not_in_list_site_a -navigate_installable_site_a, install_internal_windowed_site_a, uninstall_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, launch_internal_site_a, check_install_icon_not_shown, navigate_browser_in_scope_site_a, check_launch_icon_shown, close_pwa, check_no_crash -navigate_installable_site_a, install_omnibox, check_window_created, list_apps_internal, set_open_in_tab_internal_site_a, launch_internal_site_a, check_tab_created, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, list_apps_internal, set_open_in_tab_internal_site_a, list_apps_internal -navigate_installable_site_a, install_omnibox, check_window_created, list_apps_internal, set_open_in_tab_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, navigate_browser_in_scope_site_a, check_install_icon_not_shown, check_launch_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, set_open_in_tab_internal_site_a, launch_internal_site_a, check_tab_created, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, set_open_in_tab_internal_site_a, list_apps_internal -navigate_installable_site_a, install_omnibox, check_window_created, set_open_in_tab_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -Linux, Mac, Win | navigate_installable_site_a, install_omnibox, check_window_created, uninstall_from_menu, list_apps_internal, check_app_not_in_list_site_a -ChromeOS | navigate_installable_site_a, install_omnibox, check_window_created, uninstall_internal_site_a, list_apps_internal, check_app_not_in_list_site_a -Linux, Mac, Win | navigate_installable_site_a, install_omnibox, check_window_created, uninstall_from_menu, navigate_browser_in_scope_site_a, check_install_icon_shown -ChromeOS | navigate_installable_site_a, install_omnibox, check_window_created, uninstall_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_installable_site_a, install_omnibox, check_window_created, uninstall_internal_site_a, list_apps_internal, check_app_not_in_list_site_a -navigate_installable_site_a, install_omnibox, check_window_created, uninstall_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -Linux, Mac, Win | navigate_installable_site_a, install_omnibox, launch_internal_site_a, uninstall_from_menu, navigate_browser_in_scope_site_a, check_install_icon_shown, check_launch_icon_not_shown, -ChromeOS | navigate_installable_site_a, install_omnibox, launch_internal_site_a, uninstall_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown, check_launch_icon_not_shown, -navigate_installable_site_a, install_omnibox, list_apps_internal, set_open_in_tab_internal_site_a, launch_internal_site_a, check_tab_created, -navigate_installable_site_a, install_omnibox, list_apps_internal, set_open_in_tab_internal_site_a, check_user_display_mode_browser_internal, -navigate_installable_site_a, install_omnibox, list_apps_internal, set_open_in_tab_internal_site_a, list_apps_internal, launch_internal_site_a, check_tab_created -navigate_installable_site_a, install_omnibox, list_apps_internal, set_open_in_tab_internal_site_a, navigate_browser_in_scope_site_a, check_install_icon_shown -navigate_not_installable, check_install_icon_not_shown, -navigate_installable_site_a, install_omnibox, check_window_display_standalone, manifest_update_display_minimal_site_a, close_pwa, launch_internal_site_a, check_window_display_minimal -navigate_installable_site_a, install_omnibox, check_window_display_standalone, close_pwa, manifest_update_display_minimal_site_a, launch_internal_site_a, check_window_display_minimal
diff --git a/chrome/test/data/web_apps/web_app_integration_browsertest_sync_cases.csv b/chrome/test/data/web_apps/web_app_integration_browsertest_sync_cases.csv deleted file mode 100644 index 1286bcd..0000000 --- a/chrome/test/data/web_apps/web_app_integration_browsertest_sync_cases.csv +++ /dev/null
@@ -1,2 +0,0 @@ -Linux, Mac, Win | user_signin_internal, navigate_installable, sync_turned_off, install_omnibox, list_apps_internal, check_manifest_display_mode_standalone_internal, sync_turned_on, switch_profile_clients, list_apps_internal, check_app_not_locally_installed_internal, install_locally_internal, check_app_locally_installed_internal, check_manifest_display_mode_standalone_internal -ChromeOS | user_signin_internal, navigate_installable, sync_turned_off, install_omnibox, list_apps_internal, check_manifest_display_mode_standalone_internal, sync_turned_on, switch_profile_clients, check_manifest_display_mode_standalone_internal
diff --git a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn index e643256..d3e9377 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn +++ b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
@@ -16,6 +16,7 @@ ":local_images_element_test", ":personalization_app_test_utils", ":personalization_app_unified_test", + ":personalization_toast_element_test", ":test_mojo_interface_provider", ":test_personalization_store", ":wallpaper_collections_element_test", @@ -36,6 +37,14 @@ externs_list = [ "$externs_path/mocha-2.5.js" ] } +js_library("personalization_toast_element_test") { + deps = [ + ":test_personalization_store", + "//chromeos/components/personalization_app/resources/trusted:personalization_toast_element", + ] + externs_list = [ "$externs_path/mocha-2.5.js" ] +} + js_library("personalization_app_test_utils") { deps = [ ":test_mojo_interface_provider",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js index 1baef55..a598460 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. import {LocalImagesTest} from './local_images_element_test.js'; +import {PersonalizationToastTest} from './personalization_toast_element_test.js'; import {WallpaperBreadcrumbTest} from './wallpaper_breadcrumb_element_test.js'; import {WallpaperCollectionsTest} from './wallpaper_collections_element_test.js'; import {WallpaperImagesTest} from './wallpaper_images_element_test.js'; @@ -14,6 +15,7 @@ const testCases = [ LocalImagesTest, + PersonalizationToastTest, WallpaperBreadcrumbTest, WallpaperCollectionsTest, WallpaperImagesTest,
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_toast_element_test.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_toast_element_test.js new file mode 100644 index 0000000..e578ca6 --- /dev/null +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_toast_element_test.js
@@ -0,0 +1,54 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {ActionName} from 'chrome://personalization/trusted/personalization_actions.js'; +import {PersonalizationToastElement} from 'chrome://personalization/trusted/personalization_toast_element.js'; +import {assertEquals, assertTrue} from '../../chai_assert.js'; +import {flushTasks, waitAfterNextRender} from '../../test_util.m.js'; +import {baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js'; +import {TestPersonalizationStore} from './test_personalization_store.js'; + +export function PersonalizationToastTest() { + /** @type {!HTMLElement} */ + let personalizationToastElement; + + /** @type {?TestPersonalizationStore} */ + let personalizationStore = null; + + setup(() => { + const mocks = baseSetup(); + personalizationStore = mocks.personalizationStore; + personalizationToastElement = initElement(PersonalizationToastElement.is); + }); + + teardown(async () => { + await teardownElement(personalizationToastElement); + await flushTasks(); + }); + + test('hidden when no error is present', async () => { + assertEquals('', personalizationToastElement.innerHTML); + }); + + test('visible when error is present', async () => { + personalizationStore.data.error = 'There was an error'; + personalizationStore.notifyObservers(); + await waitAfterNextRender(personalizationToastElement); + assertTrue( + !!personalizationToastElement.shadowRoot.getElementById('container')); + assertEquals( + personalizationStore.data.error, + personalizationToastElement.shadowRoot.querySelector('p').innerText); + }); + + test('deploys an dismiss action when dismiss is clicked', async () => { + personalizationStore.data.error = 'There was an error'; + personalizationStore.notifyObservers(); + await waitAfterNextRender(personalizationToastElement); + + personalizationStore.expectAction(ActionName.DISMISS_ERROR); + personalizationToastElement.shadowRoot.querySelector('cr-button').click(); + await personalizationStore.waitForAction(ActionName.DISMISS_ERROR); + }); +}
diff --git a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js index 9864f9e..15c3b16 100644 --- a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js +++ b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
@@ -338,6 +338,8 @@ }); } + removePage() {} + completeMultiPageScan() { this.methodCalled('completeMultiPageScan'); }
diff --git a/chrome/test/data/webui/settings/chromeos/fake_bluetooth_config.js b/chrome/test/data/webui/settings/chromeos/fake_bluetooth_config.js index e5d5c5bb..9f29be9 100644 --- a/chrome/test/data/webui/settings/chromeos/fake_bluetooth_config.js +++ b/chrome/test/data/webui/settings/chromeos/fake_bluetooth_config.js
@@ -5,9 +5,34 @@ // TODO(crbug.com/1010321): Use cros_bluetooth_config.mojom-webui.js instead // as non-module JS is deprecated. import 'chrome://resources/mojo/chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-lite.js'; + +import {stringToMojoString16} from 'chrome://resources/cr_components/chromeos/bluetooth/bluetooth_utils.js'; import {assert} from 'chrome://resources/js/assert.m.js'; /** + * @param {string} id + * @param {string} publicName + * @param {boolean} connected + * @param {string|undefined} nickname + * @return {!chromeos.bluetoothConfig.mojom.PairedBluetoothDeviceProperties} + */ +export function createDefaultBluetoothDevice( + id, publicName, connected, nickname = undefined) { + const mojom = chromeos.bluetoothConfig.mojom; + return { + deviceProperties: { + id: id, + publicName: stringToMojoString16(publicName), + deviceType: mojom.DeviceType.kComputer, + audioCapability: mojom.AudioOutputCapability.kNotCapableOfAudio, + connectionState: connected ? mojom.DeviceConnectionState.kConnected : + mojom.DeviceConnectionState.kNotConnected, + }, + nickname: nickname, + }; +} + +/** * @fileoverview Fake implementation of CrosBluetoothConfig for testing. */ @@ -64,9 +89,7 @@ * @param {chromeos.bluetoothConfig.mojom.BluetoothSystemState} systemState */ setSystemState(systemState) { - const newSystemProperties = {...this.systemProperties_}; - newSystemProperties.systemState = systemState; - this.systemProperties_ = newSystemProperties; + this.systemProperties_.systemState = systemState; this.notifyObserversPropertiesUpdated_(); }
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_devices_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_devices_subpage_tests.js index 212c33e..189a6d7 100644 --- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_devices_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_devices_subpage_tests.js
@@ -9,7 +9,7 @@ // #import {flush, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {assertTrue} from '../../../chai_assert.js'; -// #import {FakeBluetoothConfig} from './fake_bluetooth_config.m.js'; +// #import {createDefaultBluetoothDevice, FakeBluetoothConfig} from './fake_bluetooth_config.m.js'; // #import {setBluetoothConfigForTesting} from 'chrome://resources/cr_components/chromeos/bluetooth/cros_bluetooth_config.js'; // clang-format on @@ -25,7 +25,12 @@ */ let propertiesObserver; + /** @type {!chromeos.bluetoothConfig.mojom} */ + let mojom; + setup(function() { + mojom = chromeos.bluetoothConfig.mojom; + bluetoothConfig = new FakeBluetoothConfig(); setBluetoothConfigForTesting(bluetoothConfig); bluetoothDevicesSubpage = @@ -97,9 +102,40 @@ assertToggleEnabledState(/*enabled=*/ true); // Mock systemState becoming unavailable. - bluetoothConfig.setSystemState( - chromeos.bluetoothConfig.mojom.BluetoothSystemState.kUnavailable); + bluetoothConfig.setSystemState(mojom.BluetoothSystemState.kUnavailable); await flushAsync(); assertTrue(enableBluetoothToggle.disabled); }); + + test('Device lists states', async function() { + const getDeviceList = (connected) => { + return bluetoothDevicesSubpage.shadowRoot.querySelector( + connected ? '#connectedDeviceList' : '#unconnectedDeviceList'); + }; + // No lists should be showing at first. + assertFalse(!!getDeviceList(/*connected=*/ true)); + assertFalse(!!getDeviceList(/*connected=*/ false)); + + const connectedDevice = createDefaultBluetoothDevice( + /*id=*/ '123456789', /*publicName=*/ 'BeatsX', /*connected=*/ true); + const unconnectedDevice = createDefaultBluetoothDevice( + /*id=*/ '987654321', /*publicName=*/ 'MX 3', /*connected=*/ false); + + // Pair connected device. + bluetoothConfig.appendToPairedDeviceList([connectedDevice]); + await flushAsync(); + + assertTrue(!!getDeviceList(/*connected=*/ true)); + assertEquals(getDeviceList(/*connected=*/ true).devices.length, 1); + assertFalse(!!getDeviceList(/*connected=*/ false)); + + // Pair unconnected device + bluetoothConfig.appendToPairedDeviceList([unconnectedDevice]); + await flushAsync(); + + assertTrue(!!getDeviceList(/*connected=*/ true)); + assertEquals(getDeviceList(/*connected=*/ true).devices.length, 1); + assertTrue(!!getDeviceList(/*connected=*/ false)); + assertEquals(getDeviceList(/*connected=*/ false).devices.length, 1); + }); }); \ No newline at end of file
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_summary_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_summary_tests.js index 57a03fb..5dc1a3a 100644 --- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_summary_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_summary_tests.js
@@ -10,9 +10,9 @@ // #import {flush, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {Router, Route, routes} from 'chrome://os-settings/chromeos/os_settings.js'; // #import {assertTrue} from '../../../chai_assert.js'; -// #import {FakeBluetoothConfig} from './fake_bluetooth_config.m.js'; +// #import {createDefaultBluetoothDevice, FakeBluetoothConfig,} from './fake_bluetooth_config.m.js'; // #import {setBluetoothConfigForTesting} from 'chrome://resources/cr_components/chromeos/bluetooth/cros_bluetooth_config.js'; -// #import {stringToMojoString16, mojoString16ToString} from 'chrome://resources/cr_components/chromeos/bluetooth/bluetooth_utils.js'; +// #import {mojoString16ToString} from 'chrome://resources/cr_components/chromeos/bluetooth/bluetooth_utils.js'; // clang-format on suite('OsBluetoothSummaryTest', function() { @@ -134,37 +134,14 @@ // Bluetooth Icon should be default because no devices are connected. assertEquals('cr:bluetooth', getBluetoothStatusIcon().icon); - const device1 = { - deviceProperties: { - id: '123456789', - publicName: stringToMojoString16('BeatsX'), - deviceType: mojom.DeviceType.kComputer, - audioCapability: mojom.AudioOutputCapability.kNotCapableOfAudio, - connectionState: mojom.DeviceConnectionState.kConnected, - }, - nickname: 'device1' - }; - - const device2 = { - deviceProperties: { - id: '987654321', - publicName: stringToMojoString16('MX master 3'), - deviceType: mojom.DeviceType.kComputer, - audioCapability: mojom.AudioOutputCapability.kNotCapableOfAudio, - connectionState: mojom.DeviceConnectionState.kConnected, - }, - }; - - const device3 = { - deviceProperties: { - id: '456789', - publicName: stringToMojoString16('Radio head'), - deviceType: mojom.DeviceType.kMouse, - audioCapability: mojom.AudioOutputCapability.kNotCapableOfAudio, - connectionState: mojom.DeviceConnectionState.kConnected, - }, - nickname: 'device3' - }; + const device1 = createDefaultBluetoothDevice( + /*id=*/ '123456789', /*publicName=*/ 'BeatsX', /*connected=*/ true, + /*nickname=*/ 'device1'); + const device2 = createDefaultBluetoothDevice( + /*id=*/ '987654321', /*publicName=*/ 'MX 3', /*connected=*/ true); + const device3 = createDefaultBluetoothDevice( + /*id=*/ '456789', /*publicName=*/ 'Radio head', /*connected=*/ true, + /*nickname=*/ 'device3'); const mockPairedBluetoothDeviceProperties = [ device1,
diff --git a/chrome/test/data/webui/settings/chromeos/os_paired_bluetooth_list_tests.js b/chrome/test/data/webui/settings/chromeos/os_paired_bluetooth_list_tests.js index 928f30b4..cddc110 100644 --- a/chrome/test/data/webui/settings/chromeos/os_paired_bluetooth_list_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_paired_bluetooth_list_tests.js
@@ -10,6 +10,7 @@ // #import {flush, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {assertTrue, assertEquals} from '../../../chai_assert.js'; // #import {eventToPromise} from 'chrome://test/test_util.m.js'; +// #import {createDefaultBluetoothDevice} from './fake_bluetooth_config.m.js'; // clang-format on suite('OsPairedBluetoothListTest', function() { @@ -34,8 +35,10 @@ }); test('Device list change renders items correctly', async function() { - // TODO(crbug.com/1010321): Use real Device objects. - pairedBluetoothList.devices = [{}, {}, {}]; + const device = createDefaultBluetoothDevice( + /*id=*/ '123456789', /*publicName=*/ 'BeatsX', /*connected=*/ true); + + pairedBluetoothList.devices = [device, device, device]; await flushAsync(); const getListItems = () => { @@ -46,7 +49,7 @@ const ironResizePromise = test_util.eventToPromise('iron-resize', pairedBluetoothList); - pairedBluetoothList.devices = [{}, {}, {}, {}, {}]; + pairedBluetoothList.devices = [device, device, device, device, device]; await ironResizePromise; Polymer.dom.flush();
diff --git a/chrome/updater/app/server/win/service_main.cc b/chrome/updater/app/server/win/service_main.cc index 670099a..e2c2ffd 100644 --- a/chrome/updater/app/server/win/service_main.cc +++ b/chrome/updater/app/server/win/service_main.cc
@@ -7,6 +7,7 @@ #include <atlsecurity.h> #include <sddl.h> +#include <string> #include <type_traits> #include "base/command_line.h" @@ -19,6 +20,7 @@ #include "chrome/updater/app/server/win/server.h" #include "chrome/updater/constants.h" #include "chrome/updater/win/win_constants.h" +#include "chrome/updater/win/win_util.h" #include "chrome/updater/win/wrl_module.h" namespace updater { @@ -87,10 +89,10 @@ ServiceMain::~ServiceMain() = default; int ServiceMain::RunAsService() { - const wchar_t* const kServiceName = - IsInternalService() ? kWindowsInternalServiceName : kWindowsServiceName; - static const SERVICE_TABLE_ENTRY dispatch_table[] = { - {const_cast<LPTSTR>(kServiceName), &ServiceMain::ServiceMainEntry}, + const std::wstring service_name = GetServiceName(IsInternalService()); + const SERVICE_TABLE_ENTRY dispatch_table[] = { + {const_cast<LPTSTR>(service_name.c_str()), + &ServiceMain::ServiceMainEntry}, {nullptr, nullptr}}; if (!::StartServiceCtrlDispatcher(dispatch_table)) { @@ -102,10 +104,9 @@ } void ServiceMain::ServiceMainImpl() { - const wchar_t* const kServiceName = - IsInternalService() ? kWindowsInternalServiceName : kWindowsServiceName; - service_status_handle_ = ::RegisterServiceCtrlHandler( - kServiceName, &ServiceMain::ServiceControlHandler); + service_status_handle_ = + ::RegisterServiceCtrlHandler(GetServiceName(IsInternalService()).c_str(), + &ServiceMain::ServiceControlHandler); if (service_status_handle_ == nullptr) { PLOG(ERROR) << "RegisterServiceCtrlHandler failed"; return;
diff --git a/chrome/updater/app/server/win/service_main.h b/chrome/updater/app/server/win/service_main.h index 43c4e74..d7997d4 100644 --- a/chrome/updater/app/server/win/service_main.h +++ b/chrome/updater/app/server/win/service_main.h
@@ -9,6 +9,7 @@ #include "base/no_destructor.h" #include "base/synchronization/waitable_event.h" +#include "base/win/atl.h" namespace base {
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc index 0ec48904..14d90ae 100644 --- a/chrome/updater/test/integration_tests_win.cc +++ b/chrome/updater/test/integration_tests_win.cc
@@ -33,6 +33,7 @@ #include "chrome/updater/util.h" #include "chrome/updater/win/setup/setup_util.h" #include "chrome/updater/win/win_constants.h" +#include "chrome/updater/win/win_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" @@ -161,9 +162,8 @@ } if (scope == UpdaterScope::kSystem) { - for (const wchar_t* const service_name : - {kWindowsInternalServiceName, kWindowsServiceName}) { - EXPECT_TRUE(DeleteService(service_name)); + for (const bool is_internal_service : {true, false}) { + EXPECT_TRUE(DeleteService(GetServiceName(is_internal_service).c_str())); } } @@ -231,9 +231,8 @@ } if (scope == UpdaterScope::kSystem) { - for (const wchar_t* const service_name : - {kWindowsInternalServiceName, kWindowsServiceName}) { - EXPECT_TRUE(IsServiceGone(service_name)); + for (const bool is_internal_service : {true, false}) { + EXPECT_TRUE(IsServiceGone(GetServiceName(is_internal_service).c_str())); } }
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc index 4753cd4..73a438d 100644 --- a/chrome/updater/win/setup/setup_util.cc +++ b/chrome/updater/win/setup/setup_util.cc
@@ -32,6 +32,7 @@ #include "chrome/updater/util.h" #include "chrome/updater/win/task_scheduler.h" #include "chrome/updater/win/win_constants.h" +#include "chrome/updater/win/win_util.h" // Specialization for std::hash so that IID instances can be stored in an // associative container. This implementation of the hash function adds @@ -216,10 +217,9 @@ com_service_command.AppendSwitch(kEnableLoggingSwitch); com_service_command.AppendSwitchASCII(kLoggingModuleSwitch, "*/chrome/updater/*=2"); - const wchar_t* const kServiceName = - internal_service ? kWindowsInternalServiceName : kWindowsServiceName; list->AddWorkItem(new installer::InstallServiceWorkItem( - kServiceName, kServiceName, com_service_command, + GetServiceName(internal_service).c_str(), + GetServiceDisplayName(internal_service).c_str(), com_service_command, base::ASCIIToWide(UPDATER_KEY), internal_service ? GetSideBySideServers(UpdaterScope::kSystem) : GetActiveServers(UpdaterScope::kSystem),
diff --git a/chrome/updater/win/setup/uninstall.cc b/chrome/updater/win/setup/uninstall.cc index 0ee4ee8..c4f31dd 100644 --- a/chrome/updater/win/setup/uninstall.cc +++ b/chrome/updater/win/setup/uninstall.cc
@@ -31,6 +31,7 @@ #include "chrome/updater/win/setup/setup_util.h" #include "chrome/updater/win/task_scheduler.h" #include "chrome/updater/win/win_constants.h" +#include "chrome/updater/win/win_util.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace updater { @@ -57,10 +58,10 @@ WorkItem::kWow64Default); } - for (const wchar_t* const service_name : - {kWindowsInternalServiceName, kWindowsServiceName}) { + for (const bool is_internal_service : {true, false}) { + const std::wstring service_name = GetServiceName(is_internal_service); if (!installer::InstallServiceWorkItem::DeleteService( - service_name, base::ASCIIToWide(UPDATER_KEY), {}, {})) { + service_name.c_str(), base::ASCIIToWide(UPDATER_KEY), {}, {})) { LOG(WARNING) << "DeleteService [" << service_name << "] failed."; } }
diff --git a/chrome/updater/win/win_constants.cc b/chrome/updater/win/win_constants.cc index 55d48ad..269e483 100644 --- a/chrome/updater/win/win_constants.cc +++ b/chrome/updater/win/win_constants.cc
@@ -29,7 +29,7 @@ const wchar_t kRegKeyCompanyEnrollment[] = COMPANY_KEY L"Enrollment\\"; const wchar_t kRegValueDmToken[] = L"dmtoken"; -const wchar_t kWindowsServiceName[] = L"UpdaterService"; -const wchar_t kWindowsInternalServiceName[] = L"UpdaterInternalService"; +const wchar_t kWindowsServiceName[] = L"Service"; +const wchar_t kWindowsInternalServiceName[] = L"InternalService"; } // namespace updater
diff --git a/chrome/updater/win/win_util.cc b/chrome/updater/win/win_util.cc index c1652847..5fbc7c5 100644 --- a/chrome/updater/win/win_util.cc +++ b/chrome/updater/win/win_util.cc
@@ -30,7 +30,9 @@ #include "base/win/registry.h" #include "base/win/scoped_handle.h" #include "chrome/updater/constants.h" +#include "chrome/updater/updater_branding.h" #include "chrome/updater/updater_scope.h" +#include "chrome/updater/updater_version.h" #include "chrome/updater/win/user_info.h" #include "chrome/updater/win/win_constants.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -539,4 +541,20 @@ return s; } + +std::wstring GetServiceName(bool is_internal_service) { + std::wstring service_name = GetServiceDisplayName(is_internal_service); + service_name.erase( + std::remove_if(service_name.begin(), service_name.end(), isspace), + service_name.end()); + return service_name; +} + +std::wstring GetServiceDisplayName(bool is_internal_service) { + return base::StrCat( + {base::ASCIIToWide(PRODUCT_FULLNAME_STRING), L" ", + is_internal_service ? kWindowsInternalServiceName : kWindowsServiceName, + L" ", kUpdaterVersionUtf16}); +} + } // namespace updater
diff --git a/chrome/updater/win/win_util.h b/chrome/updater/win/win_util.h index 438c9f4..5f35943 100644 --- a/chrome/updater/win/win_util.h +++ b/chrome/updater/win/win_util.h
@@ -127,6 +127,16 @@ // caller. The value can be used for logging purposes. std::string GetUACState(); +// Returns the versioned service name in the following format: +// "{ProductName}{InternalService/Service}{UpdaterVersion}". +// For instance: "ChromiumUpdaterInternalService92.0.0.1". +std::wstring GetServiceName(bool is_internal_service); + +// Returns the versioned service name in the following format: +// "{ProductName} {InternalService/Service} {UpdaterVersion}". +// For instance: "ChromiumUpdater InternalService 92.0.0.1". +std::wstring GetServiceDisplayName(bool is_internal_service); + } // namespace updater #endif // CHROME_UPDATER_WIN_WIN_UTIL_H_
diff --git a/chrome/updater/win/win_util_unittest.cc b/chrome/updater/win/win_util_unittest.cc index c497537a..2b356cb 100644 --- a/chrome/updater/win/win_util_unittest.cc +++ b/chrome/updater/win/win_util_unittest.cc
@@ -6,18 +6,23 @@ #include <windows.h> +#include "base/strings/strcat.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/updater/updater_branding.h" +#include "chrome/updater/updater_version.h" +#include "chrome/updater/win/win_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace updater { -TEST(UpdaterTestUtil, HRESULTFromLastError) { +TEST(WinUtil, HRESULTFromLastError) { ::SetLastError(ERROR_ACCESS_DENIED); EXPECT_EQ(E_ACCESSDENIED, HRESULTFromLastError()); ::SetLastError(ERROR_SUCCESS); EXPECT_EQ(E_FAIL, HRESULTFromLastError()); } -TEST(UpdaterTestUtil, GetDownloadProgress) { +TEST(WinUtil, GetDownloadProgress) { EXPECT_EQ(GetDownloadProgress(0, 50), 0); EXPECT_EQ(GetDownloadProgress(12, 50), 24); EXPECT_EQ(GetDownloadProgress(25, 50), 50); @@ -28,4 +33,24 @@ EXPECT_EQ(GetDownloadProgress(50, 0), -1); } +TEST(WinUtil, GetServiceDisplayName) { + for (const bool is_internal_service : {true, false}) { + EXPECT_EQ(base::StrCat({base::ASCIIToWide(PRODUCT_FULLNAME_STRING), L" ", + is_internal_service ? kWindowsInternalServiceName + : kWindowsServiceName, + L" ", kUpdaterVersionUtf16}), + GetServiceDisplayName(is_internal_service)); + } +} + +TEST(WinUtil, GetServiceName) { + for (const bool is_internal_service : {true, false}) { + EXPECT_EQ(base::StrCat({base::ASCIIToWide(PRODUCT_FULLNAME_STRING), + is_internal_service ? kWindowsInternalServiceName + : kWindowsServiceName, + kUpdaterVersionUtf16}), + GetServiceName(is_internal_service)); + } +} + } // namespace updater
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 7da5ea6..4270ba51 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -1621,6 +1621,12 @@ <message name="IDS_PERSONALIZATION_APP_NETWORK_ERROR" desc="Label for the error page when wallpaper information cannot be downloaded"> Please connect to a network and reload the page to view wallpaper. </message> + <message name="IDS_PERSONALIZATION_APP_SET_WALLPAPER_ERROR" desc="Label for the error toast notification when setting wallpaper failed"> + There was an error. Please try again by choosing other images. + </message> + <message name="IDS_PERSONALIZATION_APP_DISMISS" desc="Label for the toast notification dismiss action"> + Dismiss + </message> <!-- Traffic Counters UI --> <message name="IDS_TRAFFIC_COUNTERS_UNKNOWN" desc="Traffic counters related to an unknown source">
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_DISMISS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_DISMISS.png.sha1 new file mode 100644 index 0000000..bd61536 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_DISMISS.png.sha1
@@ -0,0 +1 @@ +bdd66526d8292c8ffb346c7381f93cbaabee82fb \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SET_WALLPAPER_ERROR.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SET_WALLPAPER_ERROR.png.sha1 new file mode 100644 index 0000000..bd61536 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SET_WALLPAPER_ERROR.png.sha1
@@ -0,0 +1 @@ +bdd66526d8292c8ffb346c7381f93cbaabee82fb \ No newline at end of file
diff --git a/chromeos/components/eche_app_ui/test/eche_app_ui_chrome_branded_browsertest.js b/chromeos/components/eche_app_ui/test/eche_app_ui_chrome_branded_browsertest.js index 30eee6f..5332c9af 100644 --- a/chromeos/components/eche_app_ui/test/eche_app_ui_chrome_branded_browsertest.js +++ b/chromeos/components/eche_app_ui/test/eche_app_ui_chrome_branded_browsertest.js
@@ -33,19 +33,6 @@ } }; -// Tests that chrome://eche-app goes somewhere instead of -// 404ing or crashing. -TEST_F('EcheAppUIBrowserTest', 'HasChromeSchemeURL', () => { - assertEquals(document.title, 'Eche'); - assertEquals(document.location.origin, HOST_ORIGIN); - testDone(); -}); - -// Tests that the implementations of echeapi.d.ts are defined. -TEST_F('EcheAppUIBrowserTest', 'HasDefinedEcheapi', () => { - chai.assert.isDefined(echeapi.webrtc.registerSignalReceiver); - chai.assert.isDefined(echeapi.webrtc.sendSignal); - chai.assert.isDefined(echeapi.webrtc.tearDownSignal); - chai.assert.isDefined(echeapi.system.registerTabletModeChangedReceiver); - testDone(); -}); +// TODO(samchiu) Temporarily disable browser_test since a future Eche roll +// will break the function of eche window. Test will be enable when we +// phase in http://go/crrev/c/3081307.
diff --git a/chromeos/components/personalization_app/personalization_app_ui.cc b/chromeos/components/personalization_app/personalization_app_ui.cc index 5110461..e783409 100644 --- a/chromeos/components/personalization_app/personalization_app_ui.cc +++ b/chromeos/components/personalization_app/personalization_app_ui.cc
@@ -70,7 +70,11 @@ {"unknownImageAttribution", IDS_PERSONALIZATION_APP_UNKNOWN_IMAGE_ATTRIBUTION}, {"networkError", IDS_PERSONALIZATION_APP_NETWORK_ERROR}, - {"ariaLabelLoading", IDS_PERSONALIZATION_APP_ARIA_LABEL_LOADING}}; + {"ariaLabelLoading", IDS_PERSONALIZATION_APP_ARIA_LABEL_LOADING}, + // Using old wallpaper app error string pending final revision. + // TODO(b/195609442) + {"setWallpaperError", IDS_PERSONALIZATION_APP_SET_WALLPAPER_ERROR}, + {"dismiss", IDS_PERSONALIZATION_APP_DISMISS}}; source->AddLocalizedStrings(kLocalizedStrings); source->UseStringsJs(); }
diff --git a/chromeos/components/personalization_app/resources/trusted/BUILD.gn b/chromeos/components/personalization_app/resources/trusted/BUILD.gn index 0deb47c..2fdc3a33 100644 --- a/chromeos/components/personalization_app/resources/trusted/BUILD.gn +++ b/chromeos/components/personalization_app/resources/trusted/BUILD.gn
@@ -8,12 +8,13 @@ polymer_element_files = [ "local_images_element.js", + "personalization_router_element.js", + "personalization_toast_element.js", "wallpaper_breadcrumb_element.js", "wallpaper_collections_element.js", "wallpaper_error_element.js", "wallpaper_images_element.js", "wallpaper_selected_element.js", - "personalization_router_element.js", ] static_files = [ @@ -61,6 +62,7 @@ ":personalization_reducers", ":personalization_router_element", ":personalization_store", + ":personalization_toast_element", ":styles", ":wallpaper_breadcrumb_element", ":wallpaper_collections_element", @@ -103,6 +105,15 @@ ] } +js_library("personalization_toast_element") { + deps = [ + ":personalization_actions", + ":personalization_store", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:load_time_data", + ] +} + js_library("personalization_store") { deps = [ ":personalization_actions", @@ -186,6 +197,7 @@ ":personalization_reducers", ":personalization_router_element", ":personalization_store", + ":personalization_toast_element", ":styles", ":wallpaper_breadcrumb_element", ":wallpaper_collections_element",
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_actions.js b/chromeos/components/personalization_app/resources/trusted/personalization_actions.js index 60823779..2f7fe8a 100644 --- a/chromeos/components/personalization_app/resources/trusted/personalization_actions.js +++ b/chromeos/components/personalization_app/resources/trusted/personalization_actions.js
@@ -25,6 +25,7 @@ SET_LOCAL_IMAGE_DATA: 'set_local_image_data', SET_SELECTED_IMAGE: 'set_selected_image', SET_UPDATED_DAILY_REFRESH_IMAGE: 'set_updated_daily_refreshed_image', + DISMISS_ERROR: 'dismiss_error', }; @@ -178,3 +179,10 @@ name: ActionName.SET_SELECTED_IMAGE, }; } + +/** + * @return {!Action} + */ +export function dismissErrorAction() { + return {name: ActionName.DISMISS_ERROR}; +}
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_app.js b/chromeos/components/personalization_app/resources/trusted/personalization_app.js index eab0b741f..e5e7c85 100644 --- a/chromeos/components/personalization_app/resources/trusted/personalization_app.js +++ b/chromeos/components/personalization_app/resources/trusted/personalization_app.js
@@ -11,6 +11,7 @@ import '/strings.m.js'; import './local_images_element.js'; import './personalization_router_element.js'; +import './personalization_toast_element.js'; import './wallpaper_breadcrumb_element.js'; import './wallpaper_collections_element.js'; import './wallpaper_error_element.js';
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_reducers.js b/chromeos/components/personalization_app/resources/trusted/personalization_reducers.js index b5e1f55b..91b330e 100644 --- a/chromeos/components/personalization_app/resources/trusted/personalization_reducers.js +++ b/chromeos/components/personalization_app/resources/trusted/personalization_reducers.js
@@ -97,6 +97,7 @@ * currentSelected: ?DisplayableImage, * pendingSelected: ?DisplayableImage, * dailyRefresh: !DailyRefreshState, + * error: ?string, * }} */ export let PersonalizationState; @@ -120,6 +121,7 @@ currentSelected: null, pendingSelected: null, dailyRefresh: {collectionId: null}, + error: null, }; } @@ -321,6 +323,31 @@ } } +/** + * @param {?string} state + * @param {!Action} action + * @return {?string} + */ +function errorReducer(state, action) { + switch (action.name) { + case ActionName.END_SELECT_IMAGE: + const {success} = + /** @type {{name: string, success: boolean}} */ (action); + if (success) { + return null; + } + return loadTimeData.getString('setWallpaperError'); + case ActionName.DISMISS_ERROR: + if (!state) { + console.warn( + 'Received dismiss error action when error is already null'); + } + return null; + default: + return state; + } +} + const root = combineReducers({ backdrop: backdropReducer, loading: loadingReducer, @@ -328,6 +355,7 @@ currentSelected: currentSelectedReducer, pendingSelected: pendingSelectedReducer, dailyRefresh: dailyRefreshReducer, + error: errorReducer, }); /**
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html b/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html index 81c9664..c2d7b6f 100644 --- a/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html +++ b/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html
@@ -10,6 +10,7 @@ ". leftspacer . rightspacer ."; grid-template-columns: 1fr 16px minmax(568px, 920px) 16px 1fr; grid-template-rows: 56px 172px 12px 1fr 12px; + position: relative; width: 100%; } #leftspacer { @@ -27,6 +28,13 @@ wallpaper-collections, wallpaper-images, local-images { grid-area: imagegrid; } + personalization-toast { + position: absolute; + bottom: 16px; + left: 50%; + max-width: 380px; + transform: translateX(-50%); + } </style> <div id="container"> <!-- dwell-time is set to 200ms to populate history state more quickly while @@ -51,4 +59,5 @@ <local-images hidden="[[!shouldShowLocalCollection_(path_)]]"></local-images> <!-- Prevent the right margin from collapsing when window gets very narrow --> <div id="rightspacer"></div> + <personalization-toast></personalization-toast> </div>
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.html b/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.html new file mode 100644 index 0000000..65bf5f5 --- /dev/null +++ b/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.html
@@ -0,0 +1,68 @@ +<style> + /* + Cannot use semantic colors because toast notification element must invert + the color scheme. These are swapped versions of --cros-* variables. + */ + :host { + --personalization-app-bg-color-elevation-2: rgb(46, 46, 49); + --personalization-app-text-color-primary: var(--google-grey-200); + } + + /* Invert cr-button colors. These are normally dark mode colors. */ + cr-button { + --ink-color: var(--google-blue-refresh-300); + --text-color: var(--google-blue-refresh-300); + } + + /* Override some cr-button variables. */ + cr-button { + --active-shadow-rgb: transparent; + --border-color: transparent; + --hover-border-color: transparent; + --hover-bg-color: transparent; + --hover-bg-action: transparent; + --cr-button-height: 36px; + border: 0; + margin: 0; + padding: 8px; + } + + @media (prefers-color-scheme: dark) { + :host { + --personalization-app-bg-color-elevation-2: white; + --personalization-app-text-color-primary: var(--google-grey-900); + } + + /* Invert cr-button colors. These are normally light mode colors. */ + cr-button { + --ink-color: var(--google-blue-600); + --text-color: var(--google-blue-600); + } + } + + #container { + background-color: var(--personalization-app-bg-color-elevation-2); + border-radius: 4px; + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px rgba(0, 0, 0, 0.15); + box-sizing: border-box; + color: var(--personalization-app-text-color-primary); + display: flex; + flex-flow: row nowrap; + justify-content: space-between; + padding: 16px; + } + + p { + margin: 0; + margin-inline-end: 16px; + } + +</style> +<template is="dom-if" if="[[error_]]"> + <div id="container"> + <p>[[error_]]</p> + <cr-button on-click="onDismissClicked_"> + [[i18n('dismiss')]] + </cr-button> + </div> +</template>
diff --git a/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.js b/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.js new file mode 100644 index 0000000..81d3fde --- /dev/null +++ b/chromeos/components/personalization_app/resources/trusted/personalization_toast_element.js
@@ -0,0 +1,50 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview This component displays toast notifications to the user. + */ + +import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; +import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {dismissErrorAction} from './personalization_actions.js'; +import {WithPersonalizationStore} from './personalization_store.js'; + +/** @polymer */ +export class PersonalizationToastElement extends WithPersonalizationStore { + static get is() { + return 'personalization-toast'; + } + + static get template() { + return html`{__html_template__}`; + } + + static get properties() { + return { + /** + * @type {?string} + * @private + */ + error_: { + type: String, + value: null, + }, + }; + } + + /** @override */ + connectedCallback() { + super.connectedCallback(); + this.watch('error_', state => state.error); + } + + /** @private */ + onDismissClicked_() { + this.dispatch(dismissErrorAction()); + } +} + +customElements.define( + PersonalizationToastElement.is, PersonalizationToastElement);
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom index 17e7895..48b721f 100644 --- a/chromeos/crosapi/mojom/crosapi.mojom +++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -420,6 +420,16 @@ kUseDlc = 2, }; +// Corresponds to BUILDFLAGs we use in ash-chrome that we want to propagate to +// Lacros Chrome. On the Lacros side we turn this into command line switches. +[Stable, Extensible] +enum BuildFlag { + [Default] kUnknown = 0, + kUseChromeosProtectedMedia = 1, + kEnablePlatformEncryptedHevc = 2, + kEnablePlatformHevc = 3, +}; + // BrowserInitParams is a set of parameters for initialization of browsers // (such as lacros-chrome), which is passed from ash-chrome to a browser. // Since ash-chrome and browsers may have different versions, the browsers must @@ -438,7 +448,7 @@ // processed by the browser. // // Next version: 24 -// Next id: 23 +// Next id: 24 [Stable, RenamedFrom="crosapi.mojom.LacrosInitParams"] struct BrowserInitParams { // This is ash-chrome's version of the Crosapi interface. This is used by @@ -580,6 +590,11 @@ // Whether (and how) on-device handwriting recognition is supported, depending // ash-chrome's startup switches. OndeviceHandwritingSupport ondevice_handwriting_support@22; + + [MinVersion=23] + // Build flags from ash-chrome that we turn into command line switches to + // enforce at run-time in lacros-chrome. + array<BuildFlag>? build_flags@23; }; // BrowserService defines the APIs that live in a browser (such as
diff --git a/chromeos/services/assistant/public/mojom/BUILD.gn b/chromeos/services/assistant/public/mojom/BUILD.gn index 84426f8..e83cb5b 100644 --- a/chromeos/services/assistant/public/mojom/BUILD.gn +++ b/chromeos/services/assistant/public/mojom/BUILD.gn
@@ -6,4 +6,6 @@ mojom("mojom") { sources = [ "assistant_audio_decoder.mojom" ] + + public_deps = [ "//sandbox/policy/mojom" ] }
diff --git a/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom b/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom index f80f079..a72ac76 100644 --- a/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom +++ b/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom
@@ -4,7 +4,10 @@ module chromeos.assistant.mojom; +import "sandbox/policy/mojom/sandbox.mojom"; + // A factory for creating an assistant audio decoder. +[ServiceSandbox=sandbox.mojom.Sandbox.kUtility] interface AssistantAudioDecoderFactory { // Creates an AssistantAudioDecoder to decode audio stream data from // |data_source|.
diff --git a/chromeos/services/ime/public/mojom/BUILD.gn b/chromeos/services/ime/public/mojom/BUILD.gn index 58c7198..f1d4725 100644 --- a/chromeos/services/ime/public/mojom/BUILD.gn +++ b/chromeos/services/ime/public/mojom/BUILD.gn
@@ -14,6 +14,7 @@ public_deps = [ "//mojo/public/mojom/base", + "//sandbox/policy/mojom", "//url/mojom:url_mojom_gurl", ]
diff --git a/chromeos/services/ime/public/mojom/ime_service.mojom b/chromeos/services/ime/public/mojom/ime_service.mojom index 6a2accb..de53c37 100644 --- a/chromeos/services/ime/public/mojom/ime_service.mojom +++ b/chromeos/services/ime/public/mojom/ime_service.mojom
@@ -9,6 +9,7 @@ import "chromeos/services/ime/public/mojom/input_engine.mojom"; import "chromeos/services/ime/public/mojom/input_method.mojom"; import "chromeos/services/ime/public/mojom/input_method_host.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; // IME on ChromeOS consists of three parts: // - The IME running in an extension to provide a soft keyboard @@ -65,6 +66,7 @@ // process to handle IME related operations. There are two clients of the IME // service: the browser process for certain first-party input methods and the // renderer process running the first-party IME extension. +[ServiceSandbox=sandbox.mojom.Sandbox.kIme] interface ImeService { // Injects a remote PlatformAccessProvider interface that the service can use // to request privileged operations from the client (i.e. the browser).
diff --git a/chromeos/services/libassistant/public/mojom/BUILD.gn b/chromeos/services/libassistant/public/mojom/BUILD.gn index 5884e73..eb7ca9d3 100644 --- a/chromeos/services/libassistant/public/mojom/BUILD.gn +++ b/chromeos/services/libassistant/public/mojom/BUILD.gn
@@ -28,6 +28,8 @@ "timer_controller.mojom", ] + public_deps = [ "//sandbox/policy/mojom" ] + deps = [ "//ash/public/mojom", "//chromeos/services/assistant/public/mojom",
diff --git a/chromeos/services/libassistant/public/mojom/service.mojom b/chromeos/services/libassistant/public/mojom/service.mojom index 9532bbe5..8ac90c0 100644 --- a/chromeos/services/libassistant/public/mojom/service.mojom +++ b/chromeos/services/libassistant/public/mojom/service.mojom
@@ -18,6 +18,7 @@ import "chromeos/services/libassistant/public/mojom/speech_recognition_observer.mojom"; import "chromeos/services/libassistant/public/mojom/timer_controller.mojom"; import "chromeos/services/libassistant/public/mojom/notification_delegate.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; // The main interface to the Libassistant service on ChromeOS. // Libassistant provides access to the Google Assistant. @@ -25,6 +26,7 @@ // all Libassistant calls to this service. // It is used by //chromeos/services/assistant/proxy, which is a trusted // service running in the browser process. +[ServiceSandbox=sandbox.mojom.Sandbox.kLibassistant] interface LibassistantService { // Bind everything needed to start the service.
diff --git a/chromeos/services/tts/public/mojom/BUILD.gn b/chromeos/services/tts/public/mojom/BUILD.gn index bb15158..014d49e 100644 --- a/chromeos/services/tts/public/mojom/BUILD.gn +++ b/chromeos/services/tts/public/mojom/BUILD.gn
@@ -7,5 +7,8 @@ mojom("mojom") { sources = [ "tts_service.mojom" ] - public_deps = [ "//media/mojo/mojom" ] + public_deps = [ + "//media/mojo/mojom", + "//sandbox/policy/mojom", + ] }
diff --git a/chromeos/services/tts/public/mojom/tts_service.mojom b/chromeos/services/tts/public/mojom/tts_service.mojom index f51e4f38b0..a54a4ca4 100644 --- a/chromeos/services/tts/public/mojom/tts_service.mojom +++ b/chromeos/services/tts/public/mojom/tts_service.mojom
@@ -5,6 +5,7 @@ module chromeos.tts.mojom; import "media/mojo/mojom/audio_stream_factory.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; // Audio parameters used for PlaybackTtsStream. struct AudioParameters { @@ -16,6 +17,7 @@ // tts-sandboxed process. TtsEngineExtensionObserver, the other end of this // interface, in the browser process, brokers a connection between TtsService // and two possible engine types, [Google|Playback]TtsStream. +[ServiceSandbox=sandbox.mojom.Sandbox.kTts] interface TtsService { // Binds a GoogleTtsStream received by this service. // The remote lives in the Google tts component extension.
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc b/components/autofill/core/browser/autofill_regex_constants.cc index 08271ba..ebe1e4f 100644 --- a/components/autofill/core/browser/autofill_regex_constants.cc +++ b/components/autofill/core/browser/autofill_regex_constants.cc
@@ -316,7 +316,7 @@ u"|メールアドレス" // ja-JP u"|Электронн(ая|ой).?Почт(а|ы)" // ru u"|邮件|邮箱" // zh-CN - u"|電郵地址" // zh-TW + u"|電郵地址|電子信箱" // zh-TW u"|ഇ-മെയില്|ഇലക്ട്രോണിക്.?" u"മെയിൽ" // ml u"|ایمیل|پست.*الکترونیک" // fa
diff --git a/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json b/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json index df9ccf22..906b9aa 100644 --- a/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json +++ b/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -2121,7 +2121,7 @@ "zh-TW": [ { "pattern_identifier": "zh_email_preserving", - "positive_pattern": "電郵地址", + "positive_pattern": "電郵地址|電子信箱", "positive_score": 1.4, "negative_pattern": null, "match_field_attributes": 3,
diff --git a/components/browsing_data/core/browsing_data_utils_unittest.cc b/components/browsing_data/core/browsing_data_utils_unittest.cc index d6021d53..338afb7 100644 --- a/components/browsing_data/core/browsing_data_utils_unittest.cc +++ b/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -8,6 +8,7 @@ #include <vector> #include "base/callback_helpers.h" +#include "base/memory/scoped_refptr.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" @@ -55,8 +56,7 @@ // Tests the complex output of the Autofill counter. TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) { - AutofillCounter counter( - scoped_refptr<FakeWebDataService>(new FakeWebDataService()), nullptr); + AutofillCounter counter(base::MakeRefCounted<FakeWebDataService>(), nullptr); // Test all configurations of zero and nonzero partial results for datatypes. // Test singular and plural for each datatype. @@ -101,8 +101,7 @@ // Tests the output of the Passwords counter. TEST_F(BrowsingDataUtilsTest, PasswordsCounterResult) { - scoped_refptr<password_manager::TestPasswordStore> store( - new password_manager::TestPasswordStore()); + auto store = base::MakeRefCounted<password_manager::TestPasswordStore>(); PasswordsCounter counter( scoped_refptr<password_manager::PasswordStore>(store), nullptr, nullptr);
diff --git a/components/cdm/renderer/widevine_key_system_properties.cc b/components/cdm/renderer/widevine_key_system_properties.cc index f0b2812..05f6d81 100644 --- a/components/cdm/renderer/widevine_key_system_properties.cc +++ b/components/cdm/renderer/widevine_key_system_properties.cc
@@ -4,6 +4,7 @@ #include "components/cdm/renderer/widevine_key_system_properties.h" +#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/feature_list.h" #include "build/build_config.h" @@ -144,12 +145,19 @@ #if defined(OS_CHROMEOS) // Hardware security requires HWDRM or remote attestation, both of these // require an identifier. - if (robustness >= Robustness::HW_SECURE_CRYPTO || hw_secure_codecs_required) + if (robustness >= Robustness::HW_SECURE_CRYPTO || hw_secure_codecs_required) { #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia)) { + return EmeConfigRule::IDENTIFIER_REQUIRED; + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) return EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED; #else return EmeConfigRule::IDENTIFIER_REQUIRED; #endif + } // For video, recommend remote attestation if HW_SECURE_ALL is available, // regardless of the value of |robustness|, because it enables hardware
diff --git a/components/download/network/network_status_listener.h b/components/download/network/network_status_listener.h index c4d68d3..a6d973d 100644 --- a/components/download/network/network_status_listener.h +++ b/components/download/network/network_status_listener.h
@@ -47,7 +47,8 @@ protected: NetworkStatusListener(); - // The only observer that listens to connection type change. + // The only observer that listens to connection type change. Must outlive this + // class. Observer* observer_ = nullptr; // The current network status.
diff --git a/components/download/network/network_status_listener_impl.cc b/components/download/network/network_status_listener_impl.cc index bcc011a..34674b1 100644 --- a/components/download/network/network_status_listener_impl.cc +++ b/components/download/network/network_status_listener_impl.cc
@@ -21,7 +21,7 @@ bool sync = network_connection_tracker_->GetConnectionType( &connection_type_, base::BindOnce(&NetworkStatusListenerImpl::OnNetworkStatusReady, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); if (sync) observer_->OnNetworkStatusReady(connection_type_); }
diff --git a/components/download/network/network_status_listener_impl.h b/components/download/network/network_status_listener_impl.h index 7aad4813..69b9473 100644 --- a/components/download/network/network_status_listener_impl.h +++ b/components/download/network/network_status_listener_impl.h
@@ -6,6 +6,7 @@ #define COMPONENTS_DOWNLOAD_NETWORK_NETWORK_STATUS_LISTENER_IMPL_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "components/download/network/network_status_listener.h" #include "services/network/public/cpp/network_connection_tracker.h" @@ -34,6 +35,7 @@ network::NetworkConnectionTracker* network_connection_tracker_; + base::WeakPtrFactory<NetworkStatusListenerImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(NetworkStatusListenerImpl); };
diff --git a/components/management_strings.grdp b/components/management_strings.grdp index c9fb9eb..82d9120 100644 --- a/components/management_strings.grdp +++ b/components/management_strings.grdp
@@ -47,12 +47,22 @@ <!-- Browser managed status section --> <if expr="not chromeos"> - <message name="IDS_MANAGEMENT_BROWSER_NOTICE" desc="Message shown when the browser is managed, it indicates what the administrator can do on the browser."> + <if expr="_google_chrome"> + <message name="IDS_MANAGEMENT_BROWSER_NOTICE" desc="Message shown when the (Google-branded) Chrome browser is managed, it indicates what the administrator can do on the browser."> Your administrator can change your browser setup remotely. Activity on this device may also be managed outside of Chrome. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a></ph> - </message> - <message name="IDS_MANAGEMENT_NOT_MANAGED_NOTICE" desc="Message indicating that the browser is not managed"> - This browser is not managed by a company or other organization. Activity on this device may be managed outside of Chrome. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a></ph> - </message> + </message> + <message name="IDS_MANAGEMENT_NOT_MANAGED_NOTICE" desc="Message indicating that the (Google-branded) Chrome browser is not managed"> + This browser is not managed by a company or other organization. Activity on this device may be managed outside of Chrome. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a></ph> + </message> + </if> + <if expr="not _google_chrome"> + <message name="IDS_MANAGEMENT_BROWSER_NOTICE" desc="Message shown when the (non-Google-branded) Chromium browser is managed, it indicates what the administrator can do on the browser."> + Your administrator can change your browser setup remotely. Activity on this device may also be managed outside of Chromium. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a></ph> + </message> + <message name="IDS_MANAGEMENT_NOT_MANAGED_NOTICE" desc="Message indicating that the (non-Google-branded) Chromium browser is not managed"> + This browser is not managed by a company or other organization. Activity on this device may be managed outside of Chromium. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a></ph> + </message> + </if> </if> <!-- Chrome OS managed status section -->
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_BROWSER_NOTICE.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_BROWSER_NOTICE.png.sha1 index e88b7c0..2ea1997 100644 --- a/components/management_strings_grdp/IDS_MANAGEMENT_BROWSER_NOTICE.png.sha1 +++ b/components/management_strings_grdp/IDS_MANAGEMENT_BROWSER_NOTICE.png.sha1
@@ -1 +1 @@ -fe07e19a701b3e8ee95eb5062063ac53cfdbe4f3 \ No newline at end of file +ad0a9ae496e2d8a74660cd371bcc9acc79b475a2 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_NOT_MANAGED_NOTICE.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_NOT_MANAGED_NOTICE.png.sha1 index e88b7c0..20ed25a 100644 --- a/components/management_strings_grdp/IDS_MANAGEMENT_NOT_MANAGED_NOTICE.png.sha1 +++ b/components/management_strings_grdp/IDS_MANAGEMENT_NOT_MANAGED_NOTICE.png.sha1
@@ -1 +1 @@ -fe07e19a701b3e8ee95eb5062063ac53cfdbe4f3 \ No newline at end of file +1a56c5e54aeb312486f7f3b4564cc6f64525aac3 \ No newline at end of file
diff --git a/components/media_router/browser/media_router_metrics.cc b/components/media_router/browser/media_router_metrics.cc index 25b1512..95337e7 100644 --- a/components/media_router/browser/media_router_metrics.cc +++ b/components/media_router/browser/media_router_metrics.cc
@@ -9,8 +9,10 @@ #include "base/macros.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/time/default_clock.h" +#include "components/media_router/common/media_route_provider_helper.h" #include "components/media_router/common/media_sink.h" #include "components/media_router/common/media_source.h" #include "components/media_router/common/mojom/media_router.mojom.h" @@ -49,6 +51,24 @@ } } +std::string GetDeviceCountHistogramName(const std::string& ui, + MediaRouterDialogOpenOrigin origin, + mojom::MediaRouteProviderId provider, + bool is_available) { + std::string trigger; + switch (origin) { + case MediaRouterDialogOpenOrigin::PAGE: + trigger = "PresentationApi"; + break; + default: + trigger = "BrowserUi"; + } + std::string mrp = ProviderIdToString(provider); + std::string state = is_available ? "Available" : "Unavailable"; + return base::StrCat({MediaRouterMetrics::kHistogramUiDeviceCount, ".", ui, + ".", trigger, ".", mrp, ".", state}); +} + PresentationUrlType GetPresentationUrlType(const GURL& url) { if (url.SchemeIs(kDialPresentationUrlScheme)) return PresentationUrlType::kDial; @@ -114,6 +134,10 @@ "MediaRouter.Ui.IconStateAtInit"; // static +const base::TimeDelta MediaRouterMetrics::kDeviceCountMetricDelay = + base::TimeDelta::FromSeconds(3); + +// static void MediaRouterMetrics::RecordMediaRouterDialogOrigin( MediaRouterDialogOpenOrigin origin) { DCHECK_LT(static_cast<int>(origin), @@ -192,6 +216,30 @@ } // static +void MediaRouterMetrics::RecordGmcDeviceCount( + MediaRouterDialogOpenOrigin origin, + mojom::MediaRouteProviderId provider, + bool is_available, + int count) { + base::UmaHistogramCounts100( + GetDeviceCountHistogramName("GlobalMediaControls", origin, provider, + is_available), + count); +} + +// static +void MediaRouterMetrics::RecordCastDialogDeviceCount( + MediaRouterDialogOpenOrigin origin, + mojom::MediaRouteProviderId provider, + bool is_available, + int count) { + base::UmaHistogramCounts100( + GetDeviceCountHistogramName("CastHarmony", origin, provider, + is_available), + count); +} + +// static void MediaRouterMetrics::RecordStartRouteDeviceIndex(int index) { base::UmaHistogramSparse(kHistogramStartLocalPosition, std::min(index, 100)); }
diff --git a/components/media_router/browser/media_router_metrics.h b/components/media_router/browser/media_router_metrics.h index 0a3c590..5cf0a48 100644 --- a/components/media_router/browser/media_router_metrics.h +++ b/components/media_router/browser/media_router_metrics.h
@@ -68,9 +68,10 @@ CONTEXTUAL_MENU = 2, PAGE = 3, APP_MENU = 4, + SYSTEM_TRAY = 5, // NOTE: Add entries only immediately above this line. - TOTAL_COUNT = 5 + TOTAL_COUNT = 6 }; // The possible outcomes from a route creation response. @@ -139,6 +140,10 @@ static const char kHistogramUiFirstAction[]; static const char kHistogramUiIconStateAtInit[]; + // When recording the number of devices shown in UI we record after a delay + // because discovering devices can take some time after the UI is shown. + static const base::TimeDelta kDeviceCountMetricDelay; + // Records where the user clicked to open the Media Router dialog. static void RecordMediaRouterDialogOrigin(MediaRouterDialogOpenOrigin origin); @@ -180,6 +185,17 @@ // may be 0. static void RecordDeviceCount(int device_count); + // Records the number of sinks in |is_available| state, provided by |provider| + // that was opened via |origin|. + static void RecordGmcDeviceCount(MediaRouterDialogOpenOrigin origin, + mojom::MediaRouteProviderId provider, + bool is_available, + int count); + static void RecordCastDialogDeviceCount(MediaRouterDialogOpenOrigin origin, + mojom::MediaRouteProviderId provider, + bool is_available, + int count); + // Records the index of the device the user has started casting to on the // devices list. The index starts at 0. static void RecordStartRouteDeviceIndex(int index);
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 57b0438..6f643acbd5 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -1302,6 +1302,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Use New Tab Page as homepage', + }, + { + 'value': False, + 'caption': 'Do not use New Tab Page as homepage', + }, + ], 'example_value': True, 'id': 2, 'caption': '''Use New Tab Page as homepage''', @@ -1349,6 +1359,16 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable the default browser check on startup', + }, + { + 'value': False, + 'caption': 'Disable the default browser check on startup', + }, + ], 'example_value': True, 'id': 3, 'caption': '''Set <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> as Default Browser''', @@ -1398,6 +1418,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable alternate error pages', + }, + { + 'value': False, + 'caption': 'Disable alternate error pages', + }, + ], 'example_value': True, 'id': 5, 'caption': '''Enable alternate error pages''', @@ -1422,6 +1452,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable search suggestions', + }, + { + 'value': False, + 'caption': 'Disable search suggestions', + }, + ], 'example_value': True, 'id': 6, 'caption': '''Enable search suggestions''', @@ -1443,6 +1483,16 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Detect covered window and suspend its painting', + }, + { + 'value': False, + 'caption': 'Do not detect covered window', + }, + ], 'deprecated': True, 'example_value': True, 'id': 675, @@ -1653,6 +1703,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable globally scoped HTTP authentication cache', + }, + { + 'value': False, + 'caption': 'Disable globally scoped HTTP authentication cache', + }, + ], 'example_value': False, 'id': 643, 'caption': '''Enable globally scoped HTTP auth cache''', @@ -1756,6 +1816,16 @@ 'dynamic_refresh': False, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable HTTP/0.9 support on non-default ports', + }, + { + 'value': False, + 'caption': 'Disable HTTP/0.9 support on non-default ports', + }, + ], 'example_value': False, 'id': 345, 'caption': '''Enable HTTP/0.9 support on non-default ports''',
diff --git a/components/renderer_context_menu/context_menu_content_type.cc b/components/renderer_context_menu/context_menu_content_type.cc index 93376436..8c13b5f 100644 --- a/components/renderer_context_menu/context_menu_content_type.cc +++ b/components/renderer_context_menu/context_menu_content_type.cc
@@ -160,7 +160,8 @@ blink::mojom::ContextMenuDataInputFieldType::kPassword; case ITEM_GROUP_LENS_REGION_SEARCH: - return true; + // Region Search is only enabled when image options are not. + return !SupportsGroupInternal(ITEM_GROUP_SEARCHWEBFORIMAGE); default: NOTREACHED();
diff --git a/components/resources/components_scaled_resources.grd b/components/resources/components_scaled_resources.grd index b404cac..940244d 100644 --- a/components/resources/components_scaled_resources.grd +++ b/components/resources/components_scaled_resources.grd
@@ -22,7 +22,6 @@ <!-- Generic resources --> <if expr="not is_android"> <structure type="chrome_scaled_image" name="IDR_HISTORY_FAVICON" file="favicon_history.png" /> - <structure type="chrome_scaled_image" name="IDR_INFO_FAVICON" file="favicon_info.png" /> </if> <structure type="chrome_scaled_image" name="IDR_SAD_WEBVIEW" file="webview-crash.png" /> <structure type="chrome_scaled_image" name="IDR_SAD_PLUGIN" file="sadplugin.png" />
diff --git a/components/resources/default_100_percent/favicon_info.png b/components/resources/default_100_percent/favicon_info.png deleted file mode 100644 index bdd0358..0000000 --- a/components/resources/default_100_percent/favicon_info.png +++ /dev/null Binary files differ
diff --git a/components/resources/default_200_percent/favicon_info.png b/components/resources/default_200_percent/favicon_info.png deleted file mode 100644 index 07f97a6..0000000 --- a/components/resources/default_200_percent/favicon_info.png +++ /dev/null Binary files differ
diff --git a/components/resources/default_300_percent/favicon_info.png b/components/resources/default_300_percent/favicon_info.png deleted file mode 100644 index fc1108a..0000000 --- a/components/resources/default_300_percent/favicon_info.png +++ /dev/null Binary files differ
diff --git a/components/test/data/history/README.md b/components/test/data/history/README.md index 1acdc663..bbd58412 100644 --- a/components/test/data/history/README.md +++ b/components/test/data/history/README.md
@@ -4,7 +4,7 @@ 1. Build the `sqlite_shell` target. This will build the [SQLite CLI]. - $ ninja sqlite_shell + $ ninja -C out/Debug/ sqlite_shell 2. Run Chrome/Chromium with a fresh profile directory and immediately quit. It doesn't really matter how long you run it, but there'll be less work for you @@ -12,14 +12,17 @@ $ out/Debug/chrome-wrapper --user-data-dir=foo -3. Locate the `History` file in the profile directory. +3. Locate the `History` file in the user-data-dir directory; e.g., `foo/Default/History`. 4. Dump the `History` database into a text file: - $ echo '.dump' | sqlite_shell foo/Default/History > history.sql + $ echo '.dump' | out/Debug/sqlite_shell foo/Default/History > history.sql 5. Manually remove all `INSERT INTO` statements other than the statements populating the `meta` table. +To generate history.N.sql, be sure to run these steps before implementing the N+1 migration in +chromium. I.e. you'll usually want to run these steps on the main branch rather than the CL branch. + [SQLite CLI]: https://www.sqlite.org/cli.html
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6b5ecc1..d13c610 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -757,6 +757,8 @@ "devtools/devtools_video_consumer.h", "devtools/forwarding_agent_host.cc", "devtools/forwarding_agent_host.h", + "devtools/frame_auto_attacher.cc", + "devtools/frame_auto_attacher.h", "devtools/network_service_devtools_observer.cc", "devtools/network_service_devtools_observer.h", "devtools/protocol/audits_handler.cc",
diff --git a/content/browser/devtools/frame_auto_attacher.cc b/content/browser/devtools/frame_auto_attacher.cc new file mode 100644 index 0000000..49299584 --- /dev/null +++ b/content/browser/devtools/frame_auto_attacher.cc
@@ -0,0 +1,267 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/frame_auto_attacher.h" + +#include "content/browser/devtools/devtools_renderer_channel.h" +#include "content/browser/devtools/render_frame_devtools_agent_host.h" +#include "content/browser/devtools/service_worker_devtools_agent_host.h" +#include "content/browser/renderer_host/frame_tree.h" +#include "content/browser/renderer_host/navigation_request.h" +#include "content/browser/web_contents/web_contents_impl.h" + +namespace content { + +namespace { + +using ScopeAgentsMap = + std::map<GURL, std::unique_ptr<ServiceWorkerDevToolsAgentHost::List>>; + +void GetMatchingHostsByScopeMap( + const ServiceWorkerDevToolsAgentHost::List& agent_hosts, + const base::flat_set<GURL>& urls, + ScopeAgentsMap* scope_agents_map) { + base::flat_set<GURL> host_name_set; + for (const GURL& url : urls) + host_name_set.insert(url.GetOrigin()); + for (const auto& host : agent_hosts) { + if (host_name_set.find(host->scope().GetOrigin()) == host_name_set.end()) + continue; + const auto& it = scope_agents_map->find(host->scope()); + if (it == scope_agents_map->end()) { + std::unique_ptr<ServiceWorkerDevToolsAgentHost::List> new_list( + new ServiceWorkerDevToolsAgentHost::List()); + new_list->push_back(host); + (*scope_agents_map)[host->scope()] = std::move(new_list); + } else { + it->second->push_back(host); + } + } +} + +void AddEligibleHosts(const ServiceWorkerDevToolsAgentHost::List& list, + ServiceWorkerDevToolsAgentHost::Map* result) { + base::Time last_installed_time; + base::Time last_doomed_time; + for (const auto& host : list) { + if (host->version_installed_time() > last_installed_time) + last_installed_time = host->version_installed_time(); + if (host->version_doomed_time() > last_doomed_time) + last_doomed_time = host->version_doomed_time(); + } + for (const auto& host : list) { + // We don't attech old redundant Service Workers when there is newer + // installed Service Worker. + if (host->version_doomed_time().is_null() || + (last_installed_time < last_doomed_time && + last_doomed_time == host->version_doomed_time())) { + (*result)[host->GetId()] = host; + } + } +} + +ServiceWorkerDevToolsAgentHost::Map GetMatchingServiceWorkers( + BrowserContext* browser_context, + const base::flat_set<GURL>& urls) { + ServiceWorkerDevToolsAgentHost::Map result; + if (!browser_context) + return result; + + ServiceWorkerDevToolsAgentHost::List agent_hosts; + ServiceWorkerDevToolsManager::GetInstance() + ->AddAllAgentHostsForBrowserContext(browser_context, &agent_hosts); + + ScopeAgentsMap scope_agents_map; + GetMatchingHostsByScopeMap(agent_hosts, urls, &scope_agents_map); + + for (const auto& it : scope_agents_map) + AddEligibleHosts(*it.second.get(), &result); + + return result; +} + +base::flat_set<GURL> GetFrameUrls(RenderFrameHostImpl* render_frame_host) { + // We try to attach to a service worker in the following cases: + // 1. SW is created while user is inspecting frame (from WorkerCreated). + // 2. Frame has navigated and we are picking up new SW corresponding to new + // url (from DidFinishNavigation). + // 3. Frame is trying to navigate and it spawns a new SW which we pick up + // (from WorkerCreated). See also https://crbug.com/907072 + // + // We are not attaching in the following case: + // 4. Frame is trying to navigate and we _should_ pick up an existing SW but + // we don't. We _could_ do this, but since we are not pausing the + // navigation, there is no principal difference between picking up SW + // earlier or later. + // + // We also try to detach from SW picked up for [3] if navigation has failed + // (from DidFinishNavigation). + + base::flat_set<GURL> frame_urls; + if (render_frame_host) { + for (FrameTreeNode* node : render_frame_host->frame_tree()->Nodes()) { + frame_urls.insert(node->current_url()); + // We use both old and new frame urls to support [3], where we attach + // while navigation is still ongoing. + if (node->navigation_request()) { + frame_urls.insert(node->navigation_request()->common_params().url); + } + } + } + return frame_urls; +} + +} // namespace + +FrameAutoAttacher::FrameAutoAttacher(DevToolsRendererChannel* renderer_channel) + : RendererAutoAttacherBase(renderer_channel) {} + +FrameAutoAttacher::~FrameAutoAttacher() = default; + +void FrameAutoAttacher::SetRenderFrameHost( + RenderFrameHostImpl* render_frame_host) { + render_frame_host_ = render_frame_host; + if (!auto_attach()) + return; + UpdateFrames(); + UpdatePortals(); + ReattachServiceWorkers(); +} + +void FrameAutoAttacher::DidFinishNavigation( + NavigationRequest* navigation_request) { + if (!render_frame_host_) + return; + + if (navigation_request->frame_tree_node() == + render_frame_host_->frame_tree_node()) { + ReattachServiceWorkers(); + return; + } + + // We only care about subframes that have |render_frame_host_| as their + // local root. + if (!navigation_request->HasCommitted()) + return; + RenderFrameHostImpl* parent = navigation_request->GetParentFrame(); + while (parent && !parent->is_local_root()) + parent = parent->GetParent(); + if (parent != render_frame_host_) + return; + + // Some subframes may not be attached through + // TargetHandler::ResponseThrottle because DevTools wasn't attached when the + // navigation started, so no throttle was installed. We auto-attach them + // here instead (note that we cannot honor |wait_for_debugger_on_start_| in + // this case). + AutoAttachToFrame(navigation_request, false); +} + +void FrameAutoAttacher::UpdatePortals() { + if (!auto_attach()) + return; + + Hosts new_hosts; + if (render_frame_host_ && + render_frame_host_->frame_tree_node()->IsMainFrame()) { + WebContentsImpl* outer_web_contents = static_cast<WebContentsImpl*>( + WebContents::FromRenderFrameHost(render_frame_host_)); + for (WebContents* web_contents : + outer_web_contents->GetInnerWebContents()) { + WebContentsImpl* web_contents_impl = + static_cast<WebContentsImpl*>(web_contents); + if (!web_contents_impl->IsPortal()) + continue; + + scoped_refptr<DevToolsAgentHost> new_host = + RenderFrameDevToolsAgentHost::GetOrCreateFor( + web_contents_impl->GetFrameTree()->root()); + new_hosts.insert(new_host); + } + } + + DispatchSetAttachedTargetsOfType(new_hosts, DevToolsAgentHost::kTypePage); +} + +void FrameAutoAttacher::UpdateAutoAttach(base::OnceClosure callback) { + if (auto_attach()) { + if (render_frame_host_ && !render_frame_host_->GetParent() && + !observing_service_workers_) { + observing_service_workers_ = true; + ServiceWorkerDevToolsManager::GetInstance()->AddObserver(this); + ReattachServiceWorkers(); + UpdateFrames(); + UpdatePortals(); + } + } else if (observing_service_workers_) { + ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this); + observing_service_workers_ = false; + } + RendererAutoAttacherBase::UpdateAutoAttach(std::move(callback)); +} + +void FrameAutoAttacher::WorkerCreated(ServiceWorkerDevToolsAgentHost* host, + bool* should_pause_on_start) { + if (!render_frame_host_) + return; + BrowserContext* browser_context = + render_frame_host_->GetProcess()->GetBrowserContext(); + auto hosts = GetMatchingServiceWorkers(browser_context, + GetFrameUrls(render_frame_host_)); + if (hosts.find(host->GetId()) == hosts.end()) + return; + + *should_pause_on_start = wait_for_debugger_on_start(); + DispatchAutoAttach(host, *should_pause_on_start); +} + +void FrameAutoAttacher::WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) { + ReattachServiceWorkers(); +} + +void FrameAutoAttacher::ReattachServiceWorkers() { + if (!observing_service_workers_ || !render_frame_host_) + return; + BrowserContext* browser_context = + render_frame_host_->GetProcess()->GetBrowserContext(); + auto matching = GetMatchingServiceWorkers(browser_context, + GetFrameUrls(render_frame_host_)); + Hosts new_hosts; + for (const auto& pair : matching) + new_hosts.insert(pair.second); + DispatchSetAttachedTargetsOfType(new_hosts, + DevToolsAgentHost::kTypeServiceWorker); +} + +void FrameAutoAttacher::UpdateFrames() { + DCHECK(auto_attach()); + + Hosts new_hosts; + if (render_frame_host_) { + base::queue<FrameTreeNode*> queue; + for (size_t i = 0; i < render_frame_host_->child_count(); ++i) { + queue.push(render_frame_host_->child_at(i)); + } + while (!queue.empty()) { + FrameTreeNode* node = queue.front(); + queue.pop(); + bool should_create = node->current_frame_host()->is_local_root_subframe(); + if (should_create) { + scoped_refptr<DevToolsAgentHost> new_host = + RenderFrameDevToolsAgentHost::GetOrCreateFor(node); + new_hosts.insert(new_host); + // Note: We don't add children of a local root to |queue|, as they + // will be looked at by a separate TargetAutoAttacher created for the + // local root. + } else { + for (size_t i = 0; i < node->child_count(); ++i) + queue.push(node->child_at(i)); + } + } + } + + DispatchSetAttachedTargetsOfType(new_hosts, DevToolsAgentHost::kTypeFrame); +} + +} // namespace content
diff --git a/content/browser/devtools/frame_auto_attacher.h b/content/browser/devtools/frame_auto_attacher.h new file mode 100644 index 0000000..2df2e52 --- /dev/null +++ b/content/browser/devtools/frame_auto_attacher.h
@@ -0,0 +1,47 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CONTENT_BROWSER_DEVTOOLS_FRAME_AUTO_ATTACHER_H_ +#define CONTENT_BROWSER_DEVTOOLS_FRAME_AUTO_ATTACHER_H_ + +#include "base/callback.h" +#include "content/browser/devtools/protocol/target_auto_attacher.h" +#include "content/browser/devtools/service_worker_devtools_manager.h" + +namespace content { + +class DevToolsRendererChannel; +class NavigationRequest; +class RenderFrameHostImpl; +class ServiceWorkerDevToolsAgentHost; + +class FrameAutoAttacher : public protocol::RendererAutoAttacherBase, + public ServiceWorkerDevToolsManager::Observer { + public: + explicit FrameAutoAttacher(DevToolsRendererChannel* renderer_channel); + ~FrameAutoAttacher() override; + + void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host); + void DidFinishNavigation(NavigationRequest* navigation_request); + void UpdatePortals(); + + protected: + // Base overrides. + void UpdateAutoAttach(base::OnceClosure callback) override; + + // ServiceWorkerDevToolsManager::Observer implementation. + void WorkerCreated(ServiceWorkerDevToolsAgentHost* host, + bool* should_pause_on_start) override; + void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) override; + + void ReattachServiceWorkers(); + void UpdateFrames(); + + private: + RenderFrameHostImpl* render_frame_host_ = nullptr; + bool observing_service_workers_ = false; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_FRAME_AUTO_ATTACHER_H_
diff --git a/content/browser/devtools/protocol/target_auto_attacher.cc b/content/browser/devtools/protocol/target_auto_attacher.cc index 72293ec..1510f3e5 100644 --- a/content/browser/devtools/protocol/target_auto_attacher.cc +++ b/content/browser/devtools/protocol/target_auto_attacher.cc
@@ -4,12 +4,8 @@ #include "content/browser/devtools/protocol/target_auto_attacher.h" -#include "base/auto_reset.h" -#include "base/containers/queue.h" #include "content/browser/devtools/devtools_renderer_channel.h" #include "content/browser/devtools/render_frame_devtools_agent_host.h" -#include "content/browser/devtools/service_worker_devtools_agent_host.h" -#include "content/browser/renderer_host/frame_tree.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/render_frame_host_impl.h"
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index 1ccc64a..02bd11d 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -22,6 +22,7 @@ #include "content/browser/devtools/devtools_manager.h" #include "content/browser/devtools/devtools_renderer_channel.h" #include "content/browser/devtools/devtools_session.h" +#include "content/browser/devtools/frame_auto_attacher.h" #include "content/browser/devtools/protocol/audits_handler.h" #include "content/browser/devtools/protocol/background_service_handler.h" #include "content/browser/devtools/protocol/browser_handler.h" @@ -100,264 +101,8 @@ ftn->current_frame_host())); } -using ScopeAgentsMap = - std::map<GURL, std::unique_ptr<ServiceWorkerDevToolsAgentHost::List>>; - -void GetMatchingHostsByScopeMap( - const ServiceWorkerDevToolsAgentHost::List& agent_hosts, - const base::flat_set<GURL>& urls, - ScopeAgentsMap* scope_agents_map) { - base::flat_set<GURL> host_name_set; - for (const GURL& url : urls) - host_name_set.insert(url.GetOrigin()); - for (const auto& host : agent_hosts) { - if (host_name_set.find(host->scope().GetOrigin()) == host_name_set.end()) - continue; - const auto& it = scope_agents_map->find(host->scope()); - if (it == scope_agents_map->end()) { - std::unique_ptr<ServiceWorkerDevToolsAgentHost::List> new_list( - new ServiceWorkerDevToolsAgentHost::List()); - new_list->push_back(host); - (*scope_agents_map)[host->scope()] = std::move(new_list); - } else { - it->second->push_back(host); - } - } -} - -void AddEligibleHosts(const ServiceWorkerDevToolsAgentHost::List& list, - ServiceWorkerDevToolsAgentHost::Map* result) { - base::Time last_installed_time; - base::Time last_doomed_time; - for (const auto& host : list) { - if (host->version_installed_time() > last_installed_time) - last_installed_time = host->version_installed_time(); - if (host->version_doomed_time() > last_doomed_time) - last_doomed_time = host->version_doomed_time(); - } - for (const auto& host : list) { - // We don't attech old redundant Service Workers when there is newer - // installed Service Worker. - if (host->version_doomed_time().is_null() || - (last_installed_time < last_doomed_time && - last_doomed_time == host->version_doomed_time())) { - (*result)[host->GetId()] = host; - } - } -} - -ServiceWorkerDevToolsAgentHost::Map GetMatchingServiceWorkers( - BrowserContext* browser_context, - const base::flat_set<GURL>& urls) { - ServiceWorkerDevToolsAgentHost::Map result; - if (!browser_context) - return result; - - ServiceWorkerDevToolsAgentHost::List agent_hosts; - ServiceWorkerDevToolsManager::GetInstance() - ->AddAllAgentHostsForBrowserContext(browser_context, &agent_hosts); - - ScopeAgentsMap scope_agents_map; - GetMatchingHostsByScopeMap(agent_hosts, urls, &scope_agents_map); - - for (const auto& it : scope_agents_map) - AddEligibleHosts(*it.second.get(), &result); - - return result; -} - -base::flat_set<GURL> GetFrameUrls(RenderFrameHostImpl* render_frame_host) { - // We try to attach to a service worker in the following cases: - // 1. SW is created while user is inspecting frame (from WorkerCreated). - // 2. Frame has navigated and we are picking up new SW corresponding to new - // url (from DidFinishNavigation). - // 3. Frame is trying to navigate and it spawns a new SW which we pick up - // (from WorkerCreated). See also https://crbug.com/907072 - // - // We are not attaching in the following case: - // 4. Frame is trying to navigate and we _should_ pick up an existing SW but - // we don't. We _could_ do this, but since we are not pausing the - // navigation, there is no principal difference between picking up SW - // earlier or later. - // - // We also try to detach from SW picked up for [3] if navigation has failed - // (from DidFinishNavigation). - - base::flat_set<GURL> frame_urls; - if (render_frame_host) { - for (FrameTreeNode* node : render_frame_host->frame_tree()->Nodes()) { - frame_urls.insert(node->current_url()); - // We use both old and new frame urls to support [3], where we attach - // while navigation is still ongoing. - if (node->navigation_request()) { - frame_urls.insert(node->navigation_request()->common_params().url); - } - } - } - return frame_urls; -} - } // namespace -class RenderFrameDevToolsAgentHost::FrameAutoAttacher - : public protocol::RendererAutoAttacherBase, - public ServiceWorkerDevToolsManager::Observer { - public: - explicit FrameAutoAttacher(DevToolsRendererChannel* renderer_channel) - : RendererAutoAttacherBase(renderer_channel) {} - ~FrameAutoAttacher() override = default; - - void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) { - render_frame_host_ = render_frame_host; - if (!auto_attach()) - return; - UpdateFrames(); - UpdatePortals(); - ReattachServiceWorkers(); - } - - void DidFinishNavigation(NavigationRequest* navigation_request) { - if (!render_frame_host_) - return; - - if (navigation_request->frame_tree_node() == - render_frame_host_->frame_tree_node()) { - ReattachServiceWorkers(); - return; - } - - // We only care about subframes that have |render_frame_host_| as their - // local root. - if (!navigation_request->HasCommitted()) - return; - RenderFrameHostImpl* parent = navigation_request->GetParentFrame(); - while (parent && !parent->is_local_root()) - parent = parent->GetParent(); - if (parent != render_frame_host_) - return; - - // Some subframes may not be attached through - // TargetHandler::ResponseThrottle because DevTools wasn't attached when the - // navigation started, so no throttle was installed. We auto-attach them - // here instead (note that we cannot honor |wait_for_debugger_on_start_| in - // this case). - AutoAttachToFrame(navigation_request, false); - } - - void UpdatePortals() { - if (!auto_attach()) - return; - - Hosts new_hosts; - if (render_frame_host_ && - render_frame_host_->frame_tree_node()->IsMainFrame()) { - WebContentsImpl* outer_web_contents = static_cast<WebContentsImpl*>( - WebContents::FromRenderFrameHost(render_frame_host_)); - for (WebContents* web_contents : - outer_web_contents->GetInnerWebContents()) { - WebContentsImpl* web_contents_impl = - static_cast<WebContentsImpl*>(web_contents); - if (!web_contents_impl->IsPortal()) - continue; - - scoped_refptr<DevToolsAgentHost> new_host = - RenderFrameDevToolsAgentHost::GetOrCreateFor( - web_contents_impl->GetFrameTree()->root()); - new_hosts.insert(new_host); - } - } - - DispatchSetAttachedTargetsOfType(new_hosts, DevToolsAgentHost::kTypePage); - } - - protected: - // ServiceWorkerDevToolsManager::Observer implementation. - void WorkerCreated(ServiceWorkerDevToolsAgentHost* host, - bool* should_pause_on_start) override { - if (!render_frame_host_) - return; - BrowserContext* browser_context = - render_frame_host_->GetProcess()->GetBrowserContext(); - auto hosts = GetMatchingServiceWorkers(browser_context, - GetFrameUrls(render_frame_host_)); - if (hosts.find(host->GetId()) == hosts.end()) - return; - - *should_pause_on_start = wait_for_debugger_on_start(); - DispatchAutoAttach(host, *should_pause_on_start); - } - - void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) override { - ReattachServiceWorkers(); - } - - void ReattachServiceWorkers() { - if (!observing_service_workers_ || !render_frame_host_) - return; - BrowserContext* browser_context = - render_frame_host_->GetProcess()->GetBrowserContext(); - auto matching = GetMatchingServiceWorkers(browser_context, - GetFrameUrls(render_frame_host_)); - Hosts new_hosts; - for (const auto& pair : matching) - new_hosts.insert(pair.second); - DispatchSetAttachedTargetsOfType(new_hosts, - DevToolsAgentHost::kTypeServiceWorker); - } - - void UpdateAutoAttach(base::OnceClosure callback) override { - if (auto_attach()) { - if (render_frame_host_ && !render_frame_host_->GetParent() && - !observing_service_workers_) { - observing_service_workers_ = true; - ServiceWorkerDevToolsManager::GetInstance()->AddObserver(this); - ReattachServiceWorkers(); - UpdateFrames(); - UpdatePortals(); - } - } else if (observing_service_workers_) { - ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this); - observing_service_workers_ = false; - } - RendererAutoAttacherBase::UpdateAutoAttach(std::move(callback)); - } - - void UpdateFrames() { - DCHECK(auto_attach()); - - Hosts new_hosts; - if (render_frame_host_) { - base::queue<FrameTreeNode*> queue; - for (size_t i = 0; i < render_frame_host_->child_count(); ++i) { - queue.push(render_frame_host_->child_at(i)); - } - while (!queue.empty()) { - FrameTreeNode* node = queue.front(); - queue.pop(); - bool should_create = - node->current_frame_host()->is_local_root_subframe(); - if (should_create) { - scoped_refptr<DevToolsAgentHost> new_host = - RenderFrameDevToolsAgentHost::GetOrCreateFor(node); - new_hosts.insert(new_host); - // Note: We don't add children of a local root to |queue|, as they - // will be looked at by a separate TargetAutoAttacher created for the - // local root. - } else { - for (size_t i = 0; i < node->child_count(); ++i) - queue.push(node->child_at(i)); - } - } - } - - DispatchSetAttachedTargetsOfType(new_hosts, DevToolsAgentHost::kTypeFrame); - } - - private: - RenderFrameHostImpl* render_frame_host_ = nullptr; - bool observing_service_workers_ = false; -}; - FrameTreeNode* GetFrameTreeNodeAncestor(FrameTreeNode* frame_tree_node) { while (frame_tree_node && !ShouldCreateDevToolsForNode(frame_tree_node)) frame_tree_node = FrameTreeNode::From(frame_tree_node->parent());
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h index 20dbd30..e9634fd 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.h +++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -35,6 +35,7 @@ class BrowserContext; class DevToolsFrameTraceRecorder; class FrameTreeNode; +class FrameAutoAttacher; class NavigationRequest; class RenderFrameHostImpl; @@ -113,7 +114,6 @@ private: friend class DevToolsAgentHost; - class FrameAutoAttacher; static void UpdateRawHeadersAccess(RenderFrameHostImpl* rfh);
diff --git a/content/browser/file_system_access/file_system_access_file_delegate_host_impl.cc b/content/browser/file_system_access/file_system_access_file_delegate_host_impl.cc index 5bdaded..988dd00ed 100644 --- a/content/browser/file_system_access/file_system_access_file_delegate_host_impl.cc +++ b/content/browser/file_system_access/file_system_access_file_delegate_host_impl.cc
@@ -8,6 +8,8 @@ #include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/bind.h" +#include "base/callback_forward.h" +#include "base/callback_helpers.h" #include "base/location.h" #include "base/memory/scoped_refptr.h" #include "base/numerics/safe_math.h" @@ -26,7 +28,9 @@ namespace { -void ReadOnIOThread(storage::FileStreamReader* reader, +void ReadOnIOThread(scoped_refptr<storage::FileSystemContext> context, + storage::FileSystemURL url, + uint64_t offset, scoped_refptr<storage::BigIOBuffer> buffer, scoped_refptr<base::SequencedTaskRunner> reply_runner, base::OnceCallback<void(int)> callback) { @@ -35,12 +39,24 @@ auto wrapped_callback = base::BindPostTask(std::move(reply_runner), std::move(callback)); + // The reader must be constructed on the IO thread. + std::unique_ptr<storage::FileStreamReader> reader = + context->CreateFileStreamReader( + url, offset, /*max_bytes_to_read=*/buffer->size(), base::Time()); + // Create two copies of |wrapped_callback| though it can still only be // called at most once. This is safe because Read() is guaranteed not to // call |wrapped_callback| if it returns synchronously. auto split_callback = base::SplitOnceCallback(std::move(wrapped_callback)); - int rv = reader->Read(buffer.get(), buffer->size(), - base::BindOnce(std::move(split_callback.first))); + // Keep the reader alive by binding it to its callback. + storage::FileStreamReader* reader_ptr = reader.get(); + int rv = reader_ptr->Read( + buffer.get(), buffer->size(), + base::BindOnce( + [](std::unique_ptr<storage::FileStreamReader>, + base::OnceCallback<void(int)> callback, + int bytes_read) { std::move(callback).Run(bytes_read); }, + std::move(reader), std::move(split_callback.first))); if (rv != net::ERR_IO_PENDING) std::move(split_callback.second).Run(rv); } @@ -82,23 +98,17 @@ auto buffer = base::MakeRefCounted<storage::BigIOBuffer>(max_bytes_to_read); - std::unique_ptr<storage::FileStreamReader> reader = - file_system_context()->CreateFileStreamReader( - url(), offset, /*max_bytes_to_read=*/buffer->size(), base::Time()); - - storage::FileStreamReader* reader_ptr = reader.get(); content::GetIOThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( - &ReadOnIOThread, reader_ptr, buffer, - base::SequencedTaskRunnerHandle::Get(), + &ReadOnIOThread, base::WrapRefCounted(file_system_context()), url(), + offset, buffer, base::SequencedTaskRunnerHandle::Get(), base::BindOnce(&FileSystemAccessFileDelegateHostImpl::DidRead, - weak_factory_.GetWeakPtr(), std::move(reader), buffer, + weak_factory_.GetWeakPtr(), buffer, std::move(callback)))); } void FileSystemAccessFileDelegateHostImpl::DidRead( - std::unique_ptr<storage::FileStreamReader> reader, scoped_refptr<storage::BigIOBuffer> buffer, ReadCallback callback, int rv) {
diff --git a/content/browser/file_system_access/file_system_access_file_delegate_host_impl.h b/content/browser/file_system_access/file_system_access_file_delegate_host_impl.h index f9a21996..762f76bc 100644 --- a/content/browser/file_system_access/file_system_access_file_delegate_host_impl.h +++ b/content/browser/file_system_access/file_system_access_file_delegate_host_impl.h
@@ -122,8 +122,7 @@ } const storage::FileSystemURL& url() { return url_; } - void DidRead(std::unique_ptr<storage::FileStreamReader> reader, - scoped_refptr<storage::BigIOBuffer> buffer, + void DidRead(scoped_refptr<storage::BigIOBuffer> buffer, ReadCallback callback, int rv); void DidWrite(WriteState* state,
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index c95b2722..20c70c6 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -312,6 +312,11 @@ #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) switches::kHardwareVideoDecodeFrameRate, #endif +#if BUILDFLAG(IS_CHROMEOS_LACROS) + switches::kLacrosEnablePlatformEncryptedHevc, + switches::kLacrosEnablePlatformHevc, + switches::kLacrosUseChromeosProtectedMedia, +#endif }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h index 645feec..ce04233 100644 --- a/content/browser/interest_group/auction_runner.h +++ b/content/browser/interest_group/auction_runner.h
@@ -14,7 +14,6 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "content/browser/interest_group/auction_process_manager.h" -//#include "content/browser/interest_group/debuggable_worklet.h" #include "content/common/content_export.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
diff --git a/content/browser/media/key_system_support_impl.cc b/content/browser/media/key_system_support_impl.cc index ab36b6b..680f6e1 100644 --- a/content/browser/media/key_system_support_impl.cc +++ b/content/browser/media/key_system_support_impl.cc
@@ -14,6 +14,7 @@ #include "base/metrics/histogram_functions.h" #include "base/strings/string_split.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "content/browser/media/cdm_registry_impl.h" #include "content/public/browser/cdm_registry.h" #include "content/public/browser/content_browser_client.h" @@ -32,10 +33,6 @@ #include "gpu/config/gpu_driver_bug_workaround_type.h" #endif -#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) -#include "ash/constants/ash_features.h" -#endif // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) - namespace content { namespace { @@ -127,7 +124,12 @@ bool* lazy_initialize) { *lazy_initialize = false; -#if !BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia)) { + return absl::nullopt; + } +#elif !BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) if (!base::FeatureList::IsEnabled(media::kHardwareSecureDecryption)) { DVLOG(1) << "Hardware secure decryption disabled"; return absl::nullopt;
diff --git a/content/browser/media/key_system_support_impl_unittest.cc b/content/browser/media/key_system_support_impl_unittest.cc index 9ba6ae48..5a5684a 100644 --- a/content/browser/media/key_system_support_impl_unittest.cc +++ b/content/browser/media/key_system_support_impl_unittest.cc
@@ -154,6 +154,26 @@ return gpu_feature_info; } + void SelectHardwareSecureDecryption(bool enabled) { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (enabled) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kLacrosUseChromeosProtectedMedia); + } else { + base::CommandLine::ForCurrentProcess()->RemoveSwitch( + switches::kLacrosUseChromeosProtectedMedia); + } +#else + if (enabled) { + scoped_feature_list_.InitAndEnableFeature( + media::kHardwareSecureDecryption); + } else { + scoped_feature_list_.InitAndDisableFeature( + media::kHardwareSecureDecryption); + } +#endif + } + mojo::Remote<media::mojom::KeySystemSupport> key_system_support_; base::MockCallback<KeySystemSupportImpl::HardwareSecureCapabilityCB> hw_secure_capability_cb_; @@ -184,14 +204,14 @@ TEST_F(KeySystemSupportImplTest, HardwareSecureCapability_HardwareSecureDecryptionDisabled) { - scoped_feature_list_.InitAndDisableFeature(media::kHardwareSecureDecryption); + SelectHardwareSecureDecryption(false); Register("KeySystem", TestCdmCapability(), Robustness::kHardwareSecure); EXPECT_FALSE(IsSupported("KeySystem")); } TEST_F(KeySystemSupportImplTest, HardwareSecureCapability) { - scoped_feature_list_.InitAndEnableFeature(media::kHardwareSecureDecryption); + SelectHardwareSecureDecryption(true); Register("KeySystem", TestCdmCapability(), Robustness::kHardwareSecure); // Simulate GPU process initialization completing with GL unavailable. @@ -246,7 +266,7 @@ } TEST_F(KeySystemSupportImplTest, LazyInitialize_Supported) { - scoped_feature_list_.InitAndEnableFeature(media::kHardwareSecureDecryption); + SelectHardwareSecureDecryption(true); Register("KeySystem", absl::nullopt, Robustness::kHardwareSecure); // Simulate GPU process initialization completing with GL unavailable. @@ -266,7 +286,7 @@ } TEST_F(KeySystemSupportImplTest, LazyInitialize_NotSupported) { - scoped_feature_list_.InitAndEnableFeature(media::kHardwareSecureDecryption); + SelectHardwareSecureDecryption(true); Register("KeySystem", absl::nullopt, Robustness::kHardwareSecure); // Simulate GPU process initialization completing with GL unavailable. @@ -287,7 +307,7 @@ TEST_F(KeySystemSupportImplTest, LazyInitialize_HardwareSecureDecryptionDisabled) { - scoped_feature_list_.InitAndDisableFeature(media::kHardwareSecureDecryption); + SelectHardwareSecureDecryption(false); Register("KeySystem", absl::nullopt, Robustness::kHardwareSecure); EXPECT_FALSE(IsSupported("KeySystem"));
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc index 7d246391..d15adcc 100644 --- a/content/browser/media/media_interface_proxy.cc +++ b/content/browser/media/media_interface_proxy.cc
@@ -46,8 +46,6 @@ #include "media/base/key_system_names.h" #include "media/mojo/mojom/cdm_service.mojom.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" -#if BUILDFLAG(IS_CHROMEOS_ASH) -#endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) #if defined(OS_WIN) || BUILDFLAG(ENABLE_LIBRARY_CDMS) @@ -81,7 +79,9 @@ return cdm_name.size() <= kMaxCdmNameSize && base::IsStringASCII(cdm_name); } -#if BUILDFLAG(IS_CHROMEOS_ASH) +#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) + +#if defined(OS_CHROMEOS) constexpr char kChromeOsCdmFileSystemId[] = "application_chromeos-cdm-factory-daemon"; @@ -96,9 +96,7 @@ void ReportCdmTypeUMA(CrosCdmType cdm_type) { UMA_HISTOGRAM_ENUMERATION("Media.EME.CrosCdmType", cdm_type); } -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - -#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) +#endif // defined(OS_CHROMEOS) // The amount of time to allow the secondary Media Service instance to idle // before tearing it down. Only used if the Content embedder defines how to @@ -225,7 +223,7 @@ DCHECK(render_frame_host_); std::string cdm_file_system_id; -#if BUILDFLAG(ENABLE_LIBRARY_CDMS) && BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_CHROMEOS) // The file system ID passed in here is only used by the CDM obtained through // the |media_interface_factory_ptr_|. cdm_file_system_id = kChromeOsCdmFileSystemId; @@ -366,8 +364,15 @@ "CDM creation failed"); // Handle `use_hw_secure_codecs` cases first. -#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) - if (cdm_config.use_hw_secure_codecs && +#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + const bool enable_cdm_factory_daemon = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia); +#else // BUILDFLAG(IS_CHROMEOS_LACROS) + const bool enable_cdm_factory_daemon = true; +#endif // else BUILDFLAG(IS_CHROMEOS_LACROS) + if (enable_cdm_factory_daemon && cdm_config.use_hw_secure_codecs && cdm_config.allow_distinctive_identifier) { auto* factory = media_interface_factory_ptr_->Get(); if (factory) { @@ -405,7 +410,7 @@ } } // Fallback to use library CDM below. -#endif // BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#endif // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) #if BUILDFLAG(ENABLE_LIBRARY_CDMS) // Fallback to use CdmFactory even if `use_hw_secure_codecs` is true. @@ -555,8 +560,9 @@ DCHECK(cdm_factory_map_.count(cdm_guid)); cdm_factory_map_.erase(cdm_guid); } +#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_CHROMEOS) void MediaInterfaceProxy::OnChromeOsCdmCreated( const std::string& key_system, const media::CdmConfig& cdm_config, @@ -584,8 +590,7 @@ ReportCdmTypeUMA(CrosCdmType::kChromeCdm); factory->CreateCdm(key_system, cdm_config, std::move(callback)); } -#endif // BUILDFLAG(IS_CHROMEOS_ASH) -#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) +#endif // defined(OS_CHROMEOS) RENDER_DOCUMENT_HOST_USER_DATA_KEY_IMPL(MediaInterfaceProxy)
diff --git a/content/browser/media/media_interface_proxy.h b/content/browser/media/media_interface_proxy.h index 28bcc04..b7ce26d4 100644 --- a/content/browser/media/media_interface_proxy.h +++ b/content/browser/media/media_interface_proxy.h
@@ -117,8 +117,9 @@ // Callback for connection error from the CdmFactoryPtr in the // |cdm_factory_map_| associated with |cdm_guid|. void OnCdmServiceConnectionError(const base::Token& cdm_guid); +#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_CHROMEOS) // Callback for for Chrome OS CDM creation to facilitate falling back to the // library CDM if the daemon is unavailable or other settings prevent usage of // it. @@ -129,8 +130,7 @@ mojo::PendingRemote<media::mojom::ContentDecryptionModule> receiver, media::mojom::CdmContextPtr cdm_context, const std::string& error_message); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) -#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) +#endif // defined(OS_CHROMEOS) #if defined(OS_WIN) // Gets the InterfaceFactory from MediaFoundationService. May return null if
diff --git a/content/browser/media/service_factory.cc b/content/browser/media/service_factory.cc index f2418637..95950f6 100644 --- a/content/browser/media/service_factory.cc +++ b/content/browser/media/service_factory.cc
@@ -13,19 +13,23 @@ #include "base/logging.h" #include "base/threading/sequence_local_storage_slot.h" #include "base/time/time.h" -#include "content/browser/service_sandbox_type.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/service_process_host.h" #include "content/public/common/content_client.h" #include "media/base/cdm_context.h" #include "media/base/media_switches.h" #include "media/media_buildflags.h" +#include "media/mojo/mojom/cdm_service.mojom.h" #if defined(OS_MAC) #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "sandbox/mac/seatbelt_extension.h" #endif // defined(OS_MAC) +#if defined(OS_WIN) +#include "media/mojo/mojom/media_foundation_service.mojom.h" +#endif // defined(OS_WIN) + namespace content { namespace {
diff --git a/content/browser/media/service_factory.h b/content/browser/media/service_factory.h index 79cf5d9..426895d 100644 --- a/content/browser/media/service_factory.h +++ b/content/browser/media/service_factory.h
@@ -8,11 +8,11 @@ #include "base/token.h" #include "build/build_config.h" #include "content/public/common/cdm_info.h" -#include "media/mojo/mojom/cdm_service.mojom.h" +#include "media/mojo/mojom/cdm_service.mojom-forward.h" #include "url/gurl.h" #if defined(OS_WIN) -#include "media/mojo/mojom/media_foundation_service.mojom.h" +#include "media/mojo/mojom/media_foundation_service.mojom-forward.h" #endif // defined(OS_WIN) namespace content {
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc index 513d177..6501b99 100644 --- a/content/browser/renderer_host/clipboard_host_impl.cc +++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -492,6 +492,79 @@ ui::ClipboardBuffer::kCopyPaste, CreateDataEndpoint()); } +bool ClipboardHostImpl::IsUnsanitizedCustomFormatContentAllowed() { + if (!base::FeatureList::IsEnabled(blink::features::kClipboardCustomFormats)) { + mojo::ReportBadMessage("Custom format read/write is not enabled."); + return false; + } + + if (render_frame_host()->HasTransientUserActivation()) + return true; + return false; +} + +void ClipboardHostImpl::ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) { + if (!IsUnsanitizedCustomFormatContentAllowed()) + return; + std::vector<std::u16string> format_types = + ui::Clipboard::GetForCurrentThread() + ->ReadAvailablePlatformSpecificFormatNames( + ui::ClipboardBuffer::kCopyPaste, CreateDataEndpoint().get()); + std::move(callback).Run(format_types); +} + +void ClipboardHostImpl::ReadUnsanitizedCustomFormat( + const std::u16string& format, + ReadUnsanitizedCustomFormatCallback callback) { + if (!IsUnsanitizedCustomFormatContentAllowed()) + return; + // `kMaxFormatSize` includes the null terminator as well so we check if + // the `format` size is strictly less than `kMaxFormatSize` or not. + if (format.length() >= blink::mojom::ClipboardHost::kMaxFormatSize) + return; + + // Extract the custom format names and then query the web custom format + // corresponding to the MIME type. + std::string format_name = base::UTF16ToASCII(format); + auto data_endpoint = CreateDataEndpoint(); + std::map<std::string, std::string> custom_format_names = + ui::Clipboard::GetForCurrentThread()->ExtractCustomPlatformNames( + ui::ClipboardBuffer::kCopyPaste, data_endpoint.get()); + std::string web_custom_format_string; + if (custom_format_names.find(format_name) != custom_format_names.end()) + web_custom_format_string = custom_format_names[format_name]; + if (web_custom_format_string.empty()) + return; + + std::string result; + ui::Clipboard::GetForCurrentThread()->ReadData( + ui::ClipboardFormatType::GetType(web_custom_format_string), + data_endpoint.get(), &result); + if (result.size() >= blink::mojom::ClipboardHost::kMaxDataSize) + return; + base::span<const uint8_t> span = base::as_bytes(base::make_span(result)); + mojo_base::BigBuffer buffer = mojo_base::BigBuffer(span); + std::move(callback).Run(std::move(buffer)); +} + +void ClipboardHostImpl::WriteUnsanitizedCustomFormat( + const std::u16string& format, + mojo_base::BigBuffer data) { + if (!IsUnsanitizedCustomFormatContentAllowed()) + return; + // `kMaxFormatSize` & `kMaxDataSize` includes the null terminator. + if (format.length() >= blink::mojom::ClipboardHost::kMaxFormatSize) + return; + if (data.size() >= blink::mojom::ClipboardHost::kMaxDataSize) + return; + + // The `format` is mapped to user agent defined web custom format before + // writing to the clipboard. This happens in + // `ScopedClipboardWriter::WriteData`. + clipboard_writer_->WriteData(format, std::move(data)); +} + void ClipboardHostImpl::PasteIfPolicyAllowed( ui::ClipboardBuffer clipboard_buffer, const ui::ClipboardFormatType& data_type,
diff --git a/content/browser/renderer_host/clipboard_host_impl.h b/content/browser/renderer_host/clipboard_host_impl.h index e920098..8778ab7 100644 --- a/content/browser/renderer_host/clipboard_host_impl.h +++ b/content/browser/renderer_host/clipboard_host_impl.h
@@ -176,6 +176,13 @@ void ReadCustomData(ui::ClipboardBuffer clipboard_buffer, const std::u16string& type, ReadCustomDataCallback callback) override; + void ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) override; + void ReadUnsanitizedCustomFormat( + const std::u16string& format, + ReadUnsanitizedCustomFormatCallback callback) override; + void WriteUnsanitizedCustomFormat(const std::u16string& format, + mojo_base::BigBuffer data) override; void WriteText(const std::u16string& text) override; void WriteHtml(const std::u16string& markup, const GURL& url) override; void WriteSvg(const std::u16string& markup) override; @@ -190,6 +197,10 @@ void WriteStringToFindPboard(const std::u16string& text) override; #endif + // Returns true if custom format is allowed to be read/written from/to the + // clipboard, else, fails. + bool IsUnsanitizedCustomFormatContentAllowed(); + // Called by PerformPasteIfContentAllowed() when an is allowed request is // needed. Virtual to be overridden in tests. virtual void StartIsPasteContentAllowedRequest(
diff --git a/content/browser/renderer_host/cross_process_frame_connector.cc b/content/browser/renderer_host/cross_process_frame_connector.cc index 570752f..b035f86d 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.cc +++ b/content/browser/renderer_host/cross_process_frame_connector.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/metrics/histogram_macros.h" +#include "base/trace_event/optional_trace_event.h" #include "components/viz/common/features.h" #include "content/browser/renderer_host/cursor_manager.h" #include "content/browser/renderer_host/frame_tree.h" @@ -112,12 +113,15 @@ } void CrossProcessFrameConnector::RenderProcessGone() { + OPTIONAL_TRACE_EVENT1("content", + "CrossProcessFrameConnector::RenderProcessGone", + "visibility", visibility_); has_crashed_ = true; - RenderFrameHost* rfh = - frame_proxy_in_parent_renderer_->frame_tree_node()->current_frame_host(); - int process_id = rfh->GetProcess()->GetID(); - for (rfh = rfh->GetParent(); rfh; rfh = rfh->GetParent()) { + RenderFrameHostImpl* current_child_rfh = current_child_frame_host(); + int process_id = current_child_rfh->GetProcess()->GetID(); + for (auto* rfh = current_child_rfh->GetParent(); rfh; + rfh = rfh->GetParent()) { if (rfh->GetProcess()->GetID() == process_id) { // The crash will be already logged by the ancestor - ignore this crash in // the current instance of the CrossProcessFrameConnector. @@ -130,9 +134,34 @@ frame_proxy_in_parent_renderer_->ChildProcessGone(); - auto* parent_view = GetParentRenderWidgetHostView(); - if (parent_view && parent_view->host()->delegate()) - parent_view->host()->delegate()->SubframeCrashed(visibility_); + if (current_child_rfh->delegate()) { + // If a subframe crashed on a hidden tab, mark the tab for reload to avoid + // showing a sad frame to the user if they ever switch back to that tab. Do + // this for subframes that are either visible in viewport or visible but + // scrolled out of view, but skip subframes that are not rendered (e.g., via + // "display:none"), since in that case the user wouldn't see a sad frame + // anyway. Prerendering subframes do not enter this code since + // RenderFrameHostImpl immediately cancels prerender if a render process + // exits. + bool did_mark_for_reload = false; + if (current_child_rfh->delegate()->GetVisibility() != Visibility::VISIBLE && + visibility_ != blink::mojom::FrameVisibility::kNotRendered && + base::FeatureList::IsEnabled( + features::kReloadHiddenTabsWithCrashedSubframes)) { + frame_proxy_in_parent_renderer_->frame_tree_node() + ->frame_tree() + ->controller() + .SetNeedsReload( + NavigationControllerImpl::NeedsReloadType::kCrashedSubframe); + did_mark_for_reload = true; + UMA_HISTOGRAM_ENUMERATION( + "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", + visibility_); + } + + UMA_HISTOGRAM_BOOLEAN("Stability.ChildFrameCrash.TabMarkedForReload", + did_mark_for_reload); + } } void CrossProcessFrameConnector::SendIntrinsicSizingInfoToParent(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 8e2e5085..feadbff8 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3553,6 +3553,11 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) switches::kSchedulerBoostUrgent, #endif +#if BUILDFLAG(IS_CHROMEOS_LACROS) + switches::kLacrosEnablePlatformEncryptedHevc, + switches::kLacrosEnablePlatformHevc, + switches::kLacrosUseChromeosProtectedMedia, +#endif }; renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames, base::size(kSwitchNames));
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index 308f0ab..0d5902f 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -177,12 +177,6 @@ // warning shown to the user. virtual void RendererResponsive(RenderWidgetHostImpl* render_widget_host) {} - // Notification that a cross-process subframe on this page has crashed, and a - // sad frame is shown if the subframe was visible. |frame_visibility| - // specifies whether the subframe is visible, scrolled out of view, or hidden - // (e.g., with "display: none"). - virtual void SubframeCrashed(blink::mojom::FrameVisibility visibility) {} - // Requests to lock the mouse. Once the request is approved or rejected, // GotResponseToLockMouseRequest() will be called on the requesting render // widget host. |privileged| means that the request is always granted, used
diff --git a/content/browser/service_sandbox_type.h b/content/browser/service_sandbox_type.h index 4b58315d..1e37242 100644 --- a/content/browser/service_sandbox_type.h +++ b/content/browser/service_sandbox_type.h
@@ -31,32 +31,6 @@ : sandbox::policy::SandboxType::kNoSandbox; } -// media::mojom::CdmServiceBroker -namespace media { -namespace mojom { -class CdmServiceBroker; -} -} // namespace media -template <> -inline sandbox::policy::SandboxType -content::GetServiceSandboxType<media::mojom::CdmServiceBroker>() { - return sandbox::policy::SandboxType::kCdm; -} - -#if defined(OS_WIN) -// media::mojom::MediaFoundationServiceBroker -namespace media { -namespace mojom { -class MediaFoundationServiceBroker; -} -} // namespace media -template <> -inline sandbox::policy::SandboxType -content::GetServiceSandboxType<media::mojom::MediaFoundationServiceBroker>() { - return sandbox::policy::SandboxType::kMediaFoundationCdm; -} -#endif // defined(OS_WIN) - // network::mojom::NetworkService namespace network { namespace mojom {
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index e0d8835..60079470 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -11712,6 +11712,7 @@ TestNavigationObserver back_load_observer(shell()->web_contents()); shell()->web_contents()->GetController().GoBack(); back_load_observer.Wait(); + new_shell->web_contents()->WasHidden(); EXPECT_EQ(1, popup_process->VisibleClientCount()); EXPECT_EQ(1u, popup_process->GetFrameDepth());
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index e9d924e..b743f78 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -7728,32 +7728,6 @@ delegate_->RendererResponsive(this, render_widget_host); } -void WebContentsImpl::SubframeCrashed( - blink::mojom::FrameVisibility visibility) { - OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::SubframeCrashed", - "visibility", visibility); - // If a subframe crashed on a hidden tab, mark the tab for reload to avoid - // showing a sad frame to the user if they ever switch back to that tab. Do - // this for subframes that are either visible in viewport or visible but - // scrolled out of view, but skip subframes that are not rendered (e.g., via - // "display:none"), since in that case the user wouldn't see a sad frame - // anyway. - bool did_mark_for_reload = false; - if (IsHidden() && visibility != blink::mojom::FrameVisibility::kNotRendered && - base::FeatureList::IsEnabled( - features::kReloadHiddenTabsWithCrashedSubframes)) { - // TODO(https://crbug.com/1170273): Handle multiple controllers (MPArch) - GetController().SetNeedsReload( - NavigationControllerImpl::NeedsReloadType::kCrashedSubframe); - did_mark_for_reload = true; - UMA_HISTOGRAM_ENUMERATION( - "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", visibility); - } - - UMA_HISTOGRAM_BOOLEAN("Stability.ChildFrameCrash.TabMarkedForReload", - did_mark_for_reload); -} - void WebContentsImpl::BeforeUnloadFiredFromRenderManager( bool proceed, const base::TimeTicks& proceed_time,
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 6921352..419619d4 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -953,7 +953,6 @@ RenderWidgetHostImpl* render_widget_host, base::RepeatingClosure hang_monitor_restarter) override; void RendererResponsive(RenderWidgetHostImpl* render_widget_host) override; - void SubframeCrashed(blink::mojom::FrameVisibility visibility) override; void RequestToLockMouse(RenderWidgetHostImpl* render_widget_host, bool user_gesture, bool last_unlocked_by_target,
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index 138f587..2f82a58 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt index 59549b4..0a2da8e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index 39245d19..a91bcdb 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt index ba7aeee..b89cd63e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt index d7c5dd6..493b5f6 100644 --- a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt index 918820a..4a77565 100644 --- a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt index 9a439b3e..c99df311 100644 --- a/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 19ef360..3755938 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt index 883b823e..492a3bda 100644 --- a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt index ce64709..571723e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index e4fa3e19..ca14c4e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt index e002dbd..cd47d234 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
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 d614b92..54a0421 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
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop @@ -755,6 +755,31 @@ crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_8_samples.html [ Failure ] crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_max_samples.html [ Failure ] +############ +# ChromeOS # +############ + +# Skip these, rather than expect them to fail to avoid that they impact the +# following tests result. +crbug.com/1237319 [ chromeos ] conformance2/reading/read-pixels-from-fbo-test.html [ Skip ] +crbug.com/1237319 [ chromeos ] conformance2/rendering/framebuffer-render-to-layer.html [ Skip ] +crbug.com/1237319 [ chromeos passthrough ] conformance/textures/misc/texture-size-limit.html [ Skip ] +crbug.com/1237319 [ chromeos passthrough ] conformance2/textures/misc/tex-3d-size-limit.html [ Skip ] +crbug.com/1237319 [ chromeos passthrough ] conformance/extensions/khr-parallel-shader-compile.html [ skip ] + +# Won't investigate failures on validating command decoder. Remove once it's unshipped. +crbug.com/1237319 [ chromeos no-passthrough ] conformance/extensions/webgl-compressed-texture-astc.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance/extensions/ext-texture-compression-bptc.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance/extensions/ext-texture-compression-rgtc.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance/extensions/s3tc-and-rgtc.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-2d-r8ui-red_integer-unsigned_byte.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-3d-* [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance2/textures/misc/origin-clean-conformance-offscreencanvas.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance2/textures/webgl_canvas/tex-2d-r8ui-red_integer-unsigned_byte.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] conformance2/textures/webgl_canvas/tex-3d-* [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] deqp/functional/gles3/clipping.html [ Skip ] +crbug.com/1237319 [ chromeos no-passthrough ] deqp/functional/gles3/negativetextureapi.html [ Skip ] + crbug.com/1037958 [ mac amd-0x679e ] conformance2/transform_feedback/switching-objects.html [ RetryOnFailure ] # Conflicting expectations to test that the
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 cd3243a..9fd6d37 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
@@ -11,7 +11,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop @@ -754,6 +754,8 @@ # Skip test that breaks subsequent tests. crbug.com/1043953 [ chromeos chromeos-board-amd64-generic ] conformance/textures/misc/texture-size-limit.html [ Skip ] +crbug.com/1237319 [ chromeos chromeos-board-eve passthrough ] conformance/textures/misc/texture-size-limit.html [ Skip ] +crbug.com/1237319 [ chromeos angle-opengles passthrough ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Skip ] # Texture compression is only expected to be available on desktop GPUs. crbug.com/1080360 [ chromeos chromeos-board-kevin ] WebglExtension_EXT_texture_compression_bptc [ Skip ]
diff --git a/content/test/gpu/validate_tag_consistency.py b/content/test/gpu/validate_tag_consistency.py index 80ac68d..674cc3b 100755 --- a/content/test/gpu/validate_tag_consistency.py +++ b/content/test/gpu/validate_tag_consistency.py
@@ -24,7 +24,7 @@ # Devices # tags: [ android-nexus-5 android-nexus-5x android-nexus-6 android-nexus-9 # android-pixel-2 android-pixel-4 android-shield-android-tv -# chromeos-board-amd64-generic chromeos-board-kevin +# chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve # fuchsia-board-astro fuchsia-board-qemu-x64 ] # Platform # tags: [ desktop
diff --git a/content/test/mock_clipboard_host.cc b/content/test/mock_clipboard_host.cc index 346e9d269..a54129a 100644 --- a/content/test/mock_clipboard_host.cc +++ b/content/test/mock_clipboard_host.cc
@@ -176,6 +176,36 @@ needs_reset_ = true; } +void MockClipboardHost::ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) { + std::vector<std::u16string> format_names; + for (const auto& item : unsanitized_custom_data_map_) + format_names.emplace_back(item.first); + std::move(callback).Run(format_names); +} + +void MockClipboardHost::ReadUnsanitizedCustomFormat( + const std::u16string& format, + ReadUnsanitizedCustomFormatCallback callback) { + const auto it = unsanitized_custom_data_map_.find(format); + if (it == unsanitized_custom_data_map_.end()) + return; + + mojo_base::BigBuffer buffer = mojo_base::BigBuffer( + base::make_span(it->second.data(), it->second.size())); + std::move(callback).Run(std::move(buffer)); +} + +void MockClipboardHost::WriteUnsanitizedCustomFormat( + const std::u16string& format, + mojo_base::BigBuffer data) { + if (needs_reset_) + Reset(); + // Simulate the underlying platform copying this data. + std::vector<uint8_t> data_copy(data.data(), data.data() + data.size()); + unsanitized_custom_data_map_[format] = data_copy; +} + #if defined(OS_MAC) void MockClipboardHost::WriteStringToFindPboard(const std::u16string& text) {} #endif
diff --git a/content/test/mock_clipboard_host.h b/content/test/mock_clipboard_host.h index 368695a2..9e9fe38a 100644 --- a/content/test/mock_clipboard_host.h +++ b/content/test/mock_clipboard_host.h
@@ -60,6 +60,13 @@ const std::u16string& title) override; void WriteImage(const SkBitmap& bitmap) override; void CommitWrite() override; + void ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) override; + void ReadUnsanitizedCustomFormat( + const std::u16string& format, + ReadUnsanitizedCustomFormatCallback callback) override; + void WriteUnsanitizedCustomFormat(const std::u16string& format, + mojo_base::BigBuffer data) override; #if defined(OS_MAC) void WriteStringToFindPboard(const std::u16string& text) override; #endif @@ -74,6 +81,7 @@ std::map<std::u16string, std::u16string> custom_data_; bool write_smart_paste_ = false; bool needs_reset_ = false; + std::map<std::u16string, std::vector<uint8_t>> unsanitized_custom_data_map_; DISALLOW_COPY_AND_ASSIGN(MockClipboardHost); };
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc index b7c41f9..bacfae8 100644 --- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -782,6 +782,12 @@ properties->eir.value()); } + // There is no guarantee that BatteryAdded is called after DeviceAdded + // (for the same device). So always update the battery value of this newly + // detected device in case we ignored BatteryAdded calls for it before this + // DeviceAdded call. + UpdateDeviceBatteryLevelFromBatteryClient(object_path); + for (auto& observer : observers_) observer.DeviceAdded(this, device_bluez); }
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc index 05339b0..28dcf9e 100644 --- a/fuchsia/engine/browser/web_engine_content_browser_client.cc +++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -37,6 +37,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_service.mojom.h" +#include "third_party/blink/public/common/switches.h" #include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom.h" #include "ui/base/l10n/l10n_util.h" @@ -175,6 +176,7 @@ int child_process_id) { // TODO(https://crbug.com/1083520): Pass based on process type. constexpr char const* kSwitchesToCopy[] = { + blink::switches::kSharedArrayBufferAllowedOrigins, switches::kCorsExemptHeaders, switches::kEnableCastStreamingReceiver, switches::kEnableContentDirectories,
diff --git a/fuchsia/engine/web_instance_host/web_instance_host.cc b/fuchsia/engine/web_instance_host/web_instance_host.cc index 8624deaa..7f32d8bf 100644 --- a/fuchsia/engine/web_instance_host/web_instance_host.cc +++ b/fuchsia/engine/web_instance_host/web_instance_host.cc
@@ -350,6 +350,7 @@ return true; static const base::StringPiece kAllowedArgs[] = { + blink::switches::kSharedArrayBufferAllowedOrigins, blink::switches::kGpuRasterizationMSAASampleCount, blink::switches::kMinHeightForGpuRasterTile, cc::switches::kEnableClippedImageScaling,
diff --git a/gpu/command_buffer/service/shared_image_video.cc b/gpu/command_buffer/service/shared_image_video.cc index 5c65b707..a4569cc 100644 --- a/gpu/command_buffer/service/shared_image_video.cc +++ b/gpu/command_buffer/service/shared_image_video.cc
@@ -34,9 +34,66 @@ #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "ui/gl/gl_utils.h" namespace gpu { +namespace { +class VideoImage : public gl::GLImage { + public: + VideoImage(AHardwareBuffer* buffer, base::ScopedFD begin_read_fence) + : handle_(base::android::ScopedHardwareBufferHandle::Create(buffer)), + begin_read_fence_(std::move(begin_read_fence)) {} + + // gl::GLImage: + std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> + GetAHardwareBuffer() override { + return std::make_unique<ScopedHardwareBufferFenceSyncImpl>( + this, base::android::ScopedHardwareBufferHandle::Create(handle_.get()), + std::move(begin_read_fence_)); + } + + base::ScopedFD TakeEndReadFence() { return std::move(end_read_fence_); } + + protected: + ~VideoImage() override = default; + + private: + class ScopedHardwareBufferFenceSyncImpl + : public base::android::ScopedHardwareBufferFenceSync { + public: + ScopedHardwareBufferFenceSyncImpl( + scoped_refptr<VideoImage> image, + base::android::ScopedHardwareBufferHandle handle, + base::ScopedFD fence_fd) + : ScopedHardwareBufferFenceSync(std::move(handle), + std::move(fence_fd), + base::ScopedFD(), + /*is_video=*/true), + image_(std::move(image)) {} + ~ScopedHardwareBufferFenceSyncImpl() override = default; + + void SetReadFence(base::ScopedFD fence_fd, bool has_context) override { + image_->end_read_fence_ = + gl::MergeFDs(std::move(image_->end_read_fence_), std::move(fence_fd)); + } + + private: + scoped_refptr<VideoImage> image_; + }; + + base::android::ScopedHardwareBufferHandle handle_; + + // This fence should be waited upon before reading from the buffer. + base::ScopedFD begin_read_fence_; + + // This fence should be waited upon to ensure that the reader is finished + // reading from the buffer. + base::ScopedFD end_read_fence_; +}; + +} // namespace + SharedImageVideo::SharedImageVideo( const Mailbox& mailbox, const gfx::Size& size, @@ -205,7 +262,7 @@ } bool BeginAccess(GLenum mode) override { - scoped_lock_ = GetScopedDrDcLock(); + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); // This representation should only be called for read or overlay. DCHECK(mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM || @@ -216,11 +273,10 @@ return true; } - void EndAccess() override { scoped_lock_.reset(); } + void EndAccess() override {} private: std::unique_ptr<gles2::AbstractTexture> texture_; - std::unique_ptr<base::AutoLockMaybe> scoped_lock_; DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureVideo); }; @@ -253,7 +309,7 @@ } bool BeginAccess(GLenum mode) override { - scoped_lock_ = GetScopedDrDcLock(); + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); // This representation should only be called for read or overlay. DCHECK(mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM || @@ -264,12 +320,11 @@ return true; } - void EndAccess() override { scoped_lock_.reset(); } + void EndAccess() override {} private: std::unique_ptr<gles2::AbstractTexture> abstract_texture_; scoped_refptr<gles2::TexturePassthrough> passthrough_texture_; - std::unique_ptr<base::AutoLockMaybe> scoped_lock_; DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTexturePassthroughVideo); }; @@ -307,7 +362,7 @@ std::vector<GrBackendSemaphore>* begin_semaphores, std::vector<GrBackendSemaphore>* end_semaphores, std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override { - scoped_lock_ = GetScopedDrDcLock(); + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); DCHECK(!scoped_hardware_buffer_); auto* video_backing = static_cast<SharedImageVideo*>(backing()); @@ -361,6 +416,7 @@ } void EndReadAccess() override { + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); DCHECK(scoped_hardware_buffer_); SharedImageRepresentationSkiaVkAndroid::EndReadAccess(); @@ -371,13 +427,11 @@ scoped_hardware_buffer_->SetReadFence(android_backing()->TakeReadFence(), true); scoped_hardware_buffer_ = nullptr; - scoped_lock_.reset(); } private: std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> scoped_hardware_buffer_; - std::unique_ptr<base::AutoLockMaybe> scoped_lock_; }; // TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared @@ -518,8 +572,7 @@ protected: bool BeginReadAccess(std::vector<gfx::GpuFence>* acquire_fences) override { - scoped_lock_ = GetScopedDrDcLock(); - + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); // A |CodecImage| is already in a SurfaceView, render content to the // overlay. if (!stream_image()->HasTextureOwner()) { @@ -531,16 +584,35 @@ } void EndReadAccess(gfx::GpuFenceHandle release_fence) override { + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); DCHECK(release_fence.is_null()); - scoped_lock_.reset(); + if (gl_image_) { + DCHECK(scoped_hardware_buffer_); + scoped_hardware_buffer_->SetReadFence(gl_image_->TakeEndReadFence(), + true); + gl_image_.reset(); + scoped_hardware_buffer_.reset(); + } } gl::GLImage* GetGLImage() override { - AssertAcquiredDrDcLock(); - + base::AutoLockMaybe auto_lock(GetDrDcLockPtr()); DCHECK(stream_image()->HasTextureOwner()) << "The backing is already in a SurfaceView!"; - return stream_image(); + + // Note that we have SurfaceView overlay as well as SurfaceControl. + // SurfaceView may/may not have TextureOwner whereas SurfaceControl always + // have TextureOwner. It is not possible to know whether we are in + // SurfaceView or SurfaceControl mode in Begin/EndReadAccess. Hence + // |scoped_hardware_buffer_| and |gl_image_| needs to be created here since + // GetGLImage will only be called for SurfaceControl. + if (!gl_image_) { + scoped_hardware_buffer_ = stream_image()->GetAHardwareBuffer(); + gl_image_ = base::MakeRefCounted<VideoImage>( + scoped_hardware_buffer_->buffer(), + scoped_hardware_buffer_->TakeFence()); + } + return gl_image_.get(); } void NotifyOverlayPromotion(bool promotion, @@ -550,7 +622,9 @@ } private: - std::unique_ptr<base::AutoLockMaybe> scoped_lock_; + std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> + scoped_hardware_buffer_; + scoped_refptr<VideoImage> gl_image_; StreamTextureSharedImageInterface* stream_image() { auto* video_backing = static_cast<SharedImageVideo*>(backing());
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py index 97214f7f..789fcb9f 100644 --- a/ios/build/bots/scripts/test_runner.py +++ b/ios/build/bots/scripts/test_runner.py
@@ -270,7 +270,7 @@ LOGGER.info(line) sys.stdout.flush() LOGGER.debug('Finished print_process_output.') - return out + return out.decode('utf-8') if sys.version_info.major == 3 else out def get_current_xcode_info():
diff --git a/ios/build/bots/scripts/xcode_log_parser.py b/ios/build/bots/scripts/xcode_log_parser.py index 2180338..1a062df3 100644 --- a/ios/build/bots/scripts/xcode_log_parser.py +++ b/ios/build/bots/scripts/xcode_log_parser.py
@@ -11,6 +11,7 @@ import re import shutil import subprocess +import sys import file_util import test_runner @@ -27,6 +28,22 @@ _XCRESULT_SUFFIX = '.xcresult' +def _sanitize_str(line): + """Encodes str when in python 2.""" + if sys.version_info.major == 2: + if isinstance(line, unicode): + line = line.encode('utf-8') + return line + + +def _sanitize_str_list(lines): + """Encodes any unicode in list when in python 2.""" + sanitized_lines = [] + for line in lines: + sanitized_lines.append(_sanitize_str(line)) + return sanitized_lines + + def get_parser(): """Returns correct parser from version of Xcode installed.""" if xcode_util.using_xcode_11_or_higher(): @@ -55,11 +72,9 @@ def _find_list_of_tests(tests, regex): """Adds test names matched by regex to result list.""" for test_line in output: - m_test = regex.search(test_line.decode("utf-8")) + m_test = regex.search(test_line) if m_test: - tests.append( - '%s/%s' % - (m_test.group(1).encode('utf-8'), m_test.group(2).encode('utf-8'))) + tests.append('%s/%s' % (m_test.group(1), m_test.group(2))) _find_list_of_tests(passed_tests, passed_test_regex) _find_list_of_tests(failed_tests, failed_test_regex) @@ -82,10 +97,11 @@ Returns: (str) Test case id in format TestClass/TestMethod. """ + test_case = _sanitize_str(test_case) test = test_case.replace('[', '').replace(']', '').replace('-', '').replace(' ', '/') - return test.encode('utf8') if isinstance(test, unicode) else test + return test def copy_screenshots_for_failed_test(failure_message, test_case_folder): @@ -178,11 +194,11 @@ return failed for failure_summary in actions_invocation_record['issues'][ 'testFailureSummaries']['_values']: - error_line = failure_summary['documentLocationInCreatingWorkspace'][ - 'url']['_value'].encode('utf8') - fail_message = [ - error_line - ] + failure_summary['message']['_value'].encode('utf8').splitlines() + error_line = _sanitize_str( + failure_summary['documentLocationInCreatingWorkspace']['url'] + ['_value']) + fail_message = [error_line] + _sanitize_str( + failure_summary['message']['_value']).splitlines() test_case_id = format_test_case(failure_summary['testCaseName']['_value']) failed[test_case_id] = fail_message return failed @@ -209,7 +225,7 @@ # can be parsed from root. continue for test in test_suite['subtests']['_values']: - test_name = test['identifier']['_value'].encode('utf8') + test_name = _sanitize_str(test['identifier']['_value']) if any( test_name.endswith(suffix) for suffix in SYSTEM_ERROR_TEST_NAME_SUFFIXES): @@ -224,14 +240,13 @@ xcresult, test['summaryRef']['id']['_value'])) failure_message = [] for failure in rootFailure['failureSummaries']['_values']: - file_name = failure.get('fileName', {}).get('_value', - '').encode('utf8') - line_number = failure.get('lineNumber', {}).get('_value', - '').encode('utf8') + file_name = _sanitize_str( + failure.get('fileName', {}).get('_value', '')) + line_number = _sanitize_str( + failure.get('lineNumber', {}).get('_value', '')) failure_location = 'file: %s, line: %s' % (file_name, line_number) - failure_message += [ - failure_location - ] + failure['message']['_value'].encode('utf8').splitlines() + failure_message += [failure_location] + _sanitize_str( + failure['message']['_value']).splitlines() results['failed'][test_name] = failure_message @staticmethod @@ -252,6 +267,8 @@ } } """ + output_path = _sanitize_str(output_path) + output = _sanitize_str_list(output) LOGGER.info('Reading %s' % output_path) test_results = { 'passed': [], @@ -283,8 +300,8 @@ test_results['failed']['BUILD_INTERRUPTED'] = [ '%s with test results does not exist.' % xcresult ] + output - passed_tests, failed_tests_dict = parse_passed_failed_tests_for_interrupted_run( - output) + passed_tests, failed_tests_dict = ( + parse_passed_failed_tests_for_interrupted_run(output)) test_results['passed'] = passed_tests test_results['failed'].update(failed_tests_dict) return test_results @@ -545,14 +562,16 @@ } } """ + output_folder = _sanitize_str(output_folder) + output = _sanitize_str_list(output) test_results = {'passed': [], 'failed': {}} plist_path = os.path.join(output_folder, 'Info.plist') if not os.path.exists(plist_path): test_results['failed']['BUILD_INTERRUPTED'] = [ '%s with test results does not exist.' % plist_path ] + output - passed_tests, failed_tests_dict = parse_passed_failed_tests_for_interrupted_run( - output) + passed_tests, failed_tests_dict = ( + parse_passed_failed_tests_for_interrupted_run(output)) test_results['passed'] = passed_tests test_results['failed'].update(failed_tests_dict) return test_results @@ -567,7 +586,7 @@ if ('ErrorSummaries' in action_result and action_result['ErrorSummaries']): test_results['failed']['TESTS_DID_NOT_START'].append('\n'.join( - error_summary['Message'] + _sanitize_str(error_summary['Message']) for error_summary in action_result['ErrorSummaries'])) else: summary_plist = os.path.join(
diff --git a/ios/build/bots/scripts/xcodebuild_runner.py b/ios/build/bots/scripts/xcodebuild_runner.py index b768ecf6..fec99a27 100644 --- a/ios/build/bots/scripts/xcodebuild_runner.py +++ b/ios/build/bots/scripts/xcodebuild_runner.py
@@ -471,17 +471,7 @@ for attempt, attempt_results in enumerate(shard_attempts): for test in attempt_results['failed'].keys(): - # TODO(crbug.com/1178923): Remove unicode check when it's figured out - # where unicode is introduced. - log_lines = [] - for line in self.logs.get(test, []): - if sys.version_info.major == 2: - if isinstance(line, unicode): - LOGGER.warning('Unicode string: %s' % line) - line = line.encode('utf-8') - log_lines.append(line) - - output.mark_failed(test, test_log='\n'.join(log_lines)) + output.mark_failed(test, test_log='\n'.join(self.logs.get(test, []))) # 'aborted tests' in logs is an array of strings, each string defined # as "{TestCase}/{testMethod}"
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index e694d24..0819b778b 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -502,10 +502,6 @@ {"url-blocklist-ios", flag_descriptions::kURLBlocklistIOSName, flag_descriptions::kURLBlocklistIOSDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kURLBlocklistIOS)}, - {"enable-ios-managed-settings-ui", - flag_descriptions::kEnableIOSManagedSettingsUIName, - flag_descriptions::kEnableIOSManagedSettingsUIDescription, - flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableIOSManagedSettingsUI)}, {"new-content-suggestions-feed", flag_descriptions::kDiscoverFeedInNtpName, flag_descriptions::kDiscoverFeedInNtpDescription, flags_ui::kOsIos, FEATURE_WITH_PARAMS_VALUE_TYPE(kDiscoverFeedInNtp,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index c1564c9..3510998d 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -212,11 +212,6 @@ "Enables the option of capturing an entire webpage as a PDF when a " "screenshot is taken."; -const char kEnableIOSManagedSettingsUIName[] = "Enable IOS Managed Settings UI"; -const char kEnableIOSManagedSettingsUIDescription[] = - "Enable showing a different UI when the setting is managed by an " - "enterprise policy on iOS."; - const char kEnableManualPasswordGenerationName[] = "Enable manual password generation."; const char kEnableManualPasswordGenerationDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 269cb48..2dade21 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -186,11 +186,6 @@ extern const char kEnableFullPageScreenshotName[]; extern const char kEnableFullPageScreenshotDescription[]; -// Title and description for the flag to enable to show a different UI when the -// setting is managed by an enterprise policy. -extern const char kEnableIOSManagedSettingsUIName[]; -extern const char kEnableIOSManagedSettingsUIDescription[]; - // Title and description for the flag to enable UI that allows the user to // create a strong password even if the field wasn't parsed as a new password // field.
diff --git a/ios/chrome/browser/infobars/infobar_ios.h b/ios/chrome/browser/infobars/infobar_ios.h index da90fee..07f522be 100644 --- a/ios/chrome/browser/infobars/infobar_ios.h +++ b/ios/chrome/browser/infobars/infobar_ios.h
@@ -62,6 +62,11 @@ bool high_priority() const { return high_priority_; } void set_high_priority(bool high_priority); + // Whether or not this infobar reference has been removed from its owning + // InfobarManager. + bool removed_from_owner() { return removed_from_owner_; } + void set_removed_from_owner() { removed_from_owner_ = true; } + // Returns a weak pointer to the infobar. base::WeakPtr<InfoBarIOS> GetWeakPtr(); @@ -77,6 +82,7 @@ bool accepted_ = false; bool skip_banner_ = false; bool high_priority_ = false; + bool removed_from_owner_ = false; base::WeakPtrFactory<InfoBarIOS> weak_factory_{this}; };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.mm index a3474702..3c25bf3 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.mm
@@ -72,7 +72,7 @@ InfoBarControllerDelegate* infobar_controller_delegate = static_cast<InfoBarControllerDelegate*>(infobar); if (!infobar || !infobar_controller_delegate->IsOwned() || - !infobar->delegate()) + !infobar->delegate() || infobar->removed_from_owner()) return; infobar_controller_delegate->RemoveInfoBar();
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm index 28b0a41b..81f75ed 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h" #include "base/check.h" +#include "base/feature_list.h" #include "components/infobars/core/infobar.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h" @@ -18,6 +19,9 @@ using infobars::InfoBar; using infobars::InfoBarManager; +const base::Feature kInfobarRemoveCheck{"InfobarRemoveCheck", + base::FEATURE_ENABLED_BY_DEFAULT}; + #pragma mark - InfobarOverlayRequestCancelHandler InfobarOverlayRequestCancelHandler::InfobarOverlayRequestCancelHandler( @@ -62,6 +66,9 @@ infobars::InfoBar* infobar, bool animate) { if (cancel_handler_->infobar() == infobar) { + if (base::FeatureList::IsEnabled(kInfobarRemoveCheck)) { + static_cast<InfoBarIOS*>(infobar)->set_removed_from_owner(); + } cancel_handler_->CancelForInfobarRemoval(); // The cancel handler is destroyed after Cancel(), so no code can be added // after this call. @@ -72,6 +79,9 @@ InfoBar* old_infobar, InfoBar* new_infobar) { if (cancel_handler_->infobar() == old_infobar) { + if (base::FeatureList::IsEnabled(kInfobarRemoveCheck)) { + static_cast<InfoBarIOS*>(old_infobar)->set_removed_from_owner(); + } cancel_handler_->HandleReplacement(static_cast<InfoBarIOS*>(new_infobar)); cancel_handler_->CancelForInfobarRemoval(); // The cancel handler is destroyed after Cancel(), so no code can be added
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc index dad4cbd3..d11a9b0 100644 --- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc +++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
@@ -150,9 +150,7 @@ // This pref is also used for logging. If it is changed, change it in the // other places. std::vector<std::string> prefs_vector = {prefs::kArticlesForYouEnabled}; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI)) { - prefs_vector.push_back(prefs::kNTPContentSuggestionsEnabled); - } + prefs_vector.push_back(prefs::kNTPContentSuggestionsEnabled); auto provider = std::make_unique<RemoteSuggestionsProviderImpl>( service, prefs, GetApplicationContext()->GetApplicationLocale(),
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_coordinator.mm b/ios/chrome/browser/ui/activity_services/activity_service_coordinator.mm index cbccacf26..6134ad7 100644 --- a/ios/chrome/browser/ui/activity_services/activity_service_coordinator.mm +++ b/ios/chrome/browser/ui/activity_services/activity_service_coordinator.mm
@@ -105,7 +105,7 @@ } - (void)stop { - [self.viewController dismissViewControllerAnimated:YES completion:nil]; + [self.baseViewController dismissViewControllerAnimated:YES completion:nil]; self.viewController = nil; self.mediator = nil;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm index 057719d5..d3437ad5 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -181,8 +181,7 @@ self.contentSuggestionsEnabled = prefs->GetBoolean(prefs::kArticlesForYouEnabled) && - (!base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) || - prefs->GetBoolean(prefs::kNTPContentSuggestionsEnabled)); + prefs->GetBoolean(prefs::kNTPContentSuggestionsEnabled); self.contentSuggestionsExpanded = [[PrefBackedBoolean alloc] initWithPrefService:prefs prefName:feed::prefs::kArticlesListVisible];
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm index dc4378c..61f5833e 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -917,8 +917,7 @@ - (BOOL)contentSuggestionsEnabled { return self.articleForYouEnabled->GetValue()->GetBool() && - (!base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) || - self.contentSuggestionsPolicyEnabled->GetValue()->GetBool()); + self.contentSuggestionsPolicyEnabled->GetValue()->GetBool(); } #pragma mark - PrefObserverDelegate
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 29655c7b..0b5bca2 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -930,8 +930,7 @@ NSArray* collectionActions = [self collectionItems]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - _browserPolicyConnector && + if (_browserPolicyConnector && _browserPolicyConnector->HasMachineLevelPolicies()) { // Show enterprise infomation when chrome is managed by policy and the // settings UI flag is enabled.
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm index 4b8ac55..a08af75 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
@@ -469,10 +469,6 @@ // Tests that the "Managed by..." item is hidden when none of the policies is // set. TEST_F(PopupMenuMediatorTest, TestEnterpriseInfoHidden) { - // Enabled the feature flag. - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(kEnableIOSManagedSettingsUI); - CreateMediator(PopupMenuTypeToolsMenu, /*is_incognito=*/NO, /*trigger_incognito_hint=*/NO); @@ -486,10 +482,6 @@ // Tests that the "Managed by..." item is shown. TEST_F(PopupMenuMediatorTest, TestEnterpriseInfoShown) { - // Enabled the feature flag. - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(kEnableIOSManagedSettingsUI); - // Set a policy. base::ScopedTempDir state_directory; ASSERT_TRUE(state_directory.CreateUniqueTempDir());
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm index c936084..52ef186 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm
@@ -165,8 +165,7 @@ TableViewModel* model = self.tableViewModel; [model addSectionWithIdentifier:SectionIdentifierSwitches]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - _browser->GetBrowserState()->GetPrefs()->IsManagedPreference( + if (_browser->GetBrowserState()->GetPrefs()->IsManagedPreference( autofill::prefs::kAutofillCreditCardEnabled)) { [model addItem:[self cardManagedItem] toSectionWithIdentifier:SectionIdentifierSwitches];
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm index f149c334..0910cf1 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
@@ -120,8 +120,7 @@ [model addSectionWithIdentifier:SectionIdentifierSwitches]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - _browserState->GetPrefs()->IsManagedPreference( + if (_browserState->GetPrefs()->IsManagedPreference( autofill::prefs::kAutofillProfileEnabled)) { [model addItem:[self managedAddressItem] toSectionWithIdentifier:SectionIdentifierSwitches];
diff --git a/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm b/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm index 396e6be3..8f88e1ea 100644 --- a/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm
@@ -118,8 +118,7 @@ // Block popups switch. [model addSectionWithIdentifier:SectionIdentifierMainSwitch]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - _browserState->GetPrefs()->IsManagedPreference( + if (_browserState->GetPrefs()->IsManagedPreference( prefs::kManagedDefaultPopupsSetting)) { _blockPopupsManagedItem = [self blockPopupsManagedItem]; [model addItem:_blockPopupsManagedItem
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm index 7f634e0..c740712 100644 --- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm +++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
@@ -715,8 +715,7 @@ kAllowSigninItemAccessibilityIdentifier; [items addObject:allowSigninItem]; } - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - self.userPrefService->IsManagedPreference( + if (self.userPrefService->IsManagedPreference( prefs::kSearchSuggestEnabled)) { TableViewInfoButtonItem* autocompleteItem = [self TableViewInfoButtonItemType:AutocompleteSearchesAndURLsManagedItemType @@ -736,8 +735,7 @@ dataType:0]; [items addObject:autocompleteItem]; } - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - self.userPrefService->IsManagedPreference( + if (self.userPrefService->IsManagedPreference( prefs::kSafeBrowsingEnabled)) { TableViewInfoButtonItem* safeBrowsingManagedItem = [self TableViewInfoButtonItemType:AutocompleteSearchesAndURLsManagedItemType @@ -760,8 +758,7 @@ [items addObject:safeBrowsingItem]; } [items addObject:self.passwordLeakCheckItem]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - self.localPrefService->IsManagedPreference( + if (self.localPrefService->IsManagedPreference( metrics::prefs::kMetricsReportingEnabled)) { TableViewInfoButtonItem* improveChromeItem = [self TableViewInfoButtonItemType:ImproveChromeManagedItemType @@ -781,8 +778,7 @@ dataType:0]; [items addObject:improveChromeItem]; } - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - self.userPrefService->IsManagedPreference( + if (self.userPrefService->IsManagedPreference( unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled)) { TableViewInfoButtonItem* betterSearchAndBrowsingItem = [self TableViewInfoButtonItemType:BetterSearchAndBrowsingManagedItemType
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm index 51478c2..ff5ab14 100644 --- a/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm
@@ -130,8 +130,7 @@ [self populateLanguagesSection]; [model addSectionWithIdentifier:SectionIdentifierTranslate]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - self.dataSource.translateManaged) { + if (self.dataSource.translateManaged) { // Translate managed item. TableViewInfoButtonItem* translateManagedItem = [[TableViewInfoButtonItem alloc] initWithType:ItemTypeTranslateManaged];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm index 7f7b2ab5..8d9b870 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -399,8 +399,7 @@ if (!self.navigationItem.searchController.active) { [model addSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch]; - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - _browserState->GetPrefs()->IsManagedPreference( + if (_browserState->GetPrefs()->IsManagedPreference( password_manager::prefs::kCredentialsEnableService)) { // TODO(crbug.com/1082827): observe the managing status of the pref. // Show managed settings UI when the pref is managed by the policy.
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 1ce54138..7e0fcd1 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -444,8 +444,7 @@ } // Show managed UI if default search engine is managed by policy. - if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) && - [self isDefaultSearchEngineManagedByPolicy]) { + if ([self isDefaultSearchEngineManagedByPolicy]) { if (@available(iOS 14, *)) { [model addItem:[self managedSearchEngineItem] toSectionWithIdentifier:SettingsSectionIdentifierDefaults]; @@ -480,8 +479,7 @@ toSectionWithIdentifier:SettingsSectionIdentifierAdvanced]; [model addItem:[self privacyDetailItem] toSectionWithIdentifier:SettingsSectionIdentifierAdvanced]; - if (!base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) || - [_contentSuggestionPolicyEnabled value]) { + if ([_contentSuggestionPolicyEnabled value]) { [model addItem:self.articlesForYouItem toSectionWithIdentifier:SettingsSectionIdentifierAdvanced]; @@ -1798,9 +1796,6 @@ self.articlesForYouItem.on = [_articlesEnabled value]; [self reconfigureCellsForItems:@[ self.articlesForYouItem ]]; } else if (observableBoolean == _contentSuggestionPolicyEnabled) { - if (!base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI)) - return; - NSIndexPath* itemIndexPath; NSInteger itemTypeToRemove; TableViewItem* itemToAdd;
diff --git a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm index 84721ef..a57ef39 100644 --- a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
@@ -192,8 +192,6 @@ [coordinator start]; - [vc_partial_mock verify]; - // Verify that the positioning is correct. auto activityHandler = static_cast<id<ActivityServicePositioner, ActivityServicePresentation>>( @@ -203,13 +201,11 @@ CGRectEqualToRect(fake_origin_view_.bounds, activityHandler.sourceRect)); // Verify that the presentation protocol works too. - id activity_vc_partial_mock = OCMPartialMock(activityViewController); - [[activity_vc_partial_mock expect] dismissViewControllerAnimated:YES - completion:nil]; + [[vc_partial_mock expect] dismissViewControllerAnimated:YES completion:nil]; [activityHandler activityServiceDidEndPresenting]; - [activity_vc_partial_mock verify]; + [vc_partial_mock verify]; } // Tests that the coordinator handles the QRGenerationCommands protocol.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm index d6858d4e..091bea2 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm
@@ -12,6 +12,7 @@ #import "ios/chrome/browser/ui/tab_switcher/tab_grid/features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -294,11 +295,10 @@ if (IsTabsBulkActionsEnabled()) { UIImageView* selectIconView = [[UIImageView alloc] init]; selectIconView.translatesAutoresizingMaskIntoConstraints = NO; - selectIconView.contentMode = UIViewContentModeCenter; + selectIconView.contentMode = UIViewContentModeScaleAspectFit; selectIconView.hidden = !self.isInSelectionMode; - selectIconView.image = [[self selectIconImageForCurrentState] - imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + selectIconView.image = [self selectIconImageForCurrentState]; [topBar addSubview:selectIconView]; _selectIconView = selectIconView; @@ -348,6 +348,10 @@ if (_selectIconView) { _selectIconConstraints = @[ + [_selectIconView.heightAnchor + constraintEqualToConstant:kGridCellSelectIconSize], + [_selectIconView.widthAnchor + constraintEqualToConstant:kGridCellSelectIconSize], [titleLabel.trailingAnchor constraintEqualToAnchor:_selectIconView.leadingAnchor constant:-kGridCellTitleLabelContentInset], @@ -355,7 +359,7 @@ constraintEqualToAnchor:_selectIconView.centerYAnchor], [_selectIconView.trailingAnchor constraintEqualToAnchor:topBar.trailingAnchor - constant:-kGridCellCloseButtonContentInset], + constant:-kGridCellSelectIconContentInset], ]; } @@ -392,7 +396,9 @@ - (UIImage*)selectIconImageForCurrentState { if (@available(iOS 13, *)) { if (_state == GridCellStateEditingUnselected) { - return [UIImage systemImageNamed:@"circle"]; + return [[UIImage systemImageNamed:@"circle"] + imageWithTintColor:[UIColor cr_systemGray3Color] + renderingMode:UIImageRenderingModeAlwaysOriginal]; } return [UIImage systemImageNamed:@"checkmark.circle.fill"]; } @@ -445,8 +451,7 @@ _state = state; _closeTapTargetButton.enabled = !self.isInSelectionMode; - self.selectIconView.image = [[self selectIconImageForCurrentState] - imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.selectIconView.image = [self selectIconImageForCurrentState]; [self configureCloseOrSelectIconConstraints]; self.border.hidden = self.isInSelectionMode;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h index 6d11cf9..7c915da 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h
@@ -89,6 +89,8 @@ extern const CGFloat kGridCellCloseButtonContentInset; extern const CGFloat kGridCellTitleLabelContentInset; extern const CGFloat kGridCellIconDiameter; +extern const CGFloat kGridCellSelectIconContentInset; +extern const CGFloat kGridCellSelectIconSize; extern const CGFloat kGridCellSelectionRingGapWidth; extern const CGFloat kGridCellSelectionRingTintWidth;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm index b3fe76d..aa047b4 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm
@@ -83,6 +83,8 @@ const CGFloat kGridCellCloseButtonContentInset = 8.5f; const CGFloat kGridCellTitleLabelContentInset = 4.0f; const CGFloat kGridCellIconDiameter = 16.0f; +const CGFloat kGridCellSelectIconContentInset = 4.0f; +const CGFloat kGridCellSelectIconSize = 25.0f; const CGFloat kGridCellSelectionRingGapWidth = 2.0f; const CGFloat kGridCellSelectionRingTintWidth = 5.0f;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm index a5c2c4f6..d5d9b76 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm
@@ -14,6 +14,7 @@ #import "ios/chrome/browser/ui/menu/menu_histograms.h" #import "ios/chrome/browser/ui/menu/tab_context_menu_delegate.h" #import "ios/chrome/browser/ui/ntp/ntp_util.h" +#import "ios/chrome/browser/ui/tab_switcher/tab_grid/features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_item.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_menu_actions_data_source.h" @@ -140,11 +141,14 @@ } } - if ([weakSelf.contextMenuDelegate - respondsToSelector:@selector(selectTabs)]) { - [menuElements addObject:[actionFactory actionToSelectTabsWithBlock:^{ - [weakSelf.contextMenuDelegate selectTabs]; - }]]; + if (IsTabsBulkActionsEnabled()) { + if ([weakSelf.contextMenuDelegate + respondsToSelector:@selector(selectTabs)]) { + [menuElements + addObject:[actionFactory actionToSelectTabsWithBlock:^{ + [weakSelf.contextMenuDelegate selectTabs]; + }]]; + } } if ([weakSelf.contextMenuDelegate respondsToSelector:@selector(closeTabWithIdentifier:
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm index c9ac354..5a04202 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
@@ -240,7 +240,18 @@ - (void)setMode:(TabGridMode)mode { _mode = mode; - [self.collectionView reloadData]; + + NSRange allSectionsRange = + NSMakeRange(/*location=*/0, self.collectionView.numberOfSections); + NSIndexSet* allSectionsIndexSet = + [NSIndexSet indexSetWithIndexesInRange:allSectionsRange]; + // Reloading specific sections in a |performBatchUpdates| fades the changes in + // rather than reloads the collection view with a harsh flash. + [self.collectionView + performBatchUpdates:^{ + [self.collectionView reloadSections:allSectionsIndexSet]; + } + completion:nil]; // Clear items when exiting selection mode. if (mode == TabGridModeNormal) {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm index 207c137..ef5ea528 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -1194,7 +1194,14 @@ } // Tests sharing multiple tabs from the tab grid edit mode. -- (void)testTabGridBulkActionShare { +// TODO(crbug.com/1238501): The pasteboard is "not available at this time" when +// running on device. +#if TARGET_OS_SIMULATOR +#define MAYBE_testTabGridBulkActionShare testTabGridBulkActionShare +#else +#define MAYBE_testTabGridBulkActionShare DISABLED_testTabGridBulkActionShare +#endif +- (void)MAYBE_testTabGridBulkActionShare { if (!base::ios::IsRunningOnIOS14OrLater()) { EARL_GREY_TEST_SKIPPED( @"Bulk actions are only supported on iOS 14 and later.");
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index 60999de..186b2cb 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -19,9 +19,6 @@ const base::Feature kTestFeature{"TestFeature", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kEnableIOSManagedSettingsUI{ - "EnableIOSManagedSettingsUI", base::FEATURE_ENABLED_BY_DEFAULT}; - const base::Feature kSharedHighlightingIOS{"SharedHighlightingIOS", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index 4ce8455..e2e75a07 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -25,10 +25,6 @@ // features in tests works. extern const base::Feature kTestFeature; -// Feature flag to enable showing a different UI when the setting is managed by -// an enterprise policy. -extern const base::Feature kEnableIOSManagedSettingsUI; - // Feature flag to enable Shared Highlighting (Link to Text). extern const base::Feature kSharedHighlightingIOS;
diff --git a/ios/chrome/common/credential_provider/BUILD.gn b/ios/chrome/common/credential_provider/BUILD.gn index e22c8c72..28db84b 100644 --- a/ios/chrome/common/credential_provider/BUILD.gn +++ b/ios/chrome/common/credential_provider/BUILD.gn
@@ -12,6 +12,8 @@ "archivable_credential.mm", "archivable_credential_store.h", "archivable_credential_store.mm", + "archivable_credential_util.h", + "archivable_credential_util.mm", "as_password_credential_identity+credential.h", "as_password_credential_identity+credential.mm", "constants.h",
diff --git a/ios/chrome/common/credential_provider/archivable_credential_store.mm b/ios/chrome/common/credential_provider/archivable_credential_store.mm index 4a51e85..eac645a 100644 --- a/ios/chrome/common/credential_provider/archivable_credential_store.mm +++ b/ios/chrome/common/credential_provider/archivable_credential_store.mm
@@ -98,8 +98,9 @@ options:0 error:&error]; DCHECK(!error) << base::SysNSStringToUTF8(error.description); - NSSet* classes = [NSSet setWithObjects:[ArchivableCredential class], - [NSMutableDictionary class], nil]; + NSSet* classes = + [NSSet setWithObjects:[ArchivableCredential class], + [NSMutableDictionary class], [NSString class], nil]; NSMutableDictionary<NSString*, ArchivableCredential*>* dictionary = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data
diff --git a/ios/chrome/common/credential_provider/archivable_credential_util.h b/ios/chrome/common/credential_provider/archivable_credential_util.h new file mode 100644 index 0000000..bb4e26d7 --- /dev/null +++ b/ios/chrome/common/credential_provider/archivable_credential_util.h
@@ -0,0 +1,15 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_COMMON_CREDENTIAL_PROVIDER_ARCHIVABLE_CREDENTIAL_UTIL_H_ +#define IOS_CHROME_COMMON_CREDENTIAL_PROVIDER_ARCHIVABLE_CREDENTIAL_UTIL_H_ + +#import <Foundation/Foundation.h> + +// Constructs a record identifier for the given data. This should be as close +// as possible to |RecordIdentifierForPasswordForm|, as this is what is used +// to detect if a credential should be updated instead of created. +NSString* RecordIdentifierForData(NSURL* url, NSString* username); + +#endif // IOS_CHROME_COMMON_CREDENTIAL_PROVIDER_ARCHIVABLE_CREDENTIAL_UTIL_H_
diff --git a/ios/chrome/common/credential_provider/archivable_credential_util.mm b/ios/chrome/common/credential_provider/archivable_credential_util.mm new file mode 100644 index 0000000..ef556b7 --- /dev/null +++ b/ios/chrome/common/credential_provider/archivable_credential_util.mm
@@ -0,0 +1,31 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/common/credential_provider/archivable_credential_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +NSString* RecordIdentifierForData(NSURL* url, NSString* username) { + NSURLComponents* urlComponents = [NSURLComponents componentsWithURL:url + resolvingAgainstBaseURL:NO]; + + // Remove specific parts of URL that are thrown away in the credential + // manager. + urlComponents.user = nil; + urlComponents.password = nil; + urlComponents.query = nil; + urlComponents.fragment = nil; + + NSString* strippedURL = urlComponents.string; + + // Replace path with / as well to end up with origin. + urlComponents.path = @"/"; + + NSString* origin = urlComponents.string; + + return + [NSString stringWithFormat:@"%@||%@||%@", strippedURL, username, origin]; +}
diff --git a/ios/chrome/common/credential_provider/user_defaults_credential_store.mm b/ios/chrome/common/credential_provider/user_defaults_credential_store.mm index 1eddca9..d1c0996 100644 --- a/ios/chrome/common/credential_provider/user_defaults_credential_store.mm +++ b/ios/chrome/common/credential_provider/user_defaults_credential_store.mm
@@ -69,8 +69,9 @@ return [[NSMutableDictionary alloc] init]; } NSError* error = nil; - NSSet* classes = [NSSet setWithObjects:[ArchivableCredential class], - [NSMutableDictionary class], nil]; + NSSet* classes = + [NSSet setWithObjects:[ArchivableCredential class], + [NSMutableDictionary class], [NSString class], nil]; NSMutableDictionary<NSString*, ArchivableCredential*>* dictionary = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data
diff --git a/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist b/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist index 34d673a..42fe8d8 100644 --- a/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist +++ b/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist
@@ -29,6 +29,7 @@ <string>IDS_IOS_CREDENTIAL_PROVIDER_EMPTY_CREDENTIALS_TITLE</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_ENTER</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_CANCEL</string> + <string>IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_HELP_ACCESSIBILITY_LABEL</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_ERROR_MESSAGE</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_ERROR_TITLE</string> @@ -38,6 +39,8 @@ <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_TITLE</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_PASSWORD</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_PASSWORD_PLACEHOLDER</string> + <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE</string> + <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_USERNAME</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_USERNAME_PLACEHOLDER</string> <string>IDS_IOS_CREDENTIAL_PROVIDER_NO_SEARCH_RESULTS</string>
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd index 23839a81..34294ea 100644 --- a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd +++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd
@@ -209,6 +209,9 @@ <message name="IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_CANCEL" desc="Title for cancel buttons" meaning="Title for buttons meant to cancel an action [CHAR_LIMIT=10]"> Cancel </message> + <message name="IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE" desc="Title for replace buttons" meaning="Title for buttons where the action replaces a password [CHAR_LIMIT=10]"> + Replace + </message> <message name="IDS_IOS_CREDENTIAL_PROVIDER_HELP_ACCESSIBILITY_LABEL" desc="Used as the accessibility label read by screen readers for a Help button." meaning="[iOS only][CHAR_LIMIT=30]"> Help </message> @@ -236,6 +239,12 @@ <message name="IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_PASSWORD_PLACEHOLDER" desc="Placeholder for password field"> password </message> + <message name="IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE" desc="Title for alert asking user if they want to replace a password"> + Replace Password? + </message> + <message name="IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE" desc="Message for alert asking user if they want to replace a password"> + You already saved a password for "<ph name="USERNAME">$1<ex>johndoe</ex></ph>" at <ph name="WEBSITE">$2<ex>google.com</ex></ph>. Do you want to replace it? + </message> <message name="IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_USERNAME" desc="Title for row to type in username"> Username </message>
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE.png.sha1 b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE.png.sha1 new file mode 100644 index 0000000..9c31c0d --- /dev/null +++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE.png.sha1
@@ -0,0 +1 @@ +8ee3dfae4e11ced386e1dd04a2e4c1b362d0b53b \ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE.png.sha1 b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE.png.sha1 new file mode 100644 index 0000000..9c31c0d --- /dev/null +++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +8ee3dfae4e11ced386e1dd04a2e4c1b362d0b53b \ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE.png.sha1 b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE.png.sha1 new file mode 100644 index 0000000..9c31c0d --- /dev/null +++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE.png.sha1
@@ -0,0 +1 @@ +8ee3dfae4e11ced386e1dd04a2e4c1b362d0b53b \ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/ui/BUILD.gn b/ios/chrome/credential_provider_extension/ui/BUILD.gn index 25cebe9..fdd95d6 100644 --- a/ios/chrome/credential_provider_extension/ui/BUILD.gn +++ b/ios/chrome/credential_provider_extension/ui/BUILD.gn
@@ -27,6 +27,7 @@ "new_password_mediator.mm", "new_password_table_cell.h", "new_password_table_cell.mm", + "new_password_ui_handler.h", "new_password_view_controller.h", "new_password_view_controller.mm", "stale_credentials_view_controller.h", @@ -86,3 +87,18 @@ ] configs += [ "//build/config/compiler:enable_arc" ] } + +source_set("unit_tests") { + testonly = true + sources = [ "new_password_mediator_unittest.mm" ] + deps = [ + ":ui", + "//base", + "//base/test:test_support", + "//ios/chrome/common/app_group", + "//ios/chrome/common/credential_provider", + "//ios/chrome/credential_provider_extension:password_util", + "//testing/gtest", + ] + configs += [ "//build/config/compiler:enable_arc" ] +}
diff --git a/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm b/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm index 49b3b73b..e6885f2 100644 --- a/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm +++ b/ios/chrome/credential_provider_extension/ui/credential_list_coordinator.mm
@@ -174,7 +174,8 @@ self.createPasswordCoordinator = [[NewPasswordCoordinator alloc] initWithBaseViewController:self.viewController context:self.context - serviceIdentifiers:self.serviceIdentifiers]; + serviceIdentifiers:self.serviceIdentifiers + existingCredentials:self.credentialStore]; [self.createPasswordCoordinator start]; }
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_coordinator.h b/ios/chrome/credential_provider_extension/ui/new_password_coordinator.h index 02346d67..00bf2d8 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_coordinator.h +++ b/ios/chrome/credential_provider_extension/ui/new_password_coordinator.h
@@ -9,6 +9,7 @@ @class ASCredentialProviderExtensionContext; @class ASCredentialServiceIdentifier; +@protocol CredentialStore; // The coordinator for the new password feature. @interface NewPasswordCoordinator : NSObject @@ -20,6 +21,7 @@ context:(ASCredentialProviderExtensionContext*)context serviceIdentifiers: (NSArray<ASCredentialServiceIdentifier*>*)serviceIdentifiers + existingCredentials:(id<CredentialStore>)existingCredentials NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_coordinator.mm b/ios/chrome/credential_provider_extension/ui/new_password_coordinator.mm index e434cf79..7941c9a 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_coordinator.mm +++ b/ios/chrome/credential_provider_extension/ui/new_password_coordinator.mm
@@ -6,6 +6,7 @@ #import <AuthenticationServices/AuthenticationServices.h> +#include "ios/chrome/common/app_group/app_group_constants.h" #import "ios/chrome/common/credential_provider/credential.h" #import "ios/chrome/credential_provider_extension/password_util.h" #import "ios/chrome/credential_provider_extension/ui/new_password_mediator.h" @@ -34,6 +35,10 @@ @property(nonatomic, strong) NSArray<ASCredentialServiceIdentifier*>* serviceIdentifiers; +// The existing credentials to check for whether a new credential already +// exists. +@property(nonatomic, weak) id<CredentialStore> existingCredentials; + @end @implementation NewPasswordCoordinator @@ -42,19 +47,24 @@ initWithBaseViewController:(UIViewController*)baseViewController context:(ASCredentialProviderExtensionContext*)context serviceIdentifiers: - (NSArray<ASCredentialServiceIdentifier*>*)serviceIdentifiers { + (NSArray<ASCredentialServiceIdentifier*>*)serviceIdentifiers + existingCredentials:(id<CredentialStore>)existingCredentials { self = [super init]; if (self) { _baseViewController = baseViewController; _context = context; _serviceIdentifiers = serviceIdentifiers; + _existingCredentials = existingCredentials; } return self; } - (void)start { self.mediator = [[NewPasswordMediator alloc] - initWithServiceIdentifier:self.serviceIdentifiers.firstObject]; + initWithUserDefaults:app_group::GetGroupUserDefaults() + serviceIdentifier:self.serviceIdentifiers.firstObject]; + self.mediator.existingCredentials = self.existingCredentials; + self.mediator.context = self.context; NewPasswordViewController* newPasswordViewController = [[NewPasswordViewController alloc] init]; @@ -63,6 +73,12 @@ newPasswordViewController.navigationItem.prompt = PromptForServiceIdentifiers(self.serviceIdentifiers); + self.mediator.uiHandler = newPasswordViewController; + + NSString* identifier = self.serviceIdentifiers.firstObject.identifier; + NSURL* url = identifier ? [NSURL URLWithString:identifier] : nil; + newPasswordViewController.currentHost = url.host; + self.viewController = [[UINavigationController alloc] initWithRootViewController:newPasswordViewController]; [self.baseViewController presentViewController:self.viewController @@ -84,14 +100,4 @@ [self.baseViewController dismissViewControllerAnimated:YES completion:nil]; } -- (void)userSelectedCredential:(id<Credential>)credential { - NSString* password = - PasswordWithKeychainIdentifier(credential.keychainIdentifier); - ASPasswordCredential* ASCredential = - [ASPasswordCredential credentialWithUser:credential.user - password:password]; - [self.context completeRequestWithSelectedCredential:ASCredential - completionHandler:nil]; -} - @end
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_mediator.h b/ios/chrome/credential_provider_extension/ui/new_password_mediator.h index 2fefa747..7be7186 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_mediator.h +++ b/ios/chrome/credential_provider_extension/ui/new_password_mediator.h
@@ -10,15 +10,34 @@ #import "ios/chrome/credential_provider_extension/ui/new_password_view_controller.h" @class ASCredentialServiceIdentifier; +@class ASCredentialProviderExtensionContext; +@protocol CredentialStore; +@protocol NewPasswordUIHandler; // This mediator fetches requirements and saves new credentials for its // consumer. @interface NewPasswordMediator : NSObject <NewCredentialHandler> -- (instancetype)initWithServiceIdentifier: - (ASCredentialServiceIdentifier*)serviceIdentifier NS_DESIGNATED_INITIALIZER; +// Initializes a new object, using |userDefaults| as the user defaults location +// to store new credentials to and |serviceIdentifier| as the current service to +// store new credentials for. +- (instancetype)initWithUserDefaults:(NSUserDefaults*)userDefaults + serviceIdentifier: + (ASCredentialServiceIdentifier*)serviceIdentifier + NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; + +// Existing credential store to check to see if a new credential already +// exists. +@property(nonatomic, weak) id<CredentialStore> existingCredentials; + +// UI handler to allow this mediator to ask the UI for any necessary updates. +@property(nonatomic, weak) id<NewPasswordUIHandler> uiHandler; + +// The extension context for the credential provider. +@property(nonatomic, weak) ASCredentialProviderExtensionContext* context; + @end #endif // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_NEW_PASSWORD_MEDIATOR_H_
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm b/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm index 4bab35859..5746d3ca 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm +++ b/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm
@@ -7,10 +7,15 @@ #import <AuthenticationServices/AuthenticationServices.h> #include "ios/chrome/common/app_group/app_group_constants.h" +#include "ios/chrome/common/app_group/app_group_metrics.h" #import "ios/chrome/common/credential_provider/archivable_credential.h" +#import "ios/chrome/common/credential_provider/archivable_credential_util.h" #import "ios/chrome/common/credential_provider/constants.h" +#import "ios/chrome/common/credential_provider/credential_store.h" #import "ios/chrome/common/credential_provider/user_defaults_credential_store.h" +#import "ios/chrome/credential_provider_extension/metrics_util.h" #import "ios/chrome/credential_provider_extension/password_util.h" +#import "ios/chrome/credential_provider_extension/ui/new_password_ui_handler.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -21,14 +26,19 @@ // The service identifier the password is being created for, @property(nonatomic, strong) ASCredentialServiceIdentifier* serviceIdentifier; +// The NSUserDefaults new credentials should be stored to. +@property(nonatomic, strong) NSUserDefaults* userDefaults; + @end @implementation NewPasswordMediator -- (instancetype)initWithServiceIdentifier: - (ASCredentialServiceIdentifier*)serviceIdentifier { +- (instancetype)initWithUserDefaults:(NSUserDefaults*)userDefaults + serviceIdentifier: + (ASCredentialServiceIdentifier*)serviceIdentifier { self = [super init]; if (self) { + _userDefaults = userDefaults; _serviceIdentifier = serviceIdentifier; } return self; @@ -36,17 +46,56 @@ #pragma mark - NewCredentialHandler +- (void)saveCredentialWithUsername:(NSString*)username + password:(NSString*)password + shouldReplace:(BOOL)shouldReplace { + if (!shouldReplace && [self credentialExistsForUsername:username]) { + [self.uiHandler alertUserCredentialExists]; + return; + } + + ArchivableCredential* credential = + [self createNewCredentialWithUsername:username password:password]; + + if (!credential) { + [self.uiHandler alertSavePasswordFailed]; + return; + } + + [self + saveNewCredential:credential + completion:^(NSError* error) { + if (error) { + UpdateUMACountForKey( + app_group::kCredentialExtensionSaveCredentialFailureCount); + [self.uiHandler alertSavePasswordFailed]; + return; + } + [self userSelectedCredential:credential]; + }]; +} + +#pragma mark - Private + +// Checks whether a credential already exists with the given username. +- (BOOL)credentialExistsForUsername:(NSString*)username { + NSURL* url = [NSURL URLWithString:self.serviceIdentifier.identifier]; + NSString* recordIdentifier = RecordIdentifierForData(url, username); + + return [self.existingCredentials + credentialWithRecordIdentifier:recordIdentifier]; +} + +// Creates a new credential but doesn't add it to any stores. - (ArchivableCredential*)createNewCredentialWithUsername:(NSString*)username password:(NSString*)password { + NSURL* url = [NSURL URLWithString:self.serviceIdentifier.identifier]; + NSString* recordIdentifier = RecordIdentifierForData(url, username); + NSString* uuid = [[NSUUID UUID] UUIDString]; if (!StorePasswordInKeychain(password, uuid)) { return nil; } - - NSURL* url = [NSURL URLWithString:self.serviceIdentifier.identifier]; - NSString* recordIdentifier = - [NSString stringWithFormat:@"CPE|%@|%@|%@", url.host, username, - self.serviceIdentifier.identifier]; NSString* validationIdentifier = AppGroupUserDefaultsCredentialProviderUserID(); @@ -61,15 +110,33 @@ validationIdentifier:validationIdentifier]; } +// Saves the given credential to disk and calls |completion| once the operation +// is finished. - (void)saveNewCredential:(ArchivableCredential*)credential completion:(void (^)(NSError* error))completion { NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials(); UserDefaultsCredentialStore* store = [[UserDefaultsCredentialStore alloc] - initWithUserDefaults:app_group::GetGroupUserDefaults() + initWithUserDefaults:self.userDefaults key:key]; - [store addCredential:credential]; + if ([store credentialWithRecordIdentifier:credential.recordIdentifier]) { + [store updateCredential:credential]; + } else { + [store addCredential:credential]; + } + [store saveDataWithCompletion:completion]; } +// Alerts the host app that the user selected a credential. +- (void)userSelectedCredential:(id<Credential>)credential { + NSString* password = + PasswordWithKeychainIdentifier(credential.keychainIdentifier); + ASPasswordCredential* ASCredential = + [ASPasswordCredential credentialWithUser:credential.user + password:password]; + [self.context completeRequestWithSelectedCredential:ASCredential + completionHandler:nil]; +} + @end
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_mediator_unittest.mm b/ios/chrome/credential_provider_extension/ui/new_password_mediator_unittest.mm new file mode 100644 index 0000000..ad82596 --- /dev/null +++ b/ios/chrome/credential_provider_extension/ui/new_password_mediator_unittest.mm
@@ -0,0 +1,255 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/credential_provider_extension/ui/new_password_mediator.h" + +#import <AuthenticationServices/AuthenticationServices.h> +#import <Foundation/Foundation.h> + +#import "base/test/ios/wait_util.h" +#include "ios/chrome/common/app_group/app_group_constants.h" +#import "ios/chrome/common/credential_provider/archivable_credential.h" +#import "ios/chrome/common/credential_provider/archivable_credential_store.h" +#import "ios/chrome/common/credential_provider/constants.h" +#import "ios/chrome/common/credential_provider/user_defaults_credential_store.h" +#import "ios/chrome/credential_provider_extension/password_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// Fake implementation of NewPasswordUIHandler so tests can tell if any UI +// methods were called +@interface FakeNewPasswordUIHandler : NSObject <NewPasswordUIHandler> + +// Whether the |-alertUserCredentialExists| method was called. +@property(nonatomic, assign) BOOL alertedCredentialExists; +// Whether the |-alertSavePasswordFailed| method was called. +@property(nonatomic, assign) BOOL alertedSaveFailed; + +@end + +@implementation FakeNewPasswordUIHandler + +- (void)alertUserCredentialExists { + self.alertedCredentialExists = YES; +} + +- (void)alertSavePasswordFailed { + self.alertedSaveFailed = YES; +} + +@end + +// Fake implementation of ASCredentialProviderExtensionContext so tests can +// tell when a credential has been saved. +@interface FakeExtensionContext : ASCredentialProviderExtensionContext + +@property(nonatomic, strong) ASPasswordCredential* credential; + +@property(nonatomic, strong) void (^receivedCredentialBlock)(); + +@end + +@implementation FakeExtensionContext + +- (void)completeRequestWithSelectedCredential:(ASPasswordCredential*)credential + completionHandler: + (void (^)(BOOL expired))completionHandler { + self.credential = credential; + if (completionHandler) { + completionHandler(NO); + } + if (self.receivedCredentialBlock) { + self.receivedCredentialBlock(); + } +} + +@end + +namespace { + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForFileOperationTimeout; + +NSString* const testWebsiteBase = @"https://wwww.example.com"; +NSString* const testWebsite = + [NSString stringWithFormat:@"%@/test?page=1", testWebsiteBase]; + +NSUserDefaults* TestUserDefaults() { + return [NSUserDefaults standardUserDefaults]; +} + +ArchivableCredential* TestCredential(NSString* recordIdentifier) { + return [[ArchivableCredential alloc] initWithFavicon:@"favicon" + keychainIdentifier:@"keychainIdentifier" + rank:5 + recordIdentifier:recordIdentifier + serviceIdentifier:@"serviceIdentifier" + serviceName:@"serviceName" + user:@"user" + validationIdentifier:@"validationIdentifier"]; +} + +class NewPasswordMediatorTest : public PlatformTest { + public: + void SetUp() override; + void TearDown() override; + + protected: + ASCredentialServiceIdentifier* serviceIdentifier_ = + [[ASCredentialServiceIdentifier alloc] + initWithIdentifier:testWebsite + type:ASCredentialServiceIdentifierTypeURL]; + NewPasswordMediator* mediator_ = + [[NewPasswordMediator alloc] initWithUserDefaults:TestUserDefaults() + serviceIdentifier:serviceIdentifier_]; + id<MutableCredentialStore> store_; + FakeNewPasswordUIHandler* uiHandler_ = + [[FakeNewPasswordUIHandler alloc] init]; + FakeExtensionContext* context_ = [[FakeExtensionContext alloc] init]; +}; + +void NewPasswordMediatorTest::SetUp() { + PlatformTest::SetUp(); + NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials(); + [TestUserDefaults() removeObjectForKey:key]; + + store_ = [[UserDefaultsCredentialStore alloc] + initWithUserDefaults:TestUserDefaults() + key:key]; + + mediator_.existingCredentials = store_; + mediator_.uiHandler = uiHandler_; + mediator_.context = context_; +} + +void NewPasswordMediatorTest::TearDown() { + PlatformTest::TearDown(); + NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials(); + [TestUserDefaults() removeObjectForKey:key]; +} + +// Tests that |-saveNewCredential:completion:| adds a new credential to the +// store and that gets saved to disk. +TEST_F(NewPasswordMediatorTest, SaveNewCredential) { + // Manually store a credential. + ArchivableCredential* tempCredential = TestCredential(@"abc"); + [store_ addCredential:tempCredential]; + EXPECT_EQ(1u, store_.credentials.count); + __block BOOL blockWaitCompleted = NO; + [store_ saveDataWithCompletion:^(NSError* error) { + EXPECT_FALSE(error); + blockWaitCompleted = YES; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^BOOL { + return blockWaitCompleted; + })); + + // Create a second credential with a new record identifier and make sure it + // gets saved to disk. + NSString* testUsername = @"user"; + NSString* testPassword = @"password"; + + context_.receivedCredentialBlock = ^() { + blockWaitCompleted = YES; + }; + + blockWaitCompleted = NO; + [mediator_ saveCredentialWithUsername:testUsername + password:testPassword + shouldReplace:NO]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^BOOL { + return blockWaitCompleted; + })); + + EXPECT_FALSE(uiHandler_.alertedCredentialExists); + EXPECT_FALSE(uiHandler_.alertedSaveFailed); + + EXPECT_NSEQ(testUsername, context_.credential.user); + EXPECT_NSEQ(testPassword, context_.credential.password); + + // Reload the store from memory and check that the credential was added. + NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials(); + UserDefaultsCredentialStore* freshCredentialStore = + [[UserDefaultsCredentialStore alloc] + initWithUserDefaults:TestUserDefaults() + key:key]; + EXPECT_TRUE(freshCredentialStore); + EXPECT_TRUE(freshCredentialStore.credentials); + EXPECT_EQ(2u, freshCredentialStore.credentials.count); + EXPECT_NSEQ(testUsername, freshCredentialStore.credentials[1].user); +} + +// Tests that |-saveNewCredential:completion:| updates an existing credential +// and that gets saved to disk. +TEST_F(NewPasswordMediatorTest, SaveUpdateCredential) { + // Create a credential that will be stored. + NSString* recordIdentifier = [NSString + stringWithFormat:@"%@/test||user||%@/", testWebsiteBase, testWebsiteBase]; + + // Create an initial credential with a known record identifier and store that + // one to disk. + ArchivableCredential* tempCredential = TestCredential(recordIdentifier); + [store_ addCredential:tempCredential]; + EXPECT_EQ(1u, store_.credentials.count); + __block BOOL blockWaitCompleted = NO; + [store_ saveDataWithCompletion:^(NSError* error) { + EXPECT_FALSE(error); + blockWaitCompleted = YES; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^BOOL { + return blockWaitCompleted; + })); + + // Store the originally created credential and that should update the existing + // one. + context_.receivedCredentialBlock = ^() { + blockWaitCompleted = YES; + }; + + // The first attempt to save should fail because the user hasn't be notified + // that their credentials are being replaced. + blockWaitCompleted = NO; + NSString* testUsername = @"user"; + NSString* testPassword = @"password"; + [mediator_ saveCredentialWithUsername:testUsername + password:testPassword + shouldReplace:NO]; + + EXPECT_TRUE(uiHandler_.alertedCredentialExists); + EXPECT_FALSE(uiHandler_.alertedSaveFailed); + EXPECT_FALSE(blockWaitCompleted); + uiHandler_.alertedCredentialExists = NO; + + // The second attempt to save should succeed. + blockWaitCompleted = NO; + [mediator_ saveCredentialWithUsername:testUsername + password:testPassword + shouldReplace:YES]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^BOOL { + return blockWaitCompleted; + })); + + EXPECT_FALSE(uiHandler_.alertedCredentialExists); + EXPECT_FALSE(uiHandler_.alertedSaveFailed); + + EXPECT_NSEQ(testUsername, context_.credential.user); + EXPECT_NSEQ(testPassword, context_.credential.password); + + // Reload the store from memory and check that the credential was updated. + NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials(); + UserDefaultsCredentialStore* freshCredentialStore = + [[UserDefaultsCredentialStore alloc] + initWithUserDefaults:TestUserDefaults() + key:key]; + EXPECT_TRUE(freshCredentialStore); + EXPECT_TRUE(freshCredentialStore.credentials); + EXPECT_EQ(1u, freshCredentialStore.credentials.count); + EXPECT_NSEQ(testUsername, freshCredentialStore.credentials.firstObject.user); +} +}
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_ui_handler.h b/ios/chrome/credential_provider_extension/ui/new_password_ui_handler.h new file mode 100644 index 0000000..982fb26 --- /dev/null +++ b/ios/chrome/credential_provider_extension/ui/new_password_ui_handler.h
@@ -0,0 +1,20 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_NEW_PASSWORD_UI_HANDLER_H_ +#define IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_NEW_PASSWORD_UI_HANDLER_H_ + +// Protocol to allow the NewPasswordMediator to interact with the UI +@protocol NewPasswordUIHandler + +// Asks the UI to alert the user that the credential they are trying to create +// already exists. +- (void)alertUserCredentialExists; + +// Asks the UI to alert the user that the saving process failed. +- (void)alertSavePasswordFailed; + +@end + +#endif // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_NEW_PASSWORD_UI_HANDLER_H_
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.h b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.h index e56f544..0d056ce 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.h +++ b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.h
@@ -7,6 +7,8 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/credential_provider_extension/ui/new_password_ui_handler.h" + @class ArchivableCredential; @protocol Credential; @class NewPasswordViewController; @@ -17,32 +19,32 @@ - (void)navigationCancelButtonWasPressedInNewPasswordViewController: (NewPasswordViewController*)viewController; -// Called when the user selects a given credential -- (void)userSelectedCredential:(id<Credential>)credential; - @end @protocol NewCredentialHandler -// Called when the user wants to create a new credential. -- (ArchivableCredential*)createNewCredentialWithUsername:(NSString*)username - password:(NSString*)password; - -// Saves the given credential to disk and calls |completion| once the operation -// is finished. -- (void)saveNewCredential:(ArchivableCredential*)credential - completion:(void (^)(NSError* error))completion; +// Asks the handler to save a credential with the given |username| and +// |password|. If |shouldReplace| is true, then the user has already been warned +// that they may be replacing an existing credential. Otherwise, the handler +// should not replace an existing credential. +- (void)saveCredentialWithUsername:(NSString*)username + password:(NSString*)password + shouldReplace:(BOOL)shouldReplace; @end // View Controller where a user can create a new credential and use a suggested // password. -@interface NewPasswordViewController : UITableViewController +@interface NewPasswordViewController + : UITableViewController <NewPasswordUIHandler> @property(nonatomic, weak) id<NewPasswordViewControllerDelegate> delegate; @property(nonatomic, weak) id<NewCredentialHandler> credentialHandler; +// The host for the password being generated. +@property(nonatomic, strong) NSString* currentHost; + @end #endif // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_NEW_PASSWORD_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm index 38f24eec..ee34f97 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm +++ b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm
@@ -9,7 +9,6 @@ #import "ios/chrome/common/credential_provider/archivable_credential.h" #import "ios/chrome/common/credential_provider/constants.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" -#import "ios/chrome/credential_provider_extension/metrics_util.h" #import "ios/chrome/credential_provider_extension/ui/new_password_table_cell.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -171,45 +170,44 @@ // Action for save button. - (void)saveButtonWasPressed { + [self saveCredential:NO]; +} + +- (NSString*)currentUsername { NSIndexPath* usernameIndexPath = [NSIndexPath indexPathForRow:NewPasswordTableCellTypeUsername inSection:0]; NewPasswordTableCell* usernameCell = [self.tableView cellForRowAtIndexPath:usernameIndexPath]; - NSString* username = usernameCell.textField.text; + return usernameCell.textField.text; +} +- (NSString*)currentPassword { NSIndexPath* passwordIndexPath = [NSIndexPath indexPathForRow:NewPasswordTableCellTypePassword inSection:0]; NewPasswordTableCell* passwordCell = [self.tableView cellForRowAtIndexPath:passwordIndexPath]; - NSString* password = passwordCell.textField.text; - - ArchivableCredential* credential = - [self.credentialHandler createNewCredentialWithUsername:username - password:password]; - - if (!credential) { - [self savePasswordFailed]; - return; - } - - [self.credentialHandler - saveNewCredential:credential - completion:^(NSError* error) { - if (error) { - UpdateUMACountForKey( - app_group::kCredentialExtensionSaveCredentialFailureCount); - [self savePasswordFailed]; - return; - } - [self.delegate userSelectedCredential:credential]; - }]; + return passwordCell.textField.text; } +// Saves the current data as a credential. If |shouldReplace| is YES, then the +// user has already said they are aware that they are replacing a previous +// credential. +- (void)saveCredential:(BOOL)shouldReplace { + NSString* username = [self currentUsername]; + NSString* password = [self currentPassword]; + + [self.credentialHandler saveCredentialWithUsername:username + password:password + shouldReplace:shouldReplace]; +} + +#pragma mark - NewPasswordUIHandler + // Alerts the user that saving their password failed. -- (void)savePasswordFailed { - UIAlertController* ac = [UIAlertController +- (void)alertSavePasswordFailed { + UIAlertController* alertController = [UIAlertController alertControllerWithTitle: NSLocalizedString( @"IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_ERROR_TITLE", @@ -225,8 +223,45 @@ style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ }]; - [ac addAction:defaultAction]; - [self presentViewController:ac animated:YES completion:nil]; + [alertController addAction:defaultAction]; + [self presentViewController:alertController animated:YES completion:nil]; +} + +- (void)alertUserCredentialExists { + NSString* messageBaseLocalizedString = NSLocalizedString( + @"IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_MESSAGE", + @"Message for password replace alert"); + NSString* message = [[messageBaseLocalizedString + stringByReplacingOccurrencesOfString:@"$2" + withString:self.currentHost] + stringByReplacingOccurrencesOfString:@"$1" + withString:[self currentUsername]]; + UIAlertController* alertController = [UIAlertController + alertControllerWithTitle: + NSLocalizedString( + @"IDS_IOS_CREDENTIAL_PROVIDER_NEW_PASSWORD_REPLACE_TITLE", + @"Replace password?") + message:message + preferredStyle:UIAlertControllerStyleAlert]; + __weak __typeof(self) weakSelf = self; + UIAlertAction* replaceAction = [UIAlertAction + actionWithTitle:NSLocalizedString( + @"IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_REPLACE", + @"Replace") + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction* action) { + [weakSelf saveCredential:YES]; + }]; + [alertController addAction:replaceAction]; + UIAlertAction* cancelAction = [UIAlertAction + actionWithTitle:NSLocalizedString( + @"IDS_IOS_CREDENTIAL_PROVIDER_EXTENSION_CANCEL", + @"Cancel") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction* action){ + }]; + [alertController addAction:cancelAction]; + [self presentViewController:alertController animated:YES completion:nil]; } // Returns a new cancel button for the navigation bar.
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index c72e932..626b554 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -394,6 +394,7 @@ deps += [ "//ios/chrome/browser/credential_provider:unit_tests", "//ios/chrome/credential_provider_extension:unit_tests", + "//ios/chrome/credential_provider_extension/ui:unit_tests", ] }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 index 6c52c3f..8256117d 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -9a9f74880a2673f2adcbf874637370f6b15e9ab8 \ No newline at end of file +12f4708be935a6b984d46c8c3fd619edfbc06aee \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 index 0567c112..006385e 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -815b75edb192863fb0f94956d83962a873b9951b \ No newline at end of file +c2cb46e66232e23ea738668538a3547c7857b27d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 index a1e569c..ab7ed20 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -88f38c115879d393d90904581a28ee6e47152975 \ No newline at end of file +567791957da493a57959ea40f2b96f49367a8db9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 index 57b77ef6..f1ab347 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -5fc70e66b5642178753c755dfa60f52a1b70b70e \ No newline at end of file +92483dbbdee94dd2a956ed882fd73e0847271e28 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 index 8e64914..4de7cc1 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -34a0fa8ab7394c030fd6b404ea1d1c3b64aaa807 \ No newline at end of file +f0383d133f13228a20e8c48e627d6316cdb27766 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 index ea35b648..e86bf91 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -f5d981de4b713bcec6ff469bbe3a2186e3539fb7 \ No newline at end of file +109be2d79ddea7d3c22be831373e6d0b626752b7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 index 278f5ae3..72b039df 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -98834484c74c544c05556db15520cb5a754eeb7e \ No newline at end of file +7ab19cab3219927743a9364e3647486e0db66780 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 index 9d0155c0..bed3489 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -53fbf94a5dfb26cfd048f592583557db9b5b883b \ No newline at end of file +504c32a942276ab61393426f25a28d972c9e01ea \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 index 354a16c..7998e0f 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -93e6df7123197059d167a787e9fe1395b522539d \ No newline at end of file +baeecd630da45013a4c1b3b383131530d96680b6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 index e6dbfd0d..d024350 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -67abcf725ff62ddd00b2f8a3ed1bd793f169226d \ No newline at end of file +484973bac940afa16b523f95d3bc758793d3e116 \ No newline at end of file
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 267da9e8d..9b32170 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -206,6 +206,20 @@ const char kEnableClearHevcForTesting[] = "enable-clear-hevc-for-testing"; #endif +#if defined(OS_CHROMEOS) +// These are flags passed from ash-chrome to lacros-chrome that correspond to +// buildflags for the platform we are running on. lacros-chrome only builds for +// x86/arm differences, so we unconditionally build in the below features into +// the relevant parts of lacros-chrome and then filter the functionality based +// on these command line flags. +MEDIA_EXPORT extern const char kLacrosEnablePlatformEncryptedHevc[] = + "lacros-enable-platform-encrypted-hevc"; +MEDIA_EXPORT extern const char kLacrosEnablePlatformHevc[] = + "lacros-enable-platform-hevc"; +MEDIA_EXPORT extern const char kLacrosUseChromeosProtectedMedia[] = + "lacros-use-chromeos-protected-media"; +#endif // defined(OS_CHROMEOS) + namespace autoplay { // Autoplay policy that requires a document user activation.
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 8b023e8..4e79508 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -91,6 +91,12 @@ MEDIA_EXPORT extern const char kEnableClearHevcForTesting[]; #endif +#if defined(OS_CHROMEOS) +MEDIA_EXPORT extern const char kLacrosEnablePlatformEncryptedHevc[]; +MEDIA_EXPORT extern const char kLacrosEnablePlatformHevc[]; +MEDIA_EXPORT extern const char kLacrosUseChromeosProtectedMedia[]; +#endif // defined(OS_CHROMEOS) + namespace autoplay { MEDIA_EXPORT extern const char kDocumentUserActivationRequiredPolicy[];
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 9965a49..336855c8 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc
@@ -468,25 +468,31 @@ DVLOG(1) << "Initialize()"; TRACE_EVENT_ASYNC_BEGIN0("media", "ChunkDemuxer::Initialize", this); - base::AutoLock auto_lock(lock_); - if (state_ == SHUTDOWN) { - // Init cb must only be run after this method returns, so post. - init_cb_ = BindToCurrentLoop(std::move(init_cb)); - RunInitCB_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); - return; + base::OnceClosure open_cb; + + // Locked scope + { + base::AutoLock auto_lock(lock_); + if (state_ == SHUTDOWN) { + // Init cb must only be run after this method returns, so post. + init_cb_ = BindToCurrentLoop(std::move(init_cb)); + RunInitCB_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); + return; + } + + DCHECK_EQ(state_, WAITING_FOR_INIT); + host_ = host; + // Do not post init_cb once this function returns because if there is an + // error after initialization, the error might be reported before init_cb + // has a chance to run. This is because ChunkDemuxer::ReportError_Locked + // directly calls DemuxerHost::OnDemuxerError: crbug.com/633016. + init_cb_ = std::move(init_cb); + + ChangeState_Locked(INITIALIZING); + open_cb = std::move(open_cb_); } - DCHECK_EQ(state_, WAITING_FOR_INIT); - host_ = host; - // Do not post init_cb once this function returns because if there is an - // error after initialization, the error might be reported before init_cb - // has a chance to run. This is because ChunkDemuxer::ReportError_Locked - // directly calls DemuxerHost::OnDemuxerError: crbug.com/633016. - init_cb_ = std::move(init_cb); - - ChangeState_Locked(INITIALIZING); - - std::move(open_cb_).Run(); + std::move(open_cb).Run(); } void ChunkDemuxer::Stop() {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index c6a847a..4575cf6 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc
@@ -22,6 +22,7 @@ #include "base/strings/string_util.h" #include "base/synchronization/waitable_event.h" #include "base/test/task_environment.h" +#include "build/build_config.h" #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" #include "media/base/decrypt_config.h" @@ -1358,6 +1359,16 @@ } } +TEST_F(ChunkDemuxerTest, AddIdDuringOpenCallback) { + // Tests that users may call |ChunkDemuxer::AddId| (or really any method that + // acquires |ChunkDemuxer::lock_|) during the open callback. + EXPECT_CALL(*this, DemuxerOpened()).WillOnce([this]() { this->AddId(); }); + + CreateNewDemuxer(); + demuxer_->Initialize(&host_, base::DoNothing()); + ShutdownDemuxer(); +} + TEST_F(ChunkDemuxerTest, AudioVideoTrackIdsChange) { // Test with 1 audio and 1 video stream. Send a second init segment in which // the audio and video track IDs change. Verify that appended buffers before
diff --git a/media/filters/source_buffer_state.cc b/media/filters/source_buffer_state.cc index 1ea91df..3a435c0 100644 --- a/media/filters/source_buffer_state.cc +++ b/media/filters/source_buffer_state.cc
@@ -718,6 +718,15 @@ if (video_config.codec() == kCodecHEVC) { #if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosEnablePlatformEncryptedHevc)) { + NOTREACHED() << "MSE parser must not emit HEVC tracks on runtime " + "configurations that do not support HEVC playback " + "via platform."; + return false; + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) // HEVC is only supported through EME under this build flag, so // require the config to be for an encrypted track. Even so, // conditionally allow clear HEVC if cmdline has test override.
diff --git a/media/gpu/args.gni b/media/gpu/args.gni index 33ab1fa3..4004937 100644 --- a/media/gpu/args.gni +++ b/media/gpu/args.gni
@@ -27,6 +27,8 @@ # Indicates if ChromeOS protected media support exists. This is used # to enable the CDM daemon in Chrome OS as well as support for # encrypted content with HW video decoders. + # TODO(jkardatzke): Enable this for Lacros always, it is determined at runtime + # in that configuration. use_chromeos_protected_media = false # Indicates if ChromeOS protected media supports the AV1 codec. By default
diff --git a/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc index fff14f9..dfa8b83 100644 --- a/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc +++ b/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc
@@ -218,6 +218,7 @@ {slice_params_->type(), slice_params_->size(), &slice_param}}}; #if BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr<uint8_t[]> protected_vp9_data; + std::string amd_decrypt_params; if (IsTranscrypted()) { CHECK(decrypt_config); CHECK_EQ(decrypt_config->subsamples().size(), 1u); @@ -228,9 +229,19 @@ return DecodeStatus::kFail; } DCHECK_EQ(decrypt_config->key_id().length(), protected_params_->size()); + // For VP9 superframes, the IV may have been incremented, so copy that + // back into the decryption parameters. The decryption parameters struct has + // a uint32_t for the first parameter, and the second is the 128-bit IV and + // then various other fields. Total max structure size is 128 bytes. The + // structure definition is in ChromeOS internal code so we do not reference + // it directly here. + constexpr uint32_t dp_iv_offset = sizeof(uint32_t); + amd_decrypt_params = decrypt_config->key_id(); + memcpy(&amd_decrypt_params[dp_iv_offset], decrypt_config->iv().data(), + DecryptConfig::kDecryptionKeySize); buffers.push_back({protected_params_->id(), {protected_params_->type(), protected_params_->size(), - decrypt_config->key_id().data()}}); + amd_decrypt_params.data()}}); // For transcrypted VP9 on AMD we need to send the UCH + cypher_bytes from // the buffer as the slice data per AMD's instructions.
diff --git a/media/mojo/clients/mojo_video_decoder.cc b/media/mojo/clients/mojo_video_decoder.cc index 2dde9217..f9eb8bc 100644 --- a/media/mojo/clients/mojo_video_decoder.cc +++ b/media/mojo/clients/mojo_video_decoder.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/command_line.h" #include "base/feature_list.h" #include "base/location.h" #include "base/logging.h" @@ -134,6 +135,12 @@ // Currently only the Android backends and specific ChromeOS configurations // support decryption. #if defined(OS_ANDROID) || BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia)) { + return false; + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) return true; #else return false;
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn index d1ead00..e4213fd8 100644 --- a/media/mojo/mojom/BUILD.gn +++ b/media/mojo/mojom/BUILD.gn
@@ -73,6 +73,7 @@ "//gpu/ipc/common:interfaces", "//media/learning/mojo/public/mojom", "//mojo/public/mojom/base", + "//sandbox/policy/mojom", "//services/media_session/public/mojom", "//services/network/public/mojom", "//services/network/public/mojom:cookies_mojom",
diff --git a/media/mojo/mojom/cdm_service.mojom b/media/mojo/mojom/cdm_service.mojom index 49b570aa..cb10ff26f 100644 --- a/media/mojo/mojom/cdm_service.mojom +++ b/media/mojo/mojom/cdm_service.mojom
@@ -7,6 +7,7 @@ import "media/mojo/mojom/content_decryption_module.mojom"; import "media/mojo/mojom/frame_interface_factory.mojom"; import "mojo/public/mojom/base/file_path.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; import "services/service_manager/public/mojom/interface_provider.mojom"; [EnableIf=is_mac] @@ -45,6 +46,7 @@ // - On Mac, the process is fully sandboxed when launched, and `token_provider` // is needed to help load the CDM in the process. // - On Linux/ChromeOS, the CDM is preloaded in the zygote sandbox. +[ServiceSandbox=sandbox.mojom.Sandbox.kCdm] interface CdmServiceBroker { // Loads the CDM at `cdm_path` into the process and returns the `CdmService`. GetService(mojo_base.mojom.FilePath cdm_path,
diff --git a/media/mojo/mojom/media_foundation_service.mojom b/media/mojo/mojom/media_foundation_service.mojom index 941e764..fd7eba5 100644 --- a/media/mojo/mojom/media_foundation_service.mojom +++ b/media/mojo/mojom/media_foundation_service.mojom
@@ -8,6 +8,7 @@ import "media/mojo/mojom/interface_factory.mojom"; import "media/mojo/mojom/key_system_support.mojom"; import "mojo/public/mojom/base/file_path.mojom"; +import "sandbox/policy/mojom/sandbox.mojom"; // A service to provide Windows MediaFoundation-based InterfaceFactory and // KeySystemCapability. See comments on MediaFoundationServiceBroker for the @@ -37,6 +38,7 @@ // be called once and the subsequent calls will simply fail. When // `MediaFoundationServiceBroker` is connected the process was not sandboxed to // allow CDM preloading. After `GetService()` the process is fully sandboxed. +[ServiceSandbox=sandbox.mojom.Sandbox.kMediaFoundationCdm] interface MediaFoundationServiceBroker { // Loads the CDM at `cdm_path` into the process and returns the // `MediaFoundationService`.
diff --git a/net/cookies/cookie_partition_key.cc b/net/cookies/cookie_partition_key.cc index 8d28310..b8b7f1f 100644 --- a/net/cookies/cookie_partition_key.cc +++ b/net/cookies/cookie_partition_key.cc
@@ -4,6 +4,8 @@ #include "net/cookies/cookie_partition_key.h" +#include "base/feature_list.h" +#include "net/base/features.h" #include "net/cookies/cookie_constants.h" namespace net { @@ -65,4 +67,17 @@ return true; } +absl::optional<CookiePartitionKey> CookiePartitionKey::FromNetworkIsolationKey( + const NetworkIsolationKey& network_isolation_key) { + if (!base::FeatureList::IsEnabled(features::kPartitionedCookies)) + return absl::nullopt; + // TODO(crbug.com/1225444): Check if the top frame site is in a First-Party + // Set or if it is an extension URL. + absl::optional<net::SchemefulSite> top_frame_site = + network_isolation_key.GetTopFrameSite(); + if (!top_frame_site) + return absl::nullopt; + return absl::make_optional(net::CookiePartitionKey(top_frame_site.value())); +} + } // namespace net
diff --git a/net/cookies/cookie_partition_key.h b/net/cookies/cookie_partition_key.h index de5580d96..754864a 100644 --- a/net/cookies/cookie_partition_key.h +++ b/net/cookies/cookie_partition_key.h
@@ -8,6 +8,7 @@ #include <string> #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/base/schemeful_site.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" @@ -63,6 +64,11 @@ return CookiePartitionKey(url); } + // Create a cookie partition key from a request's NetworkIsolationKey. + // + static absl::optional<CookiePartitionKey> FromNetworkIsolationKey( + const NetworkIsolationKey& network_isolation_key); + // Temporary method, used to mark the places where we need to supply the // cookie partition key to CanonicalCookie::Create. static absl::optional<CookiePartitionKey> Todo() { return absl::nullopt; }
diff --git a/net/cookies/cookie_partition_key_unittest.cc b/net/cookies/cookie_partition_key_unittest.cc index ef604ea..7f83ba7 100644 --- a/net/cookies/cookie_partition_key_unittest.cc +++ b/net/cookies/cookie_partition_key_unittest.cc
@@ -6,12 +6,33 @@ #define NET_COOKIES_COOKIE_PARTITION_KEY_UNITTEST_H_ #include "net/cookies/cookie_partition_key.h" +#include "base/test/scoped_feature_list.h" +#include "net/base/features.h" #include "net/cookies/cookie_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { -TEST(CookiePartitionKeyTest, Serialization) { +class CookiePartitionKeyTest : public testing::TestWithParam<bool> { + protected: + // testing::Test + void SetUp() override { + if (PartitionedCookiesEnabled()) + scoped_feature_list_.InitAndEnableFeature(features::kPartitionedCookies); + testing::TestWithParam<bool>::SetUp(); + } + + bool PartitionedCookiesEnabled() { return GetParam(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(/* no label */, + CookiePartitionKeyTest, + testing::Bool()); + +TEST_P(CookiePartitionKeyTest, Serialization) { struct { absl::optional<CookiePartitionKey> input; bool expected_ret; @@ -47,7 +68,7 @@ } } -TEST(CookiePartitionKeyTest, Deserialization) { +TEST_P(CookiePartitionKeyTest, Deserialization) { struct { std::string input; bool expected_ret; @@ -72,6 +93,23 @@ } } +TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKey) { + EXPECT_FALSE( + CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey())); + + SchemefulSite top_level_site = + SchemefulSite(GURL("https://toplevelsite.com")); + absl::optional<CookiePartitionKey> got = + CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey( + top_level_site, SchemefulSite(GURL("https://cookiesite.com")))); + + bool partitioned_cookies_enabled = PartitionedCookiesEnabled(); + EXPECT_EQ(partitioned_cookies_enabled, got.has_value()); + if (partitioned_cookies_enabled) { + EXPECT_EQ(CookiePartitionKey(top_level_site), got.value()); + } +} + } // namespace net #endif // NET_COOKIES_COOKIE_PARTITION_KEY_UNITTEST_H_
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 6de416d..a6cd1ef 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -775,7 +775,9 @@ std::unique_ptr<CanonicalCookie> cookie = net::CanonicalCookie::Create( request_->url(), cookie_string, base::Time::Now(), server_time, - net::CookiePartitionKey::Todo(), &returned_status); + net::CookiePartitionKey::FromNetworkIsolationKey( + request_->isolation_info().network_isolation_key()), + &returned_status); absl::optional<CanonicalCookie> cookie_to_return = absl::nullopt; if (returned_status.IsInclude()) {
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc index 6bde63c..cea14f3 100644 --- a/net/url_request/url_request_http_job_unittest.cc +++ b/net/url_request/url_request_http_job_unittest.cc
@@ -20,9 +20,11 @@ #include "base/strings/string_split.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "build/build_config.h" #include "net/base/auth.h" +#include "net/base/features.h" #include "net/base/isolation_info.h" #include "net/base/network_isolation_key.h" #include "net/base/request_priority.h" @@ -1910,4 +1912,73 @@ MatchesCookieAccessResult(IsInclude(), _, _, _)))); } +class PartitionedCookiesURLRequestHttpJobTest + : public URLRequestHttpJobTest, + public testing::WithParamInterface<bool> { + protected: + // testing::Test + void SetUp() override { + if (PartitionedCookiesEnabled()) + scoped_feature_list_.InitAndEnableFeature(features::kPartitionedCookies); + URLRequestHttpJobTest::SetUp(); + } + + bool PartitionedCookiesEnabled() { return GetParam(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(/* no label */, + PartitionedCookiesURLRequestHttpJobTest, + testing::Bool()); + +TEST_P(PartitionedCookiesURLRequestHttpJobTest, SetPartitionedCookie) { + EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS); + const url::Origin kTopFrameOrigin = + url::Origin::Create(GURL("https://www.toplevelsite.com")); + const IsolationInfo kTestIsolationInfo = + IsolationInfo::CreateForInternalRequest(kTopFrameOrigin); + + https_test.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(https_test.Start()); + TestURLRequestContext context; + + CookieMonster cookie_monster(nullptr, nullptr); + context.set_cookie_store(&cookie_monster); + + GURL test_url = https_test.GetURL( + "/set-cookie?__Host-foo=bar;SameSite=None;Secure;Path=/;Partitioned;"); + + TestDelegate delegate; + std::unique_ptr<URLRequest> request = context.CreateRequest( + test_url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS); + + request->set_isolation_info(kTestIsolationInfo); + request->Start(); + ASSERT_TRUE(request->is_pending()); + delegate.RunUntilComplete(); + + base::RunLoop run_loop; + bool partitioned_cookies_enabled = PartitionedCookiesEnabled(); + cookie_monster.GetAllCookiesAsync(base::BindLambdaForTesting( + [&partitioned_cookies_enabled, &run_loop](const CookieList& cookies) { + EXPECT_EQ(1u, cookies.size()); + EXPECT_EQ(partitioned_cookies_enabled, cookies[0].IsPartitioned()); + if (partitioned_cookies_enabled) { + EXPECT_EQ(CookiePartitionKey::FromURLForTesting( + GURL("https://toplevelsite.com")), + cookies[0].PartitionKey().value()); + } else { + EXPECT_FALSE(cookies[0].PartitionKey()); + } + run_loop.Quit(); + })); + run_loop.Run(); + + // TODO(crbug.com/1225444) Test that the cookie is available in a cross-site + // context on a different top-level site only when partitioned cookies are + // disabled. +} + } // namespace net
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 73d20c0..7b4a3578 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -86,7 +86,6 @@ "//remoting/host/linux:remoting_native_messaging_host", "//remoting/host/mac:remoting_native_messaging_host", "//remoting/host/mac:remoting_native_messaging_host_executable", - "//remoting/host/security_key:main", "//remoting/host/win:remoting_console", "//remoting/host/win:remoting_core", "//remoting/host/win:remoting_desktop", @@ -99,11 +98,7 @@ } source_set("common_headers") { - visibility = [ - ":base", - "//remoting/host/security_key:security_key", - "//remoting/host/security_key:test_support", - ] + visibility = [ ":base" ] sources = [ "action_executor.h", "audio_capturer.h",
diff --git a/remoting/host/security_key/BUILD.gn b/remoting/host/security_key/BUILD.gn index 99c97be1..57adea1 100644 --- a/remoting/host/security_key/BUILD.gn +++ b/remoting/host/security_key/BUILD.gn
@@ -39,7 +39,6 @@ "//mojo/public/cpp/system", "//net:net", "//net/traffic_annotation:traffic_annotation", - "//remoting/host:common_headers", "//remoting/host:host_extension", "//remoting/proto", "//remoting/protocol:protocol", @@ -72,7 +71,6 @@ "//mojo/core/embedder", "//remoting/host:base", "//remoting/host:common", - "//remoting/host:host_main_headers", ] } @@ -84,7 +82,6 @@ host_predefines + [ "REMOTING_HOST_BINARY=BINARY_REMOTE_SECURITY_KEY" ] deps = [ - ":main", "//build/win:default_exe_manifest", "//remoting/host/win:remoting_core", "//remoting/host/win:remoting_windows_resources", @@ -150,7 +147,6 @@ ":security_key", "//ipc", "//remoting/host:common", - "//remoting/host:common_headers", "//remoting/proto", "//testing/gtest", ]
diff --git a/sandbox/policy/mojom/sandbox.mojom b/sandbox/policy/mojom/sandbox.mojom index 41986b0a..40350448 100644 --- a/sandbox/policy/mojom/sandbox.mojom +++ b/sandbox/policy/mojom/sandbox.mojom
@@ -21,10 +21,41 @@ // For instance, it allows dynamic code and wider access to APIs on Windows. kUtility, + // Hosts the content decryption module. Allows pre-loading of CDM libraries. + // - On Windows, when `CdmServiceBroker` is connected the CDM was not + // sandboxed to allow CDM preloading. + // - On Mac, the process is fully sandboxed when launched. + // - On Linux/ChromeOS, the CDM is preloaded in the zygote sandbox. + kCdm, + // Composits PDF and XPS documents. kPrintCompositor, + // Equivalent to no sandbox on all non-Fuchsia platforms. + // Minimally privileged sandbox on Fuchsia. + // TODO(crbug.com/1236898) Fix this mapping. + kVideoCapture, + + // Allows LPAC capabilities for the Windws Media Foundation CDM, including + // internet and private network access, COM, Identity & others. Allows access + // to files in the `mediaFoundationCdmFiles` Chromium lpac. + [EnableIf=is_win] + kMediaFoundationCdm, + // |kXrCompositing| hosts XR Device Service on Windows. [EnableIf=is_win] kXrCompositing, + + // Hosts Input Method Editors. + [EnableIf=is_chromeos_ash] + kIme, + + // Text-to-speech. + [EnableIf=is_chromeos_ash] + kTts, + + // Hosts the Libassistant service on ChromeOS Ash, only used for + // Chrome branded builds. + [EnableIf=is_chromeos_ash] + kLibassistant, };
diff --git a/sandbox/policy/sandbox_type.cc b/sandbox/policy/sandbox_type.cc index c03b072..a0bdc15 100644 --- a/sandbox/policy/sandbox_type.cc +++ b/sandbox/policy/sandbox_type.cc
@@ -294,6 +294,15 @@ } SandboxType UtilitySandboxTypeFromString(const std::string& sandbox_string) { + // This function should cover all sandbox types used for utilities, the + // CHECK at the end should catch any attempts to forget to add a new type. + + // Most utilities are kUtility or kService so put those first. + if (sandbox_string == switches::kUtilitySandbox) + return SandboxType::kUtility; + if (sandbox_string == switches::kServiceSandbox) + return SandboxType::kService; + if (sandbox_string == switches::kNoneSandbox) return SandboxType::kNoSandbox; if (sandbox_string == switches::kNoneSandboxAndElevatedPrivileges) { @@ -347,6 +356,10 @@ return SandboxType::kLibassistant; #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) #endif // BUILDFLAG(IS_CHROMEOS_ASH) + CHECK(false) + << "Command line does not provide a valid sandbox configuration: " + << sandbox_string; + NOTREACHED(); return SandboxType::kUtility; }
diff --git a/sandbox/policy/sandbox_type.h b/sandbox/policy/sandbox_type.h index 6d4cfd1..8b841e4 100644 --- a/sandbox/policy/sandbox_type.h +++ b/sandbox/policy/sandbox_type.h
@@ -123,16 +123,36 @@ inline constexpr sandbox::policy::SandboxType MapToSandboxType( sandbox::mojom::Sandbox mojo_sandbox) { switch (mojo_sandbox) { + case sandbox::mojom::Sandbox::kCdm: + return sandbox::policy::SandboxType::kCdm; case sandbox::mojom::Sandbox::kPrintCompositor: return sandbox::policy::SandboxType::kPrintCompositor; case sandbox::mojom::Sandbox::kService: return sandbox::policy::SandboxType::kService; case sandbox::mojom::Sandbox::kUtility: return sandbox::policy::SandboxType::kUtility; + case sandbox::mojom::Sandbox::kVideoCapture: + return sandbox::policy::SandboxType::kVideoCapture; #if defined(OS_WIN) + case sandbox::mojom::Sandbox::kMediaFoundationCdm: + return sandbox::policy::SandboxType::kMediaFoundationCdm; case sandbox::mojom::Sandbox::kXrCompositing: return sandbox::policy::SandboxType::kXrCompositing; #endif // OS_WIN +#if BUILDFLAG(IS_CHROMEOS_ASH) + case sandbox::mojom::Sandbox::kIme: + return sandbox::policy::SandboxType::kIme; + case sandbox::mojom::Sandbox::kTts: + return sandbox::policy::SandboxType::kTts; + case sandbox::mojom::Sandbox::kLibassistant: +#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) + return sandbox::policy::SandboxType::kLibassistant; +#else + CHECK(false) << "Libassistant sandbox not supported"; + NOTREACHED(); + return sandbox::policy::SandboxType::kService; +#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } }
diff --git a/sandbox/policy/sandbox_type_unittest.cc b/sandbox/policy/sandbox_type_unittest.cc index e909a684..44787056 100644 --- a/sandbox/policy/sandbox_type_unittest.cc +++ b/sandbox/policy/sandbox_type_unittest.cc
@@ -54,7 +54,6 @@ base::CommandLine command_line(base::CommandLine::NO_PROGRAM); command_line.AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess); - EXPECT_EQ(SandboxType::kUtility, SandboxTypeFromCommandLine(command_line)); base::CommandLine command_line2(command_line); SetCommandLineFlagsForSandboxType(&command_line2, SandboxType::kNetwork); @@ -73,8 +72,8 @@ EXPECT_EQ(SandboxType::kPpapi, SandboxTypeFromCommandLine(command_line5)); base::CommandLine command_line6(command_line); - command_line6.AppendSwitchASCII(switches::kServiceSandboxType, "bogus"); - EXPECT_EQ(SandboxType::kUtility, SandboxTypeFromCommandLine(command_line6)); + SetCommandLineFlagsForSandboxType(&command_line6, SandboxType::kService); + EXPECT_EQ(SandboxType::kService, SandboxTypeFromCommandLine(command_line6)); base::CommandLine command_line7(command_line); SetCommandLineFlagsForSandboxType(&command_line7, @@ -130,6 +129,24 @@ EXPECT_EQ(SandboxType::kNoSandbox, SandboxTypeFromCommandLine(command_line)); } +TEST(SandboxTypeTest, UtilityDeath) { + base::CommandLine command_line(base::CommandLine::NO_PROGRAM); + command_line.AppendSwitchASCII(switches::kProcessType, + switches::kUtilityProcess); + EXPECT_DEATH_IF_SUPPORTED( + SandboxTypeFromCommandLine(command_line), + "Command line does not provide a valid sandbox configuration"); + + // kGPU not valid for utility processes. + base::CommandLine command_line1(command_line); + command_line1.AppendSwitchASCII(switches::kServiceSandboxType, "gpu"); + EXPECT_DEATH_IF_SUPPORTED(SandboxTypeFromCommandLine(command_line1), "gpu"); + + base::CommandLine command_line2(command_line); + command_line2.AppendSwitchASCII(switches::kServiceSandboxType, "bogus"); + EXPECT_DEATH_IF_SUPPORTED(SandboxTypeFromCommandLine(command_line2), "bogus"); +} + TEST(SandboxTypeTest, GPU) { base::CommandLine command_line(base::CommandLine::NO_PROGRAM); command_line.AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
diff --git a/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc b/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc index b298885..7f257c7c 100644 --- a/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc +++ b/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc
@@ -11,12 +11,10 @@ namespace media { TEST(SandboxTypeTest, Utility) { - // Setup to have '--type=utility' first. + // Setup to have '--type=utility' first (but no valid sandbox). base::CommandLine command_line(base::CommandLine::NO_PROGRAM); command_line.AppendSwitchASCII(sandbox::policy::switches::kProcessType, sandbox::policy::switches::kUtilityProcess); - EXPECT_EQ(sandbox::policy::SandboxType::kUtility, - sandbox::policy::SandboxTypeFromCommandLine(command_line)); base::CommandLine command_line2(command_line); SetCommandLineFlagsForSandboxType(
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 1c5ab77..adf1108 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -5774,7 +5774,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -6035,7 +6035,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index bb0fb27..215279a 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -55945,7 +55945,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -56209,7 +56209,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -56545,7 +56545,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -56806,7 +56806,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -57142,7 +57142,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -57403,7 +57403,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M93", - "revision": "version:93.0.4577.33" + "revision": "version:93.0.4577.35" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 0f39a99..bc28449 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1355,6 +1355,10 @@ "script": "//testing/merge_scripts/standard_gtest_merge.py" }, "name": "cc_unittests_amd64-generic", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -1379,6 +1383,10 @@ "script": "//testing/merge_scripts/standard_gtest_merge.py" }, "name": "cc_unittests_eve", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -1406,7 +1414,8 @@ }, "name": "lacros_all_tast_tests_amd64-generic", "resultdb": { - "enable": true + "enable": true, + "has_native_resultdb_integration": true }, "swarming": { "can_use_on_swarming_builders": true, @@ -1434,7 +1443,8 @@ }, "name": "lacros_all_tast_tests_eve", "resultdb": { - "enable": true + "enable": true, + "has_native_resultdb_integration": true }, "swarming": { "can_use_on_swarming_builders": true, @@ -1463,6 +1473,10 @@ "script": "//testing/merge_scripts/standard_gtest_merge.py" }, "name": "ozone_unittests_amd64-generic", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -1487,6 +1501,10 @@ "script": "//testing/merge_scripts/standard_gtest_merge.py" }, "name": "ozone_unittests_eve", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json index ad5e404..156ed274 100644 --- a/testing/buildbot/chromium.dawn.json +++ b/testing/buildbot/chromium.dawn.json
@@ -196,7 +196,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -230,7 +230,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -459,7 +459,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -493,7 +493,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -722,7 +722,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -756,7 +756,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -985,7 +985,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -1019,7 +1019,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -1263,7 +1263,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -1299,7 +1299,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -1529,7 +1529,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -1563,7 +1563,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -1812,7 +1812,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -1849,7 +1849,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -2094,7 +2094,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -2130,7 +2130,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -2360,7 +2360,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -2394,7 +2394,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -2620,7 +2620,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -2848,7 +2848,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -2881,7 +2881,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -3103,7 +3103,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -3136,7 +3136,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -3358,7 +3358,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -3391,7 +3391,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -3613,7 +3613,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator", @@ -3646,7 +3646,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -3870,7 +3870,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator" @@ -3902,7 +3902,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -4123,7 +4123,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator" @@ -4155,7 +4155,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -4376,7 +4376,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator" @@ -4408,7 +4408,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", @@ -4629,7 +4629,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests", "--additional-driver-flag=--enable-dawn-features=use_tint_generator" @@ -4661,7 +4661,7 @@ }, { "args": [ - "--initialize-webgpu-adapter-at-startup", + "--initialize-webgpu-adapter-at-startup-timeout-ms=60000", "--additional-driver-flag=--enable-dawn-backend-validation=partial", "--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis", "--additional-driver-flag=--use-gpu-in-tests",
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 6626259..69bfa8d 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -8535,9 +8535,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8561,9 +8561,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8587,9 +8587,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8617,9 +8617,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8645,9 +8645,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8674,9 +8674,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8704,9 +8704,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8732,9 +8732,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8758,9 +8758,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8782,9 +8782,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8803,9 +8803,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8841,9 +8841,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8877,9 +8877,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8913,9 +8913,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8949,9 +8949,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -8989,9 +8989,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9034,9 +9034,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9070,9 +9070,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9115,9 +9115,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9152,9 +9152,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9188,9 +9188,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9226,9 +9226,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -9264,9 +9264,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Ubuntu", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-440.100", + "os": "Ubuntu-18.04.5", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35781,9 +35781,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35809,9 +35809,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35834,9 +35834,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35860,9 +35860,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35889,9 +35889,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35916,9 +35916,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35941,9 +35941,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35965,9 +35965,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -35991,9 +35991,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36018,9 +36018,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36039,9 +36039,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36060,9 +36060,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36084,9 +36084,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36109,9 +36109,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36147,9 +36147,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36183,9 +36183,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36219,9 +36219,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36255,9 +36255,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36295,9 +36295,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36340,9 +36340,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36385,9 +36385,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36422,9 +36422,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36458,9 +36458,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36496,9 +36496,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36534,9 +36534,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36572,9 +36572,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36609,9 +36609,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36647,9 +36647,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600, @@ -36684,9 +36684,9 @@ "containment_type": "AUTO", "dimension_sets": [ { - "gpu": "10de:2184", - "os": "Windows-10", - "pool": "chromium.tests.gpu.experimental" + "gpu": "10de:2184-27.21.14.5638", + "os": "Windows-10-18363", + "pool": "chromium.tests.gpu" } ], "expiration": 21600,
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 933b430..1a552768 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1453,8 +1453,8 @@ "performance_web_engine_test_suite": { "args": [ "../../content/test/gpu/run_telemetry_benchmark_fuchsia.py", - "--system-log-file", - "${ISOLATED_OUTDIR}/system_log", + "--system-log-template", + "system_log", ], "label": "//content/test:performance_web_engine_test_suite", "script": "//testing/scripts/run_performance_tests.py",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 22d9682e..8df932c7 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -633,9 +633,9 @@ 'linux_nvidia_gtx_1660_experimental': { 'swarming': { 'dimensions': { - 'gpu': '10de:2184', - 'os': 'Ubuntu', - 'pool': 'chromium.tests.gpu.experimental', + 'gpu': '10de:2184-440.100', + 'os': 'Ubuntu-18.04.5', + 'pool': 'chromium.tests.gpu', }, }, }, @@ -1167,9 +1167,9 @@ 'win10_nvidia_geforce_gtx_1660': { 'swarming': { 'dimensions': { - 'gpu': '10de:2184', - 'os': 'Windows-10', - 'pool': 'chromium.tests.gpu.experimental', + 'gpu': '10de:2184-27.21.14.5638', + 'os': 'Windows-10-18363', + 'pool': 'chromium.tests.gpu', }, }, },
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 04bcdf2..74ba631 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -3946,7 +3946,7 @@ 'name': 'webgpu_blink_web_tests_with_backend_validation', 'args': [ # crbug.com/953991 Ensure WebGPU is ready before running tests - '--initialize-webgpu-adapter-at-startup', + '--initialize-webgpu-adapter-at-startup-timeout-ms=60000', '--additional-driver-flag=--enable-dawn-backend-validation', # Make Dawn allow "Unsafe APIs" so they can be tested with the WebGPU CTS. '--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis', @@ -3990,7 +3990,7 @@ 'name': 'webgpu_blink_web_tests', 'args': [ # crbug.com/953991 Ensure WebGPU is ready before running tests - '--initialize-webgpu-adapter-at-startup', + '--initialize-webgpu-adapter-at-startup-timeout-ms=60000', # Make Dawn allow "Unsafe APIs" so they can be tested with the WebGPU CTS. '--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis', # We need this flag to initialize ANGLE so that we can explicitly tell @@ -4033,7 +4033,7 @@ 'name': 'webgpu_blink_web_tests_with_backend_validation', 'args': [ # crbug.com/953991 Ensure WebGPU is ready before running tests - '--initialize-webgpu-adapter-at-startup', + '--initialize-webgpu-adapter-at-startup-timeout-ms=60000', '--additional-driver-flag=--enable-dawn-backend-validation=partial', # Make Dawn allow "Unsafe APIs" so they can be tested with the WebGPU CTS. '--additional-driver-flag=--disable-dawn-features=disallow_unsafe_apis',
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 84699dcf..86c4b8d 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -349,7 +349,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M93', - 'revision': 'version:93.0.4577.33', + 'revision': 'version:93.0.4577.35', } ], }, @@ -421,7 +421,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M93', - 'revision': 'version:93.0.4577.33', + 'revision': 'version:93.0.4577.35', } ], }, @@ -493,7 +493,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M93', - 'revision': 'version:93.0.4577.33', + 'revision': 'version:93.0.4577.35', } ], },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index cd5693e..65dabe4e 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1435,6 +1435,9 @@ 'additional_compile_targets': [ 'chrome', ], + 'mixins': [ + 'has_native_resultdb_integration', + ], 'test_suites': { 'gtest_tests': 'lacros_device_or_vm_tests', },
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py index d2d2e36..9e10ade 100755 --- a/testing/scripts/run_performance_tests.py +++ b/testing/scripts/run_performance_tests.py
@@ -414,6 +414,7 @@ # passthrough args must be before reference args and repeat args: # crbug.com/928928, crbug.com/894254#c78 self._get_passthrough_args() + + self._generate_syslog_args() + self._generate_repeat_args() + self._generate_reference_build_args() ) @@ -469,6 +470,16 @@ selection_args.append('--run-abridged-story-set') return selection_args + def _generate_syslog_args(self): + if self._options.system_log_template: + isolated_out_dir = os.path.dirname( + self._options.isolated_script_test_output) + return ['--system-log-file', os.path.join( + isolated_out_dir, + self.benchmark, + self._options.system_log_template)] + return [] + def _generate_story_index_ranges(self, sections): range_string = '' @@ -607,6 +618,10 @@ help='Comma separated list of benchmark names' ' to run in lieu of indexing into our benchmark bot maps', required=False) + # crbug.com/1236245: This allows for per-benchmark device logs. + parser.add_argument('--system-log-template', + help='File name template for system logs for each ' + 'benchmark', required=False) # Some executions may have a different sharding scheme and/or set of tests. # These files must live in src/tools/perf/core/shard_maps parser.add_argument('--test-shard-map-filename', type=str, required=False)
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 47783da5..67e0f6d 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -5760,6 +5760,25 @@ ] }, { + "name": "AssistantIntegration_ToolbarMic_20210810", + "params": { + "colorful_mic": "false", + "experiment_id": "47736814", + "min_agsa_version": "12.27" + }, + "enable_features": [ + "AssistantIntentExperimentId", + "OmniboxAssistantVoiceSearch", + "VoiceButtonInTopToolbar", + "VoiceSearchAudioCapturePolicy" + ], + "disable_features": [ + "AssistantIntentPageUrl", + "AssistantIntentTranslateInfo", + "TranslateIntent" + ] + }, + { "name": "AssistantVoiceSearch_DefaultMic", "params": { "colorful_mic": "false", @@ -6914,16 +6933,23 @@ ], "experiments": [ { - "name": "Enabled", + "name": "MVP_20210809", "params": { + "default_query_chip": "true", + "default_query_max_width_sp": "115", "language_allowlist": "en", "needs_content": "true", "needs_url": "true", - "stamp": "1Rb" + "stamp": "1Rs" }, "enable_features": [ "RelatedSearches", + "RelatedSearchesInBar", "RelatedSearchesUi" + ], + "disable_features": [ + "RelatedSearchesAlternateUx", + "RelatedSearchesSimplifiedUx" ] } ]
diff --git a/third_party/blink/common/switches.cc b/third_party/blink/common/switches.cc index 688a75e..cde0573 100644 --- a/third_party/blink/common/switches.cc +++ b/third_party/blink/common/switches.cc
@@ -126,5 +126,10 @@ // the platform default is used. const char kTouchTextSelectionStrategy[] = "touch-selection-strategy"; +// Comma-separated list of origins that can use SharedArrayBuffer without +// enabling cross-origin isolation. +const char kSharedArrayBufferAllowedOrigins[] = + "shared-array-buffer-allowed-origins"; + } // namespace switches } // namespace blink
diff --git a/third_party/blink/public/common/switches.h b/third_party/blink/public/common/switches.h index 680cb47..6f743b2 100644 --- a/third_party/blink/public/common/switches.h +++ b/third_party/blink/public/common/switches.h
@@ -46,6 +46,7 @@ BLINK_COMMON_EXPORT extern const char kShowLayoutShiftRegions[]; BLINK_COMMON_EXPORT extern const char kShowPaintRects[]; BLINK_COMMON_EXPORT extern const char kTouchTextSelectionStrategy[]; +BLINK_COMMON_EXPORT extern const char kSharedArrayBufferAllowedOrigins[]; } // namespace switches } // namespace blink
diff --git a/third_party/blink/public/mojom/clipboard/clipboard.mojom b/third_party/blink/public/mojom/clipboard/clipboard.mojom index bdc1116..b67ee00a 100644 --- a/third_party/blink/public/mojom/clipboard/clipboard.mojom +++ b/third_party/blink/public/mojom/clipboard/clipboard.mojom
@@ -67,6 +67,12 @@ // Failure to do so may lead to users leaking sensitive information, // that may for example be held in metadata. interface ClipboardHost { + // Conservative limits to maximum format name and data sizes, to avoid + // potential attacks with long strings. These limits are only applied to + // unsanitized custom formats. The size limit includes the null terminator. + const uint32 kMaxFormatSize = 1024; + const uint32 kMaxDataSize = 1073741824; // 1 GB, or 1 << 30 + // Returns a token which uniquely identifies clipboard state. // This can be used to version the data on the clipboard and determine // whether it has changed. @@ -122,6 +128,22 @@ ReadCustomData(ClipboardBuffer buffer, mojo_base.mojom.String16 type) => (mojo_base.mojom.BigString16 result); + // Reads both unsanitized custom formats & standard + // formats(such as text/html). + // `format_types` contains the list of all available custom & standard + // formats. + [Sync] + ReadAvailableCustomAndStandardFormats() => + (array<mojo_base.mojom.String16> format_types); + + // Reads an unsanitized custom format from the clipboard. + // `format` contains the custom format name. + // Returns the data from the clipboard corresponding to the `format`. + // Returns empty `data` if the `format` is not available in the clipboard. + [Sync] + ReadUnsanitizedCustomFormat(mojo_base.mojom.String16 format) => + (mojo_base.mojom.BigBuffer data); + // Writing to the clipboard via mojo is a two-phase operation. First, the // sender sends the different types of data it'd like to write to the // receiver. Then, it sends a commit message to commit the data to the system @@ -148,6 +170,14 @@ WriteImage(skia.mojom.BitmapN32 image); + // Writes an unsanitized custom format to the clipboard. + // `format` contains the name of the custom format and `data` contains the + // unsanitized payload provided by the web authors. + // There can only be 100 custom formats per write operation and it will be + // registered when the web authors request for a custom format. + WriteUnsanitizedCustomFormat(mojo_base.mojom.String16 format, + mojo_base.mojom.BigBuffer data); + CommitWrite(); [EnableIf=is_mac]
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record.cc b/third_party/blink/renderer/bindings/core/v8/module_record.cc index 191b1168..9bf79fe 100644 --- a/third_party/blink/renderer/bindings/core/v8/module_record.cc +++ b/third_party/blink/renderer/bindings/core/v8/module_record.cc
@@ -83,7 +83,8 @@ if (!V8ScriptRunner::CompileModule( isolate, params, text_position, compile_options, no_cache_reason, - ReferrerScriptInfo(params.BaseURL(), options)) + ReferrerScriptInfo::CreateWithReferencingScript(params.BaseURL(), + options)) .ToLocal(&module)) { DCHECK(try_catch.HasCaught()); exception_state.RethrowV8Exception(try_catch.Exception());
diff --git a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc index 53f444e2..035361f 100644 --- a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc +++ b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc
@@ -21,30 +21,31 @@ kLength }; -// Omit storing base URL if it is same as ScriptOrigin::ResourceName(). -// Note: This improves chance of getting into a fast path in -// ReferrerScriptInfo::ToV8HostDefinedOptions. -KURL GetStoredBaseUrl(const ReferrerScriptInfo& referrer_info, - const KURL& script_origin_resource_name) { - if (referrer_info.BaseURL() == script_origin_resource_name) - return KURL(); - - // TODO(https://crbug.com/1235202): Currently when either `base_url_` is - // `script_origin_resource_name` or null URL, they both result in - // `script_origin_resource_name` in FromV8HostDefinedOptions(). Subsequent - // CLs will fix this issue. - if (referrer_info.BaseURL().IsNull()) - return KURL(); - - return referrer_info.BaseURL(); -} +static_assert(HostDefinedOptionsIndex::kLength != 1, + "We use an array of length 1 to represent ReferrerScriptInfo " + "with default value, kLength should be different from 1"); } // namespace -bool ReferrerScriptInfo::IsDefaultValue( +ReferrerScriptInfo ReferrerScriptInfo::CreateNoReferencingScript() { + return ReferrerScriptInfo(); +} + +ReferrerScriptInfo ReferrerScriptInfo::CreateWithReferencingScript( + const KURL& base_url, + const ScriptFetchOptions& options) { + return ReferrerScriptInfo(base_url, options.CredentialsMode(), + options.Nonce(), options.ParserState(), + options.GetReferrerPolicy()); +} + +bool ReferrerScriptInfo::HasReferencingScriptWithDefaultValue( const KURL& script_origin_resource_name) const { + if (!HasReferencingScript()) + return false; + // TODO(https://crbug.com/1235205): `referrer_policy_` should be checked. - return GetStoredBaseUrl(*this, script_origin_resource_name).IsNull() && + return BaseURL() == script_origin_resource_name && credentials_mode_ == network::mojom::CredentialsMode::kSameOrigin && nonce_.IsEmpty() && parser_state_ == kNotParserInserted; } @@ -53,14 +54,15 @@ v8::Local<v8::Context> context, v8::Local<v8::PrimitiveArray> host_defined_options, const KURL& script_origin_resource_name) { - if (host_defined_options.IsEmpty() || !host_defined_options->Length()) { - // Default value. As base URL is null, defer to - // `script_origin_resource_name`. - ReferrerScriptInfo referrer_info( - script_origin_resource_name, - network::mojom::CredentialsMode::kSameOrigin, String(), - kNotParserInserted, network::mojom::ReferrerPolicy::kDefault); - DCHECK(referrer_info.IsDefaultValue(script_origin_resource_name)); + if (host_defined_options.IsEmpty() || !host_defined_options->Length()) + return ReferrerScriptInfo::CreateNoReferencingScript(); + + if (host_defined_options->Length() == 1) { + ReferrerScriptInfo referrer_info = + ReferrerScriptInfo::CreateWithReferencingScript( + script_origin_resource_name, ScriptFetchOptions()); + DCHECK(referrer_info.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); return referrer_info; } @@ -72,10 +74,8 @@ ToCoreString(v8::Local<v8::String>::Cast(base_url_value)); KURL base_url = base_url_string.IsEmpty() ? KURL() : KURL(base_url_string); DCHECK(base_url.IsNull() || base_url.IsValid()); - if (base_url.IsNull()) { - // If base URL is null, defer to `script_origin_resource_name`. - base_url = script_origin_resource_name; - } + // Even if base URL is null, do not defer to `script_origin_resource_name`, + // because there are cases where the original base URL is already null. v8::Local<v8::Primitive> credentials_mode_value = host_defined_options->Get(isolate, kCredentialsMode); @@ -111,15 +111,18 @@ v8::Local<v8::PrimitiveArray> ReferrerScriptInfo::ToV8HostDefinedOptions( v8::Isolate* isolate, const KURL& script_origin_resource_name) const { - if (IsDefaultValue(script_origin_resource_name)) + if (!HasReferencingScript()) return v8::Local<v8::PrimitiveArray>(); + if (HasReferencingScriptWithDefaultValue(script_origin_resource_name)) + return v8::PrimitiveArray::New(isolate, 1); + v8::Local<v8::PrimitiveArray> host_defined_options = v8::PrimitiveArray::New(isolate, HostDefinedOptionsIndex::kLength); - const KURL stored_base_url = - GetStoredBaseUrl(*this, script_origin_resource_name); - + // Even when the original `base_url_` is `script_origin_resource_name`, the + // original `base_url_` is stored here, to ditinguish `base_url_` == + // `script_origin_resource_name` and `base_url_` is null. v8::Local<v8::Primitive> base_url_value = V8String(isolate, base_url_.GetString()); host_defined_options->Set(isolate, HostDefinedOptionsIndex::kBaseURL,
diff --git a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h index b8635162..4d34241 100644 --- a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h +++ b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h
@@ -18,28 +18,36 @@ // ReferrerScriptInfo carries a copy of "referencing script's" info referenced // in HTML Spec: "HostImportModuleDynamically" algorithm. -// https://html.spec.whatwg.org/C/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability) +// https://html.spec.whatwg.org/C/#hostimportmoduledynamically(referencingscriptormodule,-modulerequest,-promisecapability) + +// There are three sub cases for a referencing script: +// +// 1. No referencing scripts (e.g. event handlers) +// - CreateNoReferencingScript(). +// - ReferrerScriptInfo::HasReferencingScript() is false. +// - V8's HostDefinedOption is empty `v8::Local<v8::PrimitiveArray>()`. +// +// 2. A referencing script with default value (e.g. many of classic scripts) +// - CreateWithReferencingScript() with the base URL == +// ScriptOrigin::ResourceName() and default `ScriptFetchOptions()`. +// - ReferrerScriptInfo::HasReferencingScript() is true. +// - V8's HostDefinedOption is `v8::PrimitiveArray` with length 1. +// +// 3. A referencing script with non-default value +// - CreateWithReferencingScript(). +// - ReferrerScriptInfo::HasReferencingScript() is true. +// - V8's HostDefinedOption is `v8::PrimitiveArray` with length +// HostDefinedOptionsIndex::kLength class CORE_EXPORT ReferrerScriptInfo { STACK_ALLOCATED(); public: - ReferrerScriptInfo() {} - ReferrerScriptInfo(const KURL& base_url, - network::mojom::CredentialsMode credentials_mode, - const String& nonce, - ParserDisposition parser_state, - network::mojom::ReferrerPolicy referrer_policy) - : base_url_(base_url), - credentials_mode_(credentials_mode), - nonce_(nonce), - parser_state_(parser_state), - referrer_policy_(referrer_policy) {} - ReferrerScriptInfo(const KURL& base_url, const ScriptFetchOptions& options) - : ReferrerScriptInfo(base_url, - options.CredentialsMode(), - options.Nonce(), - options.ParserState(), - options.GetReferrerPolicy()) {} + static ReferrerScriptInfo CreateNoReferencingScript(); + + // There should exist a corresponding `blink::Script`. + static ReferrerScriptInfo CreateWithReferencingScript( + const KURL& base_url, + const ScriptFetchOptions&); static ReferrerScriptInfo FromV8HostDefinedOptions( v8::Local<v8::Context>, @@ -49,6 +57,9 @@ v8::Isolate*, const KURL& script_origin_resource_name) const; + bool HasReferencingScript() const { return has_referencing_script_; } + bool HasReferencingScriptWithDefaultValue( + const KURL& script_origin_resource_name) const; const KURL& BaseURL() const { return base_url_; } network::mojom::CredentialsMode CredentialsMode() const { return credentials_mode_; @@ -59,12 +70,26 @@ return referrer_policy_; } - bool IsDefaultValue(const KURL& script_origin_resource_name) const; - private: + ReferrerScriptInfo() = default; + ReferrerScriptInfo(const KURL& base_url, + network::mojom::CredentialsMode credentials_mode, + const String& nonce, + ParserDisposition parser_state, + network::mojom::ReferrerPolicy referrer_policy) + : has_referencing_script_(true), + base_url_(base_url), + credentials_mode_(credentials_mode), + nonce_(nonce), + parser_state_(parser_state), + referrer_policy_(referrer_policy) {} + + // Spec: referencingScriptOrModule is not null. + const bool has_referencing_script_ = false; + // Spec: "referencing script's base URL" // https://html.spec.whatwg.org/C/#concept-script-base-url - const KURL base_url_; + const KURL base_url_ = KURL(); // Spec: "referencing script's credentials mode" // The default value is "same-origin" per: @@ -73,7 +98,7 @@ network::mojom::CredentialsMode::kSameOrigin; // Spec: "referencing script's cryptographic nonce" - const String nonce_; + const String nonce_ = String(); // Spec: "referencing script's parser state" // The default value is "not-parser-inserted" per:
diff --git a/third_party/blink/renderer/bindings/core/v8/referrer_script_info_test.cc b/third_party/blink/renderer/bindings/core/v8/referrer_script_info_test.cc index fe4050b4..6141c76 100644 --- a/third_party/blink/renderer/bindings/core/v8/referrer_script_info_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/referrer_script_info_test.cc
@@ -10,25 +10,43 @@ namespace blink { -TEST(ReferrerScriptInfo, IsDefaultValue) { +TEST(ReferrerScriptInfo, HasReferencingScriptWithDefaultValue) { const KURL script_origin_resource_name("http://example.org/script.js"); - // TODO(https://crbug.com/1114993): There three cases should be distinguished. - EXPECT_TRUE(ReferrerScriptInfo().IsDefaultValue(script_origin_resource_name)); - EXPECT_TRUE( - ReferrerScriptInfo(script_origin_resource_name, ScriptFetchOptions()) - .IsDefaultValue(script_origin_resource_name)); - EXPECT_TRUE(ReferrerScriptInfo(KURL(), ScriptFetchOptions()) - .IsDefaultValue(script_origin_resource_name)); + auto info_no_script = ReferrerScriptInfo::CreateNoReferencingScript(); + EXPECT_FALSE(info_no_script.HasReferencingScript()); + EXPECT_FALSE(info_no_script.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); - EXPECT_FALSE( - ReferrerScriptInfo(KURL("http://example.com"), ScriptFetchOptions()) - .IsDefaultValue(script_origin_resource_name)); - EXPECT_FALSE(ReferrerScriptInfo(KURL("http://example.com"), - network::mojom::CredentialsMode::kInclude, "", - kNotParserInserted, - network::mojom::ReferrerPolicy::kDefault) - .IsDefaultValue(script_origin_resource_name)); + auto info_default_script = ReferrerScriptInfo::CreateWithReferencingScript( + script_origin_resource_name, ScriptFetchOptions()); + EXPECT_TRUE(info_default_script.HasReferencingScript()); + EXPECT_TRUE(info_default_script.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); + + auto info_null_url_script = ReferrerScriptInfo::CreateWithReferencingScript( + KURL(), ScriptFetchOptions()); + EXPECT_TRUE(info_null_url_script.HasReferencingScript()); + EXPECT_FALSE(info_null_url_script.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); + + auto info_script = ReferrerScriptInfo::CreateWithReferencingScript( + KURL("http://example.com"), ScriptFetchOptions()); + EXPECT_TRUE(info_script.HasReferencingScript()); + EXPECT_FALSE(info_script.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); + + auto info_nondefault_options = + ReferrerScriptInfo::CreateWithReferencingScript( + KURL("http://example.com"), + ScriptFetchOptions("", {}, {}, kNotParserInserted, + network::mojom::CredentialsMode::kInclude, + network::mojom::ReferrerPolicy::kDefault, + mojom::FetchImportanceMode::kImportanceAuto, + RenderBlockingBehavior::kUnset)); + EXPECT_TRUE(info_nondefault_options.HasReferencingScript()); + EXPECT_FALSE(info_nondefault_options.HasReferencingScriptWithDefaultValue( + script_origin_resource_name)); } TEST(ReferrerScriptInfo, ToFromV8NoReferencingScript) { @@ -36,16 +54,15 @@ const KURL script_origin_resource_name("http://example.org/script.js"); v8::Local<v8::PrimitiveArray> v8_info = - ReferrerScriptInfo().ToV8HostDefinedOptions(scope.GetIsolate(), - script_origin_resource_name); + ReferrerScriptInfo::CreateNoReferencingScript().ToV8HostDefinedOptions( + scope.GetIsolate(), script_origin_resource_name); EXPECT_TRUE(v8_info.IsEmpty()); ReferrerScriptInfo decoded = ReferrerScriptInfo::FromV8HostDefinedOptions( scope.GetContext(), v8_info, script_origin_resource_name); - // TODO(https://crbug.com/1235202): This should be null URL. - EXPECT_EQ(script_origin_resource_name, decoded.BaseURL()); + EXPECT_FALSE(decoded.HasReferencingScript()); } TEST(ReferrerScriptInfo, ToFromV8ScriptOriginBaseUrl) { @@ -53,15 +70,18 @@ const KURL script_origin_resource_name("http://example.org/script.js"); v8::Local<v8::PrimitiveArray> v8_info = - ReferrerScriptInfo(script_origin_resource_name, ScriptFetchOptions()) + ReferrerScriptInfo::CreateWithReferencingScript( + script_origin_resource_name, ScriptFetchOptions()) .ToV8HostDefinedOptions(scope.GetIsolate(), script_origin_resource_name); - EXPECT_TRUE(v8_info.IsEmpty()); + ASSERT_FALSE(v8_info.IsEmpty()); + EXPECT_EQ(v8_info->Length(), 1); ReferrerScriptInfo decoded = ReferrerScriptInfo::FromV8HostDefinedOptions( scope.GetContext(), v8_info, script_origin_resource_name); + EXPECT_TRUE(decoded.HasReferencingScript()); EXPECT_EQ(script_origin_resource_name, decoded.BaseURL()); } @@ -70,17 +90,19 @@ const KURL script_origin_resource_name("http://example.org/script.js"); v8::Local<v8::PrimitiveArray> v8_info = - ReferrerScriptInfo(KURL(), ScriptFetchOptions()) + ReferrerScriptInfo::CreateWithReferencingScript(KURL(), + ScriptFetchOptions()) .ToV8HostDefinedOptions(scope.GetIsolate(), script_origin_resource_name); - EXPECT_TRUE(v8_info.IsEmpty()); + ASSERT_FALSE(v8_info.IsEmpty()); + EXPECT_GT(v8_info->Length(), 1); ReferrerScriptInfo decoded = ReferrerScriptInfo::FromV8HostDefinedOptions( scope.GetContext(), v8_info, script_origin_resource_name); - // TODO(https://crbug.com/1235202): This should be null URL. - EXPECT_EQ(script_origin_resource_name, decoded.BaseURL()); + EXPECT_TRUE(decoded.HasReferencingScript()); + EXPECT_EQ(KURL(), decoded.BaseURL()); } TEST(ReferrerScriptInfo, ToFromV8) { @@ -88,14 +110,23 @@ const KURL script_origin_resource_name("http://example.org/script.js"); const KURL url("http://example.com"); - ReferrerScriptInfo info(url, network::mojom::CredentialsMode::kInclude, - "foobar", kNotParserInserted, - network::mojom::ReferrerPolicy::kOrigin); + auto info = ReferrerScriptInfo::CreateWithReferencingScript( + url, ScriptFetchOptions("foobar", {}, {}, kNotParserInserted, + network::mojom::CredentialsMode::kInclude, + network::mojom::ReferrerPolicy::kOrigin, + mojom::FetchImportanceMode::kImportanceAuto, + RenderBlockingBehavior::kUnset)); + v8::Local<v8::PrimitiveArray> v8_info = info.ToV8HostDefinedOptions( scope.GetIsolate(), script_origin_resource_name); + ASSERT_FALSE(v8_info.IsEmpty()); + EXPECT_GT(v8_info->Length(), 1); + ReferrerScriptInfo decoded = ReferrerScriptInfo::FromV8HostDefinedOptions( scope.GetContext(), v8_info, script_origin_resource_name); + + EXPECT_TRUE(decoded.HasReferencingScript()); EXPECT_EQ(url, decoded.BaseURL()); EXPECT_EQ(network::mojom::CredentialsMode::kInclude, decoded.CredentialsMode());
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc index ac74f1d..84de63b 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -251,7 +251,8 @@ EXPECT_TRUE(V8ScriptRunner::CompileScript( scope.GetScriptState(), source_code, SanitizeScriptErrors::kDoNotSanitize, compile_options, - no_cache_reason, ReferrerScriptInfo()) + no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -288,7 +289,8 @@ EXPECT_FALSE(V8ScriptRunner::CompileScript( scope.GetScriptState(), source_code, SanitizeScriptErrors::kDoNotSanitize, compile_options, - no_cache_reason, ReferrerScriptInfo()) + no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)); EXPECT_TRUE(try_catch.HasCaught()); } @@ -443,7 +445,8 @@ EXPECT_TRUE(V8ScriptRunner::CompileScript( scope.GetScriptState(), source_code, SanitizeScriptErrors::kDoNotSanitize, compile_options, - no_cache_reason, ReferrerScriptInfo()) + no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -479,7 +482,8 @@ EXPECT_TRUE(V8ScriptRunner::CompileScript( scope.GetScriptState(), source_code, SanitizeScriptErrors::kDoNotSanitize, compile_options, - no_cache_reason, ReferrerScriptInfo()) + no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -516,7 +520,8 @@ EXPECT_TRUE(V8ScriptRunner::CompileScript( scope.GetScriptState(), source_code, SanitizeScriptErrors::kDoNotSanitize, compile_options, - no_cache_reason, ReferrerScriptInfo()) + no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); }
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc index 0b04fe61..10657ec 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
@@ -329,7 +329,7 @@ // v8::TryCatch is needed to suppress all exceptions thrown during the code // cache generation. v8::TryCatch block(isolate); - ReferrerScriptInfo referrer_info; + auto referrer_info = ReferrerScriptInfo::CreateNoReferencingScript(); v8::ScriptOrigin origin( isolate, V8String(isolate, file_name), 0, // line_offset
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc index 67f0f5d..6089263d 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -472,8 +472,9 @@ try_catch.SetVerbose(true); } - const ReferrerScriptInfo referrer_info(classic_script->BaseURL(), - classic_script->FetchOptions()); + const ReferrerScriptInfo referrer_info = + ReferrerScriptInfo::CreateWithReferencingScript( + classic_script->BaseURL(), classic_script->FetchOptions()); v8::Local<v8::Script> script; @@ -594,7 +595,8 @@ // - parser_state: always "not parser inserted" for internal scripts. if (!V8ScriptRunner::CompileScript( script_state, source_code, SanitizeScriptErrors::kDoNotSanitize, - compile_options, no_cache_reason, ReferrerScriptInfo()) + compile_options, no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()) .ToLocal(&script)) return v8::MaybeLocal<v8::Value>();
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc index 6c6b416..491b5f0 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc
@@ -85,7 +85,8 @@ V8CodeCache::GetCompileOptions(cache_options, source_code); v8::MaybeLocal<v8::Script> compiled_script = V8ScriptRunner::CompileScript( script_state, source_code, SanitizeScriptErrors::kSanitize, - compile_options, no_cache_reason, ReferrerScriptInfo()); + compile_options, no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()); if (compiled_script.IsEmpty()) { return false; } @@ -110,7 +111,8 @@ } v8::MaybeLocal<v8::Script> compiled_script = V8ScriptRunner::CompileScript( script_state, source_code, SanitizeScriptErrors::kSanitize, - compile_options, no_cache_reason, ReferrerScriptInfo()); + compile_options, no_cache_reason, + ReferrerScriptInfo::CreateNoReferencingScript()); if (compiled_script.IsEmpty()) { return false; }
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc index ca11b00..f3b9ef4c 100644 --- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc +++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate_generator.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/audio_data.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h" @@ -1126,7 +1127,8 @@ // Copy out the frames to make sure they haven't been changed during the // transfer. DOMArrayBuffer* copy_dest = DOMArrayBuffer::Create(kFrames, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(copy_dest); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(copy_dest); AudioDataCopyToOptions* options = MakeGarbageCollected<AudioDataCopyToOptions>();
diff --git a/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl index a1c07b9..e9cc73a 100644 --- a/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl +++ b/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
@@ -66,7 +66,7 @@ const CreateElementFlags flags) { if (!g_{{namespace|lower}}_constructors) Create{{namespace}}FunctionMap(); - if ({{namespace}}ConstructorFunction function = g_{{namespace|lower}}_constructors->at(local_name)) + if ({{namespace}}ConstructorFunction function = g_{{namespace|lower}}_constructors->DeprecatedAtOrEmptyValue(local_name)) return function(document, flags); return nullptr; }
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 318e550f..3fc054a 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1449,6 +1449,7 @@ "loader/resource/mock_image_resource_observer.cc", "loader/resource/mock_image_resource_observer.h", "loader/resource/multipart_image_resource_parser_test.cc", + "loader/resource/resource_loader_code_cache_test.cc", "loader/resource/script_resource_test.cc", "loader/resource_load_observer_for_frame_test.cc", "loader/threadable_loader_test.cc",
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc index 66b07e3..dfe5ebe 100644 --- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc +++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -370,6 +370,29 @@ } } +void SystemClipboard::ReadAvailableCustomAndStandardFormats( + mojom::blink::ClipboardHost::ReadAvailableCustomAndStandardFormatsCallback + callback) { + clipboard_->ReadAvailableCustomAndStandardFormats(std::move(callback)); +} + +void SystemClipboard::ReadUnsanitizedCustomFormat( + const String& type, + mojom::blink::ClipboardHost::ReadUnsanitizedCustomFormatCallback callback) { + // The format size restriction is added in `ClipboardWriter::IsValidType`. + DCHECK_LT(type.length(), mojom::blink::ClipboardHost::kMaxFormatSize); + clipboard_->ReadUnsanitizedCustomFormat(type, std::move(callback)); +} + +void SystemClipboard::WriteUnsanitizedCustomFormat(const String& type, + mojo_base::BigBuffer data) { + if (data.size() >= mojom::blink::ClipboardHost::kMaxDataSize) + return; + // The format size restriction is added in `ClipboardWriter::IsValidType`. + DCHECK_LT(type.length(), mojom::blink::ClipboardHost::kMaxFormatSize); + clipboard_->WriteUnsanitizedCustomFormat(type, std::move(data)); +} + void SystemClipboard::Trace(Visitor* visitor) const { visitor->Trace(clipboard_); }
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.h b/third_party/blink/renderer/core/clipboard/system_clipboard.h index 38a0a8fa..b381f12a 100644 --- a/third_party/blink/renderer/core/clipboard/system_clipboard.h +++ b/third_party/blink/renderer/core/clipboard/system_clipboard.h
@@ -86,6 +86,17 @@ void RecordClipboardImageUrls(DocumentFragment* pasting_fragment); void RecordImageLoadError(const String& image_url); + void ReadAvailableCustomAndStandardFormats( + mojom::blink::ClipboardHost::ReadAvailableCustomAndStandardFormatsCallback + callback); + void ReadUnsanitizedCustomFormat( + const String& type, + mojom::blink::ClipboardHost::ReadUnsanitizedCustomFormatCallback + callback); + + void WriteUnsanitizedCustomFormat(const String& type, + mojo_base::BigBuffer data); + void Trace(Visitor*) const; private:
diff --git a/third_party/blink/renderer/core/css/resolver/font_builder.cc b/third_party/blink/renderer/core/css/resolver/font_builder.cc index d427f22f..2fa0a3e 100644 --- a/third_party/blink/renderer/core/css/resolver/font_builder.cc +++ b/third_party/blink/renderer/core/css/resolver/font_builder.cc
@@ -217,7 +217,7 @@ bool is_initial = family_description.generic_family == FontDescription::kStandardFamily && - family_description.family.FamilyIsEmpty(); + family_description.family.Family().IsEmpty(); font_description.SetGenericFamily(family_description.generic_family); font_description.SetFamily(is_initial ? StandardFontFamily()
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc index 20fa8ff4..f079c9061 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.cc +++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -219,6 +219,11 @@ return true; } + if (SecurityPolicy::IsSharedArrayBufferAlwaysAllowedForOrigin( + GetSecurityOrigin())) { + return true; + } + #if defined(OS_ANDROID) return false; #else
diff --git a/third_party/blink/renderer/core/frame/frame_overlay_test.cc b/third_party/blink/renderer/core/frame/frame_overlay_test.cc index e8c4618..f32836f 100644 --- a/third_party/blink/renderer/core/frame/frame_overlay_test.cc +++ b/third_party/blink/renderer/core/frame/frame_overlay_test.cc
@@ -115,9 +115,10 @@ EXPECT_EQ(PropertyTreeState::Root(), graphics_layer->GetPropertyTreeState()); Vector<PreCompositedLayerInfo> pre_composited_layers; - graphics_layer->PaintRecursively(builder.Context(), pre_composited_layers); + PaintController::CycleScope cycle_scope; + graphics_layer->PaintRecursively(builder.Context(), pre_composited_layers, + cycle_scope); ASSERT_EQ(1u, pre_composited_layers.size()); - graphics_layer->GetPaintController().FinishCycle(); SkiaPaintCanvas(&canvas).drawPicture( graphics_layer->GetPaintController().GetPaintArtifact().GetPaintRecord( PropertyTreeState::Root())); @@ -171,9 +172,10 @@ EXPECT_FALSE(graphics_layer->IsHitTestable()); EXPECT_EQ(state, graphics_layer->GetPropertyTreeState()); Vector<PreCompositedLayerInfo> pre_composited_layers; - graphics_layer->PaintRecursively(context, pre_composited_layers); + PaintController::CycleScope cycle_scope; + graphics_layer->PaintRecursively(context, pre_composited_layers, + cycle_scope); check_paint_results(graphics_layer->GetPaintController()); - graphics_layer->GetPaintController().FinishCycle(); } }
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 cf18885..9e72317 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2751,17 +2751,21 @@ } }); - bool repainted = PaintTree(benchmark_mode); + bool needed_update; + { + PaintController::CycleScope cycle_scope; + bool repainted = PaintTree(benchmark_mode, cycle_scope); - if (paint_artifact_compositor_ && - benchmark_mode == - PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate) { - paint_artifact_compositor_->SetNeedsUpdate(); + if (paint_artifact_compositor_ && + benchmark_mode == + PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate) { + paint_artifact_compositor_->SetNeedsUpdate(); + } + needed_update = !paint_artifact_compositor_ || + paint_artifact_compositor_->NeedsUpdate(); + PushPaintArtifactToCompositor(repainted); } - bool needed_update = - !paint_artifact_compositor_ || paint_artifact_compositor_->NeedsUpdate(); - PushPaintArtifactToCompositor(repainted); size_t total_animations_count = 0; ForAllNonThrottledLocalFrameViews( [this, &needed_update, @@ -2796,22 +2800,6 @@ } } - // Notify the controller that the artifact has been pushed and some - // lifecycle state can be freed (such as raster invalidations). - if (paint_controller_) - paint_controller_->FinishCycle(); - - if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer(); - if (root) { - ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) { - // Notify the paint controller that the artifact has been pushed and - // some lifecycle state can be freed (such as raster invalidations). - layer.GetPaintController().FinishCycle(); - }); - } - } - if (paint_artifact_compositor_) paint_artifact_compositor_->ClearPropertyTreeChangedState(); @@ -2877,7 +2865,8 @@ }); } -bool LocalFrameView::PaintTree(PaintBenchmarkMode benchmark_mode) { +bool LocalFrameView::PaintTree(PaintBenchmarkMode benchmark_mode, + PaintController::CycleScope& cycle_scope) { SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(), LocalFrameUkmAggregator::kPaint); @@ -2925,7 +2914,11 @@ bool needs_clear_repaint_flags = false; if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { + // TODO(paint-dev): We should be able to get rid of AddController entirely + // after non-CAP code is removed. The call to EnsurePaintController() will + // need to be moved up the call stack. EnsurePaintController(); + cycle_scope.AddController(*paint_controller_); PaintChunkSubset previous_chunks( paint_controller_->GetPaintArtifactShared()); @@ -2936,7 +2929,6 @@ if (paint_controller_->ShouldForcePaintForBenchmark() || GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint() || visual_viewport_or_overlay_needs_repaint_) { - paint_controller_->ReserveCapacity(); GraphicsContext graphics_context(*paint_controller_); if (Settings* settings = frame_->GetSettings()) { @@ -2997,6 +2989,8 @@ // parented into the main frame tree, or when the LocalFrameView is the main // frame view of a page overlay. The page overlay is in the layer tree of // the host page and will be painted during painting of the host page. + // Note that paint_controller_ is not added to cycle_scope, because it is + // transient and may be deleted before cycle_scope. paint_controller_ = std::make_unique<PaintController>(PaintController::kTransient); pre_composited_layers_.clear(); @@ -3004,8 +2998,9 @@ if (GraphicsLayer* root = layout_view->Compositor()->PaintRootGraphicsLayer()) { - repainted = root->PaintRecursively( - graphics_context, pre_composited_layers_, benchmark_mode); + repainted = + root->PaintRecursively(graphics_context, pre_composited_layers_, + cycle_scope, benchmark_mode); if (visual_viewport_or_overlay_needs_repaint_ && paint_artifact_compositor_) paint_artifact_compositor_->SetNeedsUpdate(); @@ -4130,16 +4125,15 @@ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { PaintController& paint_controller = EnsurePaintController(); if (GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint()) { + PaintController::CycleScope cycle_scope(paint_controller); GraphicsContext graphics_context(paint_controller); Paint(graphics_context, kGlobalPaintNormalPhase, cull_rect); paint_controller.CommitNewDisplayItems(); } - paint_controller.FinishCycle(); } else { GraphicsLayer* graphics_layer = GetLayoutView()->Layer()->GraphicsLayerBacking(); graphics_layer->PaintForTesting(cull_rect.Rect()); - graphics_layer->GetPaintController().FinishCycle(); } Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean); }
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index cdba46e57..92b108c6 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -50,6 +50,7 @@ #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h" #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" #include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h" #include "third_party/blink/renderer/platform/graphics/subtree_paint_property_update_reason.h" #include "third_party/blink/renderer/platform/timer.h" @@ -862,7 +863,7 @@ void PerformLayout(); void PerformPostLayoutTasks(bool view_size_changed); - bool PaintTree(PaintBenchmarkMode); + bool PaintTree(PaintBenchmarkMode, PaintController::CycleScope&); void PushPaintArtifactToCompositor(bool repainted); void ClearLayoutSubtreeRootsAndMarkContainingBlocks();
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h index b9990c2..ae3e3ec 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.h +++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -228,9 +228,10 @@ mojom::blink::ColorScheme UsedColorScheme() const override; // VisualViewport scrolling may involve pinch zoom and gets routed through - // WebViewImpl explicitly rather than via ScrollingCoordinator::DidScroll - // since it needs to be set in tandem with the page scale delta. - void DidScroll(const FloatPoint&) final { NOTREACHED(); } + // WebViewImpl explicitly rather than via + // ScrollingCoordinator::DidCompositorScroll() since it needs to be set in + // tandem with the page scale delta. + void DidCompositorScroll(const FloatPoint&) final { NOTREACHED(); } // Visual Viewport API implementation. double OffsetLeft() const;
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc index 5ab0e1f..e9c1681a 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -7095,7 +7095,7 @@ auto* scrollable_area = frame_impl->GetFrameView()->LayoutViewport(); // Do a compositor scroll, verify that this is counted as a user scroll. - scrollable_area->DidScroll(FloatPoint(0, 1)); + scrollable_area->DidCompositorScroll(FloatPoint(0, 1)); web_view_helper.GetWebView() ->MainFrameWidget() ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(), @@ -7108,7 +7108,7 @@ initial_scroll_state.was_scrolled_by_user = false; // The page scale 1.0f and scroll. - scrollable_area->DidScroll(FloatPoint(0, 2)); + scrollable_area->DidCompositorScroll(FloatPoint(0, 2)); web_view_helper.GetWebView() ->MainFrameWidget() ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(), @@ -7120,7 +7120,7 @@ initial_scroll_state.was_scrolled_by_user = false; // No scroll event if there is no scroll delta. - scrollable_area->DidScroll(FloatPoint(0, 2)); + scrollable_area->DidCompositorScroll(FloatPoint(0, 2)); web_view_helper.GetWebView() ->MainFrameWidget() ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(), @@ -7131,7 +7131,7 @@ client.Reset(); // Non zero page scale and scroll. - scrollable_area->DidScroll(FloatPoint(9, 15)); + scrollable_area->DidCompositorScroll(FloatPoint(9, 15)); web_view_helper.GetWebView() ->MainFrameWidget() ->ApplyViewportChangesForTesting({gfx::ScrollOffset(), gfx::Vector2dF(),
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc index 098da2b..5c02b66 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -75,8 +75,10 @@ namespace { bool HasFormInBetween(const Node* root, const Node* descendant) { - DCHECK(descendant->IsDescendantOf(root)); DCHECK(!IsA<HTMLFormElement>(descendant)); + // |descendant| might not actually be a descendant of |root|. + if (!descendant->IsDescendantOf(root)) + return false; for (ContainerNode* parent = descendant->parentNode(); parent && parent != root; parent = parent->parentNode()) { if (DynamicTo<HTMLFormElement>(parent)) {
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc index ba89ae6..7dc0bacc 100644 --- a/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -1842,7 +1842,7 @@ // Do a compositor scroll and set |hover_needs_update_at_scroll_end| to be // true in WebViewImpl. LocalFrameView* frame_view = GetDocument().View(); - frame_view->LayoutViewport()->DidScroll(FloatPoint(0, 500)); + frame_view->LayoutViewport()->DidCompositorScroll(FloatPoint(0, 500)); WebView().MainFrameWidget()->ApplyViewportChangesForTesting( {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false, 0, 0, cc::BrowserControlsState::kBoth, true});
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc index b686cad..251f01a 100644 --- a/third_party/blink/renderer/core/layout/layout_text_control.cc +++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -157,7 +157,6 @@ // number of Mac fonts, but, in order to get similar rendering across platforms, // we do this check for all platforms. bool LayoutTextControl::HasValidAvgCharWidth(const Font& font) { - const AtomicString family = font.GetFontDescription().Family().Family(); const SimpleFontData* font_data = font.PrimaryFont(); DCHECK(font_data); if (!font_data) @@ -172,6 +171,7 @@ static HashSet<AtomicString>* font_families_with_invalid_char_width_map = nullptr; + const AtomicString& family = font.GetFontDescription().Family().Family(); if (family.IsEmpty()) return false;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 899d901..0a4e95e 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -471,6 +471,7 @@ container_builder_.SetInlineSize(inline_size); container_builder_.SetMetrics(line_box_metrics); container_builder_.SetBfcBlockOffset(block_offset); + container_builder_.SetLineBoxBfcBlockOffset(block_offset); } void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item, @@ -616,6 +617,7 @@ container_builder_.SetBaseDirection(line_info.BaseDirection()); if (absl::optional<LayoutUnit> block_offset = result.BfcBlockOffset()) { container_builder_.SetBfcBlockOffset(*block_offset); + container_builder_.SetLineBoxBfcBlockOffset(*block_offset); container_builder_.SetEndMarginStrut(result.EndMarginStrut()); container_builder_.SetAdjoiningObjectTypes(result.AdjoiningObjectTypes()); const NGConstraintSpace& space = ConstraintSpace(); @@ -656,8 +658,6 @@ DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty()) << "Non-empty lines must have a valid set of linebox metrics."; - bool is_empty_inline = Node().IsEmptyInline(); - // All children within the linebox are positioned relative to the baseline, // then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection. LayoutUnit baseline_adjustment = @@ -711,8 +711,7 @@ // If we are an empty-inline we may not have the correct BFC block-offset // yet. Due to this we need to mark this node as having adjoining // objects, and perform a re-layout if our position shifts. - if (is_empty_inline) - container_builder_.AddAdjoiningObjectTypes(kAdjoiningInlineOutOfFlow); + container_builder_.AddAdjoiningObjectTypes(kAdjoiningInlineOutOfFlow); } else { // A block-level OOF element positions itself on the "next" line. However // only shifts down if there is preceding inline-level content. @@ -1063,7 +1062,7 @@ // layout_object may be null in certain cases, e.g. if it's a kBidiControl. if (layout_object && layout_object->IsBR()) { const LayoutUnit line_box_bfc_block_offset = - ContainerBfcOffset().block_offset; + *container_builder_.LineBoxBfcBlockOffset(); NGBfcOffset bfc_offset = {LayoutUnit(), line_box_bfc_block_offset + content_size}; AdjustToClearance(
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc index 2da16bc..1b67ab8 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -26,6 +26,7 @@ unpositioned_list_marker_ = NGUnpositionedListMarker(); bfc_block_offset_.reset(); + line_box_bfc_block_offset_.reset(); size_.inline_size = LayoutUnit(); metrics_ = FontHeight::Empty();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h index 6eded710..e84780e 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -59,6 +59,14 @@ // Mark this line box is an "empty" line box. See NGLineBoxType. void SetIsEmptyLineBox(); + absl::optional<LayoutUnit> LineBoxBfcBlockOffset() const { + return line_box_bfc_block_offset_; + } + void SetLineBoxBfcBlockOffset(LayoutUnit offset) { + DCHECK(bfc_block_offset_); + line_box_bfc_block_offset_ = offset; + } + const FontHeight& Metrics() const { return metrics_; } void SetMetrics(const FontHeight& metrics) { metrics_ = metrics; } @@ -81,6 +89,7 @@ scoped_refptr<const NGLayoutResult> ToLineBoxFragment(); private: + absl::optional<LayoutUnit> line_box_bfc_block_offset_; FontHeight metrics_ = FontHeight::Empty(); LayoutUnit hang_inline_size_; NGPhysicalLineBoxFragment::NGLineBoxType line_box_type_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 8f4b076..0430d266 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1888,21 +1888,31 @@ NGFragment fragment(ConstraintSpace().GetWritingDirection(), physical_fragment); - if (ConstraintSpace().HasBlockFragmentation() && - container_builder_.BfcBlockOffset() && child_bfc_block_offset) { - // Floats only cause container separation for the outermost block child that - // gets pushed down (the container and the child may have adjoining - // block-start margins). - bool has_container_separation = - has_processed_first_child_ || (layout_result->IsPushedByFloats() && - !container_builder_.IsPushedByFloats()); - NGBreakStatus break_status = BreakBeforeChildIfNeeded( - child, *layout_result, previous_inflow_position, - *child_bfc_block_offset, has_container_separation); - if (break_status == NGBreakStatus::kBrokeBefore) - return NGLayoutResult::kSuccess; - if (break_status == NGBreakStatus::kNeedsEarlierBreak) - return NGLayoutResult::kNeedsEarlierBreak; + const absl::optional<LayoutUnit> line_box_bfc_block_offset = + layout_result->LineBoxBfcBlockOffset(); + + if (ConstraintSpace().HasBlockFragmentation()) { + if (container_builder_.BfcBlockOffset() && child_bfc_block_offset) { + bool is_line_box_pushed_by_floats = + line_box_bfc_block_offset && + *line_box_bfc_block_offset > *child_bfc_block_offset; + + // Floats only cause container separation for the outermost block child + // that gets pushed down (the container and the child may have adjoining + // block-start margins). + bool has_container_separation = + has_processed_first_child_ || + (!container_builder_.IsPushedByFloats() && + (layout_result->IsPushedByFloats() || is_line_box_pushed_by_floats)); + NGBreakStatus break_status = BreakBeforeChildIfNeeded( + child, *layout_result, previous_inflow_position, + line_box_bfc_block_offset.value_or(*child_bfc_block_offset), + has_container_separation); + if (break_status == NGBreakStatus::kBrokeBefore) + return NGLayoutResult::kSuccess; + if (break_status == NGBreakStatus::kNeedsEarlierBreak) + return NGLayoutResult::kNeedsEarlierBreak; + } if (inline_child_layout_context) { for (auto token : inline_child_layout_context->PropagatedBreakTokens()) { @@ -1913,6 +1923,9 @@ } } + if (line_box_bfc_block_offset) + child_bfc_block_offset = line_box_bfc_block_offset; + LogicalOffset logical_offset = CalculateLogicalOffset( fragment, layout_result->BfcLineOffset(), child_bfc_block_offset); if (UNLIKELY(child.IsSliderThumb()))
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc index 3121923..0f07c37 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -109,7 +109,14 @@ scoped_refptr<const NGPhysicalFragment> physical_fragment, NGLineBoxFragmentBuilder* builder) : NGLayoutResult(std::move(physical_fragment), - static_cast<NGContainerFragmentBuilder*>(builder)) {} + static_cast<NGContainerFragmentBuilder*>(builder)) { + DCHECK_EQ(builder->bfc_block_offset_.has_value(), + builder->line_box_bfc_block_offset_.has_value()); + if (builder->bfc_block_offset_ != builder->line_box_bfc_block_offset_) { + EnsureRareData()->line_box_bfc_block_offset = + builder->line_box_bfc_block_offset_; + } +} NGLayoutResult::NGLayoutResult(NGContainerFragmentBuilderPassKey key, EStatus status,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h index bfda9d6..357d7df 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -164,6 +164,29 @@ return bfc_offset_.block_offset; } + // The BFC block-offset where a line-box has been placed. Will be nullopt if + // it isn't a line-box, or an empty line-box. + // + // This can be different (but rarely) to where the |BfcBlockOffset()| + // resolves to, when floats are present. E.g. + // + // <div style="width: 100px; display: flow-root;"> + // <div style="float: left; width: 200px; height: 20px;"></div> + // text + // </div> + // + // In the above example the |BfcBlockOffset()| will be at 0px, where-as the + // |LineBoxBfcBlockOffset()| will be at 20px. + absl::optional<LayoutUnit> LineBoxBfcBlockOffset() const { + if (!PhysicalFragment().IsLineBox()) + return absl::nullopt; + + if (HasRareData() && rare_data_->line_box_bfc_block_offset) + return rare_data_->line_box_bfc_block_offset; + + return BfcBlockOffset(); + } + const NGMarginStrut EndMarginStrut() const { return HasRareData() ? rare_data_->end_margin_strut : NGMarginStrut(); } @@ -427,6 +450,7 @@ rare_data.tallest_unbreakable_block_size), exclusion_space(rare_data.exclusion_space), custom_layout_data(rare_data.custom_layout_data), + line_box_bfc_block_offset(rare_data.line_box_bfc_block_offset), annotation_overflow(rare_data.annotation_overflow), block_end_annotation_space(rare_data.block_end_annotation_space), has_violating_break(rare_data.has_violating_break), @@ -463,6 +487,7 @@ NGExclusionSpace exclusion_space; scoped_refptr<SerializedScriptValue> custom_layout_data; + absl::optional<LayoutUnit> line_box_bfc_block_offset; LayoutUnit annotation_overflow; LayoutUnit block_end_annotation_space; bool has_violating_break = false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index a1fd7ca..1d60a5d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -1039,7 +1039,7 @@ // Skip over any column spanners. if (!fragment || fragment->IsFragmentainerBox()) { - const Vector<NodeToLayout>& pending_descendants = + Vector<NodeToLayout>& pending_descendants = descendants_to_layout[index]; LayoutOOFsInFragmentainer(pending_descendants, index, column_inline_progression, @@ -1144,11 +1144,11 @@ } scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutOOFNode( - const NodeToLayout& oof_node_to_layout, + NodeToLayout& oof_node_to_layout, const LayoutBox* only_layout, const NGConstraintSpace* fragmentainer_constraint_space) { const NodeInfo& node_info = oof_node_to_layout.node_info; - OffsetInfo offset_info = oof_node_to_layout.offset_info; + OffsetInfo& offset_info = oof_node_to_layout.offset_info; if (offset_info.has_cached_layout_result) { DCHECK(offset_info.initial_layout_result); return offset_info.initial_layout_result; @@ -1158,7 +1158,7 @@ freeze_scrollbars; do { scoped_refptr<const NGLayoutResult> layout_result = - Layout(oof_node_to_layout, offset_info, fragmentainer_constraint_space); + Layout(oof_node_to_layout, fragmentainer_constraint_space); if (!freeze_scrollbars.has_value()) { // Since out-of-flow positioning sets up a constraint space with fixed @@ -1283,7 +1283,6 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( const NodeToLayout& oof_node_to_layout, - const OffsetInfo& offset_info, const NGConstraintSpace* fragmentainer_constraint_space) { const NodeInfo& node_info = oof_node_to_layout.node_info; const WritingDirectionMode candidate_writing_direction = @@ -1291,6 +1290,7 @@ LogicalSize container_content_size_in_candidate_writing_mode = node_info.container_physical_content_size.ConvertToLogical( candidate_writing_direction.GetWritingMode()); + const OffsetInfo& offset_info = oof_node_to_layout.offset_info; LogicalOffset offset = offset_info.offset; // Reset the |layout_result| computed earlier to allow fragmentation in the @@ -1404,7 +1404,7 @@ } void NGOutOfFlowLayoutPart::LayoutOOFsInFragmentainer( - const Vector<NodeToLayout>& pending_descendants, + Vector<NodeToLayout>& pending_descendants, wtf_size_t index, LayoutUnit column_inline_progression, Vector<NodeToLayout>* fragmented_descendants) { @@ -1493,7 +1493,7 @@ } void NGOutOfFlowLayoutPart::AddOOFToFragmentainer( - const NodeToLayout& descendant, + NodeToLayout& descendant, const NGConstraintSpace* fragmentainer_space, LogicalOffset fragmentainer_offset, wtf_size_t index,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index 66b9ec78..c3b4d0f2 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -226,7 +226,7 @@ NodeInfo SetupNodeInfo(const NGLogicalOutOfFlowPositionedNode& oof_node); scoped_refptr<const NGLayoutResult> LayoutOOFNode( - const NodeToLayout& oof_node_to_layout, + NodeToLayout& oof_node_to_layout, const LayoutBox* only_layout, const NGConstraintSpace* fragmentainer_constraint_space = nullptr); @@ -238,7 +238,6 @@ scoped_refptr<const NGLayoutResult> Layout( const NodeToLayout& oof_node_to_layout, - const OffsetInfo& offset_info, const NGConstraintSpace* fragmentainer_constraint_space); bool IsContainingBlockForCandidate(const NGLogicalOutOfFlowPositionedNode&); @@ -262,12 +261,11 @@ // |fragmented_descendants| is also an output variable in that any OOF that // has not finished layout in the current pass will be added back to // |fragmented_descendants| to continue layout in the next fragmentainer. - void LayoutOOFsInFragmentainer( - const Vector<NodeToLayout>& pending_descendants, - wtf_size_t index, - LayoutUnit column_inline_progression, - Vector<NodeToLayout>* fragmented_descendants); - void AddOOFToFragmentainer(const NodeToLayout& descendant, + void LayoutOOFsInFragmentainer(Vector<NodeToLayout>& pending_descendants, + wtf_size_t index, + LayoutUnit column_inline_progression, + Vector<NodeToLayout>* fragmented_descendants); + void AddOOFToFragmentainer(NodeToLayout& descendant, const NGConstraintSpace* fragmentainer_space, LogicalOffset fragmentainer_offset, wtf_size_t index,
diff --git a/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc b/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc new file mode 100644 index 0000000..ceacd700 --- /dev/null +++ b/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc
@@ -0,0 +1,192 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this sink code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h" +#include "third_party/blink/renderer/core/loader/resource/script_resource.h" +#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" +#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h" +#include "third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.h" +#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h" +#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h" +#include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h" +#include "third_party/blink/renderer/platform/testing/code_cache_loader_mock.h" +#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h" +#include "third_party/blink/renderer/platform/testing/noop_web_url_loader.h" +#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h" +#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" + +namespace blink { +namespace { + +class ResourceLoaderCodeCacheTest : public testing::Test { + protected: + static scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() { + return base::MakeRefCounted<scheduler::FakeTaskRunner>(); + } + + ResourceFetcher* MakeResourceFetcher( + TestResourceFetcherProperties* properties, + FetchContext* context, + ResourceFetcher::LoaderFactory* loader_factory) { + return MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit( + properties->MakeDetachable(), context, CreateTaskRunner(), + CreateTaskRunner(), loader_factory, + MakeGarbageCollected<MockContextLifecycleNotifier>(), + nullptr /* back_forward_cache_loader_helper */)); + } + + class CodeCacheTestLoaderFactory : public ResourceFetcher::LoaderFactory { + public: + explicit CodeCacheTestLoaderFactory( + scoped_refptr<CodeCacheLoaderMock::Controller> controller) + : controller_(std::move(controller)) {} + std::unique_ptr<WebURLLoader> CreateURLLoader( + const ResourceRequest& request, + const ResourceLoaderOptions& options, + scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner, + WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) + override { + return std::make_unique<NoopWebURLLoader>( + std::move(freezable_task_runner)); + } + std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override { + return std::make_unique<CodeCacheLoaderMock>(controller_); + } + + private: + scoped_refptr<CodeCacheLoaderMock::Controller> controller_; + }; + + void CommonSetup(const char* url_string = nullptr) { + SchemeRegistry::RegisterURLSchemeAsCodeCacheWithHashing( + "codecachewithhashing"); + + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + FetchContext* context = MakeGarbageCollected<MockFetchContext>(); + controller_ = base::MakeRefCounted<CodeCacheLoaderMock::Controller>(); + controller_->DelayResponse(); + auto* loader_factory = + MakeGarbageCollected<CodeCacheTestLoaderFactory>(controller_); + auto* fetcher = MakeResourceFetcher(properties, context, loader_factory); + + KURL url(url_string ? url_string + : "codecachewithhashing://www.example.com/"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::SCRIPT); + + FetchParameters params = FetchParameters::CreateForTest(std::move(request)); + resource_ = ScriptResource::Fetch(params, fetcher, nullptr, + ScriptResource::kNoStreaming); + loader_ = resource_->Loader(); + + response_ = ResourceResponse(url); + response_.SetHttpStatusCode(200); + } + + std::vector<uint8_t> MakeSerializedCodeCacheData() { + const size_t kCachedMetadataTypeSize = sizeof(uint32_t); + const size_t kSha256Bytes = 256 / 8; + const size_t kDataSize = + kCachedMetadataTypeSize + kSha256Bytes + kCachedMetaDataStart + 1; + std::vector<uint8_t> data(kDataSize); + *reinterpret_cast<uint32_t*>(&data[0]) = + CachedMetadataHandler::kSingleEntryWithHash; + *reinterpret_cast<uint32_t*>( + &data[kCachedMetadataTypeSize + kSha256Bytes]) = + CachedMetadataHandler::kSingleEntry; + return data; + } + + ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> + platform_; + + // State initialized by CommonSetup(). + Persistent<ScriptResource> resource_; + Persistent<ResourceLoader> loader_; + ResourceResponse response_; + scoped_refptr<CodeCacheLoaderMock::Controller> controller_; +}; + +TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheEmptyResponseFirst) { + CommonSetup(); + + loader_->DidReceiveResponse(WrappedResourceResponse(response_)); + + // Nothing has changed yet because the code cache hasn't yet responded. + EXPECT_FALSE(resource_->CodeCacheSize()); + + // An empty code cache response means no data was found. + controller_->Respond(base::Time(), mojo_base::BigBuffer()); + + // No code cache data was present. + EXPECT_FALSE(resource_->CodeCacheSize()); +} + +TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheEmptyResponseSecond) { + CommonSetup(); + + // An empty code cache response means no data was found. + controller_->Respond(base::Time(), mojo_base::BigBuffer()); + + // Nothing has changed yet because the content response hasn't arrived yet. + EXPECT_FALSE(resource_->CodeCacheSize()); + + loader_->DidReceiveResponse(WrappedResourceResponse(response_)); + + // No code cache data was present. + EXPECT_FALSE(resource_->CodeCacheSize()); +} + +TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullResponseFirst) { + CommonSetup(); + + loader_->DidReceiveResponse(WrappedResourceResponse(response_)); + + // Nothing has changed yet because the code cache hasn't yet responded. + EXPECT_FALSE(resource_->CodeCacheSize()); + + controller_->Respond(base::Time(), + mojo_base::BigBuffer(MakeSerializedCodeCacheData())); + + // Code cache data was present. + EXPECT_TRUE(resource_->CodeCacheSize()); +} + +TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullResponseSecond) { + CommonSetup(); + + controller_->Respond(base::Time(), + mojo_base::BigBuffer(MakeSerializedCodeCacheData())); + + // Nothing has changed yet because the content response hasn't arrived yet. + EXPECT_FALSE(resource_->CodeCacheSize()); + + loader_->DidReceiveResponse(WrappedResourceResponse(response_)); + + // Code cache data was present. + EXPECT_TRUE(resource_->CodeCacheSize()); +} + +TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullHttpsScheme) { + CommonSetup("https://www.example.com/"); + + controller_->Respond(base::Time(), + mojo_base::BigBuffer(MakeSerializedCodeCacheData())); + + // Nothing has changed yet because the content response hasn't arrived yet. + EXPECT_FALSE(resource_->CodeCacheSize()); + + loader_->DidReceiveResponse(WrappedResourceResponse(response_)); + + // Since the URL was https, and the response times were not set, the cached + // metadata should not be set. + EXPECT_FALSE(resource_->CodeCacheSize()); +} + +} // namespace +} // namespace blink
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.cc b/third_party/blink/renderer/core/loader/resource/script_resource.cc index 2087037..22d6955 100644 --- a/third_party/blink/renderer/core/loader/resource/script_resource.cc +++ b/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -203,7 +203,12 @@ bool ScriptResource::CodeCacheHashRequired() const { if (cached_metadata_handler_) { - return cached_metadata_handler_->HashRequired(); + bool result = cached_metadata_handler_->HashRequired(); + if (result) { + DCHECK(SchemeRegistry::SchemeSupportsCodeCacheWithHashing( + GetResourceRequest().Url().Protocol())); + } + return result; } return false; }
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc index 3103222d8..15c6c3b 100644 --- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -2849,7 +2849,7 @@ .GlobalRootScroller(); ScrollableArea* scrollable_area = To<LayoutBox>(scroller->GetLayoutObject())->GetScrollableArea(); - scrollable_area->DidScroll(FloatPoint(0, 100000)); + scrollable_area->DidCompositorScroll(FloatPoint(0, 100000)); WebView().ResizeWithBrowserControls(gfx::Size(400, 450), 50, 50, false);
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc index f49b412..a466b7a 100644 --- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc +++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -90,20 +90,21 @@ return nullptr; } -void ScrollingCoordinator::DidScroll( +void ScrollingCoordinator::DidCompositorScroll( CompositorElementId element_id, const gfx::ScrollOffset& offset, const absl::optional<cc::TargetSnapAreaElementIds>& snap_target_ids) { // Find the associated scrollable area using the element id and notify it of // the compositor-side scroll. We explicitly do not check the VisualViewport - // which handles scroll offset differently (see: VisualViewport::didScroll). - // Remote frames will receive DidScroll callbacks from their own compositor. + // which handles scroll offset differently (see: + // VisualViewport::DidCompositorScroll). Remote frames will receive + // DidCompositorScroll callbacks from their own compositor. // The ScrollableArea with matching ElementId may have been deleted and we can - // safely ignore the DidScroll callback. + // safely ignore the DidCompositorScroll callback. auto* scrollable = ScrollableAreaWithElementIdInAllLocalFrames(element_id); if (!scrollable) return; - scrollable->DidScroll(FloatPoint(offset.x(), offset.y())); + scrollable->DidCompositorScroll(FloatPoint(offset.x(), offset.y())); if (snap_target_ids) scrollable->SetTargetSnapAreaElementIds(snap_target_ids.value()); }
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h index a4ccbf16..a8fb4454 100644 --- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h +++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
@@ -113,9 +113,10 @@ const CompositorElementId&); // ScrollCallbacks implementation - void DidScroll(CompositorElementId, - const gfx::ScrollOffset&, - const absl::optional<cc::TargetSnapAreaElementIds>&) override; + void DidCompositorScroll( + CompositorElementId, + const gfx::ScrollOffset&, + const absl::optional<cc::TargetSnapAreaElementIds>&) override; void DidChangeScrollbarsHidden(CompositorElementId, bool hidden) override; base::WeakPtr<ScrollingCoordinator> GetWeakPtr() {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index a673dfe..072c1af 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -181,8 +181,8 @@ return box ? box->GetScrollableArea() : nullptr; } -void PaintLayerScrollableArea::DidScroll(const FloatPoint& position) { - ScrollableArea::DidScroll(position); +void PaintLayerScrollableArea::DidCompositorScroll(const FloatPoint& position) { + ScrollableArea::DidCompositorScroll(position); // This should be alive if it receives composited scroll callbacks. CHECK(!HasBeenDisposed()); }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h index 99148b6..d794536 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -278,7 +278,7 @@ // only a helper. cc::Layer* LayerForScrolling() const override; - void DidScroll(const FloatPoint&) override; + void DidCompositorScroll(const FloatPoint&) override; // GraphicsLayers for the scrolling components. // Any function can return nullptr if they are not accelerated.
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc index 2089cb1..0986094 100644 --- a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc +++ b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
@@ -266,17 +266,28 @@ << "ResolveDynamically should be called from V8 callback, within a valid " "context."; - // <spec step="4.1">Let referencing script be - // referencingScriptOrModule.[[HostDefined]].</spec> + // <spec step="5">If referencingScriptOrModule is not null, then:</spec> + KURL base_url; + if (referrer_info.HasReferencingScript()) { + // <spec step="5.3">Set base URL to referencing script's base URL.</spec> + base_url = referrer_info.BaseURL(); - // <spec step="4.3">Set base URL to referencing script's base URL.</spec> - KURL base_url = referrer_info.BaseURL(); - if (base_url.IsNull()) { + // Fallback to ExecutionContext's Base URL. This only occurs for + // setTimeout()/setInterval() and some internal scripts not specified by the + // HTML spec (i.e. some of `ClassicScript::CreateUnspecifiedScript()`), + // where `ReferrerScriptInfo::BaseURL()` is null. + // TODO(crbug.com/1133238): Perhaps remove this fallback or change to + // about:blank after base URLs are assigned to setTimeout() etc. + if (base_url.IsNull()) { + base_url = + ExecutionContext::From(modulator_->GetScriptState())->BaseURL(); + } + } else { // The case where "referencing script" doesn't exist. // // <spec step="1">Let settings object be the current settings object.</spec> // - // <spec step="2">Let base URL be settings object's API base URL.</spec> + // <spec step="3">Let base URL be settings object's API base URL.</spec> base_url = ExecutionContext::From(modulator_->GetScriptState())->BaseURL(); } DCHECK(!base_url.IsNull()); @@ -334,21 +345,25 @@ return; } - // <spec step="4.4">Set fetch options to the descendant script fetch options + // <spec step="4">Let fetch options be the default classic script fetch + // options.</spec> + // + // <spec step="5.4">Set fetch options to the descendant script fetch options // for referencing script's fetch options.</spec> // // <spec - // href="https://html.spec.whatwg.org/C/#descendant-script-fetch-options"> For - // any given script fetch options options, the descendant script fetch options - // are a new script fetch options whose items all have the same values, except - // for the integrity metadata, which is instead the empty string.</spec> + // href="https://html.spec.whatwg.org/C/#descendant-script-fetch-options"> + // For any given script fetch options options, the descendant script fetch + // options are a new script fetch options whose items all have the same + // values, except for the integrity metadata, which is instead the empty + // string.</spec> // - // TODO(domfarolino): It has not yet been decided how a script's "importance" - // should affect its dynamic imports. There is discussion at - // https://github.com/whatwg/html/issues/3670, but for now there is no effect, - // and dynamic imports get kImportanceAuto. If this changes, - // ReferrerScriptInfo will need a mojom::FetchImportanceMode member, that must - // be properly set. + // TODO(domfarolino): It has not yet been decided how a script's + // "importance" should affect its dynamic imports. There is discussion at + // https://github.com/whatwg/html/issues/3670, but for now there is no + // effect, and dynamic imports get kImportanceAuto. If this changes, + // ReferrerScriptInfo will need a mojom::FetchImportanceMode member, that + // must be properly set. ScriptFetchOptions options(referrer_info.Nonce(), IntegrityMetadataSet(), String(), referrer_info.ParserState(), referrer_info.CredentialsMode(),
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc index ad590e0..be6ce29 100644 --- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc +++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -40,7 +40,8 @@ return KURL(kTestDependencyURLJSON); } ReferrerScriptInfo TestReferrerScriptInfo() { - return ReferrerScriptInfo(TestReferrerURL(), ScriptFetchOptions()); + return ReferrerScriptInfo::CreateWithReferencingScript(TestReferrerURL(), + ScriptFetchOptions()); } class DynamicModuleResolverTestModulator final : public DummyModulator { @@ -445,7 +446,8 @@ ModuleRequest module_request("./dependency.js", TextPosition::MinimumPosition(), Vector<ImportAssertion>()); - resolver->ResolveDynamically(module_request, ReferrerScriptInfo(), + resolver->ResolveDynamically(module_request, + ReferrerScriptInfo::CreateNoReferencingScript(), promise_resolver); v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate()); @@ -482,10 +484,10 @@ ModuleRequest module_request("./dependency.js", TextPosition::MinimumPosition(), Vector<ImportAssertion>()); - resolver->ResolveDynamically( - module_request, - ReferrerScriptInfo(correct_base_url, ScriptFetchOptions()), - promise_resolver); + resolver->ResolveDynamically(module_request, + ReferrerScriptInfo::CreateWithReferencingScript( + correct_base_url, ScriptFetchOptions()), + promise_resolver); v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate()); EXPECT_TRUE(modulator->fetch_tree_was_called());
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc index e66e82a..7abea57 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.cc +++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -898,7 +898,7 @@ std::max(0, size.Height() - HorizontalScrollbarHeight())); } -void ScrollableArea::DidScroll(const FloatPoint& position) { +void ScrollableArea::DidCompositorScroll(const FloatPoint& position) { ScrollOffset new_offset(ScrollPositionToOffset(position)); SetScrollOffset(new_offset, mojom::blink::ScrollType::kCompositor); }
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h index ee4f50a..d17a578 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.h +++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -526,7 +526,7 @@ const = 0; // Callback for compositor-side scrolling. - virtual void DidScroll(const FloatPoint&); + virtual void DidCompositorScroll(const FloatPoint& position); virtual void ScrollbarFrameRectChanged() {}
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area_test.cc b/third_party/blink/renderer/core/scroll/scrollable_area_test.cc index 8cfee51..7d06943 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area_test.cc +++ b/third_party/blink/renderer/core/scroll/scrollable_area_test.cc
@@ -285,7 +285,7 @@ MockScrollableArea* scrollable_area = MockScrollableArea::Create(ScrollOffset(100, 100)); - scrollable_area->DidScroll(FloatPoint(40, 51)); + scrollable_area->DidCompositorScroll(FloatPoint(40, 51)); EXPECT_EQ(40, scrollable_area->ScrollOffsetInt().Width()); EXPECT_EQ(51, scrollable_area->ScrollOffsetInt().Height());
diff --git a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc index c84d33e..c042969 100644 --- a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc +++ b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc
@@ -196,6 +196,7 @@ } void SVGFilterBuilder::Add(const AtomicString& id, FilterEffect* effect) { + DCHECK(effect); if (id.IsEmpty()) { last_effect_ = effect; return; @@ -210,20 +211,21 @@ FilterEffect* SVGFilterBuilder::GetEffectById(const AtomicString& id) const { if (!id.IsEmpty()) { - if (FilterEffect* builtin_effect = - builtin_effects_.DeprecatedAtOrEmptyValue(id)) - return builtin_effect; + auto builtin_it = builtin_effects_.find(id); + if (builtin_it != builtin_effects_.end()) + return builtin_it->value; - if (FilterEffect* named_effect = - named_effects_.DeprecatedAtOrEmptyValue(id)) - return named_effect; + auto named_it = named_effects_.find(id); + if (named_it != named_effects_.end()) + return named_it->value; } if (last_effect_) return last_effect_; - return builtin_effects_.DeprecatedAtOrEmptyValue( - FilterInputKeywords::GetSourceGraphic()); + // Fallback to the 'SourceGraphic' input. We add it in the constructor so it will always be + // present. + return builtin_effects_.at(FilterInputKeywords::GetSourceGraphic()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc index 5f3f9f31..93d12ad8 100644 --- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc +++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -557,6 +557,7 @@ return nullptr; view->UpdateAllLifecyclePhasesExceptPaint(DocumentUpdateReason::kSVGImage); + PaintController::CycleScope cycle_scope(*paint_controller_); PaintRecordBuilder builder(*paint_controller_); builder.Context().SetDarkModeEnabled(draw_info.IsDarkModeEnabled()); view->PaintOutsideOfLifecycle(builder.Context(), kGlobalPaintNormalPhase);
diff --git a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc index e0ff1f0..a90377e 100644 --- a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc +++ b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
@@ -184,6 +184,37 @@ needs_reset_ = true; } +void MockClipboardHost::ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) { + Vector<String> format_names; + for (const auto& item : unsanitized_custom_data_map_) + format_names.emplace_back(item.key); + std::move(callback).Run(format_names); +} + +void MockClipboardHost::ReadUnsanitizedCustomFormat( + const String& format, + ReadUnsanitizedCustomFormatCallback callback) { + const auto it = unsanitized_custom_data_map_.find(format); + if (it == unsanitized_custom_data_map_.end()) + return; + + mojo_base::BigBuffer buffer = + mojo_base::BigBuffer(base::make_span(it->value.data(), it->value.size())); + std::move(callback).Run(std::move(buffer)); +} + +void MockClipboardHost::WriteUnsanitizedCustomFormat( + const String& format, + mojo_base::BigBuffer data) { + if (needs_reset_) + Reset(); + // Simulate the underlying platform copying this data. + Vector<uint8_t> data_copy(base::saturated_cast<wtf_size_t>(data.size()), + *data.data()); + unsanitized_custom_data_map_.Set(format, data_copy); +} + #if defined(OS_MAC) void MockClipboardHost::WriteStringToFindPboard(const String& text) {} #endif
diff --git a/third_party/blink/renderer/core/testing/mock_clipboard_host.h b/third_party/blink/renderer/core/testing/mock_clipboard_host.h index 8c40b95e..8957dbae 100644 --- a/third_party/blink/renderer/core/testing/mock_clipboard_host.h +++ b/third_party/blink/renderer/core/testing/mock_clipboard_host.h
@@ -59,6 +59,13 @@ void WriteBookmark(const String& url, const String& title) override; void WriteImage(const SkBitmap& bitmap) override; void CommitWrite() override; + void ReadAvailableCustomAndStandardFormats( + ReadAvailableCustomAndStandardFormatsCallback callback) override; + void ReadUnsanitizedCustomFormat( + const String& format, + ReadUnsanitizedCustomFormatCallback callback) override; + void WriteUnsanitizedCustomFormat(const String& format, + mojo_base::BigBuffer data) override; #if defined(OS_MAC) void WriteStringToFindPboard(const String& text) override; #endif @@ -75,6 +82,7 @@ HashMap<String, String> custom_data_; bool write_smart_paste_ = false; bool needs_reset_ = false; + HashMap<String, Vector<uint8_t>> unsanitized_custom_data_map_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.cc b/third_party/blink/renderer/core/timing/performance_user_timing.cc index a0ff985a..887e3330 100644 --- a/third_party/blink/renderer/core/timing/performance_user_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -109,7 +109,8 @@ } PerformanceTiming::PerformanceTimingGetter timing_function = - PerformanceTiming::GetAttributeMapping().at(mark_name); + PerformanceTiming::GetAttributeMapping().DeprecatedAtOrEmptyValue( + mark_name); if (!timing_function) { exception_state.ThrowDOMException( DOMExceptionCode::kSyntaxError,
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc index 28e4d473..7fb38eafa 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -261,6 +261,9 @@ // static bool ClipboardWriter::IsValidType(const String& type, bool is_custom_format_type) { + if (is_custom_format_type) + return type.length() < mojom::blink::ClipboardHost::kMaxFormatSize; + if (type == kMimeTypeImageSvg) return RuntimeEnabledFeatures::ClipboardSvgEnabled();
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc index e207fc4b..7f6a296 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
@@ -36,6 +36,7 @@ namespace { const int kThumbRadius = 6; +const base::TimeDelta kRenderTimelineInterval = base::TimeDelta::FromSeconds(1); // Only respond to main button of primary pointer(s). bool IsValidPointerEvent(const blink::Event& event) { @@ -82,6 +83,13 @@ void MediaControlTimelineElement::SetPosition(double current_time, bool suppress_aria) { + if (is_live_ && !live_anchor_time_ && current_time != 0) { + live_anchor_time_.emplace(); + live_anchor_time_->clock_time_ = base::TimeTicks::Now(); + live_anchor_time_->media_time_ = MediaElement().currentTime(); + } + + MaybeUpdateTimelineInterval(); setValue(String::Number(current_time)); if (!suppress_aria) @@ -91,8 +99,11 @@ } void MediaControlTimelineElement::SetDuration(double duration) { - double duration_value = std::isfinite(duration) ? duration : 0; - SetFloatingPointAttribute(html_names::kMaxAttr, duration_value); + is_live_ = std::isinf(duration); + double duration_value = duration; + SetFloatingPointAttribute(html_names::kMaxAttr, + is_live_ ? 0.0 : duration_value); + SetFloatingPointAttribute(html_names::kMinAttr, 0.0); RenderBarSegments(); } @@ -109,10 +120,12 @@ if (BeginScrubbingEvent(event)) { Platform::Current()->RecordAction( UserMetricsAction("Media.Controls.ScrubbingBegin")); + is_scrubbing_ = true; GetMediaControls().BeginScrubbing(MediaControlsImpl::IsTouchEvent(&event)); } else if (EndScrubbingEvent(event)) { Platform::Current()->RecordAction( UserMetricsAction("Media.Controls.ScrubbingEnd")); + is_scrubbing_ = false; GetMediaControls().EndScrubbing(); } @@ -163,6 +176,58 @@ event, GetLayoutObject()); } +void MediaControlTimelineElement::OnMediaPlaying() { + if (!is_live_) + return; + + if (render_timeline_timer_.IsRunning()) + render_timeline_timer_.Stop(); +} + +void MediaControlTimelineElement::OnMediaStoppedPlaying() { + if (!is_live_ || is_scrubbing_ || !live_anchor_time_) + return; + + render_timeline_timer_.Start( + FROM_HERE, kRenderTimelineInterval, + WTF::BindRepeating(&MediaControlTimelineElement::UpdateLiveTimeline, + WrapWeakPersistent(this))); +} + +void MediaControlTimelineElement::OnProgress() { + MaybeUpdateTimelineInterval(); + RenderBarSegments(); +} + +void MediaControlTimelineElement::UpdateLiveTimeline() { + MaybeUpdateTimelineInterval(); + RenderBarSegments(); +} + +void MediaControlTimelineElement::MaybeUpdateTimelineInterval() { + if (!is_live_ || !MediaElement().seekable()->length() || !live_anchor_time_) + return; + + int last_seekable = MediaElement().seekable()->length() - 1; + double seekable_start = + MediaElement().seekable()->start(last_seekable, ASSERT_NO_EXCEPTION); + double seekable_end = + MediaElement().seekable()->end(last_seekable, ASSERT_NO_EXCEPTION); + double expected_media_time_now = + live_anchor_time_->media_time_ + + (base::TimeTicks::Now() - live_anchor_time_->clock_time_).InSecondsF(); + + // Cap the current live time in seekable range. + if (expected_media_time_now > seekable_end) { + live_anchor_time_->media_time_ = seekable_end; + live_anchor_time_->clock_time_ = base::TimeTicks::Now(); + expected_media_time_now = seekable_end; + } + + SetFloatingPointAttribute(html_names::kMinAttr, seekable_start); + SetFloatingPointAttribute(html_names::kMaxAttr, expected_media_time_now); +} + void MediaControlTimelineElement::RenderBarSegments() { SetupBarSegments(); @@ -174,6 +239,16 @@ // buffered range containing the current play head. TimeRanges* buffered_time_ranges = MediaElement().buffered(); DCHECK(buffered_time_ranges); + + // Calculate |current_time| and |duration| for live media base on the timeline + // value since timeline's minimum value is not necessarily zero. + if (is_live_) { + current_time = + value().ToDouble() - GetFloatingPointAttribute(html_names::kMinAttr); + duration = GetFloatingPointAttribute(html_names::kMaxAttr) - + GetFloatingPointAttribute(html_names::kMinAttr); + } + if (std::isnan(duration) || std::isinf(duration) || !duration || std::isnan(current_time)) { SetBeforeSegmentPosition(MediaControlSliderElement::Position(0, 0));
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h index c40ec8d..f0c62f0 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h
@@ -5,6 +5,9 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_TIMELINE_ELEMENT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_TIMELINE_ELEMENT_H_ +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -28,6 +31,10 @@ void OnMediaKeyboardEvent(Event* event) { DefaultEventHandler(*event); } + void OnMediaPlaying(); + void OnMediaStoppedPlaying(); + void OnProgress(); + void RenderBarSegments(); // Inform the timeline that the Media Controls have been shown or hidden. @@ -40,9 +47,18 @@ const char* GetNameForHistograms() const override; private: + // Struct used to track the current live time. + struct LiveAnchorTime { + base::TimeTicks clock_time_; + double media_time_ = 0; + }; + void DefaultEventHandler(Event&) override; bool KeepEventInNode(const Event&) const override; + void UpdateLiveTimeline(); + void MaybeUpdateTimelineInterval(); + // Checks if we can begin or end a scrubbing event. If the event is a pointer // event then it needs to start and end with valid pointer events. If the // event is a pointer event followed by a touch event then it can only be @@ -55,6 +71,14 @@ bool is_touching_ = false; bool controls_hidden_ = false; + + bool is_scrubbing_ = false; + + bool is_live_ = false; + + absl::optional<LiveAnchorTime> live_anchor_time_; + + base::RepeatingTimer render_timeline_timer_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index a260d500..1b17f93 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -1864,11 +1864,13 @@ void MediaControlsImpl::OnPlaying() { StartHideMediaControlsTimer(); UpdateCSSClassFromState(); + timeline_->OnMediaPlaying(); } void MediaControlsImpl::OnPause() { UpdatePlayState(); UpdateTimeIndicators(); + timeline_->OnMediaStoppedPlaying(); MakeOpaque(); StopHideMediaControlsTimer(); @@ -1993,7 +1995,7 @@ } void MediaControlsImpl::OnLoadingProgress() { - timeline_->RenderBarSegments(); + timeline_->OnProgress(); } void MediaControlsImpl::ComputeWhichControlsFit() { @@ -2193,6 +2195,7 @@ } void MediaControlsImpl::OnWaiting() { + timeline_->OnMediaStoppedPlaying(); UpdateCSSClassFromState(); }
diff --git a/third_party/blink/renderer/modules/mediasource/DEPS b/third_party/blink/renderer/modules/mediasource/DEPS index a7b4b9d..27f0397 100644 --- a/third_party/blink/renderer/modules/mediasource/DEPS +++ b/third_party/blink/renderer/modules/mediasource/DEPS
@@ -1,7 +1,9 @@ include_rules = [ "-third_party/blink/renderer/modules", + "+base/command_line.h", "+media/base/audio_decoder_config.h", "+media/base/logging_override_if_enabled.h", + "+media/base/media_switches.h", "+media/base/mime_util.h", "+media/base/stream_parser.h", "+media/base/stream_parser_buffer.h",
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc index 537a31ce..85679fec 100644 --- a/third_party/blink/renderer/modules/mediasource/media_source.cc +++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -6,10 +6,12 @@ #include <memory> +#include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" #include "media/base/audio_decoder_config.h" #include "media/base/logging_override_if_enabled.h" +#include "media/base/media_switches.h" #include "media/base/mime_util.h" #include "media/base/supported_types.h" #include "media/base/video_decoder_config.h" @@ -553,7 +555,13 @@ // |enforce_codec_specificity| to understand if we are servicing iTS (if true) // versus aSB (if false). If servicing aSB or cT, we'll remove any detected // hevc codec from the codecs we use in the GetSupportsType() query. - if (!enforce_codec_specificity) { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + const bool allow_hevc = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosEnablePlatformEncryptedHevc); +#else + const bool allow_hevc = true; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + if (allow_hevc && !enforce_codec_specificity) { // Remove any detected HEVC codec from the query to GetSupportsType. std::string filtered_codecs; std::vector<std::string> parsed_codec_ids;
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn index 1963b664..304465f 100644 --- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn +++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -10,6 +10,7 @@ blink_modules_sources("webcodecs") { sources = [ + "allow_shared_buffer_source_util.h", "audio_data.cc", "audio_data.h", "audio_data_attachment.cc",
diff --git a/third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h b/third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h new file mode 100644 index 0000000..a0b13e46 --- /dev/null +++ b/third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ALLOW_SHARED_BUFFER_SOURCE_UTIL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ALLOW_SHARED_BUFFER_SOURCE_UTIL_H_ + +#include "base/containers/span.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybufferallowshared_arraybufferviewallowshared.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" + +namespace blink { + +using AllowSharedBufferSource = + V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared; + +// Helper function for turning various DOMArray-like things into a pointer+size. +template <typename T> +base::span<T> AsSpan(const AllowSharedBufferSource* buffer_union) { + switch (buffer_union->GetContentType()) { + case AllowSharedBufferSource::ContentType::kArrayBufferAllowShared: { + auto* buffer = buffer_union->GetAsArrayBufferAllowShared(); + return (buffer && !buffer->IsDetached()) + ? base::span<T>( + reinterpret_cast<T*>(buffer->DataMaybeShared()), + buffer->ByteLength()) + : base::span<T>(); + } + case AllowSharedBufferSource::ContentType::kArrayBufferViewAllowShared: { + auto* buffer = buffer_union->GetAsArrayBufferViewAllowShared().Get(); + return (buffer && !buffer->IsDetached()) + ? base::span<T>( + reinterpret_cast<T*>(buffer->BaseAddressMaybeShared()), + buffer->byteLength()) + : base::span<T>(); + } + } +} + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ALLOW_SHARED_BUFFER_SOURCE_UTIL_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data.cc b/third_party/blink/renderer/modules/webcodecs/audio_data.cc index af193ac..ae702573 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_data.cc
@@ -11,7 +11,6 @@ #include "media/base/sample_format.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_copy_to_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -120,19 +119,22 @@ return; } - DOMArrayPiece source_data(init->data()); - if (total_bytes > source_data.ByteLength()) { + auto data_wrapper = AsSpan<const uint8_t>(init->data()); + if (!data_wrapper.data()) { + exception_state.ThrowTypeError("data is detached."); + return; + } + if (total_bytes > data_wrapper.size()) { exception_state.ThrowTypeError( - String::Format("`data` is too small: needs %u bytes, received %zu.", - total_bytes, source_data.ByteLength())); + String::Format("data is too small: needs %u bytes, received %zu.", + total_bytes, data_wrapper.size())); return; } std::vector<const uint8_t*> wrapped_data; if (media::IsInterleaved(media_format)) { // Interleaved data can directly added. - wrapped_data.push_back( - reinterpret_cast<const uint8_t*>(source_data.Bytes())); + wrapped_data.push_back(data_wrapper.data()); } else { // Planar data needs one pointer per channel. wrapped_data.resize(init->numberOfChannels()); @@ -142,7 +144,7 @@ media::SampleFormatToBytesPerChannel(media_format); const uint8_t* plane_start = - reinterpret_cast<const uint8_t*>(source_data.Bytes()); + reinterpret_cast<const uint8_t*>(data_wrapper.data()); for (unsigned ch = 0; ch < init->numberOfChannels(); ++ch) wrapped_data[ch] = plane_start + ch * plane_size_in_bytes; @@ -290,7 +292,7 @@ return allocation_size; } -void AudioData::copyTo(const V8BufferSource* destination, +void AudioData::copyTo(const AllowSharedBufferSource* destination, AudioDataCopyToOptions* copy_to_options, ExceptionState& exception_state) { if (!data_) { @@ -306,8 +308,13 @@ return; // Validate destination buffer. - DOMArrayPiece buffer(destination); - if (buffer.ByteLength() < static_cast<size_t>(copy_size_in_bytes)) { + auto dest_wrapper = AsSpan<uint8_t>(destination); + if (!dest_wrapper.data()) { + exception_state.ThrowDOMException(DOMExceptionCode::kConstraintError, + "destination is detached."); + return; + } + if (dest_wrapper.size() < static_cast<size_t>(copy_size_in_bytes)) { exception_state.ThrowDOMException(DOMExceptionCode::kConstraintError, "destination is not large enough."); return; @@ -335,7 +342,7 @@ const uint32_t channel = copy_to_options->planeIndex(); uint8_t* data_start = data_->channel_data()[channel] + offset_in_bytes; - memcpy(buffer.Bytes(), data_start, copy_size_in_bytes); + memcpy(dest_wrapper.data(), data_start, copy_size_in_bytes); } void AudioData::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data.h b/third_party/blink/renderer/modules/webcodecs/audio_data.h index 6e3260a..01ee0f5 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data.h +++ b/third_party/blink/renderer/modules/webcodecs/audio_data.h
@@ -10,13 +10,13 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_sample_format.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { - -class ExceptionState; class AudioDataInit; class AudioDataCopyToOptions; +class ExceptionState; class MODULES_EXPORT AudioData final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -45,7 +45,7 @@ int64_t timestamp() const; uint32_t allocationSize(AudioDataCopyToOptions*, ExceptionState&); - void copyTo(const V8BufferSource* destination, + void copyTo(const AllowSharedBufferSource* destination, AudioDataCopyToOptions*, ExceptionState&);
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data.idl b/third_party/blink/renderer/modules/webcodecs/audio_data.idl index fd4b369..17ae2889 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_data.idl
@@ -15,7 +15,7 @@ void close(); [RaisesException] unsigned long allocationSize(AudioDataCopyToOptions options); - [RaisesException] void copyTo([AllowShared] BufferSource destination, + [RaisesException] void copyTo(AllowSharedBufferSource destination, AudioDataCopyToOptions options); readonly attribute AudioSampleFormat format;
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl index 3ba008c..7df6ec56 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl
@@ -10,5 +10,5 @@ required [EnforceRange] unsigned long numberOfFrames; required [EnforceRange] unsigned long numberOfChannels; required [EnforceRange] long long timestamp; // microseconds - required BufferSource data; + required AllowSharedBufferSource data; };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc b/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc index adcbaab..93ead97 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc
@@ -8,11 +8,11 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_copy_to_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -43,7 +43,7 @@ ASSERT_NEAR(data[i], start_value + i * kIncrement, kEpsilon) << "i=" << i; } - V8BufferSource* CreateDefaultData() { + AllowSharedBufferSource* CreateDefaultData() { auto* buffer = DOMArrayBuffer::Create(kChannels * kFrames, sizeof(float)); for (int ch = 0; ch < kChannels; ++ch) { float* plane_start = @@ -52,10 +52,10 @@ plane_start[i] = static_cast<float>((i + ch * kFrames) * kIncrement); } } - return MakeGarbageCollected<V8BufferSource>(buffer); + return MakeGarbageCollected<AllowSharedBufferSource>(buffer); } - AudioDataInit* CreateDefaultAudioDataInit(V8BufferSource* data) { + AudioDataInit* CreateDefaultAudioDataInit(AllowSharedBufferSource* data) { auto* audio_data_init = AudioDataInit::Create(); audio_data_init->setData(data); audio_data_init->setTimestamp(kTimestampInMicroSeconds); @@ -199,8 +199,9 @@ auto* options = CreateCopyToOptions(/*index=*/0, /*offset=*/absl::nullopt, /*count=*/absl::nullopt); - V8BufferSource* small_dest = MakeGarbageCollected<V8BufferSource>( - DOMArrayBuffer::Create(kFrames - 1, sizeof(float))); + AllowSharedBufferSource* small_dest = + MakeGarbageCollected<AllowSharedBufferSource>( + DOMArrayBuffer::Create(kFrames - 1, sizeof(float))); frame->copyTo(small_dest, options, scope.GetExceptionState()); @@ -214,7 +215,8 @@ /*count=*/absl::nullopt); DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(kFrames, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState()); @@ -231,7 +233,8 @@ /*count=*/absl::nullopt); DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(kFrames, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState()); @@ -252,7 +255,8 @@ // |data_copy| is bigger than what we need, and that's ok. DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(kFrames, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState()); @@ -272,7 +276,8 @@ DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(kPartialFrameCount, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState()); @@ -290,7 +295,8 @@ DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(kPartialFrameCount, sizeof(float)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState()); @@ -342,7 +348,8 @@ DOMArrayBuffer* data_copy = DOMArrayBuffer::Create( kPartialFrameCount * kInterleavedChannels, sizeof(uint16_t)); - V8BufferSource* dest = MakeGarbageCollected<V8BufferSource>(data_copy); + AllowSharedBufferSource* dest = + MakeGarbageCollected<AllowSharedBufferSource>(data_copy); // All frames should have been copied. frame->copyTo(dest, options, scope.GetExceptionState());
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc index 57511f68..956a696 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
@@ -16,12 +16,12 @@ #include "media/base/waiting.h" #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_support.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/audio_data.h" #include "third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h" #include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h" @@ -71,10 +71,13 @@ copy->setSampleRate(config.sampleRate()); copy->setNumberOfChannels(config.numberOfChannels()); if (config.hasDescription()) { - DOMArrayPiece buffer(config.description()); - DOMArrayBuffer* buffer_copy = - DOMArrayBuffer::Create(buffer.Data(), buffer.ByteLength()); - copy->setDescription(MakeGarbageCollected<V8BufferSource>(buffer_copy)); + auto desc_wrapper = AsSpan<const uint8_t>(config.description()); + if (!desc_wrapper.empty()) { + DOMArrayBuffer* buffer_copy = + DOMArrayBuffer::Create(desc_wrapper.data(), desc_wrapper.size()); + copy->setDescription( + MakeGarbageCollected<AllowSharedBufferSource>(buffer_copy)); + } } return copy; } @@ -197,10 +200,13 @@ std::vector<uint8_t> extra_data; if (config.hasDescription()) { - DOMArrayPiece buffer(config.description()); - uint8_t* start = static_cast<uint8_t*>(buffer.Data()); - size_t size = buffer.ByteLength(); - extra_data.assign(start, start + size); + // TODO(crbug.com/1179970): This should throw if description is detached. + auto desc_wrapper = AsSpan<const uint8_t>(config.description()); + if (!desc_wrapper.empty()) { + const uint8_t* start = desc_wrapper.data(); + const size_t size = desc_wrapper.size(); + extra_data.assign(start, start + size); + } } media::ChannelLayout channel_layout =
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl b/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl index fc3527f..62f7d7d497d 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl
@@ -19,5 +19,5 @@ // Optional byte data required to initialize audio decoders such as Vorbis // codebooks. - BufferSource description; + AllowSharedBufferSource description; };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc index 0ef02bf..484e866 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -18,13 +18,13 @@ #include "media/base/offloading_audio_encoder.h" #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_support.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_metadata.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" @@ -331,7 +331,7 @@ auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(), codec_desc.value().size()); decoder_config->setDescription( - MakeGarbageCollected<V8BufferSource>(desc_array_buf)); + MakeGarbageCollected<AllowSharedBufferSource>(desc_array_buf)); } metadata->setDecoderConfig(decoder_config); }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc index 8a89165..1110581 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc
@@ -7,20 +7,17 @@ #include <utility> #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { EncodedAudioChunk* EncodedAudioChunk::Create( const EncodedAudioChunkInit* init) { - DOMArrayPiece piece(init->data()); - auto buffer = - piece.ByteLength() - ? media::DecoderBuffer::CopyFrom( - reinterpret_cast<uint8_t*>(piece.Data()), piece.ByteLength()) - : base::MakeRefCounted<media::DecoderBuffer>(0); + auto data_wrapper = AsSpan<const uint8_t>(init->data()); + auto buffer = data_wrapper.empty() + ? base::MakeRefCounted<media::DecoderBuffer>(0) + : media::DecoderBuffer::CopyFrom(data_wrapper.data(), + data_wrapper.size()); // Clamp within bounds of our internal TimeDelta-based duration. See // media/base/timestamp_constants.h @@ -68,21 +65,21 @@ return buffer_->data_size(); } -void EncodedAudioChunk::copyTo(const V8BufferSource* destination, +void EncodedAudioChunk::copyTo(const AllowSharedBufferSource* destination, ExceptionState& exception_state) { // Validate destination buffer. - DOMArrayPiece dest_wrapper(destination); - if (dest_wrapper.IsDetached()) { + auto dest_wrapper = AsSpan<uint8_t>(destination); + if (!dest_wrapper.data()) { exception_state.ThrowTypeError("destination is detached."); return; } - if (dest_wrapper.ByteLength() < buffer_->data_size()) { + if (dest_wrapper.size() < buffer_->data_size()) { exception_state.ThrowTypeError("destination is not large enough."); return; } // Copy data. - memcpy(dest_wrapper.Bytes(), buffer_->data(), buffer_->data_size()); + memcpy(dest_wrapper.data(), buffer_->data(), buffer_->data_size()); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h index 6163977..86c5ce9 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h +++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h
@@ -7,8 +7,8 @@ #include "media/base/decoder_buffer.h" #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -30,7 +30,7 @@ int64_t timestamp() const; uint64_t byteLength() const; absl::optional<uint64_t> duration() const; - void copyTo(const V8BufferSource* destination, + void copyTo(const AllowSharedBufferSource* destination, ExceptionState& exception_state); scoped_refptr<media::DecoderBuffer> buffer() const { return buffer_; }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.idl b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.idl index ba212f77..103dfca6 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.idl
@@ -17,5 +17,5 @@ readonly attribute unsigned long byteLength; readonly attribute unsigned long long? duration; [RaisesException] - void copyTo([AllowShared] BufferSource destination); + void copyTo(AllowSharedBufferSource destination); };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl index c18f89b7..2d92fe05 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl
@@ -8,5 +8,5 @@ required EncodedAudioChunkType type; required [EnforceRange] long long timestamp; // microseconds [EnforceRange] unsigned long long duration; // microseconds - required BufferSource data; + required AllowSharedBufferSource data; };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc index 2535d2c..4bb82cb2 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
@@ -7,20 +7,17 @@ #include <utility> #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { EncodedVideoChunk* EncodedVideoChunk::Create(EncodedVideoChunkInit* init) { - DOMArrayPiece piece(init->data()); - auto buffer = - piece.ByteLength() - ? media::DecoderBuffer::CopyFrom( - reinterpret_cast<uint8_t*>(piece.Data()), piece.ByteLength()) - : base::MakeRefCounted<media::DecoderBuffer>(0); + auto data_wrapper = AsSpan<const uint8_t>(init->data()); + auto buffer = data_wrapper.empty() + ? base::MakeRefCounted<media::DecoderBuffer>(0) + : media::DecoderBuffer::CopyFrom(data_wrapper.data(), + data_wrapper.size()); // Clamp within bounds of our internal TimeDelta-based duration. See // media/base/timestamp_constants.h @@ -68,21 +65,21 @@ return buffer_->data_size(); } -void EncodedVideoChunk::copyTo(const V8BufferSource* destination, +void EncodedVideoChunk::copyTo(const AllowSharedBufferSource* destination, ExceptionState& exception_state) { // Validate destination buffer. - DOMArrayPiece dest_wrapper(destination); - if (dest_wrapper.IsDetached()) { + auto dest_wrapper = AsSpan<uint8_t>(destination); + if (!dest_wrapper.data()) { exception_state.ThrowTypeError("destination is detached."); return; } - if (dest_wrapper.ByteLength() < buffer_->data_size()) { + if (dest_wrapper.size() < buffer_->data_size()) { exception_state.ThrowTypeError("destination is not large enough."); return; } // Copy data. - memcpy(dest_wrapper.Bytes(), buffer_->data(), buffer_->data_size()); + memcpy(dest_wrapper.data(), buffer_->data(), buffer_->data_size()); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h index 3ca475c2..b89ccb62 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h
@@ -8,12 +8,11 @@ #include "media/base/decoder_buffer.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { - class EncodedVideoChunkInit; class ExceptionState; @@ -30,7 +29,7 @@ int64_t timestamp() const; absl::optional<uint64_t> duration() const; uint64_t byteLength() const; - void copyTo(const V8BufferSource* destination, + void copyTo(const AllowSharedBufferSource* destination, ExceptionState& exception_state); scoped_refptr<media::DecoderBuffer> buffer() const { return buffer_; }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl index 2456deeb..353690d 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl
@@ -19,5 +19,5 @@ readonly attribute unsigned long byteLength; [RaisesException] - void copyTo([AllowShared] BufferSource destination); + void copyTo(AllowSharedBufferSource destination); };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl index 9c86828..03127ed8 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl
@@ -8,5 +8,5 @@ required EncodedVideoChunkType type; required [EnforceRange] long long timestamp; // microseconds [EnforceRange] unsigned long long duration; // microseconds - required BufferSource data; + required AllowSharedBufferSource data; };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc index 84612680..78a183c 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc
@@ -6,8 +6,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -16,8 +16,8 @@ class EncodedVideoChunkTest : public testing::Test { public: - V8BufferSource* StringToBuffer(std::string data) { - return MakeGarbageCollected<V8BufferSource>( + AllowSharedBufferSource* StringToBuffer(std::string data) { + return MakeGarbageCollected<AllowSharedBufferSource>( DOMArrayBuffer::Create(data.data(), data.size())); }
diff --git a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc index 671ca91..3ec5d81 100644 --- a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc +++ b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h" @@ -25,6 +24,7 @@ #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.pb.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame.h" #include "third_party/blink/renderer/platform/audio/audio_bus.h" @@ -58,7 +58,8 @@ config->setCodec(proto.codec().c_str()); DOMArrayBuffer* data_copy = DOMArrayBuffer::Create( proto.description().data(), proto.description().size()); - config->setDescription(MakeGarbageCollected<V8BufferSource>(data_copy)); + config->setDescription( + MakeGarbageCollected<AllowSharedBufferSource>(data_copy)); return config; } @@ -71,7 +72,8 @@ DOMArrayBuffer* data_copy = DOMArrayBuffer::Create( proto.description().data(), proto.description().size()); - config->setDescription(MakeGarbageCollected<V8BufferSource>(data_copy)); + config->setDescription( + MakeGarbageCollected<AllowSharedBufferSource>(data_copy)); return config; } @@ -167,7 +169,7 @@ EncodedVideoChunk* MakeEncodedVideoChunk( const wc_fuzzer::EncodedVideoChunk& proto) { - auto* data = MakeGarbageCollected<V8BufferSource>( + auto* data = MakeGarbageCollected<AllowSharedBufferSource>( DOMArrayBuffer::Create(proto.data().data(), proto.data().size())); auto* init = EncodedVideoChunkInit::Create(); @@ -183,7 +185,7 @@ EncodedAudioChunk* MakeEncodedAudioChunk( const wc_fuzzer::EncodedAudioChunk& proto) { - auto* data = MakeGarbageCollected<V8BufferSource>( + auto* data = MakeGarbageCollected<AllowSharedBufferSource>( DOMArrayBuffer::Create(proto.data().data(), proto.data().size())); auto* init = EncodedAudioChunkInit::Create(); @@ -277,7 +279,7 @@ init->setNumberOfChannels(proto.channels().size()); init->setSampleRate(proto.sample_rate()); init->setFormat(format); - init->setData(MakeGarbageCollected<V8BufferSource>(buffer)); + init->setData(MakeGarbageCollected<AllowSharedBufferSource>(buffer)); return AudioData::Create(init, IGNORE_EXCEPTION_FOR_TESTING); }
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc index 3e81a58..e4b11dd 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
@@ -21,12 +21,13 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_color_space_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_support.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h" #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h" #include "third_party/blink/renderer/modules/webcodecs/gpu_factories_retriever.h" @@ -164,15 +165,21 @@ return true; } -VideoDecoderConfig* CopyConfig(const VideoDecoderConfig& config) { +VideoDecoderConfig* CopyConfig(const VideoDecoderConfig& config, + ExceptionState& exception_state) { VideoDecoderConfig* copy = VideoDecoderConfig::Create(); copy->setCodec(config.codec()); if (config.hasDescription()) { - DOMArrayPiece buffer(config.description()); + auto desc_wrapper = AsSpan<const uint8_t>(config.description()); + if (!desc_wrapper.data()) { + exception_state.ThrowTypeError("description is detached."); + return nullptr; + } DOMArrayBuffer* buffer_copy = - DOMArrayBuffer::Create(buffer.Data(), buffer.ByteLength()); - copy->setDescription(MakeGarbageCollected<V8BufferSource>(buffer_copy)); + DOMArrayBuffer::Create(desc_wrapper.data(), desc_wrapper.size()); + copy->setDescription( + MakeGarbageCollected<AllowSharedBufferSource>(buffer_copy)); } if (config.hasCodedWidth()) @@ -330,7 +337,12 @@ // Accept all supported configs if we are not requiring hardware only. VideoDecoderSupport* support = VideoDecoderSupport::Create(); support->setSupported(media::IsSupportedVideoType(video_type)); - support->setConfig(CopyConfig(*config)); + + auto* config_copy = CopyConfig(*config, exception_state); + if (exception_state.HadException()) + return ScriptPromise(); + + support->setConfig(config_copy); return ScriptPromise::Cast(script_state, ToV8(support, script_state)); } @@ -357,10 +369,14 @@ return ScriptPromise(); } + auto* config_copy = CopyConfig(*config, exception_state); + if (exception_state.HadException()) + return ScriptPromise(); + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); VideoDecoderSupport* support = VideoDecoderSupport::Create(); - support->setConfig(CopyConfig(*config)); + support->setConfig(config_copy); RetrieveGpuFactoriesWithKnownDecoderSupport(CrossThreadBindOnce( &DecoderSupport_OnKnown, WrapCrossThreadPersistent(support), @@ -398,13 +414,15 @@ if (!IsValidConfig(config, video_type, out_console_message)) return CodecConfigEval::kInvalid; - // TODO(sandersd): Can we allow shared ArrayBuffers? std::vector<uint8_t> extra_data; if (config.hasDescription()) { - DOMArrayPiece buffer(config.description()); - uint8_t* start = static_cast<uint8_t*>(buffer.Data()); - size_t size = buffer.ByteLength(); - extra_data.assign(start, start + size); + // TODO(crbug.com/1179970): This should throw if description is detached. + auto desc_wrapper = AsSpan<const uint8_t>(config.description()); + if (!desc_wrapper.empty()) { + const uint8_t* start = desc_wrapper.data(); + const size_t size = desc_wrapper.size(); + extra_data.assign(start, start + size); + } } #if BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl b/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl index 3464290..9b6e2f5 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl
@@ -15,7 +15,7 @@ // avcC, vpcC, or etc. // TODO(sandersd): Define what happens if the parsed description differs from // the metadata below. - BufferSource description; + AllowSharedBufferSource description; // Hint about the encoded size of the content. [EnforceRange] unsigned long codedWidth;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc index 30272fe..0dae13b 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -37,7 +37,6 @@ #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_avc_encoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_color_space_init.h" @@ -50,6 +49,7 @@ #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/writable_stream.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h" #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h" #include "third_party/blink/renderer/modules/webcodecs/gpu_factories_retriever.h" @@ -836,7 +836,7 @@ auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(), codec_desc.value().size()); decoder_config->setDescription( - MakeGarbageCollected<V8BufferSource>(desc_array_buf)); + MakeGarbageCollected<AllowSharedBufferSource>(desc_array_buf)); } metadata->setDecoderConfig(decoder_config); }
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index 8a94630..c0a2671b 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -21,7 +21,6 @@ #include "media/base/video_util.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybufferallowshared_arraybufferviewallowshared.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_plane_layout.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_union_cssimagevalue_htmlcanvaselement_htmlimageelement_htmlvideoelement_imagebitmap_offscreencanvas_svgimageelement_videoframe.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_color_space_init.h" @@ -194,34 +193,6 @@ } } -// Helper function for turning various DOMArray-like things into a pointer+size. -template <typename T> -base::span<T> AsSpan( - const V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared* - buffer_union) { - switch (buffer_union->GetContentType()) { - case V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared:: - ContentType::kArrayBufferAllowShared: { - auto* buffer = buffer_union->GetAsArrayBufferAllowShared(); - return (buffer && !buffer->IsDetached()) - ? base::span<T>( - reinterpret_cast<T*>(buffer->DataMaybeShared()), - buffer->ByteLength()) - : base::span<T>(); - } - case V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared:: - ContentType::kArrayBufferViewAllowShared: { - auto* buffer = buffer_union->GetAsArrayBufferViewAllowShared().Get(); - return (buffer && !buffer->IsDetached()) - ? base::span<T>( - reinterpret_cast<T*>(buffer->BaseAddressMaybeShared()), - buffer->byteLength()) - : base::span<T>(); - } - } - return base::span<T>(); -} - } // namespace VideoFrame::VideoFrame(scoped_refptr<media::VideoFrame> frame, @@ -438,11 +409,10 @@ ExecutionContext::From(script_state))); } -VideoFrame* VideoFrame::Create( - ScriptState* script_state, - const V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared* data, - const VideoFrameBufferInit* init, - ExceptionState& exception_state) { +VideoFrame* VideoFrame::Create(ScriptState* script_state, + const AllowSharedBufferSource* data, + const VideoFrameBufferInit* init, + ExceptionState& exception_state) { ExecutionContext* execution_context = ExecutionContext::From(script_state); // Handle format; the string was validated by the V8 binding. @@ -743,12 +713,10 @@ return layout.min_buffer_size; } -ScriptPromise VideoFrame::copyTo( - ScriptState* script_state, - const V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared* - destination, - VideoFrameCopyToOptions* options, - ExceptionState& exception_state) { +ScriptPromise VideoFrame::copyTo(ScriptState* script_state, + const AllowSharedBufferSource* destination, + VideoFrameCopyToOptions* options, + ExceptionState& exception_state) { auto local_frame = handle_->frame(); if (!local_frame) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h index 04dccc65..0debcc7 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.h +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" @@ -40,7 +41,6 @@ class VideoFrameBufferInit; class VideoFrameCopyToOptions; class VideoFrameInit; -class V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared; class MODULES_EXPORT VideoFrame final : public ScriptWrappable, public CanvasImageSource, @@ -66,11 +66,10 @@ const V8CanvasImageSource* source, const VideoFrameInit* init, ExceptionState& exception_state); - static VideoFrame* Create( - ScriptState*, - const V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared*, - const VideoFrameBufferInit*, - ExceptionState&); + static VideoFrame* Create(ScriptState*, + const AllowSharedBufferSource*, + const VideoFrameBufferInit*, + ExceptionState&); absl::optional<V8VideoPixelFormat> format() const; @@ -90,12 +89,10 @@ uint32_t allocationSize(VideoFrameCopyToOptions* options, ExceptionState&); - ScriptPromise copyTo( - ScriptState* script_state, - const V8UnionArrayBufferAllowSharedOrArrayBufferViewAllowShared* - destination, - VideoFrameCopyToOptions* options, - ExceptionState& exception_state); + ScriptPromise copyTo(ScriptState* script_state, + const AllowSharedBufferSource* destination, + VideoFrameCopyToOptions* options, + ExceptionState& exception_state); // Invalidates |handle_|, releasing underlying media::VideoFrame references. // This effectively "destroys" all frames sharing the same Handle.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.idl b/third_party/blink/renderer/modules/webcodecs/video_frame.idl index 4d1f464..98d0c70 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.idl
@@ -4,6 +4,8 @@ // https://github.com/WICG/web-codecs +typedef ([AllowShared] ArrayBuffer or [AllowShared] ArrayBufferView) AllowSharedBufferSource; + [ Exposed=(Window,DedicatedWorker), Serializable, @@ -13,9 +15,7 @@ constructor(CanvasImageSource source, optional VideoFrameInit init = {}); [CallWith=ScriptState, RaisesException] - constructor( - ([AllowShared] ArrayBuffer or [AllowShared] ArrayBufferView) data, - VideoFrameBufferInit init); + constructor(AllowSharedBufferSource data, VideoFrameBufferInit init); readonly attribute VideoPixelFormat? format; @@ -51,7 +51,7 @@ // The format of the data is the same as this frame's |format|. [CallWith=ScriptState, RaisesException] Promise<sequence<PlaneLayout>> copyTo( - ([AllowShared] ArrayBuffer or [AllowShared] ArrayBufferView) destination, + AllowSharedBufferSource destination, optional VideoFrameCopyToOptions options = {}); // Creates a copy of this VideoFrame, which needs to be independently closed.
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc index ac68f09..10e4675 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -726,13 +726,19 @@ return false; } + // TODO(crbug.com/1197369): config color space based on image scoped_refptr<WebGPUMailboxTexture> mailbox_texture = WebGPUMailboxTexture::FromStaticBitmapImage( GetDawnControlClient(), device_->GetHandle(), static_cast<WGPUTextureUsage>(WGPUTextureUsage_CopyDst | WGPUTextureUsage_CopySrc | WGPUTextureUsage_Sampled), - image); + image, CanvasColorSpace::kSRGB, image_info.colorType()); + + // Fail to associate staticBitmapImage to dawn resource. + if (!mailbox_texture) { + return false; + } WGPUTexture src_texture = mailbox_texture->GetTexture(); DCHECK(src_texture != nullptr);
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 40923ae..8a3e97c 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1891,6 +1891,8 @@ "testing/layer_tree_host_embedder.h", "testing/message_loop_for_mojo.h", "testing/mock_context_lifecycle_notifier.h", + "testing/noop_web_url_loader.cc", + "testing/noop_web_url_loader.h", "testing/paint_property_test_helpers.h", "testing/paint_test_configurations.h", "testing/picture_matchers.cc",
diff --git a/third_party/blink/renderer/platform/DEPS b/third_party/blink/renderer/platform/DEPS index efde8dfc..5076d74 100644 --- a/third_party/blink/renderer/platform/DEPS +++ b/third_party/blink/renderer/platform/DEPS
@@ -30,12 +30,14 @@ "+base/metrics/histogram_macros.h", "+base/metrics/histogram_samples.h", "+base/metrics/sparse_histogram.h", + "+base/no_destructor.h", "+base/numerics/checked_math.h", "+base/numerics/safe_conversions.h", "+base/process/memory.h", "+base/rand_util.h", "+base/run_loop.h", "+base/strings/pattern.h", + "+base/strings/string_split.h", "+base/strings/string_util.h", "+base/strings/stringprintf.h", "+base/synchronization/waitable_event.h",
diff --git a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc index 01cb98a..df8a6f50 100644 --- a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc +++ b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
@@ -49,7 +49,8 @@ HRTFDatabaseLoader::CreateAndLoadAsynchronouslyIfNecessary(float sample_rate) { DCHECK(IsMainThread()); - scoped_refptr<HRTFDatabaseLoader> loader = GetLoaderMap().at(sample_rate); + scoped_refptr<HRTFDatabaseLoader> loader = + GetLoaderMap().DeprecatedAtOrEmptyValue(sample_rate); if (loader) { DCHECK_EQ(sample_rate, loader->DatabaseSampleRate()); return loader;
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc index 00e0cdb8..0281384eb 100644 --- a/third_party/blink/renderer/platform/fonts/font.cc +++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -535,7 +535,7 @@ void Font::WillUseFontData(const String& text) const { const FontFamily& family = GetFontDescription().Family(); if (font_fallback_list_ && font_fallback_list_->GetFontSelector() && - !family.FamilyIsEmpty()) + !family.Family().IsEmpty()) font_fallback_list_->GetFontSelector()->WillUseFontData( GetFontDescription(), family.Family(), text); }
diff --git a/third_party/blink/renderer/platform/fonts/font_description.cc b/third_party/blink/renderer/platform/fonts/font_description.cc index 911450a..98f86c9 100644 --- a/third_party/blink/renderer/platform/fonts/font_description.cc +++ b/third_party/blink/renderer/platform/fonts/font_description.cc
@@ -388,7 +388,7 @@ unsigned hash = StyleHashWithoutFamilyList(); for (const FontFamily* family = &family_list_; family; family = family->Next()) { - if (!family->Family().length()) + if (family->Family().IsEmpty()) continue; WTF::AddIntToHash(hash, WTF::AtomicStringHash::GetHash(family->Family())); }
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc index 41492a0..5b836e5 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc +++ b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
@@ -162,7 +162,7 @@ for (; curr_family; curr_family = curr_family->Next()) { family_index_++; - if (curr_family->Family().length()) { + if (!curr_family->Family().IsEmpty()) { scoped_refptr<FontData> result; if (GetFontSelector()) { result = GetFontSelector()->GetFontData(font_description, @@ -214,7 +214,7 @@ FallbackListCompositeKey key(font_description); const FontFamily* current_family = &font_description.Family(); while (current_family) { - if (current_family->Family().length()) { + if (!current_family->Family().IsEmpty()) { FontFaceCreationParams params( AdjustFamilyNameToAvoidUnsupportedFonts(current_family->Family())); scoped_refptr<FontData> result;
diff --git a/third_party/blink/renderer/platform/fonts/font_family.h b/third_party/blink/renderer/platform/fonts/font_family.h index 947b2952..fa69d30 100644 --- a/third_party/blink/renderer/platform/fonts/font_family.h +++ b/third_party/blink/renderer/platform/fonts/font_family.h
@@ -44,7 +44,6 @@ void SetFamily(const AtomicString& family) { family_ = family; } const AtomicString& Family() const { return family_; } - bool FamilyIsEmpty() const { return family_.IsEmpty(); } const FontFamily* Next() const;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc index ac078f6..470c2d8f 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
@@ -39,10 +39,10 @@ LayerTreeFlags flags, const cc::Layer& layer, JSONObject& json) const { -#if DCHECK_IS_ON() +#if EXPENSIVE_DCHECKS_ARE_ON() if (flags & kLayerTreeIncludesDebugInfo) json.SetValue("paintChunkContents", paint_chunk_debug_data_->Clone()); -#endif +#endif // EXPENSIVE_DCHECKS_ARE_ON() if ((flags & (kLayerTreeIncludesInvalidations | kLayerTreeIncludesDetailedInvalidations)) && @@ -70,7 +70,7 @@ else id_ = absl::nullopt; -#if DCHECK_IS_ON() +#if EXPENSIVE_DCHECKS_ARE_ON() paint_chunk_debug_data_ = std::make_unique<JSONArray>(); for (auto it = paint_chunks.begin(); it != paint_chunks.end(); ++it) { auto json = std::make_unique<JSONObject>(); @@ -80,7 +80,7 @@ DisplayItemList::kCompact)); paint_chunk_debug_data_->PushObject(std::move(json)); } -#endif +#endif // EXPENSIVE_DCHECKS_ARE_ON() // The raster invalidator will only handle invalidations within a cc::Layer so // we need this invalidation if the layer's properties have changed.
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h index 05dfcdf..8f8964b 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h +++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
@@ -75,9 +75,9 @@ PropertyTreeState layer_state_; String debug_name_; -#if DCHECK_IS_ON() +#if EXPENSIVE_DCHECKS_ARE_ON() std::unique_ptr<JSONArray> paint_chunk_debug_data_; -#endif +#endif // EXPENSIVE_DCHECKS_ARE_ON() }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index d5b91eb5..0d01b1f 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -62,7 +62,7 @@ class MockScrollCallbacks : public CompositorScrollCallbacks { public: - MOCK_METHOD3(DidScroll, + MOCK_METHOD3(DidCompositorScroll, void(CompositorElementId, const gfx::ScrollOffset&, const absl::optional<cc::TargetSnapAreaElementIds>&)); @@ -1115,9 +1115,10 @@ EXPECT_EQ(scroll_layer->scroll_tree_index(), scroll_node.id); absl::optional<cc::TargetSnapAreaElementIds> targets; - EXPECT_CALL(ScrollCallbacks(), DidScroll(scroll_node.element_id, - gfx::ScrollOffset(1, 2), targets)); - GetPropertyTrees().scroll_tree.NotifyDidScroll( + EXPECT_CALL(ScrollCallbacks(), + DidCompositorScroll(scroll_node.element_id, + gfx::ScrollOffset(1, 2), targets)); + GetPropertyTrees().scroll_tree.NotifyDidCompositorScroll( scroll_node.element_id, gfx::ScrollOffset(1, 2), targets); EXPECT_CALL(ScrollCallbacks(),
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc index afcac98..5a1fec4f 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
@@ -403,11 +403,12 @@ *reinterpret_cast<const volatile gpu::Mailbox*>(mailbox_bytes)); }))); + SkImageInfo image_info = bitmap->PaintImageForCurrentFrame().GetSkImageInfo(); scoped_refptr<WebGPUMailboxTexture> mailbox_texture = WebGPUMailboxTexture::FromStaticBitmapImage( - dawn_control_client_, fake_device_, WGPUTextureUsage_CopySrc, bitmap); + dawn_control_client_, fake_device_, WGPUTextureUsage_CopySrc, bitmap, + CanvasColorSpace::kSRGB, image_info.colorType()); - EXPECT_TRUE(mailbox == bitmap->GetMailboxHolder().mailbox); EXPECT_NE(mailbox_texture->GetTexture(), nullptr); EXPECT_EQ(mailbox_texture->GetTextureIdForTest(), 1u); EXPECT_EQ(mailbox_texture->GetTextureGenerationForTest(), 1u);
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc index cda6afa..ea25005 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
@@ -6,6 +6,7 @@ #include "gpu/command_buffer/client/webgpu_interface.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource.h" +#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" namespace blink { @@ -15,16 +16,56 @@ scoped_refptr<DawnControlClientHolder> dawn_control_client, WGPUDevice device, WGPUTextureUsage usage, - scoped_refptr<StaticBitmapImage> image) { + scoped_refptr<StaticBitmapImage> image, + CanvasColorSpace color_space, + SkColorType color_type) { DCHECK(image->IsTextureBacked()); - auto finished_access_callback = - WTF::Bind(&StaticBitmapImage::UpdateSyncToken, WTF::RetainedRef(image)); - return base::AdoptRef(new WebGPUMailboxTexture( - std::move(dawn_control_client), device, usage, - image->GetMailboxHolder().mailbox, image->GetMailboxHolder().sync_token, - std::move(finished_access_callback), - /*recyclable_canvas_resource=*/nullptr)); + // TODO(crbugs.com/1217160) Mac uses IOSurface in SharedImageBackingGLImage + // which can be shared to dawn directly aftter passthrough command buffer + // supported on mac os. + // We should wrap the StaticBitmapImage directly for mac when passthrough + // command buffer has been supported. + + // If the context is lost, the resource provider would be invalid. + auto context_provider_wrapper = SharedGpuContext::ContextProviderWrapper(); + if (!context_provider_wrapper || + context_provider_wrapper->ContextProvider()->IsContextLost()) + return nullptr; + + // Keep the same config as source image. + const CanvasResourceParams params( + color_space, color_type, + image->IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); + + // Get a recyclable resource for producing WebGPU-compatible shared images. + std::unique_ptr<RecyclableCanvasResource> recyclable_canvas_resource = + dawn_control_client->GetOrCreateCanvasResource(image->Size(), params, + image->IsOriginTopLeft()); + + // Fallback to unstable intermediate resource copy path. + if (!recyclable_canvas_resource) { + auto finished_access_callback = + WTF::Bind(&StaticBitmapImage::UpdateSyncToken, WTF::RetainedRef(image)); + + return base::AdoptRef(new WebGPUMailboxTexture( + std::move(dawn_control_client), device, usage, + image->GetMailboxHolder().mailbox, image->GetMailboxHolder().sync_token, + std::move(finished_access_callback), + /*recyclable_canvas_resource=*/nullptr)); + } + + CanvasResourceProvider* resource_provider = + recyclable_canvas_resource->resource_provider(); + DCHECK(resource_provider); + + if (!image->CopyToResourceProvider(resource_provider)) { + return nullptr; + } + + return WebGPUMailboxTexture::FromCanvasResource( + dawn_control_client, device, usage, + std::move(recyclable_canvas_resource)); } // static
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h index d99bde1..b4270068 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h
@@ -28,7 +28,9 @@ scoped_refptr<DawnControlClientHolder> dawn_control_client, WGPUDevice device, WGPUTextureUsage usage, - scoped_refptr<StaticBitmapImage> image); + scoped_refptr<StaticBitmapImage> image, + CanvasColorSpace color_space, + SkColorType color_type); static scoped_refptr<WebGPUMailboxTexture> FromCanvasResource( scoped_refptr<DawnControlClientHolder> dawn_control_client,
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc index 5314fc6..7091f84 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -277,6 +277,7 @@ bool GraphicsLayer::PaintRecursively( GraphicsContext& context, Vector<PreCompositedLayerInfo>& pre_composited_layers, + PaintController::CycleScope& cycle_scope, PaintBenchmarkMode benchmark_mode) { bool repainted = false; ForAllGraphicsLayers( @@ -286,7 +287,7 @@ layer.ClearPaintStateRecursively(); return false; } - layer.Paint(pre_composited_layers, benchmark_mode); + layer.Paint(pre_composited_layers, benchmark_mode, &cycle_scope); repainted |= layer.repainted_; return true; }, @@ -313,11 +314,14 @@ void GraphicsLayer::PaintForTesting(const IntRect& interest_rect) { Vector<PreCompositedLayerInfo> pre_composited_layers; - Paint(pre_composited_layers, PaintBenchmarkMode::kNormal, &interest_rect); + PaintController::CycleScope cycle_scope; + Paint(pre_composited_layers, PaintBenchmarkMode::kNormal, &cycle_scope, + &interest_rect); } void GraphicsLayer::Paint(Vector<PreCompositedLayerInfo>& pre_composited_layers, PaintBenchmarkMode benchmark_mode, + PaintController::CycleScope* cycle_scope, const IntRect* interest_rect) { repainted_ = false; @@ -351,6 +355,8 @@ } auto& paint_controller = GetPaintController(); + if (cycle_scope) + cycle_scope->AddController(paint_controller); absl::optional<PaintChunkSubset> previous_chunks; if (ShouldCreateLayersAfterPaint()) @@ -365,7 +371,7 @@ paint_controller.ClientCacheIsValid(*this) && previous_interest_rect_ == new_interest_rect; if (!cached) { - paint_controller.ReserveCapacity(); + paint_controller.MarkClientForValidation(*this); GraphicsContext context(paint_controller); DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName(); paint_controller.UpdateCurrentPaintChunkProperties( @@ -377,9 +383,6 @@ previous_interest_rect_ = new_interest_rect; client_.PaintContents(this, context, painting_phase_, new_interest_rect); paint_controller.CommitNewDisplayItems(); - // TODO(wangxianzhu): Remove this and friend class in DisplayItemClient - // when unifying PaintController. - Validate(); DVLOG(2) << "Painted GraphicsLayer: " << DebugName() << " paintable region: " << PaintableRegion().ToString(); }
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h index 694ae97..5ddf1add 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_layer.h +++ b/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -173,6 +173,7 @@ // Returns true if any layer is repainted. bool PaintRecursively(GraphicsContext&, Vector<PreCompositedLayerInfo>&, + PaintController::CycleScope& cycle_scope, PaintBenchmarkMode = PaintBenchmarkMode::kNormal); PaintController& GetPaintController() const; @@ -239,6 +240,7 @@ void ClearPaintStateRecursively(); void Paint(Vector<PreCompositedLayerInfo>&, PaintBenchmarkMode, + PaintController::CycleScope*, const IntRect* interest_rect = nullptr); // Adds a child without calling NotifyChildListChange(), so that adding
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc b/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc index 3856e9a..af4b9ca7 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
@@ -100,12 +100,14 @@ GraphicsContext context(GetPaintController()); client.SetNeedsRepaint(true); Vector<PreCompositedLayerInfo> pre_composited_layers; - EXPECT_TRUE(root.PaintRecursively(context, pre_composited_layers)); + { + PaintController::CycleScope cycle_scope; + EXPECT_TRUE( + root.PaintRecursively(context, pre_composited_layers, cycle_scope)); + } EXPECT_TRUE(root.Repainted()); - root.GetPaintController().FinishCycle(); EXPECT_FALSE(layer1.Repainted()); EXPECT_TRUE(layer2.Repainted()); - layer2.GetPaintController().FinishCycle(); HitTestData hit_test_data; hit_test_data.touch_action_rects = {{IntRect(1, 2, 3, 4)}}; @@ -129,7 +131,11 @@ // Paint again with nothing changed. client.SetNeedsRepaint(false); pre_composited_layers.clear(); - EXPECT_FALSE(root.PaintRecursively(context, pre_composited_layers)); + { + PaintController::CycleScope cycle_scope; + EXPECT_FALSE( + root.PaintRecursively(context, pre_composited_layers, cycle_scope)); + } EXPECT_FALSE(root.Repainted()); EXPECT_FALSE(layer1.Repainted()); EXPECT_FALSE(layer2.Repainted()); @@ -138,10 +144,13 @@ // Paint again with layer1 drawing content. layer1.SetDrawsContent(true); pre_composited_layers.clear(); - EXPECT_TRUE(root.PaintRecursively(context, pre_composited_layers)); + { + PaintController::CycleScope cycle_scope; + EXPECT_TRUE( + root.PaintRecursively(context, pre_composited_layers, cycle_scope)); + } EXPECT_FALSE(root.Repainted()); EXPECT_TRUE(layer1.Repainted()); - layer1.GetPaintController().FinishCycle(); EXPECT_FALSE(layer2.Repainted()); EXPECT_EQ(3u, pre_composited_layers.size());
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_client.h b/third_party/blink/renderer/platform/graphics/paint/display_item_client.h index 24fe02f4..9023fe2 100644 --- a/third_party/blink/renderer/platform/graphics/paint/display_item_client.h +++ b/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
@@ -27,7 +27,10 @@ // dereferenced unless we can make sure the client is still alive. class PLATFORM_EXPORT DisplayItemClient { public: - DisplayItemClient() { + DisplayItemClient() + : paint_invalidation_reason_( + static_cast<uint8_t>(PaintInvalidationReason::kJustCreated)), + marked_for_validation_(0) { #if DCHECK_IS_ON() OnCreate(); #endif @@ -73,30 +76,32 @@ // However, kUncacheable overwrites any other reason. reason != PaintInvalidationReason::kUncacheable) return; - paint_invalidation_reason_ = reason; + paint_invalidation_reason_ = static_cast<uint8_t>(reason); } PaintInvalidationReason GetPaintInvalidationReason() const { - return paint_invalidation_reason_; + return static_cast<PaintInvalidationReason>(paint_invalidation_reason_); } // A client is considered "just created" if its display items have never been // validated by any PaintController since it's created. bool IsJustCreated() const { - return paint_invalidation_reason_ == PaintInvalidationReason::kJustCreated; + return GetPaintInvalidationReason() == + PaintInvalidationReason::kJustCreated; } // Whether the client is cacheable. The uncacheable status is set when the // client produces any display items that skipped caching of any // PaintController. bool IsCacheable() const { - return paint_invalidation_reason_ != PaintInvalidationReason::kUncacheable; + return GetPaintInvalidationReason() != + PaintInvalidationReason::kUncacheable; } // True if the client's display items are cached in PaintControllers without // needing to update. bool IsValid() const { - return paint_invalidation_reason_ == PaintInvalidationReason::kNone; + return GetPaintInvalidationReason() == PaintInvalidationReason::kNone; } String ToString() const; @@ -104,11 +109,15 @@ private: friend class FakeDisplayItemClient; friend class ObjectPaintInvalidatorTest; + friend class PaintChunker; friend class PaintController; - friend class GraphicsLayer; // Temporary for Validate(). + void MarkForValidation() const { marked_for_validation_ = 1; } + bool IsMarkedForValidation() const { return marked_for_validation_; } void Validate() const { - paint_invalidation_reason_ = PaintInvalidationReason::kNone; + paint_invalidation_reason_ = + static_cast<uint8_t>(PaintInvalidationReason::kNone); + marked_for_validation_ = 0; } #if DCHECK_IS_ON() @@ -116,8 +125,8 @@ void OnDestroy(); #endif - mutable PaintInvalidationReason paint_invalidation_reason_ = - PaintInvalidationReason::kJustCreated; + mutable uint8_t paint_invalidation_reason_ : 7; + mutable uint8_t marked_for_validation_ : 1; }; inline bool operator==(const DisplayItemClient& client1,
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc index 0a9925b6e..f07e50d 100644 --- a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
@@ -22,18 +22,7 @@ protected: DisplayItemRasterInvalidatorTest() = default; - Vector<RasterInvalidationInfo> GenerateRasterInvalidations() { - GetPaintController().CommitNewDisplayItems(); - invalidator_.Generate( - base::DoNothing(), - PaintChunkSubset(GetPaintController().GetPaintArtifactShared()), - // The layer bounds are big enough not to clip display item raster - // invalidation rects in the tests. - FloatPoint(), IntSize(20000, 20000), PropertyTreeState::Root()); - GetPaintController().FinishCycle(); - for (auto& chunk : GetPaintController().PaintChunks()) - chunk.properties.ClearChangedTo(PropertyTreeState::Root()); - + Vector<RasterInvalidationInfo> GetRasterInvalidations() { if (invalidator_.GetTracking()) return invalidator_.GetTracking()->Invalidations(); return Vector<RasterInvalidationInfo>(); @@ -44,6 +33,29 @@ RasterInvalidator invalidator_; }; +class RasterInvalidationCycleScope : public PaintController::CycleScope { + public: + RasterInvalidationCycleScope(PaintController& controller, + RasterInvalidator& invalidator) + : PaintController::CycleScope(controller), invalidator_(invalidator) {} + ~RasterInvalidationCycleScope() { + for (auto* controller : controllers_) { + controller->CommitNewDisplayItems(); + invalidator_.Generate( + base::DoNothing(), + PaintChunkSubset(controller->GetPaintArtifactShared()), + // The layer bounds are big enough not to clip display item raster + // invalidation rects in the tests. + FloatPoint(), IntSize(20000, 20000), PropertyTreeState::Root()); + for (auto& chunk : controller->PaintChunks()) + chunk.properties.ClearChangedTo(PropertyTreeState::Root()); + } + } + + private: + RasterInvalidator& invalidator_; +}; + INSTANTIATE_PAINT_TEST_SUITE_P(DisplayItemRasterInvalidatorTest); TEST_P(DisplayItemRasterInvalidatorTest, @@ -52,20 +64,27 @@ FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); + } first.Invalidate(PaintInvalidationReason::kStyle); invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &first, "first", IntRect(100, 100, 300, 350), PaintInvalidationReason::kStyle})); @@ -77,21 +96,28 @@ FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(100, 150, 300, 300)); + } first.Invalidate(PaintInvalidationReason::kStyle); invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(200, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(200, 150, 300, 300)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(200, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(200, 150, 300, 300)); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&first, "first", IntRect(100, 100, 300, 350), PaintInvalidationReason::kStyle}, @@ -105,18 +131,25 @@ FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &second, "second", IntRect(100, 100, 200, 200), PaintInvalidationReason::kDisappeared})); @@ -129,25 +162,32 @@ FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &first, "first", IntRect(100, 100, 100, 100), PaintInvalidationReason::kReordered})); @@ -160,20 +200,27 @@ FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - first.Invalidate(PaintInvalidationReason::kOutline); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + first.Invalidate(PaintInvalidationReason::kOutline); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &first, "first", IntRect(100, 100, 100, 100), PaintInvalidationReason::kOutline})); @@ -186,20 +233,27 @@ FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - second.Invalidate(PaintInvalidationReason::kOutline); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + second.Invalidate(PaintInvalidationReason::kOutline); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &second, "second", IntRect(100, 100, 50, 200), PaintInvalidationReason::kOutline})); @@ -212,21 +266,28 @@ FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - first.Invalidate(PaintInvalidationReason::kIncremental); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + first.Invalidate(PaintInvalidationReason::kIncremental); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + } // Incremental invalidation is not applicable when the item is reordered. - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &first, "first", IntRect(100, 100, 100, 100), PaintInvalidationReason::kReordered})); @@ -239,18 +300,25 @@ FakeDisplayItemClient third("third"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, third, kBackgroundType, IntRect(125, 100, 200, 50)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, third, kBackgroundType, IntRect(125, 100, 200, 50)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &third, "third", IntRect(125, 100, 200, 50), PaintInvalidationReason::kAppeared})); @@ -266,24 +334,31 @@ } GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); - for (auto& client : clients) - DrawRect(context, *client, kBackgroundType, IntRect(initial_rect)); - GenerateRasterInvalidations(); - - invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - IntRect visual_rects[] = { - IntRect(100, 100, 150, 100), IntRect(100, 100, 100, 150), - IntRect(100, 100, 150, 80), IntRect(100, 100, 80, 150), - IntRect(100, 100, 150, 150), IntRect(100, 100, 80, 80)}; - for (size_t i = 0; i < base::size(clients); i++) { - clients[i]->Invalidate(PaintInvalidationReason::kIncremental); - DrawRect(context, *clients[i], kBackgroundType, IntRect(visual_rects[i])); + for (auto& client : clients) + DrawRect(context, *client, kBackgroundType, IntRect(initial_rect)); } - EXPECT_THAT(GenerateRasterInvalidations(), + invalidator_.SetTracksRasterInvalidations(true); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + IntRect visual_rects[] = { + IntRect(100, 100, 150, 100), IntRect(100, 100, 100, 150), + IntRect(100, 100, 150, 80), IntRect(100, 100, 80, 150), + IntRect(100, 100, 150, 150), IntRect(100, 100, 80, 80)}; + for (size_t i = 0; i < base::size(clients); i++) { + clients[i]->Invalidate(PaintInvalidationReason::kIncremental); + DrawRect(context, *clients[i], kBackgroundType, IntRect(visual_rects[i])); + } + } + + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{clients[0].get(), "0", IntRect(200, 100, 50, 100), @@ -324,23 +399,30 @@ FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); - DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); + DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); - EXPECT_EQ(0u, NumCachedNewItems()); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); + EXPECT_EQ(0u, NumCachedNewItems()); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&first, "first", IntRect(100, 100, 150, 150), PaintInvalidationReason::kAppeared}, @@ -351,11 +433,15 @@ invalidator_.SetTracksRasterInvalidations(false); invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &first, "first", IntRect(100, 100, 150, 150), PaintInvalidationReason::kDisappeared})); @@ -367,22 +453,29 @@ FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(150, 150, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(150, 150, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); - DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(150, 150, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(150, 150, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); + DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&first, "first", IntRect(100, 100, 150, 150), PaintInvalidationReason::kFull}, @@ -391,14 +484,18 @@ invalidator_.SetTracksRasterInvalidations(false); invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&first, "first", IntRect(100, 100, 150, 150), PaintInvalidationReason::kFull}, @@ -414,31 +511,38 @@ FakeDisplayItemClient content2("content2"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + } // Simulate the situation when |container1| gets a z-index that is greater // than that of |container2|. invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&container1, "container1", IntRect(100, 100, 100, 100), @@ -456,32 +560,39 @@ FakeDisplayItemClient content2("content2"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - // Simulate the situation when |container1| gets a z-index that is greater - // than that of |container2|, and |container1| is invalidated. - container2.Invalidate(); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + // Simulate the situation when |container1| gets a z-index that is greater + // than that of |container2|, and |container1| is invalidated. + container2.Invalidate(); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&container1, "container1", IntRect(100, 100, 100, 100), @@ -512,28 +623,35 @@ PaintChunk::Id container1_id(container1, kBackgroundType); PaintChunk::Id container2_id(container2, kBackgroundType); - GetPaintController().UpdateCurrentPaintChunkProperties(&container1_id, - container1_properties); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - GetPaintController().UpdateCurrentPaintChunkProperties(&container2_id, - container2_properties); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + } // Move content2 into container1, without invalidation. invalidator_.SetTracksRasterInvalidations(true); - GetPaintController().UpdateCurrentPaintChunkProperties(&container1_id, - container1_properties); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - GetPaintController().UpdateCurrentPaintChunkProperties(&container2_id, - container2_properties); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&content2, "content2", IntRect(100, 200, 50, 200), @@ -548,50 +666,60 @@ FakeDisplayItemClient multicol("multicol"); FakeDisplayItemClient content("content"); GraphicsContext context(GetPaintController()); - - InitRootChunk(); IntRect rect1(100, 100, 50, 50); IntRect rect2(150, 100, 50, 50); IntRect rect3(200, 100, 50, 50); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - // Draw again with nothing invalidated. - EXPECT_TRUE(ClientCacheIsValid(multicol)); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + // Draw again with nothing invalidated. + EXPECT_TRUE(ClientCacheIsValid(multicol)); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + } - EXPECT_THAT(GenerateRasterInvalidations(), + EXPECT_THAT(GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &content, "content", UnionRect(rect1, rect2), PaintInvalidationReason::kUncacheable})); invalidator_.SetTracksRasterInvalidations(false); invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - // Now the multicol becomes 3 columns and repaints. - multicol.Invalidate(); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 100, 100, 100)); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + // Now the multicol becomes 3 columns and repaints. + multicol.Invalidate(); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 100, 100, 100)); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - DrawRect(context, content, kForegroundType, rect3); - GetPaintController().EndSkippingCache(); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + DrawRect(context, content, kForegroundType, rect3); + GetPaintController().EndSkippingCache(); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre( RasterInvalidationInfo{&multicol, "multicol", IntRect(100, 200, 100, 100), @@ -613,25 +741,32 @@ IntRect rect2(150, 100, 50, 50); IntRect rect3(200, 100, 50, 50); - InitRootChunk(); - DrawRect(context, content, kBackgroundType, rect1); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); - DrawRect(context, content, kForegroundType, rect3); - GenerateRasterInvalidations(); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + DrawRect(context, content, kBackgroundType, rect1); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + DrawRect(context, content, kForegroundType, rect3); + } invalidator_.SetTracksRasterInvalidations(true); - InitRootChunk(); - // Draw again with nothing invalidated. - DrawRect(context, content, kBackgroundType, rect1); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); - DrawRect(context, content, kForegroundType, rect3); + { + RasterInvalidationCycleScope cycle_scope(GetPaintController(), + invalidator_); + InitRootChunk(); + // Draw again with nothing invalidated. + DrawRect(context, content, kBackgroundType, rect1); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + DrawRect(context, content, kForegroundType, rect3); + } EXPECT_THAT( - GenerateRasterInvalidations(), + GetRasterInvalidations(), UnorderedElementsAre(RasterInvalidationInfo{ &content, "content", UnionRect(rect1, UnionRect(rect2, rect3)), PaintInvalidationReason::kUncacheable}));
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_recorder_test.cc b/third_party/blink/renderer/platform/graphics/paint/drawing_recorder_test.cc index 42eb5e04..f5295542 100644 --- a/third_party/blink/renderer/platform/graphics/paint/drawing_recorder_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/drawing_recorder_test.cc
@@ -22,9 +22,12 @@ TEST_F(DrawingRecorderTest, Nothing) { FakeDisplayItemClient client; GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawNothing(context, client, kForegroundType); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawNothing(context, client, kForegroundType); + GetPaintController().CommitNewDisplayItems(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kForegroundType))); EXPECT_FALSE( @@ -35,9 +38,12 @@ TEST_F(DrawingRecorderTest, Rect) { FakeDisplayItemClient client; GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, client, kForegroundType, kBounds); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, client, kForegroundType, kBounds); + GetPaintController().CommitNewDisplayItems(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kForegroundType))); } @@ -45,22 +51,28 @@ TEST_F(DrawingRecorderTest, Cached) { FakeDisplayItemClient client; GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawNothing(context, client, kBackgroundType); - DrawRect(context, client, kForegroundType, kBounds); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawNothing(context, client, kBackgroundType); + DrawRect(context, client, kForegroundType, kBounds); + GetPaintController().CommitNewDisplayItems(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType), IsSameId(&client, kForegroundType))); - InitRootChunk(); - DrawNothing(context, client, kBackgroundType); - DrawRect(context, client, kForegroundType, kBounds); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawNothing(context, client, kBackgroundType); + DrawRect(context, client, kForegroundType, kBounds); - EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(2u, NumCachedNewItems()); - CommitAndFinishCycle(); + GetPaintController().CommitNewDisplayItems(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType),
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc index 7c40c44..43d80b3 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
@@ -34,6 +34,26 @@ } #endif +void PaintChunker::StartMarkingClientsForValidation( + Vector<const DisplayItemClient*>& clients_to_validate) { +#if DCHECK_IS_ON() + DCHECK(IsInInitialState()); +#endif + DCHECK(!clients_to_validate_); + clients_to_validate_ = &clients_to_validate; +} + +void PaintChunker::MarkClientForValidation(const DisplayItemClient& client) { + if (clients_to_validate_ && !client.IsMarkedForValidation()) { + clients_to_validate_->push_back(&client); + client.MarkForValidation(); + } +} + +void PaintChunker::StopMarkingClientsForValidation() { + clients_to_validate_ = nullptr; +} + void PaintChunker::UpdateCurrentPaintChunkProperties( const PaintChunk::Id* chunk_id, const PropertyTreeStateOrAlias& properties) { @@ -55,6 +75,10 @@ wtf_size_t next_chunk_begin_index = chunks_->IsEmpty() ? 0 : chunks_->back().end_index; chunks_->emplace_back(next_chunk_begin_index, std::move(chunk)); + // This chunk was copied from the cache, so it should already be valid; hence + // we don't call MarkClientForValidation(). + DCHECK(!chunks_->back().id.client.IsCacheable() || + chunks_->back().id.client.IsValid()); } bool PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) { @@ -73,6 +97,7 @@ next_chunk_id_.emplace(id); FinalizeLastChunkProperties(); wtf_size_t begin = chunks_->IsEmpty() ? 0 : chunks_->back().end_index; + MarkClientForValidation(next_chunk_id_->client); chunks_->emplace_back(begin, begin, *next_chunk_id_, current_properties_, current_effectively_invisible_); next_chunk_id_ = absl::nullopt;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h index 7a18b74..9373392 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
@@ -37,6 +37,11 @@ bool IsInInitialState() const; #endif + void StartMarkingClientsForValidation( + Vector<const DisplayItemClient*>& clients_to_validate); + void MarkClientForValidation(const DisplayItemClient& client); + void StopMarkingClientsForValidation(); + const PropertyTreeStateOrAlias& CurrentPaintChunkProperties() const { return current_properties_; } @@ -101,6 +106,7 @@ void FinalizeLastChunkProperties(); Vector<PaintChunk>* chunks_ = nullptr; + Vector<const DisplayItemClient*>* clients_to_validate_ = nullptr; // The id specified by UpdateCurrentPaintChunkProperties(). If it is not // nullopt, we will use it as the id of the next new chunk. Otherwise we will
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc index 45ebb7c..c2b4895 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -231,6 +231,8 @@ return false; } + // This subsequence was copied from the cache, so client must already be + // valid, hence we don't call MarkClientForValidation(client). AppendSubsequenceByMoving(client, subsequence_index, markers.start_chunk_index, markers.end_chunk_index); return true; @@ -327,6 +329,13 @@ under_invalidation_checker_->CheckNewItem(); } +void PaintController::MarkClientForValidation(const DisplayItemClient& client) { + if (clients_to_validate_ && !client.IsMarkedForValidation()) { + clients_to_validate_->push_back(&client); + client.MarkForValidation(); + } +} + void PaintController::ProcessNewItem(DisplayItem& display_item) { if (IsSkippingCache() && usage_ == kMultiplePaints) { display_item.Client().Invalidate(PaintInvalidationReason::kUncacheable); @@ -526,6 +535,8 @@ for (auto& item : new_display_item_list.ItemsInRange( new_item_start_index, new_display_item_list.size())) { DCHECK(!item.IsTombstone()); + // This item was copied from the cache, so client must already be valid, + // hence we don't call MarkClientForValidation(client). item.SetPaintInvalidationReason(skip_cache || !item.IsCacheable() ? PaintInvalidationReason::kUncacheable : PaintInvalidationReason::kNone); @@ -615,50 +626,40 @@ #endif } +PaintController::CycleScope::~CycleScope() { + for (const auto* client : clients_to_validate_) { + if (client->IsCacheable()) + client->Validate(); + } + for (auto* controller : controllers_) + controller->FinishCycle(); +} + +void PaintController::StartCycle( + Vector<const DisplayItemClient*>& clients_to_validate) { + // StartCycle() can only be called before the controller has painted anything. + DCHECK(new_paint_artifact_); + DCHECK(new_paint_artifact_->IsEmpty()); + DCHECK(!clients_to_validate_); + if (usage_ == kTransient) + return; + clients_to_validate_ = &clients_to_validate; + paint_chunker_.StartMarkingClientsForValidation(clients_to_validate); + ReserveCapacity(); +} + void PaintController::FinishCycle() { + DCHECK(usage_ == kTransient || clients_to_validate_); + clients_to_validate_ = nullptr; + paint_chunker_.StopMarkingClientsForValidation(); if (usage_ == kTransient || !committed_) return; CheckNoNewPaint(); committed_ = false; - // Validate display item clients that have validly cached subsequence or - // display items in this PaintController. - for (auto& item : current_subsequences_.tree) { - if (item.is_moved_from_cached_subsequence) { - // We don't need to validate the client of a cached subsequence, because - // it should be already valid. See http://crbug.com/1050090 for more - // details. - DCHECK(!item.client->IsCacheable() || ClientCacheIsValid(*item.client)); - continue; - } - if (item.client->IsCacheable()) - item.client->Validate(); - } - for (wtf_size_t i = 0; i < current_paint_artifact_->PaintChunks().size(); - i++) { - auto& chunk = current_paint_artifact_->PaintChunks()[i]; + for (auto& chunk : current_paint_artifact_->PaintChunks()) chunk.client_is_just_created = false; - const auto& client = chunk.id.client; - if (chunk.is_moved_from_cached_subsequence) { - // We don't need to validate the clients of paint chunks and display - // items that are moved from a cached subsequence, because they should be - // already valid. See http://crbug.com/1050090 for more details. -#if DCHECK_IS_ON() - DCHECK(!chunk.is_cacheable || ClientCacheIsValid(client)); - for (const auto& item : current_paint_artifact_->DisplayItemsInChunk(i)) - DCHECK(!item.IsCacheable() || ClientCacheIsValid(item.Client())); -#endif - continue; - } - if (client.IsCacheable()) - client.Validate(); - - for (const auto& item : current_paint_artifact_->DisplayItemsInChunk(i)) { - if (item.Client().IsCacheable()) - item.Client().Validate(); - } - } #if DCHECK_IS_ON() if (VLOG_IS_ON(1)) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h index 5adfdf91..8a2b98c 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -82,15 +82,32 @@ PaintController& operator=(const PaintController&) = delete; ~PaintController(); - // Called before painting to optimize memory allocation by reserving space in - // |new_paint_artifact_| and |new_subsequences_| based on the size of the - // previous ones (|current_paint_artifact_| and |current_subsequences_|). - void ReserveCapacity(); - #if DCHECK_IS_ON() Usage GetUsage() const { return usage_; } #endif + class PLATFORM_EXPORT CycleScope { + STACK_ALLOCATED(); + + public: + CycleScope() = default; + explicit CycleScope(PaintController& controller) { + AddController(controller); + } + void AddController(PaintController& controller) { + controller.StartCycle(clients_to_validate_); + controllers_.push_back(&controller); + } + ~CycleScope(); + + protected: + Vector<PaintController*> controllers_; + + private: + Vector<const DisplayItemClient*> clients_to_validate_; + }; + friend class CycleScope; + // These methods are called during painting. // Provide a new set of paint chunk properties to apply to recorded display @@ -144,12 +161,15 @@ return new_paint_artifact_->PaintChunks().back().bounds; } + void MarkClientForValidation(const DisplayItemClient& client); + template <typename DisplayItemClass, typename... Args> - void CreateAndAppend(Args&&... args) { + void CreateAndAppend(const DisplayItemClient& client, Args&&... args) { + MarkClientForValidation(client); DisplayItemClass& display_item = new_paint_artifact_->GetDisplayItemList() .AllocateAndConstruct<DisplayItemClass>( - std::forward<Args>(args)...); + client, std::forward<Args>(args)...); display_item.SetFragment(current_fragment_); ProcessNewItem(display_item); } @@ -189,14 +209,6 @@ // artifact with the new paintings. void CommitNewDisplayItems(); - // Called when the caller finishes updating a full document life cycle. - // The PaintController will cleanup data that will no longer be used for the - // next cycle, and update status to be ready for the next cycle. - // It updates caching status of DisplayItemClients, so if there are - // DisplayItemClients painting on multiple PaintControllers, we should call - // there FinishCycle() at the same time to ensure consistent caching status. - void FinishCycle(); - // Returns the approximate memory usage owned by this PaintController. size_t ApproximateUnsharedMemoryUsage() const; @@ -291,6 +303,22 @@ friend class PaintUnderInvalidationChecker; friend class GraphicsLayer; // Temporary for ClientCacheIsValid(). + // Called before painting to optimize memory allocation by reserving space in + // |new_paint_artifact_| and |new_subsequences_| based on the size of the + // previous ones (|current_paint_artifact_| and |current_subsequences_|). + void ReserveCapacity(); + + // Called at the beginning of a paint cycle, as defined by CycleScope. + void StartCycle(Vector<const DisplayItemClient*>& clients_to_validate); + + // Called at the end of a paint cycle, as defined by CycleScope. + // The PaintController will cleanup data that will no longer be used for the + // next cycle, and update status to be ready for the next cycle. + // It updates caching status of DisplayItemClients, so if there are + // DisplayItemClients painting on multiple PaintControllers, we should call + // there FinishCycle() at the same time to ensure consistent caching status. + void FinishCycle(); + // True if all display items associated with the client are validly cached. // However, the current algorithm allows the following situations even if // ClientCacheIsValid() is true for a client during painting: @@ -375,6 +403,7 @@ // CommitNewDisplayItems(). scoped_refptr<PaintArtifact> new_paint_artifact_; PaintChunker paint_chunker_; + Vector<const DisplayItemClient*>* clients_to_validate_ = nullptr; bool cache_is_all_invalid_ = true; bool committed_ = false;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc index 4049044..b64b32d 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h" +#include "build/build_config.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h" @@ -25,6 +26,16 @@ public PaintControllerTestBase { }; +class CommitCycleScope : public PaintController::CycleScope { + public: + explicit CommitCycleScope(PaintController& controller) + : PaintController::CycleScope(controller) {} + ~CommitCycleScope() { + for (auto* controller : controllers_) + controller->CommitNewDisplayItems(); + } +}; + #define EXPECT_DEFAULT_ROOT_CHUNK(size) \ EXPECT_THAT(GetPaintController().PaintChunks(), \ ElementsAre(IsPaintChunk(0, size, DefaultRootChunkId(), \ @@ -37,14 +48,15 @@ kCompositeAfterPaint, kUnderInvalidationChecking, kCompositeAfterPaint | kUnderInvalidationChecking)); - TEST_P(PaintControllerTest, NestedRecorders) { GraphicsContext context(GetPaintController()); FakeDisplayItemClient client("client"); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, client, kBackgroundType, IntRect(100, 100, 200, 200)); - CommitAndFinishCycle(); + DrawRect(context, client, kBackgroundType, IntRect(100, 100, 200, 200)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType))); @@ -55,16 +67,17 @@ FakeDisplayItemClient first("first"); FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - - CommitAndFinishCycle(); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -72,19 +85,20 @@ IsSameId(&first, kForegroundType))); EXPECT_DEFAULT_ROOT_CHUNK(3); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 300, 300)); - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(1u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(1u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -97,15 +111,17 @@ FakeDisplayItemClient second("second"); FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -115,24 +131,25 @@ IsSameId(&unaffected, kBackgroundType), IsSameId(&unaffected, kForegroundType))); - InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); - EXPECT_EQ(6u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(6u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(2u, NumIndexedItems()); // first - EXPECT_EQ(5u, - NumSequentialMatches()); // second, first foreground, unaffected - EXPECT_EQ(1u, NumOutOfOrderMatches()); // first + EXPECT_EQ(2u, NumIndexedItems()); // first + EXPECT_EQ(5u, + NumSequentialMatches()); // second, first foreground, unaffected + EXPECT_EQ(1u, NumOutOfOrderMatches()); // first #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&second, kBackgroundType), @@ -149,15 +166,17 @@ FakeDisplayItemClient second("second"); FakeDisplayItemClient unaffected("unaffected"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -167,24 +186,25 @@ IsSameId(&unaffected, kBackgroundType), IsSameId(&unaffected, kForegroundType))); - InitRootChunk(); - first.Invalidate(); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); - DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + first.Invalidate(); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, unaffected, kBackgroundType, IntRect(300, 300, 10, 10)); + DrawRect(context, unaffected, kForegroundType, IntRect(300, 300, 10, 10)); - EXPECT_EQ(4u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(4u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(2u, NumIndexedItems()); - EXPECT_EQ(4u, NumSequentialMatches()); // second, unaffected - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(2u, NumIndexedItems()); + EXPECT_EQ(4u, NumSequentialMatches()); // second, unaffected + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&second, kBackgroundType), @@ -201,31 +221,34 @@ FakeDisplayItemClient second("second"); FakeDisplayItemClient third("third"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), IsSameId(&second, kBackgroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, third, kBackgroundType, IntRect(125, 100, 200, 50)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, third, kBackgroundType, IntRect(125, 100, 200, 50)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); // first, second - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); // first, second + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -239,15 +262,17 @@ FakeDisplayItemClient second("second"); FakeDisplayItemClient third("third"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, third, kBackgroundType, IntRect(300, 100, 50, 50)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, third, kForegroundType, IntRect(300, 100, 50, 50)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, third, kBackgroundType, IntRect(300, 100, 50, 50)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, third, kForegroundType, IntRect(300, 100, 50, 50)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -257,25 +282,26 @@ IsSameId(&second, kForegroundType), IsSameId(&third, kForegroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, third, kBackgroundType, IntRect(300, 100, 50, 50)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, third, kForegroundType, IntRect(300, 100, 50, 50)); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, third, kBackgroundType, IntRect(300, 100, 50, 50)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, third, kForegroundType, IntRect(300, 100, 50, 50)); - EXPECT_EQ(4u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(4u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(2u, NumIndexedItems()); - EXPECT_EQ(4u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(2u, NumIndexedItems()); + EXPECT_EQ(4u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -291,27 +317,31 @@ FakeDisplayItemClient first("first"); FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); - DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); - CommitAndFinishCycle(); + DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); + DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&second, kBackgroundType), IsSameId(&second, kForegroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -320,19 +350,20 @@ IsSameId(&second, kForegroundType))); EXPECT_DEFAULT_ROOT_CHUNK(4); - InitRootChunk(); - DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); - DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, second, kBackgroundType, IntRect(150, 250, 100, 100)); + DrawRect(context, second, kForegroundType, IntRect(150, 250, 100, 100)); - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(2u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(2u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&second, kBackgroundType), @@ -344,27 +375,31 @@ FakeDisplayItemClient first("first"); FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), IsSameId(&first, kForegroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(150, 150, 100, 100)); - DrawRect(context, first, kForegroundType, IntRect(150, 150, 100, 100)); - DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); - DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(150, 150, 100, 100)); + DrawRect(context, first, kForegroundType, IntRect(150, 150, 100, 100)); + DrawRect(context, second, kBackgroundType, IntRect(200, 200, 50, 50)); + DrawRect(context, second, kForegroundType, IntRect(200, 200, 50, 50)); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -373,14 +408,16 @@ IsSameId(&second, kForegroundType))); EXPECT_DEFAULT_ROOT_CHUNK(4); - InitRootChunk(); - first.Invalidate(); - second.Invalidate(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + first.Invalidate(); + second.Invalidate(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, first, kForegroundType, IntRect(100, 100, 150, 150)); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -392,11 +429,13 @@ FakeDisplayItemClient first("first"); FakeDisplayItemClient second("second"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 150, 150)); - CommitAndFinishCycle(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 150, 150)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -414,10 +453,12 @@ EXPECT_FALSE(ClientCacheIsValid(first)); EXPECT_TRUE(ClientCacheIsValid(second)); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 150, 150)); - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 150, 150)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 150, 150)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), @@ -447,17 +488,19 @@ FakeDisplayItemClient container2("container2"); FakeDisplayItemClient content2("content2"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - CommitAndFinishCycle(); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -469,19 +512,21 @@ IsSameId(&content2, kForegroundType), IsSameId(&container2, kForegroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - // Simulate the situation when |container1| gets a z-index that is greater - // than that of |container2|. - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - CommitAndFinishCycle(); + // Simulate the situation when |container1| gets a z-index that is greater + // than that of |container2|. + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container2, kBackgroundType), @@ -501,17 +546,19 @@ FakeDisplayItemClient container2("container2"); FakeDisplayItemClient content2("content2"); GraphicsContext context(GetPaintController()); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - CommitAndFinishCycle(); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -523,20 +570,22 @@ IsSameId(&content2, kForegroundType), IsSameId(&container2, kForegroundType))); - InitRootChunk(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - // Simulate the situation when |container1| gets a z-index that is greater - // than that of |container2|, and |container1| is invalidated. - container1.Invalidate(); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - CommitAndFinishCycle(); + // Simulate the situation when |container1| gets a z-index that is greater + // than that of |container2|, and |container1| is invalidated. + container1.Invalidate(); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container2, kBackgroundType), @@ -554,30 +603,34 @@ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) return; - GraphicsContext context(GetPaintController()); - FakeDisplayItemClient root("root"); auto root_properties = DefaultPaintChunkProperties(); PaintChunk::Id root_id(root, DisplayItem::kCaret); - GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, - root_properties); - DrawRect(context, root, kBackgroundType, IntRect(100, 100, 100, 100)); - FakeDisplayItemClient container("container"); auto container_properties = DefaultPaintChunkProperties(); PaintChunk::Id container_id(container, DisplayItem::kCaret); + GraphicsContext context(GetPaintController()); + { - SubsequenceRecorder r(context, container); - GetPaintController().UpdateCurrentPaintChunkProperties( - &container_id, container_properties); - DrawRect(context, container, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, container, kForegroundType, IntRect(100, 100, 100, 100)); + CommitCycleScope cycle_scope(GetPaintController()); + + GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, + root_properties); + DrawRect(context, root, kBackgroundType, IntRect(100, 100, 100, 100)); + + { + SubsequenceRecorder r(context, container); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container_id, container_properties); + DrawRect(context, container, kBackgroundType, + IntRect(100, 100, 100, 100)); + DrawRect(context, container, kForegroundType, + IntRect(100, 100, 100, 100)); + } + + DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); } - DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); - - CommitAndFinishCycle(); - // Even though the paint properties match, |container| should receive its // own PaintChunk because it created a subsequence. EXPECT_THAT( @@ -587,12 +640,14 @@ IsPaintChunk(3, 4, PaintChunk::Id(root, kForegroundType), root_properties))); - GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, - root_properties); - DrawRect(context, root, kBackgroundType, IntRect(100, 100, 100, 100)); - EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(container)); - DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, + root_properties); + DrawRect(context, root, kBackgroundType, IntRect(100, 100, 100, 100)); + EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(container)); + DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); + } // |container| should still receive its own PaintChunk because it is a cached // subsequence. @@ -622,26 +677,33 @@ container2_properties.SetEffect(*container2_effect); { - GetPaintController().UpdateCurrentPaintChunkProperties( - &container1_id, container1_properties); + CommitCycleScope cycle_scope(GetPaintController()); - SubsequenceRecorder r(context, container1); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - } - { - GetPaintController().UpdateCurrentPaintChunkProperties( - &container2_id, container2_properties); + { + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + SubsequenceRecorder r(context, container1); + DrawRect(context, container1, kBackgroundType, + IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, + IntRect(100, 100, 100, 100)); + } + { + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); + + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, + IntRect(100, 200, 100, 100)); + } } - CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -664,56 +726,61 @@ ElementsAre(IsPaintChunk(0, 4, container1_id, container1_properties), IsPaintChunk(4, 8, container2_id, container2_properties))); - // Simulate the situation when |container1| gets a z-index that is greater - // than that of |container2|. - if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - // When under-invalidation-checking is enabled, - // UseCachedSubsequenceIfPossible is forced off, and the client is expected - // to create the same painting as in the previous paint. - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container2)); - { - GetPaintController().UpdateCurrentPaintChunkProperties( - &container2_id, container2_properties); + { + CommitCycleScope cycle_scope(GetPaintController()); + // Simulate the situation when |container1| gets a z-index that is greater + // than that of |container2|. + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { + // When under-invalidation-checking is enabled, + // UseCachedSubsequenceIfPossible is forced off, and the client is + // expected to create the same painting as in the previous paint. + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + { + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, - IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, - IntRect(100, 200, 100, 100)); + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, + IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, + IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, + IntRect(100, 200, 100, 100)); + } + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container1)); + { + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); + + SubsequenceRecorder r(context, container1); + DrawRect(context, container1, kBackgroundType, + IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, + IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, + IntRect(100, 100, 50, 200)); + DrawRect(context, container1, kForegroundType, + IntRect(100, 100, 100, 100)); + } + } else { + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container1)); } - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container1)); - { - GetPaintController().UpdateCurrentPaintChunkProperties( - &container1_id, container1_properties); - SubsequenceRecorder r(context, container1); - DrawRect(context, container1, kBackgroundType, - IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, container1, kForegroundType, - IntRect(100, 100, 100, 100)); - } - } else { - EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container2)); - EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container1)); - } - - EXPECT_EQ(8u, NumCachedNewItems()); - EXPECT_EQ(2u, NumCachedNewSubsequences()); + EXPECT_EQ(8u, NumCachedNewItems()); + EXPECT_EQ(2u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(0u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(0u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container2, kBackgroundType), @@ -746,18 +813,22 @@ PaintChunk::Id container2_id(container2, kBackgroundType); PaintChunk::Id content2_id(content2, kBackgroundType); - InitRootChunk(); - - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); { - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, IntRect(100, 200, 100, 100)); + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + { + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, + IntRect(100, 200, 100, 100)); + } + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); } - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content1, kBackgroundType), @@ -783,42 +854,45 @@ // Simulate the situation when |container2| gets a z-index that is smaller // than that of |content1|. - InitRootChunk(); - if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - // When under-invalidation-checking is enabled, - // UseCachedSubsequenceIfPossible is forced off, and the client is expected - // to create the same painting as in the previous paint. - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container2)); - { - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, - IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - DrawRect(context, container2, kForegroundType, - IntRect(100, 200, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { + // When under-invalidation-checking is enabled, + // UseCachedSubsequenceIfPossible is forced off, and the client is + // expected to create the same painting as in the previous paint. + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + { + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, + IntRect(100, 200, 50, 200)); + DrawRect(context, content2, kForegroundType, + IntRect(100, 200, 50, 200)); + DrawRect(context, container2, kForegroundType, + IntRect(100, 200, 100, 100)); + } + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + } else { + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1, + kBackgroundType)); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1, + kForegroundType)); } - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - } else { - EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container2)); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1, - kBackgroundType)); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1, - kForegroundType)); - } - EXPECT_EQ(6u, NumCachedNewItems()); - EXPECT_EQ(1u, NumCachedNewSubsequences()); + EXPECT_EQ(6u, NumCachedNewItems()); + EXPECT_EQ(1u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container2, kBackgroundType), @@ -854,16 +928,18 @@ PaintChunk::Id content3_id(content3, kBackgroundType); IntRect rect(100, 100, 50, 200); - InitRootChunk(); - - DrawRect(context, content1a, kBackgroundType, rect); - DrawRect(context, content1b, kBackgroundType, rect); { - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, rect); + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + + DrawRect(context, content1a, kBackgroundType, rect); + DrawRect(context, content1b, kBackgroundType, rect); + { + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, rect); + } + DrawRect(context, content3, kBackgroundType, rect); } - DrawRect(context, content3, kBackgroundType, rect); - CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content1a, kBackgroundType), @@ -875,43 +951,44 @@ // Subsequence(container1): container1, content1b(cached), content1a(cached). // Subsequence(container2): cached // Subsequence(contaienr3): container3, content3 - InitRootChunk(); - if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1b, - kBackgroundType)); - DrawRect(context, content1b, kBackgroundType, rect); - EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1a, - kBackgroundType)); - DrawRect(context, content1a, kBackgroundType, rect); - { - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { + EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible( + context, content1b, kBackgroundType)); + DrawRect(context, content1b, kBackgroundType, rect); + EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible( + context, content1a, kBackgroundType)); + DrawRect(context, content1a, kBackgroundType, rect); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, rect); + } + EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible( + context, content3, kBackgroundType)); + DrawRect(context, content3, kBackgroundType, rect); + } else { + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible( + context, content1b, kBackgroundType)); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible( + context, content1a, kBackgroundType)); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( context, container2)); - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, rect); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content3, + kBackgroundType)); } - EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content3, - kBackgroundType)); - DrawRect(context, content3, kBackgroundType, rect); - } else { - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1b, - kBackgroundType)); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1a, - kBackgroundType)); - EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container2)); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content3, - kBackgroundType)); - } - EXPECT_EQ(4u, NumCachedNewItems()); - EXPECT_EQ(1u, NumCachedNewSubsequences()); + EXPECT_EQ(4u, NumCachedNewItems()); + EXPECT_EQ(1u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(1u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(1u, NumOutOfOrderMatches()); + EXPECT_EQ(1u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(1u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content1b, kBackgroundType), @@ -926,7 +1003,6 @@ constexpr wtf_size_t kFragmentCount = 3; FakeDisplayItemClient container("container"); - // The first paint. auto paint_container = [this, &context, &container]() { SubsequenceRecorder r(context, container); for (wtf_size_t i = 0; i < kFragmentCount; ++i) { @@ -938,7 +1014,10 @@ IntRect(100, 100, 100, 100)); } }; + + // The first paint. { + CommitCycleScope cycle_scope(GetPaintController()); ScopedPaintChunkProperties root_chunk_properties( GetPaintController(), DefaultPaintChunkProperties(), root, kBackgroundType); @@ -946,7 +1025,6 @@ paint_container(); DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); } - CommitAndFinishCycle(); auto check_paint_results = [this, &root, &container]() { EXPECT_THAT( @@ -966,6 +1044,7 @@ // The second paint. { + CommitCycleScope cycle_scope(GetPaintController()); ScopedPaintChunkProperties root_chunk_properties( GetPaintController(), DefaultPaintChunkProperties(), root, kBackgroundType); @@ -981,7 +1060,6 @@ } DrawRect(context, root, kForegroundType, IntRect(100, 100, 100, 100)); } - CommitAndFinishCycle(); // The second paint should produce the exactly same results. check_paint_results(); @@ -1004,15 +1082,17 @@ auto container2_properties = DefaultPaintChunkProperties(); container2_properties.SetEffect(*container2_effect); - GetPaintController().UpdateCurrentPaintChunkProperties(&container1_id, - container1_properties); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - GetPaintController().UpdateCurrentPaintChunkProperties(&container2_id, - container2_properties); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -1026,24 +1106,25 @@ IsPaintChunk(2, 4, container2_id, container2_properties))); // Move content2 into container1, without invalidation. - GetPaintController().UpdateCurrentPaintChunkProperties(&container1_id, - container1_properties); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); - GetPaintController().UpdateCurrentPaintChunkProperties(&container2_id, - container2_properties); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_id, container1_properties); + DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); + DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container2_id, container2_properties); + DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - EXPECT_EQ(4u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(4u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(1u, NumIndexedItems()); - EXPECT_EQ(3u, NumSequentialMatches()); - EXPECT_EQ(1u, NumOutOfOrderMatches()); + EXPECT_EQ(1u, NumIndexedItems()); + EXPECT_EQ(3u, NumSequentialMatches()); + EXPECT_EQ(1u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -1069,21 +1150,23 @@ const DisplayItem::Type kType4 = static_cast<DisplayItem::Type>(DisplayItem::kDrawingFirst + 3); - InitRootChunk(); - DrawRect(context, client, kType1, IntRect(100, 100, 100, 100)); - DrawRect(context, client, kType2, IntRect(100, 100, 50, 200)); - DrawRect(context, client, kType3, IntRect(100, 100, 50, 200)); - DrawRect(context, client, kType4, IntRect(100, 100, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, client, kType1, IntRect(100, 100, 100, 100)); + DrawRect(context, client, kType2, IntRect(100, 100, 50, 200)); + DrawRect(context, client, kType3, IntRect(100, 100, 50, 200)); + DrawRect(context, client, kType4, IntRect(100, 100, 100, 100)); + } - CommitAndFinishCycle(); - - InitRootChunk(); - DrawRect(context, client, kType2, IntRect(100, 100, 50, 200)); - DrawRect(context, client, kType3, IntRect(100, 100, 50, 200)); - DrawRect(context, client, kType1, IntRect(100, 100, 100, 100)); - DrawRect(context, client, kType4, IntRect(100, 100, 100, 100)); - - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, client, kType2, IntRect(100, 100, 50, 200)); + DrawRect(context, client, kType3, IntRect(100, 100, 50, 200)); + DrawRect(context, client, kType1, IntRect(100, 100, 100, 100)); + DrawRect(context, client, kType4, IntRect(100, 100, 100, 100)); + } } TEST_P(PaintControllerTest, CachedNestedSubsequenceUpdate) { @@ -1117,35 +1200,43 @@ content2_properties.SetEffect(*content2_effect); { - SubsequenceRecorder r(context, container1); - GetPaintController().UpdateCurrentPaintChunkProperties( - &container1_background_id, container1_background_properties); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); + CommitCycleScope cycle_scope(GetPaintController()); + { + SubsequenceRecorder r(context, container1); + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_background_id, container1_background_properties); + DrawRect(context, container1, kBackgroundType, + IntRect(100, 100, 100, 100)); - { - SubsequenceRecorder r(context, content1); + { + SubsequenceRecorder r(context, content1); + GetPaintController().UpdateCurrentPaintChunkProperties( + &content1_id, content1_properties); + DrawRect(context, content1, kBackgroundType, + IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, + IntRect(100, 100, 50, 200)); + } GetPaintController().UpdateCurrentPaintChunkProperties( - &content1_id, content1_properties); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); + &container1_foreground_id, container1_foreground_properties); + DrawRect(context, container1, kForegroundType, + IntRect(100, 100, 100, 100)); } - GetPaintController().UpdateCurrentPaintChunkProperties( - &container1_foreground_id, container1_foreground_properties); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - } - { - SubsequenceRecorder r(context, container2); - GetPaintController().UpdateCurrentPaintChunkProperties( - &container2_background_id, container2_background_properties); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); { - SubsequenceRecorder r(context, content2); + SubsequenceRecorder r(context, container2); GetPaintController().UpdateCurrentPaintChunkProperties( - &content2_id, content2_properties); - DrawRect(context, content2, kBackgroundType, IntRect(100, 200, 50, 200)); + &container2_background_id, container2_background_properties); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + { + SubsequenceRecorder r(context, content2); + GetPaintController().UpdateCurrentPaintChunkProperties( + &content2_id, content2_properties); + DrawRect(context, content2, kBackgroundType, + IntRect(100, 200, 50, 200)); + } } } - CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -1171,58 +1262,62 @@ container2_background_properties), IsPaintChunk(5, 6, content2_id, content2_properties))); - // Invalidate container1 but not content1. - container1.Invalidate(); - // Container2 itself now becomes empty (but still has the 'content2' child), - // and chooses not to output subsequence info. - container2.Invalidate(); - content2.Invalidate(); - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container2)); - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, content2)); - // Content2 now outputs foreground only. { - SubsequenceRecorder r(context, content2); - GetPaintController().UpdateCurrentPaintChunkProperties(&content2_id, - content2_properties); - DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); - } - // Repaint container1 with foreground only. - { - SubsequenceRecorder r(context, container1); + CommitCycleScope cycle_scope(GetPaintController()); + // Invalidate container1 but not content1. + container1.Invalidate(); + // Container2 itself now becomes empty (but still has the 'content2' child), + // and chooses not to output subsequence info. + container2.Invalidate(); + content2.Invalidate(); EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container1)); - // Use cached subsequence of content1. - if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - // When under-invalidation-checking is enabled, - // UseCachedSubsequenceIfPossible is forced off, and the client is - // expected to create the same painting as in the previous paint. - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, content1)); - SubsequenceRecorder r(context, content1); + context, container2)); + EXPECT_FALSE( + SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, content2)); + // Content2 now outputs foreground only. + { + SubsequenceRecorder r(context, content2); GetPaintController().UpdateCurrentPaintChunkProperties( - &content1_id, content1_properties); - DrawRect(context, content1, kBackgroundType, IntRect(100, 100, 50, 200)); - DrawRect(context, content1, kForegroundType, IntRect(100, 100, 50, 200)); - } else { - EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, content1)); + &content2_id, content2_properties); + DrawRect(context, content2, kForegroundType, IntRect(100, 200, 50, 200)); } - GetPaintController().UpdateCurrentPaintChunkProperties( - &container1_foreground_id, container1_foreground_properties); - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - } + // Repaint container1 with foreground only. + { + SubsequenceRecorder r(context, container1); + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container1)); + // Use cached subsequence of content1. + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { + // When under-invalidation-checking is enabled, + // UseCachedSubsequenceIfPossible is forced off, and the client is + // expected to create the same painting as in the previous paint. + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, content1)); + SubsequenceRecorder r(context, content1); + GetPaintController().UpdateCurrentPaintChunkProperties( + &content1_id, content1_properties); + DrawRect(context, content1, kBackgroundType, + IntRect(100, 100, 50, 200)); + DrawRect(context, content1, kForegroundType, + IntRect(100, 100, 50, 200)); + } else { + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, content1)); + } + GetPaintController().UpdateCurrentPaintChunkProperties( + &container1_foreground_id, container1_foreground_properties); + DrawRect(context, container1, kForegroundType, + IntRect(100, 100, 100, 100)); + } - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(1u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(1u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(0u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(0u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content2, kForegroundType), @@ -1248,10 +1343,8 @@ FakeDisplayItemClient root("root"); auto properties = DefaultPaintChunkProperties(); - PaintChunk::Id root_id(root, DisplayItem::kLayerChunk); GraphicsContext context(GetPaintController()); - GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, properties); - + PaintChunk::Id root_id(root, DisplayItem::kLayerChunk); FakeDisplayItemClient container1("container1"); PaintChunk::Id container1_bg_id(container1, kBackgroundType); PaintChunk::Id container1_fg_id(container1, kForegroundType); @@ -1265,36 +1358,47 @@ PaintChunk::Id content2a_id(content2a, kBackgroundType); FakeDisplayItemClient content2b("content2b"); PaintChunk::Id content2b_id(content2b, kForegroundType); - { - SubsequenceRecorder r(context, container1); - DrawRect(context, container1, kBackgroundType, IntRect(100, 100, 100, 100)); - { - SubsequenceRecorder r(context, content1a); - DrawRect(context, content1a, kBackgroundType, IntRect(100, 100, 50, 200)); - } - { - SubsequenceRecorder r(context, content1b); - DrawRect(context, content1b, kForegroundType, IntRect(100, 100, 50, 200)); - } - DrawRect(context, container1, kForegroundType, IntRect(100, 100, 100, 100)); - } - { - SubsequenceRecorder r(context, container2); - DrawRect(context, container2, kBackgroundType, IntRect(100, 200, 100, 100)); - { - SubsequenceRecorder r(context, content2a); - DrawRect(context, content2a, kBackgroundType, IntRect(100, 200, 50, 200)); - } - { - SubsequenceRecorder r(context, content2b); - DrawRect(context, content2b, kForegroundType, IntRect(100, 200, 50, 200)); - } - } + CommitCycleScope cycle_scope(GetPaintController()); + GetPaintController().UpdateCurrentPaintChunkProperties(&root_id, + properties); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + { + SubsequenceRecorder r(context, container1); + DrawRect(context, container1, kBackgroundType, + IntRect(100, 100, 100, 100)); + { + SubsequenceRecorder r(context, content1a); + DrawRect(context, content1a, kBackgroundType, + IntRect(100, 100, 50, 200)); + } + { + SubsequenceRecorder r(context, content1b); + DrawRect(context, content1b, kForegroundType, + IntRect(100, 100, 50, 200)); + } + DrawRect(context, container1, kForegroundType, + IntRect(100, 100, 100, 100)); + } + { + SubsequenceRecorder r(context, container2); + DrawRect(context, container2, kBackgroundType, + IntRect(100, 200, 100, 100)); + { + SubsequenceRecorder r(context, content2a); + DrawRect(context, content2a, kBackgroundType, + IntRect(100, 200, 50, 200)); + } + { + SubsequenceRecorder r(context, content2b); + DrawRect(context, content2b, kForegroundType, + IntRect(100, 200, 50, 200)); + } + } + + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -1322,14 +1426,16 @@ IsPaintChunk(6, 7, content2b_id, properties))); // Nothing invalidated. Should keep all subsequences. - EXPECT_TRUE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container1)); - EXPECT_TRUE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container2)); + { + CommitCycleScope cycle_scope(GetPaintController()); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container1)); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); - EXPECT_EQ(7u, NumCachedNewItems()); - EXPECT_EQ(6u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + EXPECT_EQ(7u, NumCachedNewItems()); + EXPECT_EQ(6u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container1, kBackgroundType), @@ -1358,14 +1464,16 @@ // Swap order of the subsequences of container1 and container2. // Nothing invalidated. Should keep all subsequences. - EXPECT_TRUE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container2)); - EXPECT_TRUE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container1)); + { + CommitCycleScope cycle_scope(GetPaintController()); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container2)); + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container1)); - EXPECT_EQ(7u, NumCachedNewItems()); - EXPECT_EQ(6u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + EXPECT_EQ(7u, NumCachedNewItems()); + EXPECT_EQ(6u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&container2, kBackgroundType), @@ -1397,20 +1505,21 @@ FakeDisplayItemClient multicol("multicol"); FakeDisplayItemClient content("content"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - IntRect rect1(100, 100, 50, 50); IntRect rect2(150, 100, 50, 50); IntRect rect3(200, 100, 50, 50); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); - CommitAndFinishCycle(); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&multicol, kBackgroundType), @@ -1425,25 +1534,26 @@ EXPECT_NE(record1, record2); EXPECT_DEFAULT_ROOT_CHUNK(3); - InitRootChunk(); - // Draw again with nothing invalidated. - EXPECT_TRUE(ClientCacheIsValid(multicol)); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + // Draw again with nothing invalidated. + EXPECT_TRUE(ClientCacheIsValid(multicol)); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 200, 100, 100)); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); - EXPECT_EQ(1u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(1u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(1u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(1u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&multicol, kBackgroundType), @@ -1457,31 +1567,32 @@ .GetPaintRecord()); EXPECT_DEFAULT_ROOT_CHUNK(3); - InitRootChunk(); - // Now the multicol becomes 3 columns and repaints. - multicol.Invalidate(); - DrawRect(context, multicol, kBackgroundType, IntRect(100, 100, 100, 100)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + // Now the multicol becomes 3 columns and repaints. + multicol.Invalidate(); + DrawRect(context, multicol, kBackgroundType, IntRect(100, 100, 100, 100)); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect1); - DrawRect(context, content, kForegroundType, rect2); - DrawRect(context, content, kForegroundType, rect3); - GetPaintController().EndSkippingCache(); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect1); + DrawRect(context, content, kForegroundType, rect2); + DrawRect(context, content, kForegroundType, rect3); + GetPaintController().EndSkippingCache(); - // We should repaint everything on invalidation of the scope container. - const auto& display_item_list = - GetPaintController().GetNewPaintArtifactShared()->GetDisplayItemList(); - EXPECT_THAT(display_item_list, - ElementsAre(IsSameId(&multicol, kBackgroundType), - IsSameId(&content, kForegroundType), - IsSameId(&content, kForegroundType), - IsSameId(&content, kForegroundType))); - EXPECT_NE(record1, - To<DrawingDisplayItem>(display_item_list[1]).GetPaintRecord()); - EXPECT_NE(record2, - To<DrawingDisplayItem>(display_item_list[2]).GetPaintRecord()); - - CommitAndFinishCycle(); + // We should repaint everything on invalidation of the scope container. + const auto& display_item_list = + GetPaintController().GetNewPaintArtifactShared()->GetDisplayItemList(); + EXPECT_THAT(display_item_list, + ElementsAre(IsSameId(&multicol, kBackgroundType), + IsSameId(&content, kForegroundType), + IsSameId(&content, kForegroundType), + IsSameId(&content, kForegroundType))); + EXPECT_NE(record1, + To<DrawingDisplayItem>(display_item_list[1]).GetPaintRecord()); + EXPECT_NE(record2, + To<DrawingDisplayItem>(display_item_list[2]).GetPaintRecord()); + } EXPECT_DEFAULT_ROOT_CHUNK(4); } @@ -1493,14 +1604,15 @@ IntRect rect2(150, 100, 50, 50); IntRect rect3(200, 100, 50, 50); - InitRootChunk(); - DrawRect(context, content, kBackgroundType, rect1); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); - DrawRect(context, content, kForegroundType, rect3); - - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, content, kBackgroundType, rect1); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + DrawRect(context, content, kForegroundType, rect3); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content, kBackgroundType), @@ -1522,23 +1634,24 @@ EXPECT_EQ(PaintInvalidationReason::kUncacheable, content.GetPaintInvalidationReason()); - InitRootChunk(); - // Draw again with nothing invalidated. - DrawRect(context, content, kBackgroundType, rect1); - GetPaintController().BeginSkippingCache(); - DrawRect(context, content, kForegroundType, rect2); - GetPaintController().EndSkippingCache(); - DrawRect(context, content, kForegroundType, rect3); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + // Draw again with nothing invalidated. + DrawRect(context, content, kBackgroundType, rect1); + GetPaintController().BeginSkippingCache(); + DrawRect(context, content, kForegroundType, rect2); + GetPaintController().EndSkippingCache(); + DrawRect(context, content, kForegroundType, rect3); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - EXPECT_EQ(0u, NumIndexedItems()); - EXPECT_EQ(0u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + EXPECT_EQ(0u, NumIndexedItems()); + EXPECT_EQ(0u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&content, kBackgroundType), @@ -1562,17 +1675,18 @@ PaintChunk::Id chunk_id(chunk_client, DisplayItem::kLayerChunk); auto& paint_controller = GetPaintController(); - GraphicsContext context(paint_controller); - paint_controller.BeginSkippingCache(); - paint_controller.SetWillForceNewChunk(true); - paint_controller.UpdateCurrentPaintChunkProperties(&chunk_id, properties); - DrawRect(context, item_client, kBackgroundType, IntRect(0, 0, 100, 100)); - paint_controller.SetWillForceNewChunk(true); - paint_controller.UpdateCurrentPaintChunkProperties(&chunk_id, properties); - DrawRect(context, item_client, kBackgroundType, IntRect(0, 0, 100, 100)); - paint_controller.EndSkippingCache(); - - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(paint_controller); + GraphicsContext context(paint_controller); + paint_controller.BeginSkippingCache(); + paint_controller.SetWillForceNewChunk(true); + paint_controller.UpdateCurrentPaintChunkProperties(&chunk_id, properties); + DrawRect(context, item_client, kBackgroundType, IntRect(0, 0, 100, 100)); + paint_controller.SetWillForceNewChunk(true); + paint_controller.UpdateCurrentPaintChunkProperties(&chunk_id, properties); + DrawRect(context, item_client, kBackgroundType, IntRect(0, 0, 100, 100)); + paint_controller.EndSkippingCache(); + } EXPECT_THAT(paint_controller.GetDisplayItemList(), ElementsAre(IsSameId(&item_client, kBackgroundType), @@ -1590,15 +1704,15 @@ TEST_P(PaintControllerTest, SmallPaintControllerHasOnePaintChunk) { FakeDisplayItemClient client("test client"); - InitRootChunk(); - GraphicsContext context(GetPaintController()); - DrawRect(context, client, kBackgroundType, IntRect(0, 0, 100, 100)); - - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + GraphicsContext context(GetPaintController()); + DrawRect(context, client, kBackgroundType, IntRect(0, 0, 100, 100)); + } EXPECT_THAT(GetPaintController().PaintChunks(), ElementsAre(IsPaintChunk(0, 1))); } - void DrawPath(GraphicsContext& context, DisplayItemClient& client, DisplayItem::Type type, @@ -1671,15 +1785,17 @@ FakeDisplayItemClient fourth("fourth"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); - EXPECT_EQ(0u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); - CommitAndFinishCycle(); + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), IsSameId(&second, kBackgroundType), @@ -1692,20 +1808,21 @@ // Simulate that a composited scrolling element is scrolled down, and "first" // and "second" are scrolled out of the interest rect. - InitRootChunk(); - DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - // We indexed "first" and "second" when finding the cached item for "third". - EXPECT_EQ(2u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + // We indexed "first" and "second" when finding the cached item for "third". + EXPECT_EQ(2u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&third, kBackgroundType), IsSameId(&fourth, kBackgroundType))); @@ -1715,22 +1832,23 @@ EXPECT_TRUE(fourth.IsValid()); // Simulate "first" and "second" are scrolled back into the interest rect. - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); - DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); - DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); - DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(100, 100, 300, 300)); + DrawRect(context, second, kBackgroundType, IntRect(100, 100, 200, 200)); + DrawRect(context, third, kBackgroundType, IntRect(100, 100, 100, 100)); + DrawRect(context, fourth, kBackgroundType, IntRect(100, 100, 50, 50)); - EXPECT_EQ(2u, NumCachedNewItems()); - EXPECT_EQ(0u, NumCachedNewSubsequences()); + EXPECT_EQ(2u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); #if DCHECK_IS_ON() - // We indexed "third" and "fourth" when finding the cached item for "first". - EXPECT_EQ(2u, NumIndexedItems()); - EXPECT_EQ(2u, NumSequentialMatches()); - EXPECT_EQ(0u, NumOutOfOrderMatches()); + // We indexed "third" and "fourth" when finding the cached item for "first". + EXPECT_EQ(2u, NumIndexedItems()); + EXPECT_EQ(2u, NumSequentialMatches()); + EXPECT_EQ(0u, NumOutOfOrderMatches()); #endif - - CommitAndFinishCycle(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&first, kBackgroundType), IsSameId(&second, kBackgroundType), @@ -1767,25 +1885,28 @@ EXPECT_TRUE(cacheable.IsCacheable()); EXPECT_FALSE(uncacheable.IsCacheable()); - InitRootChunk(); { - SubsequenceRecorder recorder(context, cacheable); - DrawRect(context, cacheable, kBackgroundType, IntRect(r)); - DrawRect(context, uncacheable, kBackgroundType, IntRect(r)); - // This should not trigger the duplicated id assert. - DrawRect(context, uncacheable, kBackgroundType, IntRect(r)); + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder recorder(context, cacheable); + DrawRect(context, cacheable, kBackgroundType, IntRect(r)); + DrawRect(context, uncacheable, kBackgroundType, IntRect(r)); + // This should not trigger the duplicated id assert. + DrawRect(context, uncacheable, kBackgroundType, IntRect(r)); + } } - - CommitAndFinishCycle(); EXPECT_TRUE(GetPaintController().GetDisplayItemList()[0].IsCacheable()); EXPECT_FALSE(GetPaintController().GetDisplayItemList()[1].IsCacheable()); EXPECT_FALSE(GetPaintController().GetDisplayItemList()[2].IsCacheable()); EXPECT_TRUE(cacheable.IsCacheable()); EXPECT_FALSE(uncacheable.IsCacheable()); - InitRootChunk(); - EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(cacheable)); - CommitAndFinishCycle(); + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(cacheable)); + } EXPECT_TRUE(GetPaintController().GetDisplayItemList()[0].IsCacheable()); EXPECT_FALSE(GetPaintController().GetDisplayItemList()[1].IsCacheable()); EXPECT_FALSE(GetPaintController().GetDisplayItemList()[2].IsCacheable()); @@ -1798,19 +1919,22 @@ TEST_P(PaintControllerTest, DuplicatedSubsequences) { FakeDisplayItemClient client("test"); - GraphicsContext context(GetPaintController()); + PaintController& controller = GetPaintController(); + GraphicsContext context(controller); auto paint_duplicated_subsequences = [&]() { - InitRootChunk(); { - SubsequenceRecorder r(context, client); - DrawRect(context, client, kBackgroundType, IntRect(100, 100, 100, 100)); + CommitCycleScope cycle_scope(controller); + InitRootChunk(); + { + SubsequenceRecorder r(context, client); + DrawRect(context, client, kBackgroundType, IntRect(100, 100, 100, 100)); + } + { + SubsequenceRecorder r(context, client); + DrawRect(context, client, kForegroundType, IntRect(100, 100, 100, 100)); + } } - { - SubsequenceRecorder r(context, client); - DrawRect(context, client, kForegroundType, IntRect(100, 100, 100, 100)); - } - CommitAndFinishCycle(); }; #if DCHECK_IS_ON() @@ -1818,27 +1942,29 @@ "Multiple subsequences for client: \"test\""); #else // The following is for non-DCHECK path. No security CHECK should trigger. - paint_duplicated_subsequences(); - // Paint again. - InitRootChunk(); - if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - EXPECT_FALSE(GetPaintController().UseCachedSubsequenceIfPossible(client)); - SubsequenceRecorder r(context, client); - DrawRect(context, client, kBackgroundType, IntRect(100, 100, 100, 100)); - } else { - EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(client)); - } { - // Should not use the cached duplicated subsequence. - EXPECT_FALSE(GetPaintController().UseCachedSubsequenceIfPossible(client)); - SubsequenceRecorder r(context, client); - DrawRect(context, client, kForegroundType, IntRect(100, 100, 100, 100)); + CommitCycleScope cycle_scope(GetPaintController()); + paint_duplicated_subsequences(); + // Paint again. + InitRootChunk(); + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { + EXPECT_FALSE(GetPaintController().UseCachedSubsequenceIfPossible(client)); + SubsequenceRecorder r(context, client); + DrawRect(context, client, kBackgroundType, IntRect(100, 100, 100, 100)); + } else { + EXPECT_TRUE(GetPaintController().UseCachedSubsequenceIfPossible(client)); + } + { + // Should not use the cached duplicated subsequence. + EXPECT_FALSE(GetPaintController().UseCachedSubsequenceIfPossible(client)); + SubsequenceRecorder r(context, client); + DrawRect(context, client, kForegroundType, IntRect(100, 100, 100, 100)); + } } - CommitAndFinishCycle(); #endif } -TEST_P(PaintControllerTest, DeletedClientInUnderInvaldiatedSubsequence) { +TEST_P(PaintControllerTest, DeletedClientInUnderInvalidatedSubsequence) { if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) return; @@ -1846,26 +1972,30 @@ auto content = std::make_unique<FakeDisplayItemClient>("content"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, container); - DrawRect(context, *content, kBackgroundType, IntRect(100, 100, 300, 300)); + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, container); + DrawRect(context, *content, kBackgroundType, IntRect(100, 100, 300, 300)); + } } - CommitAndFinishCycle(); content = nullptr; - InitRootChunk(); - // Leave container not invalidated. + { + CommitCycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + // Leave container not invalidated. #if DCHECK_IS_ON() - ASSERT_DEATH( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container), - ""); + ASSERT_DEATH( + SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container), + ""); #else - // This should not crash. - EXPECT_TRUE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container)); - CommitAndFinishCycle(); + // This should not crash. + EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, + container)); #endif + } } #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h index ca7223d5..f8839d0 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h
@@ -80,11 +80,6 @@ void InvalidateAll() { paint_controller_->InvalidateAllForTesting(); } - void CommitAndFinishCycle() { - paint_controller_->CommitNewDisplayItems(); - paint_controller_->FinishCycle(); - } - using SubsequenceMarkers = PaintController::SubsequenceMarkers; const SubsequenceMarkers* GetSubsequenceMarkers( const DisplayItemClient& client) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc b/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc index bfb86a5..a161110e 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
@@ -20,16 +20,13 @@ } PaintRecordBuilder::PaintRecordBuilder(PaintController& paint_controller) - : paint_controller_(&paint_controller), context_(*paint_controller_) { - paint_controller.ReserveCapacity(); -} + : paint_controller_(&paint_controller), context_(*paint_controller_) {} PaintRecordBuilder::~PaintRecordBuilder() = default; sk_sp<PaintRecord> PaintRecordBuilder::EndRecording( const PropertyTreeState& replay_state) { paint_controller_->CommitNewDisplayItems(); - paint_controller_->FinishCycle(); return paint_controller_->GetPaintArtifact().GetPaintRecord(replay_state); }
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc b/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc index efd5eb3cc..c7829348 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc
@@ -36,34 +36,40 @@ } TEST_F(PaintRecordBuilderTest, LastingPaintController) { - InitRootChunk(); - + FakeDisplayItemClient client("client"); PaintRecordBuilder builder(GetPaintController()); auto& context = builder.Context(); - EXPECT_EQ(&context.GetPaintController(), &GetPaintController()); - - FakeDisplayItemClient client("client"); - DrawRect(context, client, kBackgroundType, IntRect(10, 10, 20, 20)); - DrawRect(context, client, kForegroundType, IntRect(15, 15, 10, 10)); - EXPECT_FALSE(ClientCacheIsValid(client)); - MockPaintCanvas canvas; PaintFlags flags; - EXPECT_CALL(canvas, drawPicture(_)).Times(1); - builder.EndRecording(canvas); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + + EXPECT_EQ(&context.GetPaintController(), &GetPaintController()); + + DrawRect(context, client, kBackgroundType, IntRect(10, 10, 20, 20)); + DrawRect(context, client, kForegroundType, IntRect(15, 15, 10, 10)); + EXPECT_FALSE(ClientCacheIsValid(client)); + + EXPECT_CALL(canvas, drawPicture(_)).Times(1); + builder.EndRecording(canvas); + } EXPECT_TRUE(ClientCacheIsValid(client)); EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType), IsSameId(&client, kForegroundType))); - InitRootChunk(); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, client, - kBackgroundType)); - EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, client, - kForegroundType)); - EXPECT_CALL(canvas, drawPicture(_)).Times(1); - builder.EndRecording(canvas); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, client, + kBackgroundType)); + EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, client, + kForegroundType)); + EXPECT_CALL(canvas, drawPicture(_)).Times(1); + builder.EndRecording(canvas); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType), @@ -73,21 +79,27 @@ TEST_F(PaintRecordBuilderTest, TransientAndAnotherPaintController) { GraphicsContext context(GetPaintController()); - - InitRootChunk(); FakeDisplayItemClient client("client"); - DrawRect(context, client, kBackgroundType, IntRect(10, 10, 20, 20)); - DrawRect(context, client, kForegroundType, IntRect(15, 15, 10, 10)); - CommitAndFinishCycle(); + PaintRecordBuilder builder; + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, client, kBackgroundType, IntRect(10, 10, 20, 20)); + DrawRect(context, client, kForegroundType, IntRect(15, 15, 10, 10)); + GetPaintController().CommitNewDisplayItems(); + } EXPECT_THAT(GetPaintController().GetDisplayItemList(), ElementsAre(IsSameId(&client, kBackgroundType), IsSameId(&client, kForegroundType))); EXPECT_TRUE(ClientCacheIsValid(client)); - PaintRecordBuilder builder; - EXPECT_NE(&builder.Context().GetPaintController(), &GetPaintController()); - DrawRect(builder.Context(), client, kBackgroundType, IntRect(10, 10, 20, 20)); - builder.EndRecording(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + EXPECT_NE(&builder.Context().GetPaintController(), &GetPaintController()); + DrawRect(builder.Context(), client, kBackgroundType, + IntRect(10, 10, 20, 20)); + builder.EndRecording(); + } // The transient PaintController in PaintRecordBuilder doesn't affect the // client's cache status in another PaintController.
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker_test.cc b/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker_test.cc index 1b22a95..f93aba6 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker_test.cc
@@ -29,15 +29,21 @@ FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + GetPaintController().CommitNewDisplayItems(); + } - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(2, 2, 3, 3)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(2, 2, 3, 3)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + GetPaintController().CommitNewDisplayItems(); + } }; EXPECT_DEATH(test(), @@ -55,14 +61,20 @@ FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + GetPaintController().CommitNewDisplayItems(); + } - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + GetPaintController().CommitNewDisplayItems(); + } } TEST_F(PaintControllerUnderInvalidationTest, LessDrawing) { @@ -71,37 +83,49 @@ FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + GetPaintController().CommitNewDisplayItems(); + } - InitRootChunk(); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - CommitAndFinishCycle(); + { + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + GetPaintController().CommitNewDisplayItems(); + } } TEST_F(PaintControllerUnderInvalidationTest, ChangeDrawingInSubsequence) { auto test = [&]() { FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, first)); - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(2, 2, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, first)); + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(2, 2, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); }; EXPECT_DEATH(test(), @@ -119,22 +143,28 @@ FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, first)); - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, first)); + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 1, 1)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); }; EXPECT_DEATH(test(), @@ -151,22 +181,28 @@ FakeDisplayItemClient first("first"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 3, 3)); - DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 3, 3)); + DrawRect(context, first, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, first)); - SubsequenceRecorder r(context, first); - DrawRect(context, first, kBackgroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, first)); + SubsequenceRecorder r(context, first); + DrawRect(context, first, kBackgroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); }; EXPECT_DEATH(test(), @@ -182,23 +218,29 @@ FakeDisplayItemClient content("content"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, container); - DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, container); + DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); content.Invalidate(); - InitRootChunk(); - // Leave container not invalidated. { - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container)); - SubsequenceRecorder r(context, container); - DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + // Leave container not invalidated. + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container)); + SubsequenceRecorder r(context, container); + DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); } TEST_F(PaintControllerUnderInvalidationTest, SubsequenceBecomesEmpty) { @@ -206,20 +248,26 @@ FakeDisplayItemClient target("target"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, target); - DrawRect(context, target, kBackgroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, target); + DrawRect(context, target, kBackgroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, target)); - SubsequenceRecorder r(context, target); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, target)); + SubsequenceRecorder r(context, target); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); }; EXPECT_DEATH(test(), @@ -232,29 +280,35 @@ FakeDisplayItemClient content("content"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, container); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); { - DisplayItemCacheSkipper cache_skipper(context); - DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + SubsequenceRecorder r(context, container); + { + DisplayItemCacheSkipper cache_skipper(context); + DrawRect(context, content, kBackgroundType, IntRect(1, 1, 3, 3)); + } + DrawRect(context, content, kForegroundType, IntRect(2, 2, 4, 4)); } - DrawRect(context, content, kForegroundType, IntRect(2, 2, 4, 4)); + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container)); - SubsequenceRecorder r(context, container); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); { - DisplayItemCacheSkipper cache_skipper(context); - DrawRect(context, content, kBackgroundType, IntRect(2, 2, 4, 4)); + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container)); + SubsequenceRecorder r(context, container); + { + DisplayItemCacheSkipper cache_skipper(context); + DrawRect(context, content, kBackgroundType, IntRect(2, 2, 4, 4)); + } + DrawRect(context, content, kForegroundType, IntRect(2, 2, 4, 4)); } - DrawRect(context, content, kForegroundType, IntRect(2, 2, 4, 4)); + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); } TEST_F(PaintControllerUnderInvalidationTest, @@ -263,27 +317,33 @@ FakeDisplayItemClient content("content"); GraphicsContext context(GetPaintController()); - InitRootChunk(); { - SubsequenceRecorder r(context, container); - DrawRect(context, container, kBackgroundType, IntRect(1, 1, 3, 3)); - { SubsequenceRecorder r1(context, content); } - DrawRect(context, container, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + SubsequenceRecorder r(context, container); + DrawRect(context, container, kBackgroundType, IntRect(1, 1, 3, 3)); + { SubsequenceRecorder r1(context, content); } + DrawRect(context, container, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); - InitRootChunk(); { - EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( - context, container)); - SubsequenceRecorder r(context, container); - DrawRect(context, container, kBackgroundType, IntRect(1, 1, 3, 3)); - EXPECT_FALSE( - SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, content)); - { SubsequenceRecorder r1(context, content); } - DrawRect(context, container, kForegroundType, IntRect(1, 1, 3, 3)); + PaintController::CycleScope cycle_scope(GetPaintController()); + InitRootChunk(); + { + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, container)); + SubsequenceRecorder r(context, container); + DrawRect(context, container, kBackgroundType, IntRect(1, 1, 3, 3)); + EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible( + context, content)); + { SubsequenceRecorder r1(context, content); } + DrawRect(context, container, kForegroundType, IntRect(1, 1, 3, 3)); + } + GetPaintController().CommitNewDisplayItems(); } - CommitAndFinishCycle(); } #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/third_party/blink/renderer/platform/graphics/paint/subsequence_recorder.h b/third_party/blink/renderer/platform/graphics/paint/subsequence_recorder.h index b8a22435..9781d7e9 100644 --- a/third_party/blink/renderer/platform/graphics/paint/subsequence_recorder.h +++ b/third_party/blink/renderer/platform/graphics/paint/subsequence_recorder.h
@@ -37,6 +37,7 @@ SubsequenceRecorder(GraphicsContext& context, const DisplayItemClient& client) : paint_controller_(context.GetPaintController()) { subsequence_index_ = paint_controller_.BeginSubsequence(client); + paint_controller_.MarkClientForValidation(client); } SubsequenceRecorder(const SubsequenceRecorder&) = delete;
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.h b/third_party/blink/renderer/platform/loader/fetch/raw_resource.h index e13e7fc..3608238f 100644 --- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
@@ -40,9 +40,7 @@ class RawResourceClient; class ResourceFetcher; -// TODO(chromium:1210399): Make RawResource final again once -// ResourceLoaderCodeCacheTest is moved to blink_unittests. -class PLATFORM_EXPORT RawResource : public Resource { +class PLATFORM_EXPORT RawResource final : public Resource { public: static RawResource* FetchSynchronously(FetchParameters&, ResourceFetcher*,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h index af5d5d36..b9816c50 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -275,9 +275,6 @@ // Gets whether the serialized cached metadata must contain a hash of the // source text. For resources other than ScriptResource, this is always false. - // TODO(chromium:1210399): This can be true in non-ScriptResource in unit - // tests. Fix this once ResourceLoaderCodeCacheTest is moved to - // blink_unittests. virtual bool CodeCacheHashRequired() const; AtomicString HttpContentType() const;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc index e6ff4ec5..09fd868f 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
@@ -29,8 +29,8 @@ #include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h" #include "third_party/blink/renderer/platform/testing/code_cache_loader_mock.h" #include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h" +#include "third_party/blink/renderer/platform/testing/noop_web_url_loader.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h" -#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -78,8 +78,7 @@ const KURL foo_url_; const KURL bar_url_; - class NoopLoaderFactory : public ResourceFetcher::LoaderFactory { - public: + class NoopLoaderFactory final : public ResourceFetcher::LoaderFactory { std::unique_ptr<WebURLLoader> CreateURLLoader( const ResourceRequest& request, const ResourceLoaderOptions& options, @@ -101,61 +100,13 @@ ResourceFetcher* MakeResourceFetcher( TestResourceFetcherProperties* properties, - FetchContext* context, - ResourceFetcher::LoaderFactory* loader_factory = nullptr) { + FetchContext* context) { return MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit( properties->MakeDetachable(), context, CreateTaskRunner(), - CreateTaskRunner(), - loader_factory ? loader_factory - : MakeGarbageCollected<NoopLoaderFactory>(), + CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(), MakeGarbageCollected<MockContextLifecycleNotifier>(), nullptr /* back_forward_cache_loader_helper */)); } - - private: - class NoopWebURLLoader final : public WebURLLoader { - public: - explicit NoopWebURLLoader( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : task_runner_(task_runner) {} - ~NoopWebURLLoader() override = default; - void LoadSynchronously( - std::unique_ptr<network::ResourceRequest> request, - scoped_refptr<WebURLRequestExtraData> url_request_extra_data, - bool pass_response_pipe_to_client, - bool no_mime_sniffing, - base::TimeDelta timeout_interval, - WebURLLoaderClient*, - WebURLResponse&, - absl::optional<WebURLError>&, - WebData&, - int64_t& encoded_data_length, - int64_t& encoded_body_length, - WebBlobInfo& downloaded_blob, - std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> - resource_load_info_notifier_wrapper) override { - NOTREACHED(); - } - void LoadAsynchronously( - std::unique_ptr<network::ResourceRequest> request, - scoped_refptr<WebURLRequestExtraData> url_request_extra_data, - bool no_mime_sniffing, - std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> - resource_load_info_notifier_wrapper, - WebURLLoaderClient*) override {} - - void Freeze(LoaderFreezeMode) override {} - void DidChangePriority(WebURLRequest::Priority, int) override { - NOTREACHED(); - } - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForBodyLoader() - override { - return task_runner_; - } - - private: - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - }; }; std::ostream& operator<<(std::ostream& o, const ResourceLoaderTest::From& f) { @@ -841,203 +792,4 @@ ExpectHistogramsMatching(info); } -// TODO(chromium:1210399): Move this to blink_unittests and use ScriptResource. -class ResourceLoaderCodeCacheTest : public ResourceLoaderTest { - public: - ResourceLoaderCodeCacheTest() = default; - - protected: - class CodeCacheTestLoaderFactory final : public NoopLoaderFactory { - public: - explicit CodeCacheTestLoaderFactory( - scoped_refptr<CodeCacheLoaderMock::Controller> controller) - : controller_(std::move(controller)) {} - std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override { - return std::make_unique<CodeCacheLoaderMock>(controller_); - } - - private: - scoped_refptr<CodeCacheLoaderMock::Controller> controller_; - }; - - // A version of RawResource that overrides a few virtual methods so that we - // can observe how ResourceLoader is calling functions on its Resource. - class TestRawResource : public RawResource { - public: - TestRawResource(const ResourceRequest& resource_request, - ResourceType type, - const ResourceLoaderOptions& options) - : RawResource(resource_request, type, options) {} - - bool CodeCacheHashRequired() const override { - return code_cache_hash_required_; - } - void SetSerializedCachedMetadata(mojo_base::BigBuffer data) override { - cached_metadata_ = std::move(data); - } - - const mojo_base::BigBuffer* CachedMetadata() { - return cached_metadata_ ? &*cached_metadata_ : nullptr; - } - - void SetCodeCacheHashRequired(bool code_cache_hash_required) { - code_cache_hash_required_ = code_cache_hash_required; - } - - private: - bool code_cache_hash_required_ = false; - absl::optional<mojo_base::BigBuffer> cached_metadata_; - }; - - class TestRawResourceFactory : public NonTextResourceFactory { - public: - TestRawResourceFactory() : NonTextResourceFactory(ResourceType::kScript) {} - - Resource* Create(const ResourceRequest& request, - const ResourceLoaderOptions& options) const override { - return MakeGarbageCollected<TestRawResource>(request, type_, options); - } - }; - - // All relevant variables after running CommonSetup. - struct State { - STACK_ALLOCATED(); - - public: - TestRawResource* resource; - ResourceLoader* loader; - ResourceResponse response; - scoped_refptr<CodeCacheLoaderMock::Controller> controller; - }; - - State CommonSetup(const char* url_string = nullptr) { - SchemeRegistry::RegisterURLSchemeAsCodeCacheWithHashing( - "codecachewithhashing"); - - State state; - auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); - FetchContext* context = MakeGarbageCollected<MockFetchContext>(); - state.controller = base::MakeRefCounted<CodeCacheLoaderMock::Controller>(); - state.controller->DelayResponse(); - auto* loader_factory = - MakeGarbageCollected<CodeCacheTestLoaderFactory>(state.controller); - auto* fetcher = MakeResourceFetcher(properties, context, loader_factory); - - KURL url(url_string ? url_string - : "codecachewithhashing://www.example.com/"); - ResourceRequest request(url); - request.SetRequestContext(mojom::blink::RequestContextType::SCRIPT); - - FetchParameters params = FetchParameters::CreateForTest(std::move(request)); - state.resource = static_cast<TestRawResource*>( - fetcher->RequestResource(params, TestRawResourceFactory(), nullptr)); - state.resource->SetCodeCacheHashRequired(true); - state.loader = state.resource->Loader(); - - state.response = ResourceResponse(url); - state.response.SetHttpStatusCode(200); - - return state; - } -}; - -TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheEmptyResponseFirst) { - State state = CommonSetup(); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // Nothing has changed yet because the code cache hasn't yet responded. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - // An empty code cache response means no data was found. - state.controller->Respond(base::Time(), mojo_base::BigBuffer()); - - // No code cache data was present. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); -} - -TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheEmptyResponseSecond) { - State state = CommonSetup(); - - // An empty code cache response means no data was found. - state.controller->Respond(base::Time(), mojo_base::BigBuffer()); - - // Nothing has changed yet because the content response hasn't arrived yet. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // No code cache data was present. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); -} - -TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullResponseFirst) { - State state = CommonSetup(); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // Nothing has changed yet because the code cache hasn't yet responded. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - const uint8_t data[] = {2, 3, 4, 5}; - state.controller->Respond(base::Time(), mojo_base::BigBuffer(data)); - - // Code cache data was present. - ASSERT_TRUE(state.resource->CachedMetadata()); - EXPECT_EQ(state.resource->CachedMetadata()->size(), 4UL); - EXPECT_EQ(state.resource->CachedMetadata()->data()[3], 5UL); -} - -TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullResponseSecond) { - State state = CommonSetup(); - - const uint8_t data[] = {2, 3, 4, 5}; - state.controller->Respond(base::Time(), mojo_base::BigBuffer(data)); - - // Nothing has changed yet because the content response hasn't arrived yet. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // Code cache data was present. - ASSERT_TRUE(state.resource->CachedMetadata()); - EXPECT_EQ(state.resource->CachedMetadata()->size(), 4UL); - EXPECT_EQ(state.resource->CachedMetadata()->data()[3], 5UL); -} - -TEST_F(ResourceLoaderCodeCacheTest, - WebUICodeCacheFullResponseSecondResourceDoesNotSupportHashing) { - State state = CommonSetup(); - state.resource->SetCodeCacheHashRequired(false); - - const uint8_t data[] = {2, 3, 4, 5}; - state.controller->Respond(base::Time(), mojo_base::BigBuffer(data)); - - // Nothing has changed yet because the content response hasn't arrived yet. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // Since the Resource didn't specify that a hash check is required, - // the cached metadata should not be set. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); -} - -TEST_F(ResourceLoaderCodeCacheTest, - WebUICodeCacheFullResponseSecondHttpsScheme) { - State state = CommonSetup("https://www.example.com/"); - - const uint8_t data[] = {2, 3, 4, 5}; - state.controller->Respond(base::Time(), mojo_base::BigBuffer(data)); - - // Nothing has changed yet because the content response hasn't arrived yet. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); - - state.loader->DidReceiveResponse(WrappedResourceResponse(state.response)); - - // Since the URL was https, and the response times were not set, the cached - // metadata should not be set. - EXPECT_EQ(state.resource->CachedMetadata(), nullptr); -} - } // namespace blink
diff --git a/third_party/blink/renderer/platform/media/key_system_config_selector.cc b/third_party/blink/renderer/platform/media/key_system_config_selector.cc index ec2da87..373c03c 100644 --- a/third_party/blink/renderer/platform/media/key_system_config_selector.cc +++ b/third_party/blink/renderer/platform/media/key_system_config_selector.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/bind.h" +#include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" @@ -18,6 +19,7 @@ #include "media/base/key_systems.h" #include "media/base/logging_override_if_enabled.h" #include "media/base/media_permission.h" +#include "media/base/media_switches.h" #include "media/base/mime_util.h" #include "media/media_buildflags.h" #include "third_party/blink/public/platform/web_content_settings_client.h" @@ -168,7 +170,13 @@ // avoid asking IsSupported*MediaFormat() about HEVC. EME support for HEVC // profiles is described via KeySystemProperties::GetSupportedCodecs(). // TODO(1156282): Decouple the rest of clear vs EME codec support. - if (!use_aes_decryptor && +#if BUILDFLAG(IS_CHROMEOS_LACROS) + const bool allow_hevc = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosEnablePlatformEncryptedHevc); +#else + const bool allow_hevc = true; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + if (allow_hevc && !use_aes_decryptor && base::ToLowerASCII(container_mime_type) == "video/mp4" && !codec_vector.empty()) { auto it = codec_vector.begin();
diff --git a/third_party/blink/renderer/platform/testing/noop_web_url_loader.cc b/third_party/blink/renderer/platform/testing/noop_web_url_loader.cc new file mode 100644 index 0000000..a744186 --- /dev/null +++ b/third_party/blink/renderer/platform/testing/noop_web_url_loader.cc
@@ -0,0 +1,39 @@ +// Copyright 2021 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/platform/testing/noop_web_url_loader.h" + +#include "services/network/public/cpp/resource_request.h" +#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h" +#include "third_party/blink/public/platform/web_url_request_extra_data.h" + +namespace blink { + +void NoopWebURLLoader::LoadSynchronously( + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<WebURLRequestExtraData> url_request_extra_data, + bool pass_response_pipe_to_client, + bool no_mime_sniffing, + base::TimeDelta timeout_interval, + WebURLLoaderClient*, + WebURLResponse&, + absl::optional<WebURLError>&, + WebData&, + int64_t& encoded_data_length, + int64_t& encoded_body_length, + WebBlobInfo& downloaded_blob, + std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> + resource_load_info_notifier_wrapper) { + NOTREACHED(); +} + +void NoopWebURLLoader::LoadAsynchronously( + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<WebURLRequestExtraData> url_request_extra_data, + bool no_mime_sniffing, + std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> + resource_load_info_notifier_wrapper, + WebURLLoaderClient*) {} + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/noop_web_url_loader.h b/third_party/blink/renderer/platform/testing/noop_web_url_loader.h new file mode 100644 index 0000000..7283c5e6 --- /dev/null +++ b/third_party/blink/renderer/platform/testing/noop_web_url_loader.h
@@ -0,0 +1,56 @@ +// Copyright 2021 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_PLATFORM_TESTING_NOOP_WEB_URL_LOADER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_NOOP_WEB_URL_LOADER_H_ + +#include "third_party/blink/public/platform/web_url_loader.h" + +namespace blink { + +class NoopWebURLLoader final : public WebURLLoader { + public: + explicit NoopWebURLLoader( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner) {} + ~NoopWebURLLoader() override = default; + void LoadSynchronously( + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<WebURLRequestExtraData> url_request_extra_data, + bool pass_response_pipe_to_client, + bool no_mime_sniffing, + base::TimeDelta timeout_interval, + WebURLLoaderClient*, + WebURLResponse&, + absl::optional<WebURLError>&, + WebData&, + int64_t& encoded_data_length, + int64_t& encoded_body_length, + WebBlobInfo& downloaded_blob, + std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> + resource_load_info_notifier_wrapper) override; + void LoadAsynchronously( + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<WebURLRequestExtraData> url_request_extra_data, + bool no_mime_sniffing, + std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> + resource_load_info_notifier_wrapper, + WebURLLoaderClient*) override; + + void Freeze(WebLoaderFreezeMode) override {} + void DidChangePriority(WebURLRequest::Priority, int) override { + NOTREACHED(); + } + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForBodyLoader() + override { + return task_runner_; + } + + private: + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_NOOP_WEB_URL_LOADER_H_
diff --git a/third_party/blink/renderer/platform/weborigin/security_policy.cc b/third_party/blink/renderer/platform/weborigin/security_policy.cc index 42210764..4ebbed3 100644 --- a/third_party/blink/renderer/platform/weborigin/security_policy.cc +++ b/third_party/blink/renderer/platform/weborigin/security_policy.cc
@@ -30,10 +30,15 @@ #include <memory> +#include "base/command_line.h" +#include "base/no_destructor.h" #include "base/strings/pattern.h" +#include "base/strings/string_split.h" +#include "build/build_config.h" #include "services/network/public/cpp/cors/origin_access_list.h" #include "services/network/public/mojom/referrer_policy.mojom-blink.h" #include "third_party/blink/public/common/loader/referrer_utils.h" +#include "third_party/blink/public/common/switches.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" @@ -306,4 +311,45 @@ return true; } +#if defined(OS_FUCHSIA) +namespace { +std::vector<url::Origin> GetSharedArrayBufferOrigins() { + std::string switch_value = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kSharedArrayBufferAllowedOrigins); + std::vector<std::string> list = + SplitString(switch_value, ",", base::WhitespaceHandling::TRIM_WHITESPACE, + base::SplitResult::SPLIT_WANT_NONEMPTY); + std::vector<url::Origin> result; + for (auto& origin : list) { + GURL url(origin); + if (!url.is_valid() || url.scheme() != url::kHttpsScheme) { + LOG(FATAL) << "Invalid --" << switches::kSharedArrayBufferAllowedOrigins + << " specified: " << switch_value; + } + result.push_back(url::Origin::Create(url)); + } + return result; +} +} // namespace +#endif // defined(OS_FUCHSIA) + +// static +bool SecurityPolicy::IsSharedArrayBufferAlwaysAllowedForOrigin( + const SecurityOrigin* security_origin) { +#if defined(OS_FUCHSIA) + static base::NoDestructor<std::vector<url::Origin>> allowed_origins( + GetSharedArrayBufferOrigins()); + url::Origin origin = security_origin->ToUrlOrigin(); + for (const url::Origin& allowed_origin : *allowed_origins) { + if (origin.scheme() == allowed_origin.scheme() && + origin.DomainIs(allowed_origin.host()) && + origin.port() == allowed_origin.port()) { + return true; + } + } +#endif + return false; +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/weborigin/security_policy.h b/third_party/blink/renderer/platform/weborigin/security_policy.h index 66a9ffa2..1a617c33 100644 --- a/third_party/blink/renderer/platform/weborigin/security_policy.h +++ b/third_party/blink/renderer/platform/weborigin/security_policy.h
@@ -95,6 +95,9 @@ const String& header_value, ReferrerPolicyLegacyKeywordsSupport, network::mojom::ReferrerPolicy* result); + + static bool IsSharedArrayBufferAlwaysAllowedForOrigin( + const SecurityOrigin* origin); }; } // namespace blink
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index fbdcec20..a8d3029 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1036,7 +1036,9 @@ 'third_party/blink/renderer/modules/mediasource/', ], 'allowed': [ + 'base::CommandLine', 'media::.+', + 'switches::kLacrosEnablePlatformEncryptedHevc', ] }, {
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/driver.py b/third_party/blink/tools/blinkpy/web_tests/port/driver.py index c073a8f..00848e8 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/driver.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/driver.py
@@ -486,7 +486,8 @@ # so that the rest of the error-handling code can deal with # this as if the test has simply crashed. - if self._port.get_option('initialize_webgpu_adapter_at_startup'): + if self._port.get_option( + 'initialize_webgpu_adapter_at_startup_timeout_ms'): return self._initialize_webgpu_adapter_at_startup(per_test_args) return True, None @@ -500,9 +501,11 @@ # startup to be slower (if the workaround is triggered via the # --initialize-webgpu-adapter-at-startup flag, right above in the # code in _start()). + init_timeout = self._port.get_option( + 'initialize_webgpu_adapter_at_startup_timeout_ms') startup_input = DriverInput( "wpt_internal/webgpu/000_run_me_first.html", - timeout=self._port.timeout_ms(), + timeout=init_timeout, image_hash=None, args=per_test_args) output = self._run_one_input(startup_input, start_time=time.time()) @@ -510,7 +513,7 @@ return True, None output.text = ('Failed to initialize WebGPU adapter at startup ' - 'via wpt_internal_webgpu/0000_run_me_first.html:\n' + + 'via wpt_internal_webgpu/000_run_me_first.html:\n' + output.text) return False, output
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py index 2a28b8b..dd67be6 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
@@ -551,8 +551,8 @@ optparse.make_option('--time-out-ms', help='Set the timeout for each test'), optparse.make_option( - '--initialize-webgpu-adapter-at-startup', - action='store_true', + '--initialize-webgpu-adapter-at-startup-timeout-ms', + type='float', help='Initialize WebGPU adapter before running any tests.'), optparse.make_option( '--wrapper',
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 5db61fb..3728130 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -1238,12 +1238,16 @@ # The no-layout-ng bot compiles without proprietary codecs. # Timeout due to https://github.com/web-platform-tests/wpt/issues/29373 +crbug.com/591099 external/wpt/webcodecs/audio-decoder.https.any.html [ Failure ] crbug.com/591099 external/wpt/webcodecs/audioDecoder-codec-specific.any.html?adts_aac [ Failure ] crbug.com/591099 external/wpt/webcodecs/audioDecoder-codec-specific.any.html?mp4_aac [ Failure ] +crbug.com/591099 external/wpt/webcodecs/video-decoder.https.any.html [ Failure ] crbug.com/591099 external/wpt/webcodecs/videoDecoder-codec-specific.any.html?h264_annexb [ Failure ] crbug.com/591099 external/wpt/webcodecs/videoDecoder-codec-specific.any.html?h264_avc [ Failure ] +crbug.com/591099 external/wpt/webcodecs/audio-decoder.https.any.worker.html [ Failure Timeout ] crbug.com/591099 external/wpt/webcodecs/audioDecoder-codec-specific.any.worker.html?adts_aac [ Failure Timeout ] crbug.com/591099 external/wpt/webcodecs/audioDecoder-codec-specific.any.worker.html?mp4_aac [ Failure Timeout ] +crbug.com/591099 external/wpt/webcodecs/video-decoder.https.any.worker.html [ Failure Timeout ] crbug.com/591099 external/wpt/webcodecs/videoDecoder-codec-specific.any.worker.html?h264_annexb [ Failure Timeout ] crbug.com/591099 external/wpt/webcodecs/videoDecoder-codec-specific.any.worker.html?h264_avc [ Failure Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic-expected.txt index 8e4257e..715d9e2 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic-expected.txt
@@ -2,7 +2,7 @@ FAIL setTimeout should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/imports-a.js?label=setTimeout" PASS eval should successfully import PASS Function should successfully import -FAIL reflected-inline-event-handlers should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=reflected-inline-event-handlers" -FAIL inline-event-handlers-UA-code should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=inline-event-handlers-UA-code" +PASS reflected-inline-event-handlers should successfully import +PASS inline-event-handlers-UA-code should successfully import Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module-expected.txt index 8e4257e..715d9e2 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module-expected.txt
@@ -2,7 +2,7 @@ FAIL setTimeout should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/imports-a.js?label=setTimeout" PASS eval should successfully import PASS Function should successfully import -FAIL reflected-inline-event-handlers should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=reflected-inline-event-handlers" -FAIL inline-event-handlers-UA-code should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=inline-event-handlers-UA-code" +PASS reflected-inline-event-handlers should successfully import +PASS inline-event-handlers-UA-code should successfully import Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic-expected.txt index bb78d07..fe32f25 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic-expected.txt
@@ -2,7 +2,7 @@ FAIL setTimeout should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/imports-a.js?label=setTimeout" PASS eval should successfully import PASS the Function constructor should successfully import -FAIL reflected inline event handlers should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=reflected%20inline%20event%20handlers" -FAIL inline event handlers triggered via UA code should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=inline%20event%20handlers%20triggered%20via%20UA%20code" +PASS reflected inline event handlers should successfully import +PASS inline event handlers triggered via UA code should successfully import Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module-expected.txt index bb78d07..fe32f25 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module-expected.txt
@@ -2,7 +2,7 @@ FAIL setTimeout should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/imports-a.js?label=setTimeout" PASS eval should successfully import PASS the Function constructor should successfully import -FAIL reflected inline event handlers should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=reflected%20inline%20event%20handlers" -FAIL inline event handlers triggered via UA code should successfully import promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch dynamically imported module: http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/dynamic-import/imports-a.js?label=inline%20event%20handlers%20triggered%20via%20UA%20code" +PASS reflected inline event handlers should successfully import +PASS inline event handlers triggered via UA code should successfully import Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js new file mode 100644 index 0000000..a5cb478 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js
@@ -0,0 +1,44 @@ +// META: global=window +// META: script=/common/media.js +// META: script=/webcodecs/utils.js + +var defaultInit = { + timestamp: 1234, + channels: 2, + sampleRate: 8000, + frames: 1, +}; + +function testAudioData(useView) { + let localData = + new SharedArrayBuffer(defaultInit.channels * defaultInit.frames * 4); + let view = new Float32Array(localData); + view[0] = -1.0; + view[1] = 1.0; + + let audio_data_init = { + timestamp: defaultInit.timestamp, + data: useView ? view : localData, + numberOfFrames: defaultInit.frames, + numberOfChannels: defaultInit.channels, + sampleRate: defaultInit.sampleRate, + format: 'f32-planar', + } + + let data = new AudioData(audio_data_init); + + let copyDest = new SharedArrayBuffer(data.allocationSize({planeIndex: 0})); + let destView = new Float32Array(copyDest); + data.copyTo(useView ? destView : copyDest, {planeIndex: 0}); + assert_equals(destView[0], -1.0, 'copyDest[0]'); + data.copyTo(useView ? destView : copyDest, {planeIndex: 1}); + assert_equals(destView[0], 1.0, 'copyDest[1]'); +} + +test(t => { + testAudioData(/*useView=*/ false); +}, 'Test construction and copyTo() using a SharedArrayBuffer'); + +test(t => { + testAudioData(/*useView=*/ true); +}, 'Test construction and copyTo() using a Uint8Array(SharedArrayBuffer)');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js.headers b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js.headers new file mode 100644 index 0000000..5f8621ef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.https.any.js.headers
@@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js new file mode 100644 index 0000000..a13fb87 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js
@@ -0,0 +1,70 @@ +// META: global=window,dedicatedworker +// META: script=/webcodecs/utils.js + +const testData = { + src: 'sfx-aac.mp4', + config: { + codec: 'mp4a.40.2', + sampleRate: 48000, + numberOfChannels: 1, + description: {offset: 2552, size: 5}, + } +}; + +// Create a view of an ArrayBuffer. +function view(buffer, {offset, size}) { + return new Uint8Array(buffer, offset, size); +} + +function testSharedArrayBufferDescription(t, useView) { + const data = testData; + + // Don't run test if the codec is not supported. + let supported = false; + return AudioDecoder + .isConfigSupported({ + codec: data.config.codec, + sampleRate: data.config.sampleRate, + numberOfChannels: data.config.numberOfChannels + }) + .catch(_ => { + assert_implements_optional(false, data.config.codec + ' unsupported'); + }) + .then(support => { + supported = support.supported; + assert_implements_optional( + supported, data.config.codec + ' unsupported'); + return fetch(data.src); + }) + .then(response => { + return response.arrayBuffer(); + }) + .then(buf => { + config = {...data.config}; + if (data.config.description) { + let desc = new SharedArrayBuffer(data.config.description.size); + let descView = new Uint8Array(desc); + descView.set(view(buf, data.config.description)); + config.description = useView ? descView : desc; + } + + // Support was verified above, so the description shouldn't change + // that. + return AudioDecoder.isConfigSupported(config); + }) + .then(support => { + assert_true(support.supported); + + const decoder = new AudioDecoder(getDefaultCodecInit(t)); + decoder.configure(config); + assert_equals(decoder.state, 'configured', 'state'); + }); +} + +promise_test(t => { + return testSharedArrayBufferDescription(t, /*useView=*/ false); +}, 'Test isConfigSupported() and configure() using a SharedArrayBuffer'); + +promise_test(t => { + return testSharedArrayBufferDescription(t, /*useView=*/ true); +}, 'Test isConfigSupported() and configure() using a Uint8Array(SharedArrayBuffer)');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js.headers b/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js.headers new file mode 100644 index 0000000..5f8621ef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-decoder.https.any.js.headers
@@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js new file mode 100644 index 0000000..7063d858 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js
@@ -0,0 +1,29 @@ +// META: global=window,dedicatedworker +// META: script=/webcodecs/utils.js + +function testSharedArrayBufferEncodedAudioChunk(useView) { + let data = new SharedArrayBuffer(3); + let view = new Uint8Array(data); + view[0] = 0x0A; + view[1] = 0x0B; + view[2] = 0x0C; + + let chunk = new EncodedAudioChunk( + {type: 'key', timestamp: 10, duration: 123, data: useView ? view : data}); + assert_equals(chunk.byteLength, 3, 'byteLength'); + + let copyDest = new SharedArrayBuffer(3); + let destView = new Uint8Array(copyDest); + chunk.copyTo(useView ? destView : copyDest); + assert_equals(destView[0], 0x0A, 'copyDest[0]'); + assert_equals(destView[1], 0x0B, 'copyDest[1]'); + assert_equals(destView[2], 0x0C, 'copyDest[2]'); +} + +test(t => { + testSharedArrayBufferEncodedAudioChunk(/*useView=*/ false); +}, 'Test construction and copyTo() using a SharedArrayBuffer'); + +test(t => { + testSharedArrayBufferEncodedAudioChunk(/*useView=*/ true); +}, 'Test construction and copyTo() using a Uint8Array(SharedArrayBuffer)');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js.headers b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js.headers new file mode 100644 index 0000000..5f8621ef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-audio-chunk.https.any.js.headers
@@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js new file mode 100644 index 0000000..7f414fe --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js
@@ -0,0 +1,29 @@ +// META: global=window,dedicatedworker +// META: script=/webcodecs/utils.js + +function testSharedArrayBufferEncodedVideoChunk(useView) { + let data = new SharedArrayBuffer(3); + let view = new Uint8Array(data); + view[0] = 0x0A; + view[1] = 0x0B; + view[2] = 0x0C; + + let chunk = new EncodedVideoChunk( + {type: 'key', timestamp: 10, duration: 123, data: useView ? view : data}); + assert_equals(chunk.byteLength, 3, 'byteLength'); + + let copyDest = new SharedArrayBuffer(3); + let destView = new Uint8Array(copyDest); + chunk.copyTo(useView ? destView : copyDest); + assert_equals(destView[0], 0x0A, 'copyDest[0]'); + assert_equals(destView[1], 0x0B, 'copyDest[1]'); + assert_equals(destView[2], 0x0C, 'copyDest[2]'); +} + +test(t => { + testSharedArrayBufferEncodedVideoChunk(/*useView=*/ false); +}, 'Test construction and copyTo() using a SharedArrayBuffer'); + +test(t => { + testSharedArrayBufferEncodedVideoChunk(/*useView=*/ true); +}, 'Test construction and copyTo() using a Uint8Array(SharedArrayBuffer)');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js.headers b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js.headers new file mode 100644 index 0000000..5f8621ef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/encoded-video-chunk.https.any.js.headers
@@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js new file mode 100644 index 0000000..14777c55 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js
@@ -0,0 +1,67 @@ +// META: global=window,dedicatedworker +// META: script=/webcodecs/utils.js + +const testData = { + src: 'h264.mp4', + config: { + codec: 'avc1.64000b', + description: {offset: 9490, size: 45}, + codedWidth: 320, + codedHeight: 240, + displayAspectWidth: 320, + displayAspectHeight: 240, + } +}; + +// Create a view of an ArrayBuffer. +function view(buffer, {offset, size}) { + return new Uint8Array(buffer, offset, size); +} + +function testSharedArrayBufferDescription(t, useView) { + const data = testData; + + // Don't run test if the codec is not supported. + let supported = false; + return VideoDecoder.isConfigSupported({codec: data.config.codec}) + .catch(_ => { + assert_implements_optional(false, data.config.codec + ' unsupported'); + }) + .then(support => { + supported = support.supported; + assert_implements_optional( + supported, data.config.codec + ' unsupported'); + return fetch(data.src); + }) + .then(response => { + return response.arrayBuffer(); + }) + .then(buf => { + config = {...data.config}; + if (data.config.description) { + let desc = new SharedArrayBuffer(data.config.description.size); + let descView = new Uint8Array(desc); + descView.set(view(buf, data.config.description)); + config.description = useView ? descView : desc; + } + + // Support was verified above, so the description shouldn't change + // that. + return VideoDecoder.isConfigSupported(config); + }) + .then(support => { + assert_true(support.supported); + + const decoder = new VideoDecoder(getDefaultCodecInit(t)); + decoder.configure(config); + assert_equals(decoder.state, 'configured', 'state'); + }); +} + +promise_test(t => { + return testSharedArrayBufferDescription(t, /*useView=*/ false); +}, 'Test isConfigSupported() and configure() using a SharedArrayBuffer'); + +promise_test(t => { + return testSharedArrayBufferDescription(t, /*useView=*/ true); +}, 'Test isConfigSupported() and configure() using a Uint8Array(SharedArrayBuffer)');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js.headers b/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js.headers new file mode 100644 index 0000000..5f8621ef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/video-decoder.https.any.js.headers
@@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin
diff --git a/third_party/blink/web_tests/http/tests/media/media-controls-live-timeline.html b/third_party/blink/web_tests/http/tests/media/media-controls-live-timeline.html new file mode 100644 index 0000000..7ee055b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/media/media-controls-live-timeline.html
@@ -0,0 +1,46 @@ +<title>Test timeline work properly when playing live video.</title> +<script src="/w3c/resources/testharness.js"></script> +<script src="/w3c/resources/testharnessreport.js"></script> +<script src="media-source/mediasource-util.js"></script> +<script src="../../media-resources/media-controls.js"></script> +<video controls></video> +<script> + const epsilon = 0.2; + const pause_delay = 1; // 1 second. + + mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData){ + mediaElement.play(); + mediaSource.duration = +Infinity; + let timeline = timelineElement(mediaElement); + + // Append all media data for complete playback. + test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.'); + test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA'); + test.expectEvent(mediaElement, 'playing', 'Playing media.'); + sourceBuffer.appendBuffer(mediaData); + + test.waitForExpectedEvents(function() { + test.waitForCurrentTimeChange(mediaElement, function() { + assert_approx_equals(Number(timeline.value), Number(timeline.max), + epsilon, "timline thumb should be near the end"); + + mediaElement.onpause = test.step_func(function() { + // Timeline value should be at least 1s away from end at some point + // after paused. + function waitForTimeline() { + if (Number(timeline.max) - Number(timeline.value) >= pause_delay) { + test.done(); + return; + } + test.step_timeout(waitForTimeline, 1000); + } + + waitForTimeline(); + }); + + mediaElement.pause(); + }); + }); + }, "Timeline work properly when playing live video"); + +</script>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt index 762c7838..00d227d 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 633 tests; 376 PASS, 257 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 659 tests; 377 PASS, 282 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -297,7 +297,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/" FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/" @@ -421,11 +420,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> FAIL Parsing: <http://10000000000> against <http://other.com/> assert_equals: failure should set href to input expected "http://10000000000" but got "http://10000000000/" PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -434,7 +437,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> FAIL Parsing: <http://0xffffffff1> against <http://other.com/> assert_equals: failure should set href to input expected "http://0xffffffff1" but got "http://0xffffffff1/" FAIL Parsing: <http://256.256.256.256> against <http://other.com/> assert_equals: failure should set href to input expected "http://256.256.256.256" but got "http://256.256.256.256/" -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -589,7 +591,6 @@ FAIL Parsing: <non-special://[:80/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> FAIL Parsing: <http://[::127.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "http://[::127.0.0.0.1]" but got "http://[::127.0.0.0.1]/" @@ -644,5 +645,30 @@ FAIL Parsing: <abc:rootless> against <abc:/path> assert_equals: href expected "abc:rootless" but got "abc:/rootless" PASS Parsing: <abc:rootless> against <abc:path> FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x100.2.3.4> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4" but got "http://0x100.2.3.4/" +FAIL Parsing: <http://0x100.2.3.4.> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4." but got "http://0x100.2.3.4./" +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt index 21264a7..e5fd1f4 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 485 tests; 265 PASS, 220 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 611 tests; 275 PASS, 336 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw PASS URL's href: file://example:1/ should throw @@ -485,5 +485,131 @@ PASS sendBeacon(): file://xn--/p should throw FAIL Location's href: file://xn--/p should throw assert_throws_js: function "() => self[0].location = test.input" did not throw FAIL window.open(): file://xn--/p should throw assert_throws_dom: function "() => self.open(test.input).close()" threw object "TypeError: Cannot read properties of null (reading 'close')" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12 +FAIL URL's constructor's base argument: http://0..0x300/ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300/ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0..0x300./ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300./ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300./ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300./ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300./ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300./ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +PASS URL's constructor's base argument: http://0x100.2.3.4 should throw +PASS URL's href: http://0x100.2.3.4 should throw +PASS XHR: http://0x100.2.3.4 should throw +PASS sendBeacon(): http://0x100.2.3.4 should throw +FAIL Location's href: http://0x100.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4 should throw +PASS URL's constructor's base argument: http://0x100.2.3.4. should throw +PASS URL's href: http://0x100.2.3.4. should throw +PASS XHR: http://0x100.2.3.4. should throw +PASS sendBeacon(): http://0x100.2.3.4. should throw +FAIL Location's href: http://0x100.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4.' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4. should throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any-expected.txt index eb20797..e931b952 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 452 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 455 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -673,7 +675,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -732,5 +733,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker-expected.txt index eb20797..e931b952 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 452 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 455 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -673,7 +675,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -732,5 +733,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-expected.txt deleted file mode 100644 index b80c6751..0000000 --- a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-expected.txt +++ /dev/null
@@ -1,648 +0,0 @@ -This is a testharness.js-based test. -Found 633 tests; 376 PASS, 257 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Parsing: <http://example . -org> against <http://example.org/foo/bar> -PASS Parsing: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Parsing: <https://test:@test> against <about:blank> -PASS Parsing: <https://:@test> against <about:blank> -FAIL Parsing: <non-special://test:@test/x> against <about:blank> assert_equals: href expected "non-special://test@test/x" but got "non-special://test:@test/x" -FAIL Parsing: <non-special://:@test/x> against <about:blank> assert_equals: href expected "non-special://test/x" but got "non-special://:@test/x" -PASS Parsing: <http:foo.com> against <http://example.org/foo/bar> -PASS Parsing: < :foo.com -> against <http://example.org/foo/bar> -PASS Parsing: < foo.com > against <http://example.org/foo/bar> -PASS Parsing: <a: foo.com> against <http://example.org/foo/bar> -PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Parsing: <lolscheme:x x#x x> against <about:blank> -PASS Parsing: <http://f:/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:b/c> against <http://example.org/foo/bar> -FAIL Parsing: <http://f: /c> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://f: /c" but got "http://f:%20/c" -PASS Parsing: <http://f: -/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:fifty-two/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:999999/c> against <http://example.org/foo/bar> -FAIL Parsing: <non-special://f:999999/c> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://f: 21 / b ? d # e > against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://f: 21 / b ? d # e " but got "http://f:%2021%20/%20b%20?%20d%20#%20e" -PASS Parsing: <> against <http://example.org/foo/bar> -PASS Parsing: < > against <http://example.org/foo/bar> -PASS Parsing: <:foo.com/> against <http://example.org/foo/bar> -PASS Parsing: <:foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <:> against <http://example.org/foo/bar> -PASS Parsing: <:a> against <http://example.org/foo/bar> -PASS Parsing: <:/> against <http://example.org/foo/bar> -PASS Parsing: <:\> against <http://example.org/foo/bar> -PASS Parsing: <:#> against <http://example.org/foo/bar> -PASS Parsing: <#> against <http://example.org/foo/bar> -PASS Parsing: <#/> against <http://example.org/foo/bar> -PASS Parsing: <#\> against <http://example.org/foo/bar> -PASS Parsing: <#;?> against <http://example.org/foo/bar> -PASS Parsing: <?> against <http://example.org/foo/bar> -PASS Parsing: </> against <http://example.org/foo/bar> -PASS Parsing: <:23> against <http://example.org/foo/bar> -PASS Parsing: </:23> against <http://example.org/foo/bar> -PASS Parsing: <\x> against <http://example.org/foo/bar> -PASS Parsing: <\\x\hello> against <http://example.org/foo/bar> -PASS Parsing: <::> against <http://example.org/foo/bar> -PASS Parsing: <::23> against <http://example.org/foo/bar> -FAIL Parsing: <foo://> against <http://example.org/foo/bar> assert_equals: pathname expected "" but got "//" -PASS Parsing: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Parsing: <http::@c:29> against <http://example.org/foo/bar> -PASS Parsing: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Parsing: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Parsing: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Parsing: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Parsing: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <foo:/> against <http://example.org/foo/bar> -PASS Parsing: <foo:/bar.com/> against <http://example.org/foo/bar> -FAIL Parsing: <foo://///////> against <http://example.org/foo/bar> assert_equals: pathname expected "///////" but got "/////////" -FAIL Parsing: <foo://///////bar.com/> against <http://example.org/foo/bar> assert_equals: pathname expected "///////bar.com/" but got "/////////bar.com/" -FAIL Parsing: <foo:////://///> against <http://example.org/foo/bar> assert_equals: pathname expected "//://///" but got "////://///" -PASS Parsing: <c:/foo> against <http://example.org/foo/bar> -PASS Parsing: <//foo/bar> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Parsing: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Parsing: <http:[61:27]/:foo> against <http://example.org/foo/bar> -FAIL Parsing: <http://[1::2]:3:4> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[1::2]:3:4" but got "http://[1::2]:3:4/" -FAIL Parsing: <http://2001::1> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1" but got "http://2001::1/" -FAIL Parsing: <http://2001::1]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]" but got "http://2001::1]/" -FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/" -PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <https:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <file:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <file://example:1/> against <about:blank> -PASS Parsing: <file://example:test/> against <about:blank> -FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/" -PASS Parsing: <file://[example]/> against <about:blank> -PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <http:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <https:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <data:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Parsing: </a/b/c> against <http://example.org/foo/bar> -PASS Parsing: </a/ /c> against <http://example.org/foo/bar> -PASS Parsing: </a%2fc> against <http://example.org/foo/bar> -PASS Parsing: </a/%2f/c> against <http://example.org/foo/bar> -PASS Parsing: <#β> against <http://example.org/foo/bar> -PASS Parsing: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Parsing: <tel:1234567890> against <http://example.org/foo/bar> -FAIL Parsing: <ssh://example.com/foo/bar.git> against <http://example.org/> assert_equals: host expected "example.com" but got "" -FAIL Parsing: <file:c:\foo\bar.html> against <file:///tmp/mock/path> assert_equals: href expected "file:///c:/foo/bar.html" but got "file:///tmp/mock/c:/foo/bar.html" -FAIL Parsing: < File:c|////foo\bar.html> against <file:///tmp/mock/path> assert_equals: href expected "file:///c:////foo/bar.html" but got "file:///tmp/mock/c%7C////foo/bar.html" -FAIL Parsing: <C|/foo/bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file:///tmp/mock/C%7C/foo/bar" -FAIL Parsing: </C|\foo\bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file:///C%7C/foo/bar" -FAIL Parsing: <//C|/foo/bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file://c%7C/foo/bar" -PASS Parsing: <//server/file> against <file:///tmp/mock/path> -PASS Parsing: <\\server\file> against <file:///tmp/mock/path> -PASS Parsing: </\server/file> against <file:///tmp/mock/path> -PASS Parsing: <file:///foo/bar.txt> against <file:///tmp/mock/path> -PASS Parsing: <file:///home/me> against <file:///tmp/mock/path> -PASS Parsing: <//> against <file:///tmp/mock/path> -PASS Parsing: <///> against <file:///tmp/mock/path> -PASS Parsing: <///test> against <file:///tmp/mock/path> -PASS Parsing: <file://test> against <file:///tmp/mock/path> -FAIL Parsing: <file://localhost> against <file:///tmp/mock/path> assert_equals: href expected "file:///" but got "file://localhost/" -FAIL Parsing: <file://localhost/> against <file:///tmp/mock/path> assert_equals: href expected "file:///" but got "file://localhost/" -FAIL Parsing: <file://localhost/test> against <file:///tmp/mock/path> assert_equals: href expected "file:///test" but got "file://localhost/test" -PASS Parsing: <test> against <file:///tmp/mock/path> -PASS Parsing: <file:test> against <file:///tmp/mock/path> -PASS Parsing: <http://example.com/././foo> against <about:blank> -PASS Parsing: <http://example.com/./.foo> against <about:blank> -PASS Parsing: <http://example.com/foo/.> against <about:blank> -PASS Parsing: <http://example.com/foo/./> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../> against <about:blank> -PASS Parsing: <http://example.com/foo/..bar> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Parsing: <http://example.com/foo/../../..> against <about:blank> -PASS Parsing: <http://example.com/foo/../../../ton> against <about:blank> -PASS Parsing: <http://example.com/foo/%2e> against <about:blank> -FAIL Parsing: <http://example.com/foo/%2e%2> against <about:blank> assert_equals: href expected "http://example.com/foo/%2e%2" but got "http://example.com/foo/.%2" -FAIL Parsing: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> assert_equals: href expected "http://example.com/%2e.bar" but got "http://example.com/..bar" -PASS Parsing: <http://example.com////../..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar//../..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar//..> against <about:blank> -PASS Parsing: <http://example.com/foo> against <about:blank> -PASS Parsing: <http://example.com/%20foo> against <about:blank> -PASS Parsing: <http://example.com/foo%> against <about:blank> -PASS Parsing: <http://example.com/foo%2> against <about:blank> -PASS Parsing: <http://example.com/foo%2zbar> against <about:blank> -PASS Parsing: <http://example.com/foo%2©zbar> against <about:blank> -FAIL Parsing: <http://example.com/foo%41%7a> against <about:blank> assert_equals: href expected "http://example.com/foo%41%7a" but got "http://example.com/fooAz" -PASS Parsing: <http://example.com/foo %91> against <about:blank> -FAIL Parsing: <http://example.com/foo%00%51> against <about:blank> assert_equals: href expected "http://example.com/foo%00%51" but got "http://example.com/foo%00Q" -PASS Parsing: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Parsing: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Parsing: <http://example.com/foo bar> against <about:blank> -PASS Parsing: <http://example.com\\foo\\bar> against <about:blank> -PASS Parsing: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Parsing: <http://example.com/@asdf%40> against <about:blank> -PASS Parsing: <http://example.com/你好你好> against <about:blank> -PASS Parsing: <http://example.com/‥/foo> against <about:blank> -PASS Parsing: <http://example.com//foo> against <about:blank> -PASS Parsing: <http://example.com//foo//bar> against <about:blank> -PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Parsing: <data:test# »> against <about:blank> -PASS Parsing: <http://www.google.com> against <about:blank> -PASS Parsing: <http://192.0x00A80001> against <about:blank> -FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html" -PASS Parsing: <http://www/foo/%2E/html> against <about:blank> -PASS Parsing: <http://user:pass@/> against <about:blank> -PASS Parsing: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Parsing: <http:\\www.google.com\foo> against <about:blank> -PASS Parsing: <http://foo:80/> against <about:blank> -PASS Parsing: <http://foo:81/> against <about:blank> -FAIL Parsing: <httpa://foo:80/> against <about:blank> assert_equals: host expected "foo:80" but got "" -PASS Parsing: <http://foo:-80/> against <about:blank> -PASS Parsing: <https://foo:443/> against <about:blank> -PASS Parsing: <https://foo:80/> against <about:blank> -PASS Parsing: <ftp://foo:21/> against <about:blank> -PASS Parsing: <ftp://foo:80/> against <about:blank> -FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: host expected "foo:70" but got "" -FAIL Parsing: <gopher://foo:443/> against <about:blank> assert_equals: host expected "foo:443" but got "" -PASS Parsing: <ws://foo:80/> against <about:blank> -PASS Parsing: <ws://foo:81/> against <about:blank> -PASS Parsing: <ws://foo:443/> against <about:blank> -PASS Parsing: <ws://foo:815/> against <about:blank> -PASS Parsing: <wss://foo:80/> against <about:blank> -PASS Parsing: <wss://foo:81/> against <about:blank> -PASS Parsing: <wss://foo:443/> against <about:blank> -PASS Parsing: <wss://foo:815/> against <about:blank> -PASS Parsing: <http:/example.com/> against <about:blank> -PASS Parsing: <ftp:/example.com/> against <about:blank> -PASS Parsing: <https:/example.com/> against <about:blank> -PASS Parsing: <madeupscheme:/example.com/> against <about:blank> -PASS Parsing: <file:/example.com/> against <about:blank> -PASS Parsing: <ftps:/example.com/> against <about:blank> -PASS Parsing: <gopher:/example.com/> against <about:blank> -PASS Parsing: <ws:/example.com/> against <about:blank> -PASS Parsing: <wss:/example.com/> against <about:blank> -PASS Parsing: <data:/example.com/> against <about:blank> -PASS Parsing: <javascript:/example.com/> against <about:blank> -PASS Parsing: <mailto:/example.com/> against <about:blank> -PASS Parsing: <http:example.com/> against <about:blank> -PASS Parsing: <ftp:example.com/> against <about:blank> -PASS Parsing: <https:example.com/> against <about:blank> -PASS Parsing: <madeupscheme:example.com/> against <about:blank> -PASS Parsing: <ftps:example.com/> against <about:blank> -PASS Parsing: <gopher:example.com/> against <about:blank> -PASS Parsing: <ws:example.com/> against <about:blank> -PASS Parsing: <wss:example.com/> against <about:blank> -PASS Parsing: <data:example.com/> against <about:blank> -PASS Parsing: <javascript:example.com/> against <about:blank> -PASS Parsing: <mailto:example.com/> against <about:blank> -PASS Parsing: <http:@www.example.com> against <about:blank> -PASS Parsing: <http:/@www.example.com> against <about:blank> -PASS Parsing: <http://@www.example.com> against <about:blank> -PASS Parsing: <http:a:b@www.example.com> against <about:blank> -PASS Parsing: <http:/a:b@www.example.com> against <about:blank> -PASS Parsing: <http://a:b@www.example.com> against <about:blank> -PASS Parsing: <http://@pple.com> against <about:blank> -PASS Parsing: <http::b@www.example.com> against <about:blank> -PASS Parsing: <http:/:b@www.example.com> against <about:blank> -PASS Parsing: <http://:b@www.example.com> against <about:blank> -FAIL Parsing: <http:/:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/:@/www.example.com" but got "http:///www.example.com" -PASS Parsing: <http://user@/www.example.com> against <about:blank> -FAIL Parsing: <http:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <http:/@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <http://@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http://@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <https:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "https:@/www.example.com" but got "https:///www.example.com" -FAIL Parsing: <http:a:b@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:a:b@/www.example.com" but got "http://a:b@/www.example.com" -FAIL Parsing: <http:/a:b@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/a:b@/www.example.com" but got "http://a:b@/www.example.com" -PASS Parsing: <http://a:b@/www.example.com> against <about:blank> -FAIL Parsing: <http::@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http::@/www.example.com" but got "http:///www.example.com" -PASS Parsing: <http:a:@www.example.com> against <about:blank> -PASS Parsing: <http:/a:@www.example.com> against <about:blank> -PASS Parsing: <http://a:@www.example.com> against <about:blank> -PASS Parsing: <http://www.@pple.com> against <about:blank> -FAIL Parsing: <http:@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:@:www.example.com" but got "http://:www.example.com/" -FAIL Parsing: <http:/@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/@:www.example.com" but got "http://:www.example.com/" -FAIL Parsing: <http://@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http://@:www.example.com" but got "http://:www.example.com/" -PASS Parsing: <http://:@www.example.com> against <about:blank> -PASS Parsing: </> against <http://www.example.com/test> -PASS Parsing: </test.txt> against <http://www.example.com/test> -PASS Parsing: <.> against <http://www.example.com/test> -PASS Parsing: <..> against <http://www.example.com/test> -PASS Parsing: <test.txt> against <http://www.example.com/test> -PASS Parsing: <./test.txt> against <http://www.example.com/test> -PASS Parsing: <../test.txt> against <http://www.example.com/test> -PASS Parsing: <../aaa/test.txt> against <http://www.example.com/test> -PASS Parsing: <../../test.txt> against <http://www.example.com/test> -PASS Parsing: <中/test.txt> against <http://www.example.com/test> -PASS Parsing: <http://www.example2.com> against <http://www.example.com/test> -PASS Parsing: <//www.example2.com> against <http://www.example.com/test> -PASS Parsing: <file:...> against <http://www.example.com/test> -PASS Parsing: <file:..> against <http://www.example.com/test> -PASS Parsing: <file:a> against <http://www.example.com/test> -PASS Parsing: <http://ExAmPlE.CoM> against <http://other.com/> -FAIL Parsing: <http://example example.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://Goo%20 goo%7C|.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[]" but got "http://[]/" -FAIL Parsing: <http://[:]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[:]" but got "http://[:]/" -FAIL Parsing: <http://GOO goo.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://GOOgoo.com> against <http://other.com/> -PASS Parsing: <\0 http://example.com/ \r > against <about:blank> -PASS Parsing: <http://www.foo。bar.com> against <http://other.com/> -FAIL Parsing: <http://zyx.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://zyx.com" but got "http://%EF%BF%BDzyx.com/" -FAIL Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%ef%b7%90zyx.com" but got "http://%EF%BF%BDzyx.com/" -FAIL Parsing: <https://�> against <about:blank> assert_equals: failure should set href to input expected "https://\ufffd" but got "https://%EF%BF%BD/" -FAIL Parsing: <https://%EF%BF%BD> against <about:blank> assert_equals: failure should set href to input expected "https://%EF%BF%BD" but got "https://%EF%BF%BD/" -PASS Parsing: <https://x/�?�#�> against <about:blank> -FAIL Parsing: <http://a.b.c.xn--pokxncvks> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://10.0.0.xn--pokxncvks> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://Go.com> against <http://other.com/> -FAIL Parsing: <http://%41.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://%ef%bc%85%ef%bc%94%ef%bc%91.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://%00.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%00.com" but got "http://%00.com/" -FAIL Parsing: <http://%ef%bc%85%ef%bc%90%ef%bc%90.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%ef%bc%85%ef%bc%90%ef%bc%90.com" but got "http://%00.com/" -PASS Parsing: <http://你好你好> against <http://other.com/> -FAIL Parsing: <https://faß.ExAmPlE/> against <about:blank> assert_equals: href expected "https://xn--fa-hia.example/" but got "https://fass.example/" -FAIL Parsing: <sc://faß.ExAmPlE/> against <about:blank> assert_equals: host expected "fa%C3%9F.ExAmPlE" but got "" -FAIL Parsing: <http://%zz%66%a.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%zz%66%a.com" but got "http://%25zzf%25a.com/" -FAIL Parsing: <http://%25> against <http://other.com/> assert_equals: failure should set href to input expected "http://%25" but got "http://%25/" -FAIL Parsing: <http://hello%00> against <http://other.com/> assert_equals: failure should set href to input expected "http://hello%00" but got "http://hello%00/" -PASS Parsing: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Parsing: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -FAIL Parsing: <http://192.168.0.257> against <http://other.com/> assert_equals: failure should set href to input expected "http://192.168.0.257" but got "http://192.168.0.257/" -FAIL Parsing: <http://%3g%78%63%30%2e%30%32%35%30%2E.01> against <http://other.com/> assert_equals: failure should set href to input expected "http://%3g%78%63%30%2e%30%32%35%30%2E.01" but got "http://%253gxc0.0250..01/" -FAIL Parsing: <http://192.168.0.1 hello> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <https://x x:12> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> -PASS Parsing: <http://./> against <about:blank> -PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> -PASS Parsing: <http://[www.google.com]/> against <about:blank> -FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/" -FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/" -FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Parsing: <#> against <test:test> -PASS Parsing: <#x> against <mailto:x@x.com> -FAIL Parsing: <#x> against <data:,> assert_equals: href expected "data:,#x" but got "mailto:x@x.com#x" -PASS Parsing: <#x> against <about:blank> -PASS Parsing: <#> against <test:test?test> -PASS Parsing: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Parsing: <https://@@@example> against <http://doesnotmatter/> -PASS Parsing: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Parsing: <http://host/?'> against <about:blank> -FAIL Parsing: <notspecial://host/?'> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: </some/path> against <http://user@example.org/smth> -PASS Parsing: <> against <http://user:pass@example.org:21/smth> -PASS Parsing: </some/path> against <http://user:pass@example.org:21/smth> -FAIL Parsing: <i> against <sc:sd> assert_equals: failure should set href to input expected "i" but got "" -FAIL Parsing: <i> against <sc:sd/sd> assert_equals: failure should set href to input expected "i" but got "" -PASS Parsing: <i> against <sc:/pa/pa> -FAIL Parsing: <i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/i" but got "///pa/i" -FAIL Parsing: <../i> against <sc:sd> assert_equals: failure should set href to input expected "../i" but got "" -FAIL Parsing: <../i> against <sc:sd/sd> assert_equals: failure should set href to input expected "../i" but got "" -PASS Parsing: <../i> against <sc:/pa/pa> -FAIL Parsing: <../i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <../i> against <sc:///pa/pa> assert_equals: href expected "sc:///i" but got "sc:///pa/i" -FAIL Parsing: </i> against <sc:sd> assert_equals: failure should set href to input expected "/i" but got "" -FAIL Parsing: </i> against <sc:sd/sd> assert_equals: failure should set href to input expected "/i" but got "" -PASS Parsing: </i> against <sc:/pa/pa> -FAIL Parsing: </i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: </i> against <sc:///pa/pa> assert_equals: href expected "sc:///i" but got "sc:///pa/i" -FAIL Parsing: <?i> against <sc:sd> assert_equals: failure should set href to input expected "?i" but got "" -FAIL Parsing: <?i> against <sc:sd/sd> assert_equals: failure should set href to input expected "?i" but got "" -PASS Parsing: <?i> against <sc:/pa/pa> -FAIL Parsing: <?i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <?i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/pa" but got "///pa/pa" -PASS Parsing: <#i> against <sc:sd> -PASS Parsing: <#i> against <sc:sd/sd> -PASS Parsing: <#i> against <sc:/pa/pa> -FAIL Parsing: <#i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <#i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/pa" but got "///pa/pa" -FAIL Parsing: <about:/../> against <about:blank> assert_equals: href expected "about:/" but got "about:/../" -FAIL Parsing: <data:/../> against <about:blank> assert_equals: href expected "data:/" but got "data:/../" -FAIL Parsing: <javascript:/../> against <about:blank> assert_equals: href expected "javascript:/" but got "javascript:/../" -FAIL Parsing: <mailto:/../> against <about:blank> assert_equals: href expected "mailto:/" but got "mailto:/../" -FAIL Parsing: <sc://ñ.test/> against <about:blank> assert_equals: host expected "%C3%B1.test" but got "" -FAIL Parsing: <sc://\0/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc:// /> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://%/> against <about:blank> assert_equals: host expected "%" but got "" -FAIL Parsing: <sc://@/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://te@s:t@/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://:/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://:12/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://[/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://\/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://]/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1/x" but got "sc://%C3%B1" -PASS Parsing: <sc:\../> against <about:blank> -PASS Parsing: <sc::a@example.net> against <about:blank> -PASS Parsing: <wow:%NBD> against <about:blank> -PASS Parsing: <wow:%1G> against <about:blank> -FAIL Parsing: <wow:> against <about:blank> assert_equals: href expected "wow:%EF%BF%BF" but got "wow:%EF%BF%BD" -FAIL Parsing: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> assert_equals: href expected "http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF" but got "http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%BF%BD%EF%B7%8F%EF%BF%BD%EF%B7%B0%EF%BF%BD%EF%BF%BD?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%BF%BD%EF%B7%8F%EF%BF%BD%EF%B7%B0%EF%BF%BD%EF%BF%BD" -FAIL Parsing: <http://a<b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://a>b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://a^b> against <about:blank> assert_equals: failure should set href to input expected "http://a^b" but got "http://a%5Eb/" -FAIL Parsing: <non-special://a<b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <non-special://a>b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <non-special://a^b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho\0st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho|st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho st/> against <about:blank> assert_equals: host expected "host" but got "" -FAIL Parsing: <foo://ho -st/> against <about:blank> assert_equals: host expected "host" but got "" -FAIL Parsing: <foo://ho\rst/> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: <http://ho%00st/> against <about:blank> -PASS Parsing: <http://ho%09st/> against <about:blank> -PASS Parsing: <http://ho%0Ast/> against <about:blank> -PASS Parsing: <http://ho%0Dst/> against <about:blank> -FAIL Parsing: <http://ho%20st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%23st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://ho%2Fst/> against <about:blank> -FAIL Parsing: <http://ho%3Ast/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%3Ast/" but got "http://ho:st/" -FAIL Parsing: <http://ho%3Cst/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%3Est/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://ho%3Fst/> against <about:blank> -FAIL Parsing: <http://ho%40st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%5Bst/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%5Bst/" but got "http://ho[st/" -PASS Parsing: <http://ho%5Cst/> against <about:blank> -FAIL Parsing: <http://ho%5Dst/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%5Dst/" but got "http://ho]st/" -FAIL Parsing: <http://ho%7Cst/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: href expected "http://\x1f!\"$&'()*+,-.;=_`{}~/" but got "http://%1F%21%22%24%26%27%28%29%2A+%2C-.%3B%3D_%60%7B%7D%7E/" -FAIL Parsing: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: host expected "%1F!\"$&'()*+,-.;=_`{}~" but got "" -FAIL Parsing: <ftp://example.com%80/> against <about:blank> assert_equals: failure should set href to input expected "ftp://example.com%80/" but got "ftp://example.com%EF%BF%BD/" -FAIL Parsing: <ftp://example.com%A0/> against <about:blank> assert_equals: failure should set href to input expected "ftp://example.com%A0/" but got "ftp://example.com%EF%BF%BD/" -FAIL Parsing: <https://example.com%80/> against <about:blank> assert_equals: failure should set href to input expected "https://example.com%80/" but got "https://example.com%EF%BF%BD/" -FAIL Parsing: <https://example.com%A0/> against <about:blank> assert_equals: failure should set href to input expected "https://example.com%A0/" but got "https://example.com%EF%BF%BD/" -PASS Parsing: <ftp://%e2%98%83> against <about:blank> -PASS Parsing: <https://%e2%98%83> against <about:blank> -PASS Parsing: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Parsing: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Parsing: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Parsing: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Parsing: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing: <http:> against <http://example.org/foo/bar> -PASS Parsing: <http:> against <https://example.org/foo/bar> -PASS Parsing: <sc:> against <https://example.org/foo/bar> -PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Parsing: <http://192.168.257> against <http://other.com/> -PASS Parsing: <http://192.168.257.com> against <http://other.com/> -PASS Parsing: <http://256> against <http://other.com/> -PASS Parsing: <http://256.com> against <http://other.com/> -PASS Parsing: <http://999999999> against <http://other.com/> -PASS Parsing: <http://999999999.com> against <http://other.com/> -FAIL Parsing: <http://10000000000> against <http://other.com/> assert_equals: failure should set href to input expected "http://10000000000" but got "http://10000000000/" -PASS Parsing: <http://10000000000.com> against <http://other.com/> -PASS Parsing: <http://4294967295> against <http://other.com/> -FAIL Parsing: <http://4294967296> against <http://other.com/> assert_equals: failure should set href to input expected "http://4294967296" but got "http://4294967296/" -PASS Parsing: <http://0xffffffff> against <http://other.com/> -FAIL Parsing: <http://0xffffffff1> against <http://other.com/> assert_equals: failure should set href to input expected "http://0xffffffff1" but got "http://0xffffffff1/" -FAIL Parsing: <http://256.256.256.256> against <http://other.com/> assert_equals: failure should set href to input expected "http://256.256.256.256" but got "http://256.256.256.256/" -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> -PASS Parsing: <https://0x.0x.0> against <about:blank> -PASS Parsing: <https://0x100000000/test> against <about:blank> -PASS Parsing: <https://256.0.0.1/test> against <about:blank> -PASS Parsing: <file:///C%3A/> against <about:blank> -PASS Parsing: <file:///C%7C/> against <about:blank> -FAIL Parsing: <file://%43%3A> against <about:blank> assert_equals: failure should set href to input expected "file://%43%3A" but got "file://c:/" -FAIL Parsing: <file://%43%7C> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://%43|> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://C%7C> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://%43%7C/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <https://%43%7C/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <asdf://%43|/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <asdf://%43%7C/> against <about:blank> assert_equals: host expected "%43%7C" but got "" -PASS Parsing: <pix/submit.gif> against <file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html> -FAIL Parsing: <..> against <file:///C:/> assert_equals: href expected "file:///C:/" but got "file:///" -PASS Parsing: <..> against <file:///> -FAIL Parsing: </> against <file:///C:/a/b> assert_equals: href expected "file:///C:/" but got "file:///" -FAIL Parsing: </> against <file://h/C:/a/b> assert_equals: href expected "file://h/C:/" but got "file:///" -FAIL Parsing: </> against <file://h/a/b> assert_equals: href expected "file://h/" but got "file:///" -FAIL Parsing: <//d:> against <file:///C:/a/b> assert_equals: href expected "file:///d:" but got "file://d:/" -FAIL Parsing: <//d:/..> against <file:///C:/a/b> assert_equals: href expected "file:///d:/" but got "file://d:/" -PASS Parsing: <..> against <file:///ab:/> -PASS Parsing: <..> against <file:///1:/> -PASS Parsing: <> against <file:///test?test#test> -PASS Parsing: <file:> against <file:///test?test#test> -PASS Parsing: <?x> against <file:///test?test#test> -PASS Parsing: <file:?x> against <file:///test?test#test> -PASS Parsing: <#x> against <file:///test?test#test> -PASS Parsing: <file:#x> against <file:///test?test#test> -FAIL Parsing: <file:\\//> against <about:blank> assert_equals: href expected "file:////" but got "file:///" -FAIL Parsing: <file:\\\\> against <about:blank> assert_equals: href expected "file:////" but got "file:///" -FAIL Parsing: <file:\\\\?fox> against <about:blank> assert_equals: href expected "file:////?fox" but got "file:///?fox" -FAIL Parsing: <file:\\\\#guppy> against <about:blank> assert_equals: href expected "file:////#guppy" but got "file:///#guppy" -PASS Parsing: <file://spider///> against <about:blank> -FAIL Parsing: <file:\\localhost//> against <about:blank> assert_equals: href expected "file:////" but got "file://localhost//" -PASS Parsing: <file:///localhost//cat> against <about:blank> -FAIL Parsing: <file://\/localhost//cat> against <about:blank> assert_equals: href expected "file:////localhost//cat" but got "file:///localhost//cat" -FAIL Parsing: <file://localhost//a//../..//> against <about:blank> assert_equals: href expected "file://///" but got "file://localhost///" -FAIL Parsing: </////mouse> against <file:///elephant> assert_equals: href expected "file://///mouse" but got "file:///mouse" -PASS Parsing: <\//pig> against <file://lion/> -FAIL Parsing: <\/localhost//pig> against <file://lion/> assert_equals: href expected "file:////pig" but got "file://localhost//pig" -FAIL Parsing: <//localhost//pig> against <file://lion/> assert_equals: href expected "file:////pig" but got "file://localhost//pig" -PASS Parsing: </..//localhost//pig> against <file://lion/> -PASS Parsing: <file://> against <file://ape/> -PASS Parsing: </rooibos> against <file://tea/> -PASS Parsing: </?chai> against <file://tea/> -FAIL Parsing: <C|> against <file://host/dir/file> assert_equals: href expected "file://host/C:" but got "file://host/dir/C%7C" -FAIL Parsing: <C|> against <file://host/D:/dir1/dir2/file> assert_equals: href expected "file://host/C:" but got "file://host/D:/dir1/dir2/C%7C" -FAIL Parsing: <C|#> against <file://host/dir/file> assert_equals: href expected "file://host/C:#" but got "file://host/dir/C%7C#" -FAIL Parsing: <C|?> against <file://host/dir/file> assert_equals: href expected "file://host/C:?" but got "file://host/dir/C%7C?" -FAIL Parsing: <C|/> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -FAIL Parsing: <C| -/> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -FAIL Parsing: <C|\> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -PASS Parsing: <C> against <file://host/dir/file> -FAIL Parsing: <C|a> against <file://host/dir/file> assert_equals: href expected "file://host/dir/C|a" but got "file://host/dir/C%7Ca" -PASS Parsing: </c:/foo/bar> against <file:///c:/baz/qux> -FAIL Parsing: </c|/foo/bar> against <file:///c:/baz/qux> assert_equals: href expected "file:///c:/foo/bar" but got "file:///c%7C/foo/bar" -PASS Parsing: <file:\c:\foo\bar> against <file:///c:/baz/qux> -PASS Parsing: </c:/foo/bar> against <file://host/path> -PASS Parsing: <file://example.net/C:/> against <about:blank> -PASS Parsing: <file://1.2.3.4/C:/> against <about:blank> -PASS Parsing: <file://[1::8]/C:/> against <about:blank> -FAIL Parsing: <C|/> against <file://host/> assert_equals: href expected "file://host/C:/" but got "file://host/C%7C/" -PASS Parsing: </C:/> against <file://host/> -PASS Parsing: <file:C:/> against <file://host/> -PASS Parsing: <file:/C:/> against <file://host/> -FAIL Parsing: <//C:/> against <file://host/> assert_equals: href expected "file:///C:/" but got "file://c:/" -FAIL Parsing: <file://C:/> against <file://host/> assert_equals: href expected "file:///C:/" but got "file://c:/" -PASS Parsing: <///C:/> against <file://host/> -PASS Parsing: <file:///C:/> against <file://host/> -FAIL Parsing: <file:/C|/> against <about:blank> assert_equals: href expected "file:///C:/" but got "file:///C%7C/" -FAIL Parsing: <file://C|/> against <about:blank> assert_equals: href expected "file:///C:/" but got "file://c%7C/" -PASS Parsing: <file:> against <about:blank> -PASS Parsing: <file:?q=v> against <about:blank> -PASS Parsing: <file:#frag> against <about:blank> -PASS Parsing: <file:///Y:> against <about:blank> -PASS Parsing: <file:///Y:/> against <about:blank> -PASS Parsing: <file:///./Y> against <about:blank> -PASS Parsing: <file:///./Y:> against <about:blank> -FAIL Parsing: <\\\.\Y:> against <about:blank> assert_equals: failure should set href to input expected "\\\\\\.\\Y:" but got "" -PASS Parsing: <file:///y:> against <about:blank> -PASS Parsing: <file:///y:/> against <about:blank> -PASS Parsing: <file:///./y> against <about:blank> -PASS Parsing: <file:///./y:> against <about:blank> -FAIL Parsing: <\\\.\y:> against <about:blank> assert_equals: failure should set href to input expected "\\\\\\.\\y:" but got "" -FAIL Parsing: <file://localhost//a//../..//foo> against <about:blank> assert_equals: href expected "file://///foo" but got "file://localhost///foo" -FAIL Parsing: <file://localhost////foo> against <about:blank> assert_equals: href expected "file://////foo" but got "file://localhost////foo" -FAIL Parsing: <file:////foo> against <about:blank> assert_equals: href expected "file:////foo" but got "file:///foo" -PASS Parsing: <file:///one/two> against <file:///> -FAIL Parsing: <file:////one/two> against <file:///> assert_equals: href expected "file:////one/two" but got "file:///one/two" -PASS Parsing: <//one/two> against <file:///> -PASS Parsing: <///one/two> against <file:///> -FAIL Parsing: <////one/two> against <file:///> assert_equals: href expected "file:////one/two" but got "file:///one/two" -PASS Parsing: <file:///.//> against <file:////> -PASS Parsing: <file:.//p> against <about:blank> -PASS Parsing: <file:/.//p> against <about:blank> -PASS Parsing: <http://[1:0::]> against <http://example.net/> -FAIL Parsing: <http://[0:1:2:3:4:5:6:7:8]> against <http://example.net/> assert_equals: failure should set href to input expected "http://[0:1:2:3:4:5:6:7:8]" but got "http://[0:1:2:3:4:5:6:7:8]/" -FAIL Parsing: <https://[0::0::0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0::0::0]" but got "https://[0::0::0]/" -FAIL Parsing: <https://[0:.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:.0]" but got "https://[0:.0]/" -FAIL Parsing: <https://[0:0:]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:0:]" but got "https://[0:0:]/" -FAIL Parsing: <https://[0:1:2:3:4:5:6:7.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1:2:3:4:5:6:7.0.0.0.1]" but got "https://[0:1:2:3:4:5:6:7.0.0.0.1]/" -FAIL Parsing: <https://[0:1.00.0.0.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.00.0.0.0]" but got "https://[0:1.00.0.0.0]/" -FAIL Parsing: <https://[0:1.290.0.0.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.290.0.0.0]" but got "https://[0:1.290.0.0.0]/" -FAIL Parsing: <https://[0:1.23.23]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.23.23]" but got "https://[0:1.23.23]/" -FAIL Parsing: <http://?> against <about:blank> assert_equals: failure should set href to input expected "http://?" but got "http:/?" -FAIL Parsing: <http://#> against <about:blank> assert_equals: failure should set href to input expected "http://#" but got "http:/#" -PASS Parsing: <http://f:4294967377/c> against <http://example.org/> -PASS Parsing: <http://f:18446744073709551697/c> against <http://example.org/> -PASS Parsing: <http://f:340282366920938463463374607431768211537/c> against <http://example.org/> -FAIL Parsing: <sc://ñ> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <sc://ñ?x> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <sc://ñ#x> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <#x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1#x" but got "sc://%C3%B1" -FAIL Parsing: <?x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1?x" but got "sc://%C3%B1" -FAIL Parsing: <sc://?> against <about:blank> assert_equals: pathname expected "" but got "//" -FAIL Parsing: <sc://#> against <about:blank> assert_equals: pathname expected "" but got "//" -FAIL Parsing: <///> against <sc://x/> assert_equals: href expected "sc:///" but got "sc:" -FAIL Parsing: <////> against <sc://x/> assert_equals: href expected "sc:////" but got "sc:" -FAIL Parsing: <////x/> against <sc://x/> assert_equals: href expected "sc:////x/" but got "sc://x/" -FAIL Parsing: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> assert_equals: host expected "foobar.com" but got "" -FAIL Parsing: <telnet://user:pass@foobar.com:23/> against <about:blank> assert_equals: username expected "user" but got "" -FAIL Parsing: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> assert_equals: host expected "10.10.10.10:7777" but got "" -FAIL Parsing: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> assert_equals: username expected "foo" but got "" -FAIL Parsing: <rsync://foo@host:911/sup> against <about:blank> assert_equals: username expected "foo" but got "" -FAIL Parsing: <git://github.com/foo/bar.git> against <about:blank> assert_equals: host expected "github.com" but got "" -FAIL Parsing: <irc://myserver.com:6999/channel?passwd> against <about:blank> assert_equals: host expected "myserver.com:6999" but got "" -FAIL Parsing: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> assert_equals: host expected "fw.example.org:9999" but got "" -FAIL Parsing: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> assert_equals: host expected "localhost:389" but got "" -FAIL Parsing: <git+https://github.com/foo/bar> against <about:blank> assert_equals: host expected "github.com" but got "" -PASS Parsing: <urn:ietf:rfc:2648> against <about:blank> -PASS Parsing: <tag:joe@example.org,2001:foo/bar> against <about:blank> -FAIL Parsing: <non-spec:/.//> against <about:blank> assert_equals: pathname expected "//" but got "/.//" -FAIL Parsing: <non-spec:/..//> against <about:blank> assert_equals: href expected "non-spec:/.//" but got "non-spec:/..//" -FAIL Parsing: <non-spec:/a/..//> against <about:blank> assert_equals: href expected "non-spec:/.//" but got "non-spec:/a/..//" -FAIL Parsing: <non-spec:/.//path> against <about:blank> assert_equals: pathname expected "//path" but got "/.//path" -FAIL Parsing: <non-spec:/..//path> against <about:blank> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/..//path" -FAIL Parsing: <non-spec:/a/..//path> against <about:blank> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/a/..//path" -FAIL Parsing: </.//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: </..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <a/..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <> against <non-spec:/..//p> assert_equals: href expected "non-spec:/.//p" but got "non-spec:/..//p" -FAIL Parsing: <path> against <non-spec:/..//p> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/..//path" -FAIL Parsing: <../path> against <non-spec:/.//p> assert_equals: href expected "non-spec:/path" but got "non-spec:/./path" -FAIL Parsing: <non-special://%E2%80%A0/> against <about:blank> assert_equals: host expected "%E2%80%A0" but got "" -FAIL Parsing: <non-special://H%4fSt/path> against <about:blank> assert_equals: host expected "H%4fSt" but got "" -FAIL Parsing: <non-special://[1:2:0:0:5:0:0:0]/> against <about:blank> assert_equals: href expected "non-special://[1:2:0:0:5::]/" but got "non-special://[1:2:0:0:5:0:0:0]/" -FAIL Parsing: <non-special://[1:2:0:0:0:0:0:3]/> against <about:blank> assert_equals: href expected "non-special://[1:2::3]/" but got "non-special://[1:2:0:0:0:0:0:3]/" -FAIL Parsing: <non-special://[1:2::3]:80/> against <about:blank> assert_equals: host expected "[1:2::3]:80" but got "" -FAIL Parsing: <non-special://[:80/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <blob:https://example.com:443/> against <about:blank> -PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> -PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> -PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> -FAIL Parsing: <http://[::127.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "http://[::127.0.0.0.1]" but got "http://[::127.0.0.0.1]/" -PASS Parsing: <http://[0:1:0:1:0:1:0:1]> against <about:blank> -PASS Parsing: <http://[1:0:1:0:1:0:1:0]> against <about:blank> -PASS Parsing: <http://example.org/test?"> against <about:blank> -PASS Parsing: <http://example.org/test?#> against <about:blank> -PASS Parsing: <http://example.org/test?<> against <about:blank> -PASS Parsing: <http://example.org/test?>> against <about:blank> -PASS Parsing: <http://example.org/test?⌣> against <about:blank> -PASS Parsing: <http://example.org/test?%23%23> against <about:blank> -PASS Parsing: <http://example.org/test?%GH> against <about:blank> -PASS Parsing: <http://example.org/test?a#%EF> against <about:blank> -PASS Parsing: <http://example.org/test?a#%GH> against <about:blank> -FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got "" -FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got "" -FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got "" -FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got "" -FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got "" -PASS Parsing: <test-a-colon-slash.html> against <a:/> -FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got "" -PASS Parsing: <test-a-colon-slash-b.html> against <a:/b> -FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b" -PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank> -FAIL Parsing: <non-spec://example.org/test?a#b\0c> against <about:blank> assert_equals: host expected "example.org" but got "" -PASS Parsing: <non-spec:/test?a#b\0c> against <about:blank> -PASS Parsing: <10.0.0.7:8080/foo.html> against <file:///some/dir/bar.html> -PASS Parsing: <a!@$*=/foo.html> against <file:///some/dir/bar.html> -PASS Parsing: <a1234567890-+.:foo/bar> against <http://example.com/dir/file> -PASS Parsing: <file://ab/p> against <about:blank> -PASS Parsing: <file://a%C2%ADb/p> against <about:blank> -FAIL Parsing: <file:///p> against <about:blank> assert_equals: failure should set href to input expected "file:///p" but got "file://%C2%AD/p" -PASS Parsing: <file://%C2%AD/p> against <about:blank> -FAIL Parsing: <file://xn--/p> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <#link> against <https://example.org/##link> -PASS Parsing: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Parsing: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Parsing: <https://user:pass[@foo/bar> against <http://example.org> -FAIL Parsing: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> assert_equals: href expected "foo://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/" but got "foo:// !\"$%&'()*+,-.;<=>@[\\]^_`{|}~@host/" -FAIL Parsing: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> assert_equals: href expected "wss://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" but got "wss://%20!%22$%&%27()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" -FAIL Parsing: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> assert_equals: href expected "foo://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/" but got "foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/" -FAIL Parsing: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> assert_equals: href expected "wss://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" but got "wss://joe:%20!%22$%&%27()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" -FAIL Parsing: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: host expected "!\"$%&'()*+,-.;=_`{}~" but got "" -FAIL Parsing: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: href expected "wss://!\"$&'()*+,-.;=_`{}~/" but got "wss://%21%22%24%26%27%28%29%2A+%2C-.%3B%3D_%60%7B%7D%7E/" -FAIL Parsing: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> assert_equals: href expected "foo://host/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]^_%60%7B|%7D~" but got "foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~" -FAIL Parsing: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> assert_equals: href expected "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]^_%60%7B|%7D~" but got "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B%7C%7D~" -FAIL Parsing: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> assert_equals: href expected "foo://host/dir/?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\]^_`{|}~" but got "foo://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~" -PASS Parsing: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -FAIL Parsing: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -FAIL Parsing: <abc:rootless> against <abc://host/path> assert_equals: href expected "abc:rootless" but got "abc://host/rootless" -FAIL Parsing: <abc:rootless> against <abc:/path> assert_equals: href expected "abc:rootless" but got "abc:/rootless" -PASS Parsing: <abc:rootless> against <abc:path> -FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-expected.txt deleted file mode 100644 index e1738cb..0000000 --- a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-expected.txt +++ /dev/null
@@ -1,337 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 319 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Parsing origin: <http://example . -org> against <http://example.org/foo/bar> -PASS Parsing origin: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Parsing origin: <https://test:@test> against <about:blank> -PASS Parsing origin: <https://:@test> against <about:blank> -PASS Parsing origin: <non-special://test:@test/x> against <about:blank> -PASS Parsing origin: <non-special://:@test/x> against <about:blank> -PASS Parsing origin: <http:foo.com> against <http://example.org/foo/bar> -PASS Parsing origin: < :foo.com -> against <http://example.org/foo/bar> -PASS Parsing origin: < foo.com > against <http://example.org/foo/bar> -PASS Parsing origin: <a: foo.com> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:0/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f: -/c> against <http://example.org/foo/bar> -PASS Parsing origin: <> against <http://example.org/foo/bar> -PASS Parsing origin: < > against <http://example.org/foo/bar> -PASS Parsing origin: <:foo.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <:foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <:> against <http://example.org/foo/bar> -PASS Parsing origin: <:a> against <http://example.org/foo/bar> -PASS Parsing origin: <:/> against <http://example.org/foo/bar> -PASS Parsing origin: <:\> against <http://example.org/foo/bar> -PASS Parsing origin: <:#> against <http://example.org/foo/bar> -PASS Parsing origin: <#> against <http://example.org/foo/bar> -PASS Parsing origin: <#/> against <http://example.org/foo/bar> -PASS Parsing origin: <#\> against <http://example.org/foo/bar> -PASS Parsing origin: <#;?> against <http://example.org/foo/bar> -PASS Parsing origin: <?> against <http://example.org/foo/bar> -PASS Parsing origin: </> against <http://example.org/foo/bar> -PASS Parsing origin: <:23> against <http://example.org/foo/bar> -PASS Parsing origin: </:23> against <http://example.org/foo/bar> -PASS Parsing origin: <\x> against <http://example.org/foo/bar> -PASS Parsing origin: <\\x\hello> against <http://example.org/foo/bar> -PASS Parsing origin: <::> against <http://example.org/foo/bar> -PASS Parsing origin: <::23> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://> against <http://example.org/foo/bar> -PASS Parsing origin: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Parsing origin: <http::@c:29> against <http://example.org/foo/bar> -PASS Parsing origin: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Parsing origin: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Parsing origin: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:/bar.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://///////> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://///////bar.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:////://///> against <http://example.org/foo/bar> -PASS Parsing origin: <c:/foo> against <http://example.org/foo/bar> -PASS Parsing origin: <//foo/bar> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Parsing origin: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Parsing origin: <http:[61:27]/:foo> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Parsing origin: <http:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <http:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: </a/b/c> against <http://example.org/foo/bar> -PASS Parsing origin: </a/ /c> against <http://example.org/foo/bar> -PASS Parsing origin: </a%2fc> against <http://example.org/foo/bar> -PASS Parsing origin: </a/%2f/c> against <http://example.org/foo/bar> -PASS Parsing origin: <#β> against <http://example.org/foo/bar> -PASS Parsing origin: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Parsing origin: <tel:1234567890> against <http://example.org/foo/bar> -PASS Parsing origin: <ssh://example.com/foo/bar.git> against <http://example.org/> -PASS Parsing origin: <http://example.com/././foo> against <about:blank> -PASS Parsing origin: <http://example.com/./.foo> against <about:blank> -PASS Parsing origin: <http://example.com/foo/.> against <about:blank> -PASS Parsing origin: <http://example.com/foo/./> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../> against <about:blank> -PASS Parsing origin: <http://example.com/foo/..bar> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Parsing origin: <http://example.com/foo/../../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/../../../ton> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e%2> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> -PASS Parsing origin: <http://example.com////../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar//../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar//..> against <about:blank> -PASS Parsing origin: <http://example.com/foo> against <about:blank> -PASS Parsing origin: <http://example.com/%20foo> against <about:blank> -PASS Parsing origin: <http://example.com/foo%> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2zbar> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2©zbar> against <about:blank> -PASS Parsing origin: <http://example.com/foo%41%7a> against <about:blank> -PASS Parsing origin: <http://example.com/foo %91> against <about:blank> -FAIL Parsing origin: <http://example.com/foo%00%51> against <about:blank> assert_equals: origin expected "http://example.com" but got "null" -PASS Parsing origin: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Parsing origin: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Parsing origin: <http://example.com/foo bar> against <about:blank> -PASS Parsing origin: <http://example.com\\foo\\bar> against <about:blank> -PASS Parsing origin: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Parsing origin: <http://example.com/@asdf%40> against <about:blank> -PASS Parsing origin: <http://example.com/你好你好> against <about:blank> -PASS Parsing origin: <http://example.com/‥/foo> against <about:blank> -PASS Parsing origin: <http://example.com//foo> against <about:blank> -PASS Parsing origin: <http://example.com//foo//bar> against <about:blank> -PASS Parsing origin: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Parsing origin: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Parsing origin: <data:test# »> against <about:blank> -PASS Parsing origin: <http://www.google.com> against <about:blank> -PASS Parsing origin: <http://192.0x00A80001> against <about:blank> -PASS Parsing origin: <http://www/foo%2Ehtml> against <about:blank> -PASS Parsing origin: <http://www/foo/%2E/html> against <about:blank> -PASS Parsing origin: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Parsing origin: <http:\\www.google.com\foo> against <about:blank> -PASS Parsing origin: <http://foo:80/> against <about:blank> -PASS Parsing origin: <http://foo:81/> against <about:blank> -PASS Parsing origin: <httpa://foo:80/> against <about:blank> -PASS Parsing origin: <https://foo:443/> against <about:blank> -PASS Parsing origin: <https://foo:80/> against <about:blank> -PASS Parsing origin: <ftp://foo:21/> against <about:blank> -PASS Parsing origin: <ftp://foo:80/> against <about:blank> -PASS Parsing origin: <gopher://foo:70/> against <about:blank> -PASS Parsing origin: <gopher://foo:443/> against <about:blank> -PASS Parsing origin: <ws://foo:80/> against <about:blank> -PASS Parsing origin: <ws://foo:81/> against <about:blank> -PASS Parsing origin: <ws://foo:443/> against <about:blank> -PASS Parsing origin: <ws://foo:815/> against <about:blank> -PASS Parsing origin: <wss://foo:80/> against <about:blank> -PASS Parsing origin: <wss://foo:81/> against <about:blank> -PASS Parsing origin: <wss://foo:443/> against <about:blank> -PASS Parsing origin: <wss://foo:815/> against <about:blank> -PASS Parsing origin: <http:/example.com/> against <about:blank> -PASS Parsing origin: <ftp:/example.com/> against <about:blank> -PASS Parsing origin: <https:/example.com/> against <about:blank> -PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank> -PASS Parsing origin: <ftps:/example.com/> against <about:blank> -PASS Parsing origin: <gopher:/example.com/> against <about:blank> -PASS Parsing origin: <ws:/example.com/> against <about:blank> -PASS Parsing origin: <wss:/example.com/> against <about:blank> -PASS Parsing origin: <data:/example.com/> against <about:blank> -PASS Parsing origin: <javascript:/example.com/> against <about:blank> -PASS Parsing origin: <mailto:/example.com/> against <about:blank> -PASS Parsing origin: <http:example.com/> against <about:blank> -PASS Parsing origin: <ftp:example.com/> against <about:blank> -PASS Parsing origin: <https:example.com/> against <about:blank> -PASS Parsing origin: <madeupscheme:example.com/> against <about:blank> -PASS Parsing origin: <ftps:example.com/> against <about:blank> -PASS Parsing origin: <gopher:example.com/> against <about:blank> -PASS Parsing origin: <ws:example.com/> against <about:blank> -PASS Parsing origin: <wss:example.com/> against <about:blank> -PASS Parsing origin: <data:example.com/> against <about:blank> -PASS Parsing origin: <javascript:example.com/> against <about:blank> -PASS Parsing origin: <mailto:example.com/> against <about:blank> -PASS Parsing origin: <http:@www.example.com> against <about:blank> -PASS Parsing origin: <http:/@www.example.com> against <about:blank> -PASS Parsing origin: <http://@www.example.com> against <about:blank> -PASS Parsing origin: <http:a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http:/a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://@pple.com> against <about:blank> -PASS Parsing origin: <http::b@www.example.com> against <about:blank> -PASS Parsing origin: <http:/:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://:b@www.example.com> against <about:blank> -PASS Parsing origin: <http:a:@www.example.com> against <about:blank> -PASS Parsing origin: <http:/a:@www.example.com> against <about:blank> -PASS Parsing origin: <http://a:@www.example.com> against <about:blank> -PASS Parsing origin: <http://www.@pple.com> against <about:blank> -PASS Parsing origin: <http://:@www.example.com> against <about:blank> -PASS Parsing origin: </> against <http://www.example.com/test> -PASS Parsing origin: </test.txt> against <http://www.example.com/test> -PASS Parsing origin: <.> against <http://www.example.com/test> -PASS Parsing origin: <..> against <http://www.example.com/test> -PASS Parsing origin: <test.txt> against <http://www.example.com/test> -PASS Parsing origin: <./test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../aaa/test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../../test.txt> against <http://www.example.com/test> -PASS Parsing origin: <中/test.txt> against <http://www.example.com/test> -PASS Parsing origin: <http://www.example2.com> against <http://www.example.com/test> -PASS Parsing origin: <//www.example2.com> against <http://www.example.com/test> -PASS Parsing origin: <http://ExAmPlE.CoM> against <http://other.com/> -PASS Parsing origin: <http://GOOgoo.com> against <http://other.com/> -PASS Parsing origin: <\0 http://example.com/ \r > against <about:blank> -PASS Parsing origin: <http://www.foo。bar.com> against <http://other.com/> -PASS Parsing origin: <https://x/�?�#�> against <about:blank> -PASS Parsing origin: <http://Go.com> against <http://other.com/> -PASS Parsing origin: <http://你好你好> against <http://other.com/> -FAIL Parsing origin: <https://faß.ExAmPlE/> against <about:blank> assert_equals: origin expected "https://xn--fa-hia.example" but got "https://fass.example" -PASS Parsing origin: <sc://faß.ExAmPlE/> against <about:blank> -PASS Parsing origin: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Parsing origin: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -PASS Parsing origin: <http://0Xc0.0250.01> against <http://other.com/> -PASS Parsing origin: <http://./> against <about:blank> -PASS Parsing origin: <http://../> against <about:blank> -PASS Parsing origin: <http://0..0x300/> against <about:blank> -PASS Parsing origin: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Parsing origin: <#> against <test:test> -PASS Parsing origin: <#x> against <mailto:x@x.com> -PASS Parsing origin: <#x> against <data:,> -PASS Parsing origin: <#x> against <about:blank> -PASS Parsing origin: <#> against <test:test?test> -PASS Parsing origin: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Parsing origin: <https://@@@example> against <http://doesnotmatter/> -PASS Parsing origin: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Parsing origin: <http://host/?'> against <about:blank> -PASS Parsing origin: <notspecial://host/?'> against <about:blank> -PASS Parsing origin: </some/path> against <http://user@example.org/smth> -PASS Parsing origin: <> against <http://user:pass@example.org:21/smth> -PASS Parsing origin: </some/path> against <http://user:pass@example.org:21/smth> -PASS Parsing origin: <i> against <sc:/pa/pa> -PASS Parsing origin: <i> against <sc://ho/pa> -PASS Parsing origin: <i> against <sc:///pa/pa> -PASS Parsing origin: <../i> against <sc:/pa/pa> -PASS Parsing origin: <../i> against <sc://ho/pa> -PASS Parsing origin: <../i> against <sc:///pa/pa> -PASS Parsing origin: </i> against <sc:/pa/pa> -PASS Parsing origin: </i> against <sc://ho/pa> -PASS Parsing origin: </i> against <sc:///pa/pa> -PASS Parsing origin: <?i> against <sc:/pa/pa> -PASS Parsing origin: <?i> against <sc://ho/pa> -PASS Parsing origin: <?i> against <sc:///pa/pa> -PASS Parsing origin: <#i> against <sc:sd> -PASS Parsing origin: <#i> against <sc:sd/sd> -PASS Parsing origin: <#i> against <sc:/pa/pa> -PASS Parsing origin: <#i> against <sc://ho/pa> -PASS Parsing origin: <#i> against <sc:///pa/pa> -PASS Parsing origin: <about:/../> against <about:blank> -PASS Parsing origin: <data:/../> against <about:blank> -PASS Parsing origin: <javascript:/../> against <about:blank> -PASS Parsing origin: <mailto:/../> against <about:blank> -PASS Parsing origin: <sc://ñ.test/> against <about:blank> -PASS Parsing origin: <x> against <sc://ñ> -PASS Parsing origin: <sc:\../> against <about:blank> -PASS Parsing origin: <sc::a@example.net> against <about:blank> -PASS Parsing origin: <wow:%NBD> against <about:blank> -PASS Parsing origin: <wow:%1G> against <about:blank> -PASS Parsing origin: <wow:> against <about:blank> -FAIL Parsing origin: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> assert_equals: origin expected "http://example.com" but got "null" -FAIL Parsing origin: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: origin expected "http://\x1f!\"$&'()*+,-.;=_`{}~" but got "null" -PASS Parsing origin: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> -PASS Parsing origin: <ftp://%e2%98%83> against <about:blank> -PASS Parsing origin: <https://%e2%98%83> against <about:blank> -PASS Parsing origin: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Parsing origin: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Parsing origin: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Parsing origin: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Parsing origin: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing origin: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing origin: <http:> against <http://example.org/foo/bar> -PASS Parsing origin: <sc:> against <https://example.org/foo/bar> -PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Parsing origin: <http://192.168.257> against <http://other.com/> -PASS Parsing origin: <http://192.168.257.com> against <http://other.com/> -PASS Parsing origin: <http://256> against <http://other.com/> -PASS Parsing origin: <http://256.com> against <http://other.com/> -PASS Parsing origin: <http://999999999> against <http://other.com/> -PASS Parsing origin: <http://999999999.com> against <http://other.com/> -PASS Parsing origin: <http://10000000000.com> against <http://other.com/> -PASS Parsing origin: <http://4294967295> against <http://other.com/> -PASS Parsing origin: <http://0xffffffff> against <http://other.com/> -PASS Parsing origin: <http://256.256.256.256.256> against <http://other.com/> -PASS Parsing origin: <https://0x.0x.0> against <about:blank> -PASS Parsing origin: <asdf://%43%7C/> against <about:blank> -PASS Parsing origin: <http://[1:0::]> against <http://example.net/> -PASS Parsing origin: <sc://ñ> against <about:blank> -PASS Parsing origin: <sc://ñ?x> against <about:blank> -PASS Parsing origin: <sc://ñ#x> against <about:blank> -PASS Parsing origin: <#x> against <sc://ñ> -PASS Parsing origin: <?x> against <sc://ñ> -PASS Parsing origin: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> -PASS Parsing origin: <telnet://user:pass@foobar.com:23/> against <about:blank> -PASS Parsing origin: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> -PASS Parsing origin: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> -PASS Parsing origin: <rsync://foo@host:911/sup> against <about:blank> -PASS Parsing origin: <git://github.com/foo/bar.git> against <about:blank> -PASS Parsing origin: <irc://myserver.com:6999/channel?passwd> against <about:blank> -PASS Parsing origin: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> -PASS Parsing origin: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> -PASS Parsing origin: <git+https://github.com/foo/bar> against <about:blank> -PASS Parsing origin: <urn:ietf:rfc:2648> against <about:blank> -PASS Parsing origin: <tag:joe@example.org,2001:foo/bar> against <about:blank> -PASS Parsing origin: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Parsing origin: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Parsing origin: <https://user:pass[@foo/bar> against <http://example.org> -PASS Parsing origin: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> -FAIL Parsing origin: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: origin expected "wss://!\"$&'()*+,-.;=_`{}~" but got "null" -PASS Parsing origin: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-xhtml-expected.txt deleted file mode 100644 index e1738cb..0000000 --- a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/a-element-origin-xhtml-expected.txt +++ /dev/null
@@ -1,337 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 319 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Parsing origin: <http://example . -org> against <http://example.org/foo/bar> -PASS Parsing origin: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Parsing origin: <https://test:@test> against <about:blank> -PASS Parsing origin: <https://:@test> against <about:blank> -PASS Parsing origin: <non-special://test:@test/x> against <about:blank> -PASS Parsing origin: <non-special://:@test/x> against <about:blank> -PASS Parsing origin: <http:foo.com> against <http://example.org/foo/bar> -PASS Parsing origin: < :foo.com -> against <http://example.org/foo/bar> -PASS Parsing origin: < foo.com > against <http://example.org/foo/bar> -PASS Parsing origin: <a: foo.com> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:0/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Parsing origin: <http://f: -/c> against <http://example.org/foo/bar> -PASS Parsing origin: <> against <http://example.org/foo/bar> -PASS Parsing origin: < > against <http://example.org/foo/bar> -PASS Parsing origin: <:foo.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <:foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <:> against <http://example.org/foo/bar> -PASS Parsing origin: <:a> against <http://example.org/foo/bar> -PASS Parsing origin: <:/> against <http://example.org/foo/bar> -PASS Parsing origin: <:\> against <http://example.org/foo/bar> -PASS Parsing origin: <:#> against <http://example.org/foo/bar> -PASS Parsing origin: <#> against <http://example.org/foo/bar> -PASS Parsing origin: <#/> against <http://example.org/foo/bar> -PASS Parsing origin: <#\> against <http://example.org/foo/bar> -PASS Parsing origin: <#;?> against <http://example.org/foo/bar> -PASS Parsing origin: <?> against <http://example.org/foo/bar> -PASS Parsing origin: </> against <http://example.org/foo/bar> -PASS Parsing origin: <:23> against <http://example.org/foo/bar> -PASS Parsing origin: </:23> against <http://example.org/foo/bar> -PASS Parsing origin: <\x> against <http://example.org/foo/bar> -PASS Parsing origin: <\\x\hello> against <http://example.org/foo/bar> -PASS Parsing origin: <::> against <http://example.org/foo/bar> -PASS Parsing origin: <::23> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://> against <http://example.org/foo/bar> -PASS Parsing origin: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Parsing origin: <http::@c:29> against <http://example.org/foo/bar> -PASS Parsing origin: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Parsing origin: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Parsing origin: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:/bar.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://///////> against <http://example.org/foo/bar> -PASS Parsing origin: <foo://///////bar.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <foo:////://///> against <http://example.org/foo/bar> -PASS Parsing origin: <c:/foo> against <http://example.org/foo/bar> -PASS Parsing origin: <//foo/bar> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Parsing origin: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Parsing origin: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Parsing origin: <http:[61:27]/:foo> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Parsing origin: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Parsing origin: <http:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <https:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <data:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <http:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <https:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <ws:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <wss:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <data:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Parsing origin: </a/b/c> against <http://example.org/foo/bar> -PASS Parsing origin: </a/ /c> against <http://example.org/foo/bar> -PASS Parsing origin: </a%2fc> against <http://example.org/foo/bar> -PASS Parsing origin: </a/%2f/c> against <http://example.org/foo/bar> -PASS Parsing origin: <#β> against <http://example.org/foo/bar> -PASS Parsing origin: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Parsing origin: <tel:1234567890> against <http://example.org/foo/bar> -PASS Parsing origin: <ssh://example.com/foo/bar.git> against <http://example.org/> -PASS Parsing origin: <http://example.com/././foo> against <about:blank> -PASS Parsing origin: <http://example.com/./.foo> against <about:blank> -PASS Parsing origin: <http://example.com/foo/.> against <about:blank> -PASS Parsing origin: <http://example.com/foo/./> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../> against <about:blank> -PASS Parsing origin: <http://example.com/foo/..bar> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Parsing origin: <http://example.com/foo/../../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/../../../ton> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e%2> against <about:blank> -PASS Parsing origin: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> -PASS Parsing origin: <http://example.com////../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar//../..> against <about:blank> -PASS Parsing origin: <http://example.com/foo/bar//..> against <about:blank> -PASS Parsing origin: <http://example.com/foo> against <about:blank> -PASS Parsing origin: <http://example.com/%20foo> against <about:blank> -PASS Parsing origin: <http://example.com/foo%> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2zbar> against <about:blank> -PASS Parsing origin: <http://example.com/foo%2©zbar> against <about:blank> -PASS Parsing origin: <http://example.com/foo%41%7a> against <about:blank> -PASS Parsing origin: <http://example.com/foo %91> against <about:blank> -FAIL Parsing origin: <http://example.com/foo%00%51> against <about:blank> assert_equals: origin expected "http://example.com" but got "null" -PASS Parsing origin: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Parsing origin: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Parsing origin: <http://example.com/foo bar> against <about:blank> -PASS Parsing origin: <http://example.com\\foo\\bar> against <about:blank> -PASS Parsing origin: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Parsing origin: <http://example.com/@asdf%40> against <about:blank> -PASS Parsing origin: <http://example.com/你好你好> against <about:blank> -PASS Parsing origin: <http://example.com/‥/foo> against <about:blank> -PASS Parsing origin: <http://example.com//foo> against <about:blank> -PASS Parsing origin: <http://example.com//foo//bar> against <about:blank> -PASS Parsing origin: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Parsing origin: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Parsing origin: <data:test# »> against <about:blank> -PASS Parsing origin: <http://www.google.com> against <about:blank> -PASS Parsing origin: <http://192.0x00A80001> against <about:blank> -PASS Parsing origin: <http://www/foo%2Ehtml> against <about:blank> -PASS Parsing origin: <http://www/foo/%2E/html> against <about:blank> -PASS Parsing origin: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Parsing origin: <http:\\www.google.com\foo> against <about:blank> -PASS Parsing origin: <http://foo:80/> against <about:blank> -PASS Parsing origin: <http://foo:81/> against <about:blank> -PASS Parsing origin: <httpa://foo:80/> against <about:blank> -PASS Parsing origin: <https://foo:443/> against <about:blank> -PASS Parsing origin: <https://foo:80/> against <about:blank> -PASS Parsing origin: <ftp://foo:21/> against <about:blank> -PASS Parsing origin: <ftp://foo:80/> against <about:blank> -PASS Parsing origin: <gopher://foo:70/> against <about:blank> -PASS Parsing origin: <gopher://foo:443/> against <about:blank> -PASS Parsing origin: <ws://foo:80/> against <about:blank> -PASS Parsing origin: <ws://foo:81/> against <about:blank> -PASS Parsing origin: <ws://foo:443/> against <about:blank> -PASS Parsing origin: <ws://foo:815/> against <about:blank> -PASS Parsing origin: <wss://foo:80/> against <about:blank> -PASS Parsing origin: <wss://foo:81/> against <about:blank> -PASS Parsing origin: <wss://foo:443/> against <about:blank> -PASS Parsing origin: <wss://foo:815/> against <about:blank> -PASS Parsing origin: <http:/example.com/> against <about:blank> -PASS Parsing origin: <ftp:/example.com/> against <about:blank> -PASS Parsing origin: <https:/example.com/> against <about:blank> -PASS Parsing origin: <madeupscheme:/example.com/> against <about:blank> -PASS Parsing origin: <ftps:/example.com/> against <about:blank> -PASS Parsing origin: <gopher:/example.com/> against <about:blank> -PASS Parsing origin: <ws:/example.com/> against <about:blank> -PASS Parsing origin: <wss:/example.com/> against <about:blank> -PASS Parsing origin: <data:/example.com/> against <about:blank> -PASS Parsing origin: <javascript:/example.com/> against <about:blank> -PASS Parsing origin: <mailto:/example.com/> against <about:blank> -PASS Parsing origin: <http:example.com/> against <about:blank> -PASS Parsing origin: <ftp:example.com/> against <about:blank> -PASS Parsing origin: <https:example.com/> against <about:blank> -PASS Parsing origin: <madeupscheme:example.com/> against <about:blank> -PASS Parsing origin: <ftps:example.com/> against <about:blank> -PASS Parsing origin: <gopher:example.com/> against <about:blank> -PASS Parsing origin: <ws:example.com/> against <about:blank> -PASS Parsing origin: <wss:example.com/> against <about:blank> -PASS Parsing origin: <data:example.com/> against <about:blank> -PASS Parsing origin: <javascript:example.com/> against <about:blank> -PASS Parsing origin: <mailto:example.com/> against <about:blank> -PASS Parsing origin: <http:@www.example.com> against <about:blank> -PASS Parsing origin: <http:/@www.example.com> against <about:blank> -PASS Parsing origin: <http://@www.example.com> against <about:blank> -PASS Parsing origin: <http:a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http:/a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://a:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://@pple.com> against <about:blank> -PASS Parsing origin: <http::b@www.example.com> against <about:blank> -PASS Parsing origin: <http:/:b@www.example.com> against <about:blank> -PASS Parsing origin: <http://:b@www.example.com> against <about:blank> -PASS Parsing origin: <http:a:@www.example.com> against <about:blank> -PASS Parsing origin: <http:/a:@www.example.com> against <about:blank> -PASS Parsing origin: <http://a:@www.example.com> against <about:blank> -PASS Parsing origin: <http://www.@pple.com> against <about:blank> -PASS Parsing origin: <http://:@www.example.com> against <about:blank> -PASS Parsing origin: </> against <http://www.example.com/test> -PASS Parsing origin: </test.txt> against <http://www.example.com/test> -PASS Parsing origin: <.> against <http://www.example.com/test> -PASS Parsing origin: <..> against <http://www.example.com/test> -PASS Parsing origin: <test.txt> against <http://www.example.com/test> -PASS Parsing origin: <./test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../aaa/test.txt> against <http://www.example.com/test> -PASS Parsing origin: <../../test.txt> against <http://www.example.com/test> -PASS Parsing origin: <中/test.txt> against <http://www.example.com/test> -PASS Parsing origin: <http://www.example2.com> against <http://www.example.com/test> -PASS Parsing origin: <//www.example2.com> against <http://www.example.com/test> -PASS Parsing origin: <http://ExAmPlE.CoM> against <http://other.com/> -PASS Parsing origin: <http://GOOgoo.com> against <http://other.com/> -PASS Parsing origin: <\0 http://example.com/ \r > against <about:blank> -PASS Parsing origin: <http://www.foo。bar.com> against <http://other.com/> -PASS Parsing origin: <https://x/�?�#�> against <about:blank> -PASS Parsing origin: <http://Go.com> against <http://other.com/> -PASS Parsing origin: <http://你好你好> against <http://other.com/> -FAIL Parsing origin: <https://faß.ExAmPlE/> against <about:blank> assert_equals: origin expected "https://xn--fa-hia.example" but got "https://fass.example" -PASS Parsing origin: <sc://faß.ExAmPlE/> against <about:blank> -PASS Parsing origin: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Parsing origin: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -PASS Parsing origin: <http://0Xc0.0250.01> against <http://other.com/> -PASS Parsing origin: <http://./> against <about:blank> -PASS Parsing origin: <http://../> against <about:blank> -PASS Parsing origin: <http://0..0x300/> against <about:blank> -PASS Parsing origin: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Parsing origin: <#> against <test:test> -PASS Parsing origin: <#x> against <mailto:x@x.com> -PASS Parsing origin: <#x> against <data:,> -PASS Parsing origin: <#x> against <about:blank> -PASS Parsing origin: <#> against <test:test?test> -PASS Parsing origin: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Parsing origin: <https://@@@example> against <http://doesnotmatter/> -PASS Parsing origin: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Parsing origin: <http://host/?'> against <about:blank> -PASS Parsing origin: <notspecial://host/?'> against <about:blank> -PASS Parsing origin: </some/path> against <http://user@example.org/smth> -PASS Parsing origin: <> against <http://user:pass@example.org:21/smth> -PASS Parsing origin: </some/path> against <http://user:pass@example.org:21/smth> -PASS Parsing origin: <i> against <sc:/pa/pa> -PASS Parsing origin: <i> against <sc://ho/pa> -PASS Parsing origin: <i> against <sc:///pa/pa> -PASS Parsing origin: <../i> against <sc:/pa/pa> -PASS Parsing origin: <../i> against <sc://ho/pa> -PASS Parsing origin: <../i> against <sc:///pa/pa> -PASS Parsing origin: </i> against <sc:/pa/pa> -PASS Parsing origin: </i> against <sc://ho/pa> -PASS Parsing origin: </i> against <sc:///pa/pa> -PASS Parsing origin: <?i> against <sc:/pa/pa> -PASS Parsing origin: <?i> against <sc://ho/pa> -PASS Parsing origin: <?i> against <sc:///pa/pa> -PASS Parsing origin: <#i> against <sc:sd> -PASS Parsing origin: <#i> against <sc:sd/sd> -PASS Parsing origin: <#i> against <sc:/pa/pa> -PASS Parsing origin: <#i> against <sc://ho/pa> -PASS Parsing origin: <#i> against <sc:///pa/pa> -PASS Parsing origin: <about:/../> against <about:blank> -PASS Parsing origin: <data:/../> against <about:blank> -PASS Parsing origin: <javascript:/../> against <about:blank> -PASS Parsing origin: <mailto:/../> against <about:blank> -PASS Parsing origin: <sc://ñ.test/> against <about:blank> -PASS Parsing origin: <x> against <sc://ñ> -PASS Parsing origin: <sc:\../> against <about:blank> -PASS Parsing origin: <sc::a@example.net> against <about:blank> -PASS Parsing origin: <wow:%NBD> against <about:blank> -PASS Parsing origin: <wow:%1G> against <about:blank> -PASS Parsing origin: <wow:> against <about:blank> -FAIL Parsing origin: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> assert_equals: origin expected "http://example.com" but got "null" -FAIL Parsing origin: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: origin expected "http://\x1f!\"$&'()*+,-.;=_`{}~" but got "null" -PASS Parsing origin: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> -PASS Parsing origin: <ftp://%e2%98%83> against <about:blank> -PASS Parsing origin: <https://%e2%98%83> against <about:blank> -PASS Parsing origin: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Parsing origin: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Parsing origin: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Parsing origin: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Parsing origin: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing origin: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing origin: <http:> against <http://example.org/foo/bar> -PASS Parsing origin: <sc:> against <https://example.org/foo/bar> -PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Parsing origin: <http://192.168.257> against <http://other.com/> -PASS Parsing origin: <http://192.168.257.com> against <http://other.com/> -PASS Parsing origin: <http://256> against <http://other.com/> -PASS Parsing origin: <http://256.com> against <http://other.com/> -PASS Parsing origin: <http://999999999> against <http://other.com/> -PASS Parsing origin: <http://999999999.com> against <http://other.com/> -PASS Parsing origin: <http://10000000000.com> against <http://other.com/> -PASS Parsing origin: <http://4294967295> against <http://other.com/> -PASS Parsing origin: <http://0xffffffff> against <http://other.com/> -PASS Parsing origin: <http://256.256.256.256.256> against <http://other.com/> -PASS Parsing origin: <https://0x.0x.0> against <about:blank> -PASS Parsing origin: <asdf://%43%7C/> against <about:blank> -PASS Parsing origin: <http://[1:0::]> against <http://example.net/> -PASS Parsing origin: <sc://ñ> against <about:blank> -PASS Parsing origin: <sc://ñ?x> against <about:blank> -PASS Parsing origin: <sc://ñ#x> against <about:blank> -PASS Parsing origin: <#x> against <sc://ñ> -PASS Parsing origin: <?x> against <sc://ñ> -PASS Parsing origin: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> -PASS Parsing origin: <telnet://user:pass@foobar.com:23/> against <about:blank> -PASS Parsing origin: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> -PASS Parsing origin: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> -PASS Parsing origin: <rsync://foo@host:911/sup> against <about:blank> -PASS Parsing origin: <git://github.com/foo/bar.git> against <about:blank> -PASS Parsing origin: <irc://myserver.com:6999/channel?passwd> against <about:blank> -PASS Parsing origin: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> -PASS Parsing origin: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> -PASS Parsing origin: <git+https://github.com/foo/bar> against <about:blank> -PASS Parsing origin: <urn:ietf:rfc:2648> against <about:blank> -PASS Parsing origin: <tag:joe@example.org,2001:foo/bar> against <about:blank> -PASS Parsing origin: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Parsing origin: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Parsing origin: <https://user:pass[@foo/bar> against <http://example.org> -PASS Parsing origin: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Parsing origin: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> -FAIL Parsing origin: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: origin expected "wss://!\"$&'()*+,-.;=_`{}~" but got "null" -PASS Parsing origin: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Parsing origin: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any-expected.txt deleted file mode 100644 index dac7874..0000000 --- a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any-expected.txt +++ /dev/null
@@ -1,337 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 316 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Origin parsing: <http://example . -org> against <http://example.org/foo/bar> -PASS Origin parsing: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Origin parsing: <https://test:@test> against <about:blank> -PASS Origin parsing: <https://:@test> against <about:blank> -PASS Origin parsing: <non-special://test:@test/x> against <about:blank> -PASS Origin parsing: <non-special://:@test/x> against <about:blank> -PASS Origin parsing: <http:foo.com> against <http://example.org/foo/bar> -PASS Origin parsing: < :foo.com -> against <http://example.org/foo/bar> -PASS Origin parsing: < foo.com > against <http://example.org/foo/bar> -PASS Origin parsing: <a: foo.com> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:0/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f: -/c> against <http://example.org/foo/bar> -PASS Origin parsing: <> against <http://example.org/foo/bar> -PASS Origin parsing: < > against <http://example.org/foo/bar> -PASS Origin parsing: <:foo.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <:foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <:> against <http://example.org/foo/bar> -PASS Origin parsing: <:a> against <http://example.org/foo/bar> -PASS Origin parsing: <:/> against <http://example.org/foo/bar> -PASS Origin parsing: <:\> against <http://example.org/foo/bar> -PASS Origin parsing: <:#> against <http://example.org/foo/bar> -PASS Origin parsing: <#> against <http://example.org/foo/bar> -PASS Origin parsing: <#/> against <http://example.org/foo/bar> -PASS Origin parsing: <#\> against <http://example.org/foo/bar> -PASS Origin parsing: <#;?> against <http://example.org/foo/bar> -PASS Origin parsing: <?> against <http://example.org/foo/bar> -PASS Origin parsing: </> against <http://example.org/foo/bar> -PASS Origin parsing: <:23> against <http://example.org/foo/bar> -PASS Origin parsing: </:23> against <http://example.org/foo/bar> -PASS Origin parsing: <\x> against <http://example.org/foo/bar> -PASS Origin parsing: <\\x\hello> against <http://example.org/foo/bar> -PASS Origin parsing: <::> against <http://example.org/foo/bar> -PASS Origin parsing: <::23> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://> against <http://example.org/foo/bar> -PASS Origin parsing: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Origin parsing: <http::@c:29> against <http://example.org/foo/bar> -PASS Origin parsing: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Origin parsing: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Origin parsing: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:/bar.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://///////> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://///////bar.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:////://///> against <http://example.org/foo/bar> -PASS Origin parsing: <c:/foo> against <http://example.org/foo/bar> -PASS Origin parsing: <//foo/bar> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Origin parsing: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Origin parsing: <http:[61:27]/:foo> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Origin parsing: <http:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <https:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <data:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <http:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <https:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ws:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <wss:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <data:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: </a/b/c> against <http://example.org/foo/bar> -PASS Origin parsing: </a/ /c> against <http://example.org/foo/bar> -PASS Origin parsing: </a%2fc> against <http://example.org/foo/bar> -PASS Origin parsing: </a/%2f/c> against <http://example.org/foo/bar> -PASS Origin parsing: <#β> against <http://example.org/foo/bar> -PASS Origin parsing: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Origin parsing: <tel:1234567890> against <http://example.org/foo/bar> -PASS Origin parsing: <ssh://example.com/foo/bar.git> against <http://example.org/> -PASS Origin parsing: <http://example.com/././foo> against <about:blank> -PASS Origin parsing: <http://example.com/./.foo> against <about:blank> -PASS Origin parsing: <http://example.com/foo/.> against <about:blank> -PASS Origin parsing: <http://example.com/foo/./> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../> against <about:blank> -PASS Origin parsing: <http://example.com/foo/..bar> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Origin parsing: <http://example.com/foo/../../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/../../../ton> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e%2> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> -PASS Origin parsing: <http://example.com////../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar//../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar//..> against <about:blank> -PASS Origin parsing: <http://example.com/foo> against <about:blank> -PASS Origin parsing: <http://example.com/%20foo> against <about:blank> -PASS Origin parsing: <http://example.com/foo%> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2zbar> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2©zbar> against <about:blank> -PASS Origin parsing: <http://example.com/foo%41%7a> against <about:blank> -PASS Origin parsing: <http://example.com/foo %91> against <about:blank> -FAIL Origin parsing: <http://example.com/foo%00%51> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Origin parsing: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Origin parsing: <http://example.com/foo bar> against <about:blank> -PASS Origin parsing: <http://example.com\\foo\\bar> against <about:blank> -PASS Origin parsing: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Origin parsing: <http://example.com/@asdf%40> against <about:blank> -PASS Origin parsing: <http://example.com/你好你好> against <about:blank> -PASS Origin parsing: <http://example.com/‥/foo> against <about:blank> -PASS Origin parsing: <http://example.com//foo> against <about:blank> -PASS Origin parsing: <http://example.com//foo//bar> against <about:blank> -PASS Origin parsing: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Origin parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Origin parsing: <data:test# »> against <about:blank> -PASS Origin parsing: <http://www.google.com> against <about:blank> -PASS Origin parsing: <http://192.0x00A80001> against <about:blank> -PASS Origin parsing: <http://www/foo%2Ehtml> against <about:blank> -PASS Origin parsing: <http://www/foo/%2E/html> against <about:blank> -PASS Origin parsing: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Origin parsing: <http:\\www.google.com\foo> against <about:blank> -PASS Origin parsing: <http://foo:80/> against <about:blank> -PASS Origin parsing: <http://foo:81/> against <about:blank> -PASS Origin parsing: <httpa://foo:80/> against <about:blank> -PASS Origin parsing: <https://foo:443/> against <about:blank> -PASS Origin parsing: <https://foo:80/> against <about:blank> -PASS Origin parsing: <ftp://foo:21/> against <about:blank> -PASS Origin parsing: <ftp://foo:80/> against <about:blank> -PASS Origin parsing: <gopher://foo:70/> against <about:blank> -PASS Origin parsing: <gopher://foo:443/> against <about:blank> -PASS Origin parsing: <ws://foo:80/> against <about:blank> -PASS Origin parsing: <ws://foo:81/> against <about:blank> -PASS Origin parsing: <ws://foo:443/> against <about:blank> -PASS Origin parsing: <ws://foo:815/> against <about:blank> -PASS Origin parsing: <wss://foo:80/> against <about:blank> -PASS Origin parsing: <wss://foo:81/> against <about:blank> -PASS Origin parsing: <wss://foo:443/> against <about:blank> -PASS Origin parsing: <wss://foo:815/> against <about:blank> -PASS Origin parsing: <http:/example.com/> against <about:blank> -PASS Origin parsing: <ftp:/example.com/> against <about:blank> -PASS Origin parsing: <https:/example.com/> against <about:blank> -PASS Origin parsing: <madeupscheme:/example.com/> against <about:blank> -PASS Origin parsing: <ftps:/example.com/> against <about:blank> -PASS Origin parsing: <gopher:/example.com/> against <about:blank> -PASS Origin parsing: <ws:/example.com/> against <about:blank> -PASS Origin parsing: <wss:/example.com/> against <about:blank> -PASS Origin parsing: <data:/example.com/> against <about:blank> -PASS Origin parsing: <javascript:/example.com/> against <about:blank> -PASS Origin parsing: <mailto:/example.com/> against <about:blank> -PASS Origin parsing: <http:example.com/> against <about:blank> -PASS Origin parsing: <ftp:example.com/> against <about:blank> -PASS Origin parsing: <https:example.com/> against <about:blank> -PASS Origin parsing: <madeupscheme:example.com/> against <about:blank> -PASS Origin parsing: <ftps:example.com/> against <about:blank> -PASS Origin parsing: <gopher:example.com/> against <about:blank> -PASS Origin parsing: <ws:example.com/> against <about:blank> -PASS Origin parsing: <wss:example.com/> against <about:blank> -PASS Origin parsing: <data:example.com/> against <about:blank> -PASS Origin parsing: <javascript:example.com/> against <about:blank> -PASS Origin parsing: <mailto:example.com/> against <about:blank> -PASS Origin parsing: <http:@www.example.com> against <about:blank> -PASS Origin parsing: <http:/@www.example.com> against <about:blank> -PASS Origin parsing: <http://@www.example.com> against <about:blank> -PASS Origin parsing: <http:a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http:/a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://@pple.com> against <about:blank> -PASS Origin parsing: <http::b@www.example.com> against <about:blank> -PASS Origin parsing: <http:/:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://:b@www.example.com> against <about:blank> -PASS Origin parsing: <http:a:@www.example.com> against <about:blank> -PASS Origin parsing: <http:/a:@www.example.com> against <about:blank> -PASS Origin parsing: <http://a:@www.example.com> against <about:blank> -PASS Origin parsing: <http://www.@pple.com> against <about:blank> -PASS Origin parsing: <http://:@www.example.com> against <about:blank> -PASS Origin parsing: </> against <http://www.example.com/test> -PASS Origin parsing: </test.txt> against <http://www.example.com/test> -PASS Origin parsing: <.> against <http://www.example.com/test> -PASS Origin parsing: <..> against <http://www.example.com/test> -PASS Origin parsing: <test.txt> against <http://www.example.com/test> -PASS Origin parsing: <./test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../aaa/test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../../test.txt> against <http://www.example.com/test> -PASS Origin parsing: <中/test.txt> against <http://www.example.com/test> -PASS Origin parsing: <http://www.example2.com> against <http://www.example.com/test> -PASS Origin parsing: <//www.example2.com> against <http://www.example.com/test> -PASS Origin parsing: <http://ExAmPlE.CoM> against <http://other.com/> -PASS Origin parsing: <http://GOOgoo.com> against <http://other.com/> -PASS Origin parsing: <\0 http://example.com/ \r > against <about:blank> -PASS Origin parsing: <http://www.foo。bar.com> against <http://other.com/> -PASS Origin parsing: <https://x/�?�#�> against <about:blank> -PASS Origin parsing: <http://Go.com> against <http://other.com/> -PASS Origin parsing: <http://你好你好> against <http://other.com/> -FAIL Origin parsing: <https://faß.ExAmPlE/> against <about:blank> assert_equals: origin expected "https://xn--fa-hia.example" but got "https://fass.example" -PASS Origin parsing: <sc://faß.ExAmPlE/> against <about:blank> -PASS Origin parsing: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Origin parsing: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -PASS Origin parsing: <http://0Xc0.0250.01> against <http://other.com/> -PASS Origin parsing: <http://./> against <about:blank> -PASS Origin parsing: <http://../> against <about:blank> -PASS Origin parsing: <http://0..0x300/> against <about:blank> -PASS Origin parsing: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Origin parsing: <#> against <test:test> -PASS Origin parsing: <#x> against <mailto:x@x.com> -PASS Origin parsing: <#x> against <data:,> -PASS Origin parsing: <#x> against <about:blank> -PASS Origin parsing: <#> against <test:test?test> -PASS Origin parsing: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Origin parsing: <https://@@@example> against <http://doesnotmatter/> -PASS Origin parsing: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Origin parsing: <http://host/?'> against <about:blank> -PASS Origin parsing: <notspecial://host/?'> against <about:blank> -PASS Origin parsing: </some/path> against <http://user@example.org/smth> -PASS Origin parsing: <> against <http://user:pass@example.org:21/smth> -PASS Origin parsing: </some/path> against <http://user:pass@example.org:21/smth> -PASS Origin parsing: <i> against <sc:/pa/pa> -PASS Origin parsing: <i> against <sc://ho/pa> -PASS Origin parsing: <i> against <sc:///pa/pa> -PASS Origin parsing: <../i> against <sc:/pa/pa> -PASS Origin parsing: <../i> against <sc://ho/pa> -PASS Origin parsing: <../i> against <sc:///pa/pa> -PASS Origin parsing: </i> against <sc:/pa/pa> -PASS Origin parsing: </i> against <sc://ho/pa> -PASS Origin parsing: </i> against <sc:///pa/pa> -PASS Origin parsing: <?i> against <sc:/pa/pa> -PASS Origin parsing: <?i> against <sc://ho/pa> -PASS Origin parsing: <?i> against <sc:///pa/pa> -PASS Origin parsing: <#i> against <sc:sd> -PASS Origin parsing: <#i> against <sc:sd/sd> -PASS Origin parsing: <#i> against <sc:/pa/pa> -PASS Origin parsing: <#i> against <sc://ho/pa> -PASS Origin parsing: <#i> against <sc:///pa/pa> -PASS Origin parsing: <about:/../> against <about:blank> -PASS Origin parsing: <data:/../> against <about:blank> -PASS Origin parsing: <javascript:/../> against <about:blank> -PASS Origin parsing: <mailto:/../> against <about:blank> -PASS Origin parsing: <sc://ñ.test/> against <about:blank> -FAIL Origin parsing: <x> against <sc://ñ> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <sc:\../> against <about:blank> -PASS Origin parsing: <sc::a@example.net> against <about:blank> -PASS Origin parsing: <wow:%NBD> against <about:blank> -PASS Origin parsing: <wow:%1G> against <about:blank> -PASS Origin parsing: <wow:> against <about:blank> -FAIL Origin parsing: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> Failed to construct 'URL': Invalid URL -FAIL Origin parsing: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> -PASS Origin parsing: <ftp://%e2%98%83> against <about:blank> -PASS Origin parsing: <https://%e2%98%83> against <about:blank> -PASS Origin parsing: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Origin parsing: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Origin parsing: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Origin parsing: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Origin parsing: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Origin parsing: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Origin parsing: <http:> against <http://example.org/foo/bar> -PASS Origin parsing: <sc:> against <https://example.org/foo/bar> -PASS Origin parsing: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Origin parsing: <http://192.168.257> against <http://other.com/> -PASS Origin parsing: <http://192.168.257.com> against <http://other.com/> -PASS Origin parsing: <http://256> against <http://other.com/> -PASS Origin parsing: <http://256.com> against <http://other.com/> -PASS Origin parsing: <http://999999999> against <http://other.com/> -PASS Origin parsing: <http://999999999.com> against <http://other.com/> -PASS Origin parsing: <http://10000000000.com> against <http://other.com/> -PASS Origin parsing: <http://4294967295> against <http://other.com/> -PASS Origin parsing: <http://0xffffffff> against <http://other.com/> -PASS Origin parsing: <http://256.256.256.256.256> against <http://other.com/> -PASS Origin parsing: <https://0x.0x.0> against <about:blank> -PASS Origin parsing: <asdf://%43%7C/> against <about:blank> -PASS Origin parsing: <http://[1:0::]> against <http://example.net/> -PASS Origin parsing: <sc://ñ> against <about:blank> -PASS Origin parsing: <sc://ñ?x> against <about:blank> -PASS Origin parsing: <sc://ñ#x> against <about:blank> -FAIL Origin parsing: <#x> against <sc://ñ> Failed to construct 'URL': Invalid URL -FAIL Origin parsing: <?x> against <sc://ñ> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> -PASS Origin parsing: <telnet://user:pass@foobar.com:23/> against <about:blank> -PASS Origin parsing: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> -PASS Origin parsing: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> -PASS Origin parsing: <rsync://foo@host:911/sup> against <about:blank> -PASS Origin parsing: <git://github.com/foo/bar.git> against <about:blank> -PASS Origin parsing: <irc://myserver.com:6999/channel?passwd> against <about:blank> -PASS Origin parsing: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> -PASS Origin parsing: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> -PASS Origin parsing: <git+https://github.com/foo/bar> against <about:blank> -PASS Origin parsing: <urn:ietf:rfc:2648> against <about:blank> -PASS Origin parsing: <tag:joe@example.org,2001:foo/bar> against <about:blank> -PASS Origin parsing: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Origin parsing: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Origin parsing: <https://user:pass[@foo/bar> against <http://example.org> -PASS Origin parsing: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> -FAIL Origin parsing: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any.worker-expected.txt deleted file mode 100644 index dac7874..0000000 --- a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-origin.any.worker-expected.txt +++ /dev/null
@@ -1,337 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 316 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Origin parsing: <http://example . -org> against <http://example.org/foo/bar> -PASS Origin parsing: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Origin parsing: <https://test:@test> against <about:blank> -PASS Origin parsing: <https://:@test> against <about:blank> -PASS Origin parsing: <non-special://test:@test/x> against <about:blank> -PASS Origin parsing: <non-special://:@test/x> against <about:blank> -PASS Origin parsing: <http:foo.com> against <http://example.org/foo/bar> -PASS Origin parsing: < :foo.com -> against <http://example.org/foo/bar> -PASS Origin parsing: < foo.com > against <http://example.org/foo/bar> -PASS Origin parsing: <a: foo.com> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:0/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Origin parsing: <http://f: -/c> against <http://example.org/foo/bar> -PASS Origin parsing: <> against <http://example.org/foo/bar> -PASS Origin parsing: < > against <http://example.org/foo/bar> -PASS Origin parsing: <:foo.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <:foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <:> against <http://example.org/foo/bar> -PASS Origin parsing: <:a> against <http://example.org/foo/bar> -PASS Origin parsing: <:/> against <http://example.org/foo/bar> -PASS Origin parsing: <:\> against <http://example.org/foo/bar> -PASS Origin parsing: <:#> against <http://example.org/foo/bar> -PASS Origin parsing: <#> against <http://example.org/foo/bar> -PASS Origin parsing: <#/> against <http://example.org/foo/bar> -PASS Origin parsing: <#\> against <http://example.org/foo/bar> -PASS Origin parsing: <#;?> against <http://example.org/foo/bar> -PASS Origin parsing: <?> against <http://example.org/foo/bar> -PASS Origin parsing: </> against <http://example.org/foo/bar> -PASS Origin parsing: <:23> against <http://example.org/foo/bar> -PASS Origin parsing: </:23> against <http://example.org/foo/bar> -PASS Origin parsing: <\x> against <http://example.org/foo/bar> -PASS Origin parsing: <\\x\hello> against <http://example.org/foo/bar> -PASS Origin parsing: <::> against <http://example.org/foo/bar> -PASS Origin parsing: <::23> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://> against <http://example.org/foo/bar> -PASS Origin parsing: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Origin parsing: <http::@c:29> against <http://example.org/foo/bar> -PASS Origin parsing: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Origin parsing: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Origin parsing: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:/bar.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://///////> against <http://example.org/foo/bar> -PASS Origin parsing: <foo://///////bar.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <foo:////://///> against <http://example.org/foo/bar> -PASS Origin parsing: <c:/foo> against <http://example.org/foo/bar> -PASS Origin parsing: <//foo/bar> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Origin parsing: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Origin parsing: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Origin parsing: <http:[61:27]/:foo> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Origin parsing: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Origin parsing: <http:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <https:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <data:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <http:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <https:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <ws:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <wss:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <data:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Origin parsing: </a/b/c> against <http://example.org/foo/bar> -PASS Origin parsing: </a/ /c> against <http://example.org/foo/bar> -PASS Origin parsing: </a%2fc> against <http://example.org/foo/bar> -PASS Origin parsing: </a/%2f/c> against <http://example.org/foo/bar> -PASS Origin parsing: <#β> against <http://example.org/foo/bar> -PASS Origin parsing: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Origin parsing: <tel:1234567890> against <http://example.org/foo/bar> -PASS Origin parsing: <ssh://example.com/foo/bar.git> against <http://example.org/> -PASS Origin parsing: <http://example.com/././foo> against <about:blank> -PASS Origin parsing: <http://example.com/./.foo> against <about:blank> -PASS Origin parsing: <http://example.com/foo/.> against <about:blank> -PASS Origin parsing: <http://example.com/foo/./> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../> against <about:blank> -PASS Origin parsing: <http://example.com/foo/..bar> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Origin parsing: <http://example.com/foo/../../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/../../../ton> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e%2> against <about:blank> -PASS Origin parsing: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> -PASS Origin parsing: <http://example.com////../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar//../..> against <about:blank> -PASS Origin parsing: <http://example.com/foo/bar//..> against <about:blank> -PASS Origin parsing: <http://example.com/foo> against <about:blank> -PASS Origin parsing: <http://example.com/%20foo> against <about:blank> -PASS Origin parsing: <http://example.com/foo%> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2zbar> against <about:blank> -PASS Origin parsing: <http://example.com/foo%2©zbar> against <about:blank> -PASS Origin parsing: <http://example.com/foo%41%7a> against <about:blank> -PASS Origin parsing: <http://example.com/foo %91> against <about:blank> -FAIL Origin parsing: <http://example.com/foo%00%51> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Origin parsing: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Origin parsing: <http://example.com/foo bar> against <about:blank> -PASS Origin parsing: <http://example.com\\foo\\bar> against <about:blank> -PASS Origin parsing: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Origin parsing: <http://example.com/@asdf%40> against <about:blank> -PASS Origin parsing: <http://example.com/你好你好> against <about:blank> -PASS Origin parsing: <http://example.com/‥/foo> against <about:blank> -PASS Origin parsing: <http://example.com//foo> against <about:blank> -PASS Origin parsing: <http://example.com//foo//bar> against <about:blank> -PASS Origin parsing: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Origin parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Origin parsing: <data:test# »> against <about:blank> -PASS Origin parsing: <http://www.google.com> against <about:blank> -PASS Origin parsing: <http://192.0x00A80001> against <about:blank> -PASS Origin parsing: <http://www/foo%2Ehtml> against <about:blank> -PASS Origin parsing: <http://www/foo/%2E/html> against <about:blank> -PASS Origin parsing: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Origin parsing: <http:\\www.google.com\foo> against <about:blank> -PASS Origin parsing: <http://foo:80/> against <about:blank> -PASS Origin parsing: <http://foo:81/> against <about:blank> -PASS Origin parsing: <httpa://foo:80/> against <about:blank> -PASS Origin parsing: <https://foo:443/> against <about:blank> -PASS Origin parsing: <https://foo:80/> against <about:blank> -PASS Origin parsing: <ftp://foo:21/> against <about:blank> -PASS Origin parsing: <ftp://foo:80/> against <about:blank> -PASS Origin parsing: <gopher://foo:70/> against <about:blank> -PASS Origin parsing: <gopher://foo:443/> against <about:blank> -PASS Origin parsing: <ws://foo:80/> against <about:blank> -PASS Origin parsing: <ws://foo:81/> against <about:blank> -PASS Origin parsing: <ws://foo:443/> against <about:blank> -PASS Origin parsing: <ws://foo:815/> against <about:blank> -PASS Origin parsing: <wss://foo:80/> against <about:blank> -PASS Origin parsing: <wss://foo:81/> against <about:blank> -PASS Origin parsing: <wss://foo:443/> against <about:blank> -PASS Origin parsing: <wss://foo:815/> against <about:blank> -PASS Origin parsing: <http:/example.com/> against <about:blank> -PASS Origin parsing: <ftp:/example.com/> against <about:blank> -PASS Origin parsing: <https:/example.com/> against <about:blank> -PASS Origin parsing: <madeupscheme:/example.com/> against <about:blank> -PASS Origin parsing: <ftps:/example.com/> against <about:blank> -PASS Origin parsing: <gopher:/example.com/> against <about:blank> -PASS Origin parsing: <ws:/example.com/> against <about:blank> -PASS Origin parsing: <wss:/example.com/> against <about:blank> -PASS Origin parsing: <data:/example.com/> against <about:blank> -PASS Origin parsing: <javascript:/example.com/> against <about:blank> -PASS Origin parsing: <mailto:/example.com/> against <about:blank> -PASS Origin parsing: <http:example.com/> against <about:blank> -PASS Origin parsing: <ftp:example.com/> against <about:blank> -PASS Origin parsing: <https:example.com/> against <about:blank> -PASS Origin parsing: <madeupscheme:example.com/> against <about:blank> -PASS Origin parsing: <ftps:example.com/> against <about:blank> -PASS Origin parsing: <gopher:example.com/> against <about:blank> -PASS Origin parsing: <ws:example.com/> against <about:blank> -PASS Origin parsing: <wss:example.com/> against <about:blank> -PASS Origin parsing: <data:example.com/> against <about:blank> -PASS Origin parsing: <javascript:example.com/> against <about:blank> -PASS Origin parsing: <mailto:example.com/> against <about:blank> -PASS Origin parsing: <http:@www.example.com> against <about:blank> -PASS Origin parsing: <http:/@www.example.com> against <about:blank> -PASS Origin parsing: <http://@www.example.com> against <about:blank> -PASS Origin parsing: <http:a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http:/a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://a:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://@pple.com> against <about:blank> -PASS Origin parsing: <http::b@www.example.com> against <about:blank> -PASS Origin parsing: <http:/:b@www.example.com> against <about:blank> -PASS Origin parsing: <http://:b@www.example.com> against <about:blank> -PASS Origin parsing: <http:a:@www.example.com> against <about:blank> -PASS Origin parsing: <http:/a:@www.example.com> against <about:blank> -PASS Origin parsing: <http://a:@www.example.com> against <about:blank> -PASS Origin parsing: <http://www.@pple.com> against <about:blank> -PASS Origin parsing: <http://:@www.example.com> against <about:blank> -PASS Origin parsing: </> against <http://www.example.com/test> -PASS Origin parsing: </test.txt> against <http://www.example.com/test> -PASS Origin parsing: <.> against <http://www.example.com/test> -PASS Origin parsing: <..> against <http://www.example.com/test> -PASS Origin parsing: <test.txt> against <http://www.example.com/test> -PASS Origin parsing: <./test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../aaa/test.txt> against <http://www.example.com/test> -PASS Origin parsing: <../../test.txt> against <http://www.example.com/test> -PASS Origin parsing: <中/test.txt> against <http://www.example.com/test> -PASS Origin parsing: <http://www.example2.com> against <http://www.example.com/test> -PASS Origin parsing: <//www.example2.com> against <http://www.example.com/test> -PASS Origin parsing: <http://ExAmPlE.CoM> against <http://other.com/> -PASS Origin parsing: <http://GOOgoo.com> against <http://other.com/> -PASS Origin parsing: <\0 http://example.com/ \r > against <about:blank> -PASS Origin parsing: <http://www.foo。bar.com> against <http://other.com/> -PASS Origin parsing: <https://x/�?�#�> against <about:blank> -PASS Origin parsing: <http://Go.com> against <http://other.com/> -PASS Origin parsing: <http://你好你好> against <http://other.com/> -FAIL Origin parsing: <https://faß.ExAmPlE/> against <about:blank> assert_equals: origin expected "https://xn--fa-hia.example" but got "https://fass.example" -PASS Origin parsing: <sc://faß.ExAmPlE/> against <about:blank> -PASS Origin parsing: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Origin parsing: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -PASS Origin parsing: <http://0Xc0.0250.01> against <http://other.com/> -PASS Origin parsing: <http://./> against <about:blank> -PASS Origin parsing: <http://../> against <about:blank> -PASS Origin parsing: <http://0..0x300/> against <about:blank> -PASS Origin parsing: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Origin parsing: <#> against <test:test> -PASS Origin parsing: <#x> against <mailto:x@x.com> -PASS Origin parsing: <#x> against <data:,> -PASS Origin parsing: <#x> against <about:blank> -PASS Origin parsing: <#> against <test:test?test> -PASS Origin parsing: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Origin parsing: <https://@@@example> against <http://doesnotmatter/> -PASS Origin parsing: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Origin parsing: <http://host/?'> against <about:blank> -PASS Origin parsing: <notspecial://host/?'> against <about:blank> -PASS Origin parsing: </some/path> against <http://user@example.org/smth> -PASS Origin parsing: <> against <http://user:pass@example.org:21/smth> -PASS Origin parsing: </some/path> against <http://user:pass@example.org:21/smth> -PASS Origin parsing: <i> against <sc:/pa/pa> -PASS Origin parsing: <i> against <sc://ho/pa> -PASS Origin parsing: <i> against <sc:///pa/pa> -PASS Origin parsing: <../i> against <sc:/pa/pa> -PASS Origin parsing: <../i> against <sc://ho/pa> -PASS Origin parsing: <../i> against <sc:///pa/pa> -PASS Origin parsing: </i> against <sc:/pa/pa> -PASS Origin parsing: </i> against <sc://ho/pa> -PASS Origin parsing: </i> against <sc:///pa/pa> -PASS Origin parsing: <?i> against <sc:/pa/pa> -PASS Origin parsing: <?i> against <sc://ho/pa> -PASS Origin parsing: <?i> against <sc:///pa/pa> -PASS Origin parsing: <#i> against <sc:sd> -PASS Origin parsing: <#i> against <sc:sd/sd> -PASS Origin parsing: <#i> against <sc:/pa/pa> -PASS Origin parsing: <#i> against <sc://ho/pa> -PASS Origin parsing: <#i> against <sc:///pa/pa> -PASS Origin parsing: <about:/../> against <about:blank> -PASS Origin parsing: <data:/../> against <about:blank> -PASS Origin parsing: <javascript:/../> against <about:blank> -PASS Origin parsing: <mailto:/../> against <about:blank> -PASS Origin parsing: <sc://ñ.test/> against <about:blank> -FAIL Origin parsing: <x> against <sc://ñ> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <sc:\../> against <about:blank> -PASS Origin parsing: <sc::a@example.net> against <about:blank> -PASS Origin parsing: <wow:%NBD> against <about:blank> -PASS Origin parsing: <wow:%1G> against <about:blank> -PASS Origin parsing: <wow:> against <about:blank> -FAIL Origin parsing: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> Failed to construct 'URL': Invalid URL -FAIL Origin parsing: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> -PASS Origin parsing: <ftp://%e2%98%83> against <about:blank> -PASS Origin parsing: <https://%e2%98%83> against <about:blank> -PASS Origin parsing: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Origin parsing: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Origin parsing: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Origin parsing: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Origin parsing: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Origin parsing: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Origin parsing: <http:> against <http://example.org/foo/bar> -PASS Origin parsing: <sc:> against <https://example.org/foo/bar> -PASS Origin parsing: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Origin parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Origin parsing: <http://192.168.257> against <http://other.com/> -PASS Origin parsing: <http://192.168.257.com> against <http://other.com/> -PASS Origin parsing: <http://256> against <http://other.com/> -PASS Origin parsing: <http://256.com> against <http://other.com/> -PASS Origin parsing: <http://999999999> against <http://other.com/> -PASS Origin parsing: <http://999999999.com> against <http://other.com/> -PASS Origin parsing: <http://10000000000.com> against <http://other.com/> -PASS Origin parsing: <http://4294967295> against <http://other.com/> -PASS Origin parsing: <http://0xffffffff> against <http://other.com/> -PASS Origin parsing: <http://256.256.256.256.256> against <http://other.com/> -PASS Origin parsing: <https://0x.0x.0> against <about:blank> -PASS Origin parsing: <asdf://%43%7C/> against <about:blank> -PASS Origin parsing: <http://[1:0::]> against <http://example.net/> -PASS Origin parsing: <sc://ñ> against <about:blank> -PASS Origin parsing: <sc://ñ?x> against <about:blank> -PASS Origin parsing: <sc://ñ#x> against <about:blank> -FAIL Origin parsing: <#x> against <sc://ñ> Failed to construct 'URL': Invalid URL -FAIL Origin parsing: <?x> against <sc://ñ> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> -PASS Origin parsing: <telnet://user:pass@foobar.com:23/> against <about:blank> -PASS Origin parsing: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> -PASS Origin parsing: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> -PASS Origin parsing: <rsync://foo@host:911/sup> against <about:blank> -PASS Origin parsing: <git://github.com/foo/bar.git> against <about:blank> -PASS Origin parsing: <irc://myserver.com:6999/channel?passwd> against <about:blank> -PASS Origin parsing: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> -PASS Origin parsing: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> -PASS Origin parsing: <git+https://github.com/foo/bar> against <about:blank> -PASS Origin parsing: <urn:ietf:rfc:2648> against <about:blank> -PASS Origin parsing: <tag:joe@example.org,2001:foo/bar> against <about:blank> -PASS Origin parsing: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Origin parsing: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Origin parsing: <https://user:pass[@foo/bar> against <http://example.org> -PASS Origin parsing: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> -PASS Origin parsing: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> -FAIL Origin parsing: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> Failed to construct 'URL': Invalid URL -PASS Origin parsing: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -PASS Origin parsing: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/url/a-element-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/url/a-element-expected.txt deleted file mode 100644 index b80c6751..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/url/a-element-expected.txt +++ /dev/null
@@ -1,648 +0,0 @@ -This is a testharness.js-based test. -Found 633 tests; 376 PASS, 257 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Loading data… -PASS Parsing: <http://example . -org> against <http://example.org/foo/bar> -PASS Parsing: <http://user:pass@foo:21/bar;par?b#c> against <http://example.org/foo/bar> -PASS Parsing: <https://test:@test> against <about:blank> -PASS Parsing: <https://:@test> against <about:blank> -FAIL Parsing: <non-special://test:@test/x> against <about:blank> assert_equals: href expected "non-special://test@test/x" but got "non-special://test:@test/x" -FAIL Parsing: <non-special://:@test/x> against <about:blank> assert_equals: href expected "non-special://test/x" but got "non-special://:@test/x" -PASS Parsing: <http:foo.com> against <http://example.org/foo/bar> -PASS Parsing: < :foo.com -> against <http://example.org/foo/bar> -PASS Parsing: < foo.com > against <http://example.org/foo/bar> -PASS Parsing: <a: foo.com> against <http://example.org/foo/bar> -PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> -PASS Parsing: <lolscheme:x x#x x> against <about:blank> -PASS Parsing: <http://f:/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:00000000000000000000080/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:b/c> against <http://example.org/foo/bar> -FAIL Parsing: <http://f: /c> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://f: /c" but got "http://f:%20/c" -PASS Parsing: <http://f: -/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:fifty-two/c> against <http://example.org/foo/bar> -PASS Parsing: <http://f:999999/c> against <http://example.org/foo/bar> -FAIL Parsing: <non-special://f:999999/c> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://f: 21 / b ? d # e > against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://f: 21 / b ? d # e " but got "http://f:%2021%20/%20b%20?%20d%20#%20e" -PASS Parsing: <> against <http://example.org/foo/bar> -PASS Parsing: < > against <http://example.org/foo/bar> -PASS Parsing: <:foo.com/> against <http://example.org/foo/bar> -PASS Parsing: <:foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <:> against <http://example.org/foo/bar> -PASS Parsing: <:a> against <http://example.org/foo/bar> -PASS Parsing: <:/> against <http://example.org/foo/bar> -PASS Parsing: <:\> against <http://example.org/foo/bar> -PASS Parsing: <:#> against <http://example.org/foo/bar> -PASS Parsing: <#> against <http://example.org/foo/bar> -PASS Parsing: <#/> against <http://example.org/foo/bar> -PASS Parsing: <#\> against <http://example.org/foo/bar> -PASS Parsing: <#;?> against <http://example.org/foo/bar> -PASS Parsing: <?> against <http://example.org/foo/bar> -PASS Parsing: </> against <http://example.org/foo/bar> -PASS Parsing: <:23> against <http://example.org/foo/bar> -PASS Parsing: </:23> against <http://example.org/foo/bar> -PASS Parsing: <\x> against <http://example.org/foo/bar> -PASS Parsing: <\\x\hello> against <http://example.org/foo/bar> -PASS Parsing: <::> against <http://example.org/foo/bar> -PASS Parsing: <::23> against <http://example.org/foo/bar> -FAIL Parsing: <foo://> against <http://example.org/foo/bar> assert_equals: pathname expected "" but got "//" -PASS Parsing: <http://a:b@c:29/d> against <http://example.org/foo/bar> -PASS Parsing: <http::@c:29> against <http://example.org/foo/bar> -PASS Parsing: <http://&a:foo(b]c@d:2/> against <http://example.org/foo/bar> -PASS Parsing: <http://::@c@d:2> against <http://example.org/foo/bar> -PASS Parsing: <http://foo.com:b@d/> against <http://example.org/foo/bar> -PASS Parsing: <http://foo.com/\@> against <http://example.org/foo/bar> -PASS Parsing: <http:\\foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <http:\\a\b:c\d@foo.com\> against <http://example.org/foo/bar> -PASS Parsing: <foo:/> against <http://example.org/foo/bar> -PASS Parsing: <foo:/bar.com/> against <http://example.org/foo/bar> -FAIL Parsing: <foo://///////> against <http://example.org/foo/bar> assert_equals: pathname expected "///////" but got "/////////" -FAIL Parsing: <foo://///////bar.com/> against <http://example.org/foo/bar> assert_equals: pathname expected "///////bar.com/" but got "/////////bar.com/" -FAIL Parsing: <foo:////://///> against <http://example.org/foo/bar> assert_equals: pathname expected "//://///" but got "////://///" -PASS Parsing: <c:/foo> against <http://example.org/foo/bar> -PASS Parsing: <//foo/bar> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/path;a??e#f#g> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/abcd?efgh?ijkl> against <http://example.org/foo/bar> -PASS Parsing: <http://foo/abcd#foo?bar> against <http://example.org/foo/bar> -PASS Parsing: <[61:24:74]:98> against <http://example.org/foo/bar> -PASS Parsing: <http:[61:27]/:foo> against <http://example.org/foo/bar> -FAIL Parsing: <http://[1::2]:3:4> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[1::2]:3:4" but got "http://[1::2]:3:4/" -FAIL Parsing: <http://2001::1> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1" but got "http://2001::1/" -FAIL Parsing: <http://2001::1]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]" but got "http://2001::1]/" -FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/" -PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar> -PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar> -PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar> -PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar> -PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftp:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <https:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <file:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <file://example:1/> against <about:blank> -PASS Parsing: <file://example:test/> against <about:blank> -FAIL Parsing: <file://example%/> against <about:blank> assert_equals: failure should set href to input expected "file://example%/" but got "file://example%25/" -PASS Parsing: <file://[example]/> against <about:blank> -PASS Parsing: <ftps:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <gopher:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ws:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <wss:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <data:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <javascript:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <mailto:/example.com/> against <http://example.org/foo/bar> -PASS Parsing: <http:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftp:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <https:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <madeupscheme:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ftps:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <gopher:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <ws:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <wss:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <data:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <javascript:example.com/> against <http://example.org/foo/bar> -PASS Parsing: <mailto:example.com/> against <http://example.org/foo/bar> -PASS Parsing: </a/b/c> against <http://example.org/foo/bar> -PASS Parsing: </a/ /c> against <http://example.org/foo/bar> -PASS Parsing: </a%2fc> against <http://example.org/foo/bar> -PASS Parsing: </a/%2f/c> against <http://example.org/foo/bar> -PASS Parsing: <#β> against <http://example.org/foo/bar> -PASS Parsing: <data:text/html,test#test> against <http://example.org/foo/bar> -PASS Parsing: <tel:1234567890> against <http://example.org/foo/bar> -FAIL Parsing: <ssh://example.com/foo/bar.git> against <http://example.org/> assert_equals: host expected "example.com" but got "" -FAIL Parsing: <file:c:\foo\bar.html> against <file:///tmp/mock/path> assert_equals: href expected "file:///c:/foo/bar.html" but got "file:///tmp/mock/c:/foo/bar.html" -FAIL Parsing: < File:c|////foo\bar.html> against <file:///tmp/mock/path> assert_equals: href expected "file:///c:////foo/bar.html" but got "file:///tmp/mock/c%7C////foo/bar.html" -FAIL Parsing: <C|/foo/bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file:///tmp/mock/C%7C/foo/bar" -FAIL Parsing: </C|\foo\bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file:///C%7C/foo/bar" -FAIL Parsing: <//C|/foo/bar> against <file:///tmp/mock/path> assert_equals: href expected "file:///C:/foo/bar" but got "file://c%7C/foo/bar" -PASS Parsing: <//server/file> against <file:///tmp/mock/path> -PASS Parsing: <\\server\file> against <file:///tmp/mock/path> -PASS Parsing: </\server/file> against <file:///tmp/mock/path> -PASS Parsing: <file:///foo/bar.txt> against <file:///tmp/mock/path> -PASS Parsing: <file:///home/me> against <file:///tmp/mock/path> -PASS Parsing: <//> against <file:///tmp/mock/path> -PASS Parsing: <///> against <file:///tmp/mock/path> -PASS Parsing: <///test> against <file:///tmp/mock/path> -PASS Parsing: <file://test> against <file:///tmp/mock/path> -FAIL Parsing: <file://localhost> against <file:///tmp/mock/path> assert_equals: href expected "file:///" but got "file://localhost/" -FAIL Parsing: <file://localhost/> against <file:///tmp/mock/path> assert_equals: href expected "file:///" but got "file://localhost/" -FAIL Parsing: <file://localhost/test> against <file:///tmp/mock/path> assert_equals: href expected "file:///test" but got "file://localhost/test" -PASS Parsing: <test> against <file:///tmp/mock/path> -PASS Parsing: <file:test> against <file:///tmp/mock/path> -PASS Parsing: <http://example.com/././foo> against <about:blank> -PASS Parsing: <http://example.com/./.foo> against <about:blank> -PASS Parsing: <http://example.com/foo/.> against <about:blank> -PASS Parsing: <http://example.com/foo/./> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../> against <about:blank> -PASS Parsing: <http://example.com/foo/..bar> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../ton> against <about:blank> -PASS Parsing: <http://example.com/foo/bar/../ton/../../a> against <about:blank> -PASS Parsing: <http://example.com/foo/../../..> against <about:blank> -PASS Parsing: <http://example.com/foo/../../../ton> against <about:blank> -PASS Parsing: <http://example.com/foo/%2e> against <about:blank> -FAIL Parsing: <http://example.com/foo/%2e%2> against <about:blank> assert_equals: href expected "http://example.com/foo/%2e%2" but got "http://example.com/foo/.%2" -FAIL Parsing: <http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar> against <about:blank> assert_equals: href expected "http://example.com/%2e.bar" but got "http://example.com/..bar" -PASS Parsing: <http://example.com////../..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar//../..> against <about:blank> -PASS Parsing: <http://example.com/foo/bar//..> against <about:blank> -PASS Parsing: <http://example.com/foo> against <about:blank> -PASS Parsing: <http://example.com/%20foo> against <about:blank> -PASS Parsing: <http://example.com/foo%> against <about:blank> -PASS Parsing: <http://example.com/foo%2> against <about:blank> -PASS Parsing: <http://example.com/foo%2zbar> against <about:blank> -PASS Parsing: <http://example.com/foo%2©zbar> against <about:blank> -FAIL Parsing: <http://example.com/foo%41%7a> against <about:blank> assert_equals: href expected "http://example.com/foo%41%7a" but got "http://example.com/fooAz" -PASS Parsing: <http://example.com/foo %91> against <about:blank> -FAIL Parsing: <http://example.com/foo%00%51> against <about:blank> assert_equals: href expected "http://example.com/foo%00%51" but got "http://example.com/foo%00Q" -PASS Parsing: <http://example.com/(%28:%3A%29)> against <about:blank> -PASS Parsing: <http://example.com/%3A%3a%3C%3c> against <about:blank> -PASS Parsing: <http://example.com/foo bar> against <about:blank> -PASS Parsing: <http://example.com\\foo\\bar> against <about:blank> -PASS Parsing: <http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd> against <about:blank> -PASS Parsing: <http://example.com/@asdf%40> against <about:blank> -PASS Parsing: <http://example.com/你好你好> against <about:blank> -PASS Parsing: <http://example.com/‥/foo> against <about:blank> -PASS Parsing: <http://example.com//foo> against <about:blank> -PASS Parsing: <http://example.com//foo//bar> against <about:blank> -PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank> -PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> -PASS Parsing: <data:test# »> against <about:blank> -PASS Parsing: <http://www.google.com> against <about:blank> -PASS Parsing: <http://192.0x00A80001> against <about:blank> -FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html" -PASS Parsing: <http://www/foo/%2E/html> against <about:blank> -PASS Parsing: <http://user:pass@/> against <about:blank> -PASS Parsing: <http://%25DOMAIN:foobar@foodomain.com/> against <about:blank> -PASS Parsing: <http:\\www.google.com\foo> against <about:blank> -PASS Parsing: <http://foo:80/> against <about:blank> -PASS Parsing: <http://foo:81/> against <about:blank> -FAIL Parsing: <httpa://foo:80/> against <about:blank> assert_equals: host expected "foo:80" but got "" -PASS Parsing: <http://foo:-80/> against <about:blank> -PASS Parsing: <https://foo:443/> against <about:blank> -PASS Parsing: <https://foo:80/> against <about:blank> -PASS Parsing: <ftp://foo:21/> against <about:blank> -PASS Parsing: <ftp://foo:80/> against <about:blank> -FAIL Parsing: <gopher://foo:70/> against <about:blank> assert_equals: host expected "foo:70" but got "" -FAIL Parsing: <gopher://foo:443/> against <about:blank> assert_equals: host expected "foo:443" but got "" -PASS Parsing: <ws://foo:80/> against <about:blank> -PASS Parsing: <ws://foo:81/> against <about:blank> -PASS Parsing: <ws://foo:443/> against <about:blank> -PASS Parsing: <ws://foo:815/> against <about:blank> -PASS Parsing: <wss://foo:80/> against <about:blank> -PASS Parsing: <wss://foo:81/> against <about:blank> -PASS Parsing: <wss://foo:443/> against <about:blank> -PASS Parsing: <wss://foo:815/> against <about:blank> -PASS Parsing: <http:/example.com/> against <about:blank> -PASS Parsing: <ftp:/example.com/> against <about:blank> -PASS Parsing: <https:/example.com/> against <about:blank> -PASS Parsing: <madeupscheme:/example.com/> against <about:blank> -PASS Parsing: <file:/example.com/> against <about:blank> -PASS Parsing: <ftps:/example.com/> against <about:blank> -PASS Parsing: <gopher:/example.com/> against <about:blank> -PASS Parsing: <ws:/example.com/> against <about:blank> -PASS Parsing: <wss:/example.com/> against <about:blank> -PASS Parsing: <data:/example.com/> against <about:blank> -PASS Parsing: <javascript:/example.com/> against <about:blank> -PASS Parsing: <mailto:/example.com/> against <about:blank> -PASS Parsing: <http:example.com/> against <about:blank> -PASS Parsing: <ftp:example.com/> against <about:blank> -PASS Parsing: <https:example.com/> against <about:blank> -PASS Parsing: <madeupscheme:example.com/> against <about:blank> -PASS Parsing: <ftps:example.com/> against <about:blank> -PASS Parsing: <gopher:example.com/> against <about:blank> -PASS Parsing: <ws:example.com/> against <about:blank> -PASS Parsing: <wss:example.com/> against <about:blank> -PASS Parsing: <data:example.com/> against <about:blank> -PASS Parsing: <javascript:example.com/> against <about:blank> -PASS Parsing: <mailto:example.com/> against <about:blank> -PASS Parsing: <http:@www.example.com> against <about:blank> -PASS Parsing: <http:/@www.example.com> against <about:blank> -PASS Parsing: <http://@www.example.com> against <about:blank> -PASS Parsing: <http:a:b@www.example.com> against <about:blank> -PASS Parsing: <http:/a:b@www.example.com> against <about:blank> -PASS Parsing: <http://a:b@www.example.com> against <about:blank> -PASS Parsing: <http://@pple.com> against <about:blank> -PASS Parsing: <http::b@www.example.com> against <about:blank> -PASS Parsing: <http:/:b@www.example.com> against <about:blank> -PASS Parsing: <http://:b@www.example.com> against <about:blank> -FAIL Parsing: <http:/:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/:@/www.example.com" but got "http:///www.example.com" -PASS Parsing: <http://user@/www.example.com> against <about:blank> -FAIL Parsing: <http:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <http:/@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <http://@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http://@/www.example.com" but got "http:///www.example.com" -FAIL Parsing: <https:@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "https:@/www.example.com" but got "https:///www.example.com" -FAIL Parsing: <http:a:b@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:a:b@/www.example.com" but got "http://a:b@/www.example.com" -FAIL Parsing: <http:/a:b@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/a:b@/www.example.com" but got "http://a:b@/www.example.com" -PASS Parsing: <http://a:b@/www.example.com> against <about:blank> -FAIL Parsing: <http::@/www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http::@/www.example.com" but got "http:///www.example.com" -PASS Parsing: <http:a:@www.example.com> against <about:blank> -PASS Parsing: <http:/a:@www.example.com> against <about:blank> -PASS Parsing: <http://a:@www.example.com> against <about:blank> -PASS Parsing: <http://www.@pple.com> against <about:blank> -FAIL Parsing: <http:@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:@:www.example.com" but got "http://:www.example.com/" -FAIL Parsing: <http:/@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http:/@:www.example.com" but got "http://:www.example.com/" -FAIL Parsing: <http://@:www.example.com> against <about:blank> assert_equals: failure should set href to input expected "http://@:www.example.com" but got "http://:www.example.com/" -PASS Parsing: <http://:@www.example.com> against <about:blank> -PASS Parsing: </> against <http://www.example.com/test> -PASS Parsing: </test.txt> against <http://www.example.com/test> -PASS Parsing: <.> against <http://www.example.com/test> -PASS Parsing: <..> against <http://www.example.com/test> -PASS Parsing: <test.txt> against <http://www.example.com/test> -PASS Parsing: <./test.txt> against <http://www.example.com/test> -PASS Parsing: <../test.txt> against <http://www.example.com/test> -PASS Parsing: <../aaa/test.txt> against <http://www.example.com/test> -PASS Parsing: <../../test.txt> against <http://www.example.com/test> -PASS Parsing: <中/test.txt> against <http://www.example.com/test> -PASS Parsing: <http://www.example2.com> against <http://www.example.com/test> -PASS Parsing: <//www.example2.com> against <http://www.example.com/test> -PASS Parsing: <file:...> against <http://www.example.com/test> -PASS Parsing: <file:..> against <http://www.example.com/test> -PASS Parsing: <file:a> against <http://www.example.com/test> -PASS Parsing: <http://ExAmPlE.CoM> against <http://other.com/> -FAIL Parsing: <http://example example.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://Goo%20 goo%7C|.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[]" but got "http://[]/" -FAIL Parsing: <http://[:]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[:]" but got "http://[:]/" -FAIL Parsing: <http://GOO goo.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://GOOgoo.com> against <http://other.com/> -PASS Parsing: <\0 http://example.com/ \r > against <about:blank> -PASS Parsing: <http://www.foo。bar.com> against <http://other.com/> -FAIL Parsing: <http://zyx.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://zyx.com" but got "http://%EF%BF%BDzyx.com/" -FAIL Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%ef%b7%90zyx.com" but got "http://%EF%BF%BDzyx.com/" -FAIL Parsing: <https://�> against <about:blank> assert_equals: failure should set href to input expected "https://\ufffd" but got "https://%EF%BF%BD/" -FAIL Parsing: <https://%EF%BF%BD> against <about:blank> assert_equals: failure should set href to input expected "https://%EF%BF%BD" but got "https://%EF%BF%BD/" -PASS Parsing: <https://x/�?�#�> against <about:blank> -FAIL Parsing: <http://a.b.c.xn--pokxncvks> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://10.0.0.xn--pokxncvks> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://Go.com> against <http://other.com/> -FAIL Parsing: <http://%41.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://%ef%bc%85%ef%bc%94%ef%bc%91.com> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://%00.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%00.com" but got "http://%00.com/" -FAIL Parsing: <http://%ef%bc%85%ef%bc%90%ef%bc%90.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%ef%bc%85%ef%bc%90%ef%bc%90.com" but got "http://%00.com/" -PASS Parsing: <http://你好你好> against <http://other.com/> -FAIL Parsing: <https://faß.ExAmPlE/> against <about:blank> assert_equals: href expected "https://xn--fa-hia.example/" but got "https://fass.example/" -FAIL Parsing: <sc://faß.ExAmPlE/> against <about:blank> assert_equals: host expected "fa%C3%9F.ExAmPlE" but got "" -FAIL Parsing: <http://%zz%66%a.com> against <http://other.com/> assert_equals: failure should set href to input expected "http://%zz%66%a.com" but got "http://%25zzf%25a.com/" -FAIL Parsing: <http://%25> against <http://other.com/> assert_equals: failure should set href to input expected "http://%25" but got "http://%25/" -FAIL Parsing: <http://hello%00> against <http://other.com/> assert_equals: failure should set href to input expected "http://hello%00" but got "http://hello%00/" -PASS Parsing: <http://%30%78%63%30%2e%30%32%35%30.01> against <http://other.com/> -PASS Parsing: <http://%30%78%63%30%2e%30%32%35%30.01%2e> against <http://other.com/> -FAIL Parsing: <http://192.168.0.257> against <http://other.com/> assert_equals: failure should set href to input expected "http://192.168.0.257" but got "http://192.168.0.257/" -FAIL Parsing: <http://%3g%78%63%30%2e%30%32%35%30%2E.01> against <http://other.com/> assert_equals: failure should set href to input expected "http://%3g%78%63%30%2e%30%32%35%30%2E.01" but got "http://%253gxc0.0250..01/" -FAIL Parsing: <http://192.168.0.1 hello> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <https://x x:12> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> -PASS Parsing: <http://./> against <about:blank> -PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> -PASS Parsing: <http://[www.google.com]/> against <about:blank> -FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/" -FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/" -FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://foo:💩@example.com/bar> against <http://other.com/> -PASS Parsing: <#> against <test:test> -PASS Parsing: <#x> against <mailto:x@x.com> -FAIL Parsing: <#x> against <data:,> assert_equals: href expected "data:,#x" but got "mailto:x@x.com#x" -PASS Parsing: <#x> against <about:blank> -PASS Parsing: <#> against <test:test?test> -PASS Parsing: <https://@test@test@example:800/> against <http://doesnotmatter/> -PASS Parsing: <https://@@@example> against <http://doesnotmatter/> -PASS Parsing: <http://`{}:`{}@h/`{}?`{}> against <http://doesnotmatter/> -PASS Parsing: <http://host/?'> against <about:blank> -FAIL Parsing: <notspecial://host/?'> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: </some/path> against <http://user@example.org/smth> -PASS Parsing: <> against <http://user:pass@example.org:21/smth> -PASS Parsing: </some/path> against <http://user:pass@example.org:21/smth> -FAIL Parsing: <i> against <sc:sd> assert_equals: failure should set href to input expected "i" but got "" -FAIL Parsing: <i> against <sc:sd/sd> assert_equals: failure should set href to input expected "i" but got "" -PASS Parsing: <i> against <sc:/pa/pa> -FAIL Parsing: <i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/i" but got "///pa/i" -FAIL Parsing: <../i> against <sc:sd> assert_equals: failure should set href to input expected "../i" but got "" -FAIL Parsing: <../i> against <sc:sd/sd> assert_equals: failure should set href to input expected "../i" but got "" -PASS Parsing: <../i> against <sc:/pa/pa> -FAIL Parsing: <../i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <../i> against <sc:///pa/pa> assert_equals: href expected "sc:///i" but got "sc:///pa/i" -FAIL Parsing: </i> against <sc:sd> assert_equals: failure should set href to input expected "/i" but got "" -FAIL Parsing: </i> against <sc:sd/sd> assert_equals: failure should set href to input expected "/i" but got "" -PASS Parsing: </i> against <sc:/pa/pa> -FAIL Parsing: </i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: </i> against <sc:///pa/pa> assert_equals: href expected "sc:///i" but got "sc:///pa/i" -FAIL Parsing: <?i> against <sc:sd> assert_equals: failure should set href to input expected "?i" but got "" -FAIL Parsing: <?i> against <sc:sd/sd> assert_equals: failure should set href to input expected "?i" but got "" -PASS Parsing: <?i> against <sc:/pa/pa> -FAIL Parsing: <?i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <?i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/pa" but got "///pa/pa" -PASS Parsing: <#i> against <sc:sd> -PASS Parsing: <#i> against <sc:sd/sd> -PASS Parsing: <#i> against <sc:/pa/pa> -FAIL Parsing: <#i> against <sc://ho/pa> assert_equals: host expected "ho" but got "" -FAIL Parsing: <#i> against <sc:///pa/pa> assert_equals: pathname expected "/pa/pa" but got "///pa/pa" -FAIL Parsing: <about:/../> against <about:blank> assert_equals: href expected "about:/" but got "about:/../" -FAIL Parsing: <data:/../> against <about:blank> assert_equals: href expected "data:/" but got "data:/../" -FAIL Parsing: <javascript:/../> against <about:blank> assert_equals: href expected "javascript:/" but got "javascript:/../" -FAIL Parsing: <mailto:/../> against <about:blank> assert_equals: href expected "mailto:/" but got "mailto:/../" -FAIL Parsing: <sc://ñ.test/> against <about:blank> assert_equals: host expected "%C3%B1.test" but got "" -FAIL Parsing: <sc://\0/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc:// /> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://%/> against <about:blank> assert_equals: host expected "%" but got "" -FAIL Parsing: <sc://@/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://te@s:t@/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://:/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://:12/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://[/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://\/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <sc://]/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1/x" but got "sc://%C3%B1" -PASS Parsing: <sc:\../> against <about:blank> -PASS Parsing: <sc::a@example.net> against <about:blank> -PASS Parsing: <wow:%NBD> against <about:blank> -PASS Parsing: <wow:%1G> against <about:blank> -FAIL Parsing: <wow:> against <about:blank> assert_equals: href expected "wow:%EF%BF%BF" but got "wow:%EF%BF%BD" -FAIL Parsing: <http://example.com/U+d800U+dfff﷏ﷰ?U+d800U+dfff﷏ﷰ> against <about:blank> assert_equals: href expected "http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF" but got "http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%BF%BD%EF%B7%8F%EF%BF%BD%EF%B7%B0%EF%BF%BD%EF%BF%BD?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%BF%BD%EF%B7%8F%EF%BF%BD%EF%B7%B0%EF%BF%BD%EF%BF%BD" -FAIL Parsing: <http://a<b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://a>b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://a^b> against <about:blank> assert_equals: failure should set href to input expected "http://a^b" but got "http://a%5Eb/" -FAIL Parsing: <non-special://a<b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <non-special://a>b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <non-special://a^b> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho\0st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho|st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <foo://ho st/> against <about:blank> assert_equals: host expected "host" but got "" -FAIL Parsing: <foo://ho -st/> against <about:blank> assert_equals: host expected "host" but got "" -FAIL Parsing: <foo://ho\rst/> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: <http://ho%00st/> against <about:blank> -PASS Parsing: <http://ho%09st/> against <about:blank> -PASS Parsing: <http://ho%0Ast/> against <about:blank> -PASS Parsing: <http://ho%0Dst/> against <about:blank> -FAIL Parsing: <http://ho%20st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%23st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://ho%2Fst/> against <about:blank> -FAIL Parsing: <http://ho%3Ast/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%3Ast/" but got "http://ho:st/" -FAIL Parsing: <http://ho%3Cst/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%3Est/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <http://ho%3Fst/> against <about:blank> -FAIL Parsing: <http://ho%40st/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://ho%5Bst/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%5Bst/" but got "http://ho[st/" -PASS Parsing: <http://ho%5Cst/> against <about:blank> -FAIL Parsing: <http://ho%5Dst/> against <about:blank> assert_equals: failure should set href to input expected "http://ho%5Dst/" but got "http://ho]st/" -FAIL Parsing: <http://ho%7Cst/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <http://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: href expected "http://\x1f!\"$&'()*+,-.;=_`{}~/" but got "http://%1F%21%22%24%26%27%28%29%2A+%2C-.%3B%3D_%60%7B%7D%7E/" -FAIL Parsing: <sc://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: host expected "%1F!\"$&'()*+,-.;=_`{}~" but got "" -FAIL Parsing: <ftp://example.com%80/> against <about:blank> assert_equals: failure should set href to input expected "ftp://example.com%80/" but got "ftp://example.com%EF%BF%BD/" -FAIL Parsing: <ftp://example.com%A0/> against <about:blank> assert_equals: failure should set href to input expected "ftp://example.com%A0/" but got "ftp://example.com%EF%BF%BD/" -FAIL Parsing: <https://example.com%80/> against <about:blank> assert_equals: failure should set href to input expected "https://example.com%80/" but got "https://example.com%EF%BF%BD/" -FAIL Parsing: <https://example.com%A0/> against <about:blank> assert_equals: failure should set href to input expected "https://example.com%A0/" but got "https://example.com%EF%BF%BD/" -PASS Parsing: <ftp://%e2%98%83> against <about:blank> -PASS Parsing: <https://%e2%98%83> against <about:blank> -PASS Parsing: <http://127.0.0.1:10100/relative_import.html> against <about:blank> -PASS Parsing: <http://facebook.com/?foo=%7B%22abc%22> against <about:blank> -PASS Parsing: <https://localhost:3000/jqueryui@1.2.3> against <about:blank> -PASS Parsing: <h t -t\rp://h o -s\rt:9 0 -0\r0/p a -t\rh?q u -e\rry#f r -a\rg> against <about:blank> -PASS Parsing: <?a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing: <??a=b&c=d> against <http://example.org/foo/bar> -PASS Parsing: <http:> against <http://example.org/foo/bar> -PASS Parsing: <http:> against <https://example.org/foo/bar> -PASS Parsing: <sc:> against <https://example.org/foo/bar> -PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> -PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> -PASS Parsing: <http://192.168.257> against <http://other.com/> -PASS Parsing: <http://192.168.257.com> against <http://other.com/> -PASS Parsing: <http://256> against <http://other.com/> -PASS Parsing: <http://256.com> against <http://other.com/> -PASS Parsing: <http://999999999> against <http://other.com/> -PASS Parsing: <http://999999999.com> against <http://other.com/> -FAIL Parsing: <http://10000000000> against <http://other.com/> assert_equals: failure should set href to input expected "http://10000000000" but got "http://10000000000/" -PASS Parsing: <http://10000000000.com> against <http://other.com/> -PASS Parsing: <http://4294967295> against <http://other.com/> -FAIL Parsing: <http://4294967296> against <http://other.com/> assert_equals: failure should set href to input expected "http://4294967296" but got "http://4294967296/" -PASS Parsing: <http://0xffffffff> against <http://other.com/> -FAIL Parsing: <http://0xffffffff1> against <http://other.com/> assert_equals: failure should set href to input expected "http://0xffffffff1" but got "http://0xffffffff1/" -FAIL Parsing: <http://256.256.256.256> against <http://other.com/> assert_equals: failure should set href to input expected "http://256.256.256.256" but got "http://256.256.256.256/" -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> -PASS Parsing: <https://0x.0x.0> against <about:blank> -PASS Parsing: <https://0x100000000/test> against <about:blank> -PASS Parsing: <https://256.0.0.1/test> against <about:blank> -PASS Parsing: <file:///C%3A/> against <about:blank> -PASS Parsing: <file:///C%7C/> against <about:blank> -FAIL Parsing: <file://%43%3A> against <about:blank> assert_equals: failure should set href to input expected "file://%43%3A" but got "file://c:/" -FAIL Parsing: <file://%43%7C> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://%43|> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://C%7C> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <file://%43%7C/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <https://%43%7C/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <asdf://%43|/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -FAIL Parsing: <asdf://%43%7C/> against <about:blank> assert_equals: host expected "%43%7C" but got "" -PASS Parsing: <pix/submit.gif> against <file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html> -FAIL Parsing: <..> against <file:///C:/> assert_equals: href expected "file:///C:/" but got "file:///" -PASS Parsing: <..> against <file:///> -FAIL Parsing: </> against <file:///C:/a/b> assert_equals: href expected "file:///C:/" but got "file:///" -FAIL Parsing: </> against <file://h/C:/a/b> assert_equals: href expected "file://h/C:/" but got "file:///" -FAIL Parsing: </> against <file://h/a/b> assert_equals: href expected "file://h/" but got "file:///" -FAIL Parsing: <//d:> against <file:///C:/a/b> assert_equals: href expected "file:///d:" but got "file://d:/" -FAIL Parsing: <//d:/..> against <file:///C:/a/b> assert_equals: href expected "file:///d:/" but got "file://d:/" -PASS Parsing: <..> against <file:///ab:/> -PASS Parsing: <..> against <file:///1:/> -PASS Parsing: <> against <file:///test?test#test> -PASS Parsing: <file:> against <file:///test?test#test> -PASS Parsing: <?x> against <file:///test?test#test> -PASS Parsing: <file:?x> against <file:///test?test#test> -PASS Parsing: <#x> against <file:///test?test#test> -PASS Parsing: <file:#x> against <file:///test?test#test> -FAIL Parsing: <file:\\//> against <about:blank> assert_equals: href expected "file:////" but got "file:///" -FAIL Parsing: <file:\\\\> against <about:blank> assert_equals: href expected "file:////" but got "file:///" -FAIL Parsing: <file:\\\\?fox> against <about:blank> assert_equals: href expected "file:////?fox" but got "file:///?fox" -FAIL Parsing: <file:\\\\#guppy> against <about:blank> assert_equals: href expected "file:////#guppy" but got "file:///#guppy" -PASS Parsing: <file://spider///> against <about:blank> -FAIL Parsing: <file:\\localhost//> against <about:blank> assert_equals: href expected "file:////" but got "file://localhost//" -PASS Parsing: <file:///localhost//cat> against <about:blank> -FAIL Parsing: <file://\/localhost//cat> against <about:blank> assert_equals: href expected "file:////localhost//cat" but got "file:///localhost//cat" -FAIL Parsing: <file://localhost//a//../..//> against <about:blank> assert_equals: href expected "file://///" but got "file://localhost///" -FAIL Parsing: </////mouse> against <file:///elephant> assert_equals: href expected "file://///mouse" but got "file:///mouse" -PASS Parsing: <\//pig> against <file://lion/> -FAIL Parsing: <\/localhost//pig> against <file://lion/> assert_equals: href expected "file:////pig" but got "file://localhost//pig" -FAIL Parsing: <//localhost//pig> against <file://lion/> assert_equals: href expected "file:////pig" but got "file://localhost//pig" -PASS Parsing: </..//localhost//pig> against <file://lion/> -PASS Parsing: <file://> against <file://ape/> -PASS Parsing: </rooibos> against <file://tea/> -PASS Parsing: </?chai> against <file://tea/> -FAIL Parsing: <C|> against <file://host/dir/file> assert_equals: href expected "file://host/C:" but got "file://host/dir/C%7C" -FAIL Parsing: <C|> against <file://host/D:/dir1/dir2/file> assert_equals: href expected "file://host/C:" but got "file://host/D:/dir1/dir2/C%7C" -FAIL Parsing: <C|#> against <file://host/dir/file> assert_equals: href expected "file://host/C:#" but got "file://host/dir/C%7C#" -FAIL Parsing: <C|?> against <file://host/dir/file> assert_equals: href expected "file://host/C:?" but got "file://host/dir/C%7C?" -FAIL Parsing: <C|/> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -FAIL Parsing: <C| -/> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -FAIL Parsing: <C|\> against <file://host/dir/file> assert_equals: href expected "file://host/C:/" but got "file://host/dir/C%7C/" -PASS Parsing: <C> against <file://host/dir/file> -FAIL Parsing: <C|a> against <file://host/dir/file> assert_equals: href expected "file://host/dir/C|a" but got "file://host/dir/C%7Ca" -PASS Parsing: </c:/foo/bar> against <file:///c:/baz/qux> -FAIL Parsing: </c|/foo/bar> against <file:///c:/baz/qux> assert_equals: href expected "file:///c:/foo/bar" but got "file:///c%7C/foo/bar" -PASS Parsing: <file:\c:\foo\bar> against <file:///c:/baz/qux> -PASS Parsing: </c:/foo/bar> against <file://host/path> -PASS Parsing: <file://example.net/C:/> against <about:blank> -PASS Parsing: <file://1.2.3.4/C:/> against <about:blank> -PASS Parsing: <file://[1::8]/C:/> against <about:blank> -FAIL Parsing: <C|/> against <file://host/> assert_equals: href expected "file://host/C:/" but got "file://host/C%7C/" -PASS Parsing: </C:/> against <file://host/> -PASS Parsing: <file:C:/> against <file://host/> -PASS Parsing: <file:/C:/> against <file://host/> -FAIL Parsing: <//C:/> against <file://host/> assert_equals: href expected "file:///C:/" but got "file://c:/" -FAIL Parsing: <file://C:/> against <file://host/> assert_equals: href expected "file:///C:/" but got "file://c:/" -PASS Parsing: <///C:/> against <file://host/> -PASS Parsing: <file:///C:/> against <file://host/> -FAIL Parsing: <file:/C|/> against <about:blank> assert_equals: href expected "file:///C:/" but got "file:///C%7C/" -FAIL Parsing: <file://C|/> against <about:blank> assert_equals: href expected "file:///C:/" but got "file://c%7C/" -PASS Parsing: <file:> against <about:blank> -PASS Parsing: <file:?q=v> against <about:blank> -PASS Parsing: <file:#frag> against <about:blank> -PASS Parsing: <file:///Y:> against <about:blank> -PASS Parsing: <file:///Y:/> against <about:blank> -PASS Parsing: <file:///./Y> against <about:blank> -PASS Parsing: <file:///./Y:> against <about:blank> -FAIL Parsing: <\\\.\Y:> against <about:blank> assert_equals: failure should set href to input expected "\\\\\\.\\Y:" but got "" -PASS Parsing: <file:///y:> against <about:blank> -PASS Parsing: <file:///y:/> against <about:blank> -PASS Parsing: <file:///./y> against <about:blank> -PASS Parsing: <file:///./y:> against <about:blank> -FAIL Parsing: <\\\.\y:> against <about:blank> assert_equals: failure should set href to input expected "\\\\\\.\\y:" but got "" -FAIL Parsing: <file://localhost//a//../..//foo> against <about:blank> assert_equals: href expected "file://///foo" but got "file://localhost///foo" -FAIL Parsing: <file://localhost////foo> against <about:blank> assert_equals: href expected "file://////foo" but got "file://localhost////foo" -FAIL Parsing: <file:////foo> against <about:blank> assert_equals: href expected "file:////foo" but got "file:///foo" -PASS Parsing: <file:///one/two> against <file:///> -FAIL Parsing: <file:////one/two> against <file:///> assert_equals: href expected "file:////one/two" but got "file:///one/two" -PASS Parsing: <//one/two> against <file:///> -PASS Parsing: <///one/two> against <file:///> -FAIL Parsing: <////one/two> against <file:///> assert_equals: href expected "file:////one/two" but got "file:///one/two" -PASS Parsing: <file:///.//> against <file:////> -PASS Parsing: <file:.//p> against <about:blank> -PASS Parsing: <file:/.//p> against <about:blank> -PASS Parsing: <http://[1:0::]> against <http://example.net/> -FAIL Parsing: <http://[0:1:2:3:4:5:6:7:8]> against <http://example.net/> assert_equals: failure should set href to input expected "http://[0:1:2:3:4:5:6:7:8]" but got "http://[0:1:2:3:4:5:6:7:8]/" -FAIL Parsing: <https://[0::0::0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0::0::0]" but got "https://[0::0::0]/" -FAIL Parsing: <https://[0:.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:.0]" but got "https://[0:.0]/" -FAIL Parsing: <https://[0:0:]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:0:]" but got "https://[0:0:]/" -FAIL Parsing: <https://[0:1:2:3:4:5:6:7.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1:2:3:4:5:6:7.0.0.0.1]" but got "https://[0:1:2:3:4:5:6:7.0.0.0.1]/" -FAIL Parsing: <https://[0:1.00.0.0.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.00.0.0.0]" but got "https://[0:1.00.0.0.0]/" -FAIL Parsing: <https://[0:1.290.0.0.0]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.290.0.0.0]" but got "https://[0:1.290.0.0.0]/" -FAIL Parsing: <https://[0:1.23.23]> against <about:blank> assert_equals: failure should set href to input expected "https://[0:1.23.23]" but got "https://[0:1.23.23]/" -FAIL Parsing: <http://?> against <about:blank> assert_equals: failure should set href to input expected "http://?" but got "http:/?" -FAIL Parsing: <http://#> against <about:blank> assert_equals: failure should set href to input expected "http://#" but got "http:/#" -PASS Parsing: <http://f:4294967377/c> against <http://example.org/> -PASS Parsing: <http://f:18446744073709551697/c> against <http://example.org/> -PASS Parsing: <http://f:340282366920938463463374607431768211537/c> against <http://example.org/> -FAIL Parsing: <sc://ñ> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <sc://ñ?x> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <sc://ñ#x> against <about:blank> assert_equals: host expected "%C3%B1" but got "" -FAIL Parsing: <#x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1#x" but got "sc://%C3%B1" -FAIL Parsing: <?x> against <sc://ñ> assert_equals: href expected "sc://%C3%B1?x" but got "sc://%C3%B1" -FAIL Parsing: <sc://?> against <about:blank> assert_equals: pathname expected "" but got "//" -FAIL Parsing: <sc://#> against <about:blank> assert_equals: pathname expected "" but got "//" -FAIL Parsing: <///> against <sc://x/> assert_equals: href expected "sc:///" but got "sc:" -FAIL Parsing: <////> against <sc://x/> assert_equals: href expected "sc:////" but got "sc:" -FAIL Parsing: <////x/> against <sc://x/> assert_equals: href expected "sc:////x/" but got "sc://x/" -FAIL Parsing: <tftp://foobar.com/someconfig;mode=netascii> against <about:blank> assert_equals: host expected "foobar.com" but got "" -FAIL Parsing: <telnet://user:pass@foobar.com:23/> against <about:blank> assert_equals: username expected "user" but got "" -FAIL Parsing: <ut2004://10.10.10.10:7777/Index.ut2> against <about:blank> assert_equals: host expected "10.10.10.10:7777" but got "" -FAIL Parsing: <redis://foo:bar@somehost:6379/0?baz=bam&qux=baz> against <about:blank> assert_equals: username expected "foo" but got "" -FAIL Parsing: <rsync://foo@host:911/sup> against <about:blank> assert_equals: username expected "foo" but got "" -FAIL Parsing: <git://github.com/foo/bar.git> against <about:blank> assert_equals: host expected "github.com" but got "" -FAIL Parsing: <irc://myserver.com:6999/channel?passwd> against <about:blank> assert_equals: host expected "myserver.com:6999" but got "" -FAIL Parsing: <dns://fw.example.org:9999/foo.bar.org?type=TXT> against <about:blank> assert_equals: host expected "fw.example.org:9999" but got "" -FAIL Parsing: <ldap://localhost:389/ou=People,o=JNDITutorial> against <about:blank> assert_equals: host expected "localhost:389" but got "" -FAIL Parsing: <git+https://github.com/foo/bar> against <about:blank> assert_equals: host expected "github.com" but got "" -PASS Parsing: <urn:ietf:rfc:2648> against <about:blank> -PASS Parsing: <tag:joe@example.org,2001:foo/bar> against <about:blank> -FAIL Parsing: <non-spec:/.//> against <about:blank> assert_equals: pathname expected "//" but got "/.//" -FAIL Parsing: <non-spec:/..//> against <about:blank> assert_equals: href expected "non-spec:/.//" but got "non-spec:/..//" -FAIL Parsing: <non-spec:/a/..//> against <about:blank> assert_equals: href expected "non-spec:/.//" but got "non-spec:/a/..//" -FAIL Parsing: <non-spec:/.//path> against <about:blank> assert_equals: pathname expected "//path" but got "/.//path" -FAIL Parsing: <non-spec:/..//path> against <about:blank> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/..//path" -FAIL Parsing: <non-spec:/a/..//path> against <about:blank> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/a/..//path" -FAIL Parsing: </.//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: </..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <a/..//path> against <non-spec:/p> assert_equals: href expected "non-spec:/.//path" but got "non-spec://path" -FAIL Parsing: <> against <non-spec:/..//p> assert_equals: href expected "non-spec:/.//p" but got "non-spec:/..//p" -FAIL Parsing: <path> against <non-spec:/..//p> assert_equals: href expected "non-spec:/.//path" but got "non-spec:/..//path" -FAIL Parsing: <../path> against <non-spec:/.//p> assert_equals: href expected "non-spec:/path" but got "non-spec:/./path" -FAIL Parsing: <non-special://%E2%80%A0/> against <about:blank> assert_equals: host expected "%E2%80%A0" but got "" -FAIL Parsing: <non-special://H%4fSt/path> against <about:blank> assert_equals: host expected "H%4fSt" but got "" -FAIL Parsing: <non-special://[1:2:0:0:5:0:0:0]/> against <about:blank> assert_equals: href expected "non-special://[1:2:0:0:5::]/" but got "non-special://[1:2:0:0:5:0:0:0]/" -FAIL Parsing: <non-special://[1:2:0:0:0:0:0:3]/> against <about:blank> assert_equals: href expected "non-special://[1:2::3]/" but got "non-special://[1:2:0:0:0:0:0:3]/" -FAIL Parsing: <non-special://[1:2::3]:80/> against <about:blank> assert_equals: host expected "[1:2::3]:80" but got "" -FAIL Parsing: <non-special://[:80/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <blob:https://example.com:443/> against <about:blank> -PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> -PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> -PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> -FAIL Parsing: <http://[::127.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "http://[::127.0.0.0.1]" but got "http://[::127.0.0.0.1]/" -PASS Parsing: <http://[0:1:0:1:0:1:0:1]> against <about:blank> -PASS Parsing: <http://[1:0:1:0:1:0:1:0]> against <about:blank> -PASS Parsing: <http://example.org/test?"> against <about:blank> -PASS Parsing: <http://example.org/test?#> against <about:blank> -PASS Parsing: <http://example.org/test?<> against <about:blank> -PASS Parsing: <http://example.org/test?>> against <about:blank> -PASS Parsing: <http://example.org/test?⌣> against <about:blank> -PASS Parsing: <http://example.org/test?%23%23> against <about:blank> -PASS Parsing: <http://example.org/test?%GH> against <about:blank> -PASS Parsing: <http://example.org/test?a#%EF> against <about:blank> -PASS Parsing: <http://example.org/test?a#%GH> against <about:blank> -FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got "" -FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got "" -FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got "" -FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got "" -FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got "" -PASS Parsing: <test-a-colon-slash.html> against <a:/> -FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got "" -PASS Parsing: <test-a-colon-slash-b.html> against <a:/b> -FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b" -PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank> -FAIL Parsing: <non-spec://example.org/test?a#b\0c> against <about:blank> assert_equals: host expected "example.org" but got "" -PASS Parsing: <non-spec:/test?a#b\0c> against <about:blank> -PASS Parsing: <10.0.0.7:8080/foo.html> against <file:///some/dir/bar.html> -PASS Parsing: <a!@$*=/foo.html> against <file:///some/dir/bar.html> -PASS Parsing: <a1234567890-+.:foo/bar> against <http://example.com/dir/file> -PASS Parsing: <file://ab/p> against <about:blank> -PASS Parsing: <file://a%C2%ADb/p> against <about:blank> -FAIL Parsing: <file:///p> against <about:blank> assert_equals: failure should set href to input expected "file:///p" but got "file://%C2%AD/p" -PASS Parsing: <file://%C2%AD/p> against <about:blank> -FAIL Parsing: <file://xn--/p> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code -PASS Parsing: <#link> against <https://example.org/##link> -PASS Parsing: <non-special:cannot-be-a-base-url-\0~> against <about:blank> -PASS Parsing: <https://www.example.com/path{path.html?query'=query#fragment<fragment> against <about:blank> -PASS Parsing: <https://user:pass[@foo/bar> against <http://example.org> -FAIL Parsing: <foo:// !"$%&'()*+,-.;<=>@[\]^_`{|}~@host/> against <about:blank> assert_equals: href expected "foo://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/" but got "foo:// !\"$%&'()*+,-.;<=>@[\\]^_`{|}~@host/" -FAIL Parsing: <wss:// !"$%&'()*+,-.;<=>@[]^_`{|}~@host/> against <about:blank> assert_equals: href expected "wss://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" but got "wss://%20!%22$%&%27()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" -FAIL Parsing: <foo://joe: !"$%&'()*+,-.:;<=>@[\]^_`{|}~@host/> against <about:blank> assert_equals: href expected "foo://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/" but got "foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/" -FAIL Parsing: <wss://joe: !"$%&'()*+,-.:;<=>@[]^_`{|}~@host/> against <about:blank> assert_equals: href expected "wss://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" but got "wss://joe:%20!%22$%&%27()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/" -FAIL Parsing: <foo://!"$%&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: host expected "!\"$%&'()*+,-.;=_`{}~" but got "" -FAIL Parsing: <wss://!"$&'()*+,-.;=_`{}~/> against <about:blank> assert_equals: href expected "wss://!\"$&'()*+,-.;=_`{}~/" but got "wss://%21%22%24%26%27%28%29%2A+%2C-.%3B%3D_%60%7B%7D%7E/" -FAIL Parsing: <foo://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> assert_equals: href expected "foo://host/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]^_%60%7B|%7D~" but got "foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~" -FAIL Parsing: <wss://host/ !"$%&'()*+,-./:;<=>@[\]^_`{|}~> against <about:blank> assert_equals: href expected "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]^_%60%7B|%7D~" but got "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B%7C%7D~" -FAIL Parsing: <foo://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> assert_equals: href expected "foo://host/dir/?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\]^_`{|}~" but got "foo://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~" -PASS Parsing: <wss://host/dir/? !"$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -FAIL Parsing: <foo://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> assert_equals: host expected "host" but got "" -PASS Parsing: <wss://host/dir/# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~> against <about:blank> -FAIL Parsing: <abc:rootless> against <abc://host/path> assert_equals: href expected "abc:rootless" but got "abc://host/rootless" -FAIL Parsing: <abc:rootless> against <abc:/path> assert_equals: href expected "abc:rootless" but got "abc:/rootless" -PASS Parsing: <abc:rootless> against <abc:path> -FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt index 762c7838..00d227d 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 633 tests; 376 PASS, 257 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 659 tests; 377 PASS, 282 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -297,7 +297,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/" FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/" @@ -421,11 +420,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> FAIL Parsing: <http://10000000000> against <http://other.com/> assert_equals: failure should set href to input expected "http://10000000000" but got "http://10000000000/" PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -434,7 +437,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> FAIL Parsing: <http://0xffffffff1> against <http://other.com/> assert_equals: failure should set href to input expected "http://0xffffffff1" but got "http://0xffffffff1/" FAIL Parsing: <http://256.256.256.256> against <http://other.com/> assert_equals: failure should set href to input expected "http://256.256.256.256" but got "http://256.256.256.256/" -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -589,7 +591,6 @@ FAIL Parsing: <non-special://[:80/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> FAIL Parsing: <http://[::127.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "http://[::127.0.0.0.1]" but got "http://[::127.0.0.0.1]/" @@ -644,5 +645,30 @@ FAIL Parsing: <abc:rootless> against <abc:/path> assert_equals: href expected "abc:rootless" but got "abc:/rootless" PASS Parsing: <abc:rootless> against <abc:path> FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x100.2.3.4> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4" but got "http://0x100.2.3.4/" +FAIL Parsing: <http://0x100.2.3.4.> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4." but got "http://0x100.2.3.4./" +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt index 21264a7..e5fd1f4 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 485 tests; 265 PASS, 220 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 611 tests; 275 PASS, 336 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw PASS URL's href: file://example:1/ should throw @@ -485,5 +485,131 @@ PASS sendBeacon(): file://xn--/p should throw FAIL Location's href: file://xn--/p should throw assert_throws_js: function "() => self[0].location = test.input" did not throw FAIL window.open(): file://xn--/p should throw assert_throws_dom: function "() => self.open(test.input).close()" threw object "TypeError: Cannot read properties of null (reading 'close')" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12 +FAIL URL's constructor's base argument: http://0..0x300/ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300/ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0..0x300./ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300./ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300./ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300./ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300./ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300./ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +PASS URL's constructor's base argument: http://0x100.2.3.4 should throw +PASS URL's href: http://0x100.2.3.4 should throw +PASS XHR: http://0x100.2.3.4 should throw +PASS sendBeacon(): http://0x100.2.3.4 should throw +FAIL Location's href: http://0x100.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4 should throw +PASS URL's constructor's base argument: http://0x100.2.3.4. should throw +PASS URL's href: http://0x100.2.3.4. should throw +PASS XHR: http://0x100.2.3.4. should throw +PASS sendBeacon(): http://0x100.2.3.4. should throw +FAIL Location's href: http://0x100.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4.' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4. should throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any-expected.txt index eb20797..e931b952 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 452 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 455 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -673,7 +675,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -732,5 +733,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker-expected.txt index eb20797..e931b952 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 452 PASS, 183 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 455 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -673,7 +675,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -732,5 +733,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt index 65ebbc32..ac8155bb 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 633 tests; 360 PASS, 273 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 659 tests; 361 PASS, 298 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -297,7 +297,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/" FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/" @@ -421,11 +420,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> FAIL Parsing: <http://10000000000> against <http://other.com/> assert_equals: failure should set href to input expected "http://10000000000" but got "http://10000000000/" PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -434,7 +437,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> FAIL Parsing: <http://0xffffffff1> against <http://other.com/> assert_equals: failure should set href to input expected "http://0xffffffff1" but got "http://0xffffffff1/" FAIL Parsing: <http://256.256.256.256> against <http://other.com/> assert_equals: failure should set href to input expected "http://256.256.256.256" but got "http://256.256.256.256/" -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -589,7 +591,6 @@ FAIL Parsing: <non-special://[:80/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> FAIL Parsing: <http://[::127.0.0.0.1]> against <about:blank> assert_equals: failure should set href to input expected "http://[::127.0.0.0.1]" but got "http://[::127.0.0.0.1]/" @@ -644,5 +645,30 @@ FAIL Parsing: <abc:rootless> against <abc:/path> assert_equals: href expected "abc:rootless" but got "abc:/rootless" PASS Parsing: <abc:rootless> against <abc:path> FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x100.2.3.4> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4" but got "http://0x100.2.3.4/" +FAIL Parsing: <http://0x100.2.3.4.> against <about:blank> assert_equals: failure should set href to input expected "http://0x100.2.3.4." but got "http://0x100.2.3.4./" +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.09.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt index 42c34f9..f6f037b2 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 485 tests; 261 PASS, 224 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 611 tests; 271 PASS, 340 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw PASS URL's href: file://example:1/ should throw @@ -485,5 +485,131 @@ PASS sendBeacon(): file://xn--/p should throw FAIL Location's href: file://xn--/p should throw assert_throws_js: function "() => self[0].location = test.input" did not throw FAIL window.open(): file://xn--/p should throw assert_throws_dom: function "() => self.open(test.input).close()" threw object "TypeError: Cannot read properties of null (reading 'close')" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12 +FAIL URL's constructor's base argument: http://0..0x300/ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300/ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0..0x300./ should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0..0x300./ should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0..0x300./ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0..0x300./ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0..0x300./ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0..0x300./ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.08. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.08. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.08. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.08. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.08. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.08. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://1.2.3.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://1.2.3.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://1.2.3.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://1.2.3.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://1.2.3.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://1.2.3.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://09.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://09.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://09.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://09.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://09.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://09.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://01.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://01.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://01.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://01.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://01.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +PASS URL's constructor's base argument: http://0x100.2.3.4 should throw +PASS URL's href: http://0x100.2.3.4 should throw +PASS XHR: http://0x100.2.3.4 should throw +PASS sendBeacon(): http://0x100.2.3.4 should throw +FAIL Location's href: http://0x100.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4 should throw +PASS URL's constructor's base argument: http://0x100.2.3.4. should throw +PASS URL's href: http://0x100.2.3.4. should throw +PASS XHR: http://0x100.2.3.4. should throw +PASS sendBeacon(): http://0x100.2.3.4. should throw +FAIL Location's href: http://0x100.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://0x100.2.3.4.' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") +PASS window.open(): http://0x100.2.3.4. should throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://0x1.2.3.4.5. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://0x1.2.3.4.5. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.1.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.1.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.1.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.1.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.1.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.2.3.4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.2.3.4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.2.3.4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.2.3.4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.2.3.4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.2.3.4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.09. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.09. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.09. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.09. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.09. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.09. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4 should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4 should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4 should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4 should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4 should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4 should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw +FAIL URL's constructor's base argument: http://foo.0x4. should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw +FAIL URL's href: http://foo.0x4. should throw assert_throws_js: function "() => url.href = test.input" did not throw +FAIL XHR: http://foo.0x4. should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw +FAIL sendBeacon(): http://foo.0x4. should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw +FAIL Location's href: http://foo.0x4. should throw assert_throws_js: function "() => self[0].location = test.input" did not throw +FAIL window.open(): http://foo.0x4. should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any-expected.txt index 8c28967..be7edeca 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 432 PASS, 203 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 435 PASS, 226 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -677,7 +679,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -740,5 +741,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker-expected.txt index 8c28967..be7edeca 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 635 tests; 432 PASS, 203 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 661 tests; 435 PASS, 226 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS Parsing: <http://example . org> against <http://example.org/foo/bar> @@ -317,7 +317,6 @@ PASS Parsing: <http://0Xc0.0250.01> against <http://other.com/> PASS Parsing: <http://./> against <about:blank> PASS Parsing: <http://../> against <about:blank> -PASS Parsing: <http://0..0x300/> against <about:blank> PASS Parsing: <http://[www.google.com]/> against <about:blank> PASS Parsing: <http://[google.com]> against <http://other.com/> PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/> @@ -491,11 +490,15 @@ PASS Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> PASS Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> +PASS Parsing: <http://1.2.3.4/> against <http://other.com/> +PASS Parsing: <http://1.2.3.4./> against <http://other.com/> PASS Parsing: <http://192.168.257> against <http://other.com/> +PASS Parsing: <http://192.168.257.> against <http://other.com/> PASS Parsing: <http://192.168.257.com> against <http://other.com/> PASS Parsing: <http://256> against <http://other.com/> PASS Parsing: <http://256.com> against <http://other.com/> PASS Parsing: <http://999999999> against <http://other.com/> +PASS Parsing: <http://999999999.> against <http://other.com/> PASS Parsing: <http://999999999.com> against <http://other.com/> PASS Parsing: <http://10000000000> against <http://other.com/> PASS Parsing: <http://10000000000.com> against <http://other.com/> @@ -504,7 +507,6 @@ PASS Parsing: <http://0xffffffff> against <http://other.com/> PASS Parsing: <http://0xffffffff1> against <http://other.com/> PASS Parsing: <http://256.256.256.256> against <http://other.com/> -PASS Parsing: <http://256.256.256.256.256> against <http://other.com/> PASS Parsing: <https://0x.0x.0> against <about:blank> PASS Parsing: <https://0x100000000/test> against <about:blank> PASS Parsing: <https://256.0.0.1/test> against <about:blank> @@ -677,7 +679,6 @@ }" did not throw PASS Parsing: <blob:https://example.com:443/> against <about:blank> PASS Parsing: <blob:d3958f5c-0777-0845-9dcf-2cb28783acaf> against <about:blank> -PASS Parsing: <http://0177.0.0.0189> against <about:blank> PASS Parsing: <http://0x7f.0.0.0x7g> against <about:blank> PASS Parsing: <http://0X7F.0.0.0X7G> against <about:blank> PASS Parsing: <http://[::127.0.0.0.1]> against <about:blank> @@ -740,5 +741,76 @@ FAIL Parsing: <abc:/rooted> against <abc://host/path> assert_equals: href expected "abc:/rooted" but got "abc://host/rooted" PASS Parsing: <#> against <null> PASS Parsing: <?> against <null> +FAIL Parsing: <http://1.2.3.4.5> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.4.5.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300/> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0..0x300./> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://256.256.256.256.256.> against <http://other.com/> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.08.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://1.2.3.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://09.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://01.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +PASS Parsing: <http://0x100.2.3.4> against <about:blank> +PASS Parsing: <http://0x100.2.3.4.> against <about:blank> +FAIL Parsing: <http://0x1.2.3.4.5> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://0x1.2.3.4.5.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.1.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.2.3.4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.09.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw +FAIL Parsing: <http://foo.0x4.> against <about:blank> assert_throws_js: function "function() { + bURL(expected.input, expected.base) + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png b/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png index 07bb176..2f6af964b 100644 --- a/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png +++ b/third_party/blink/web_tests/virtual/jxl-enabled/images/jxl/jxl-images-expected.png Binary files differ
diff --git a/third_party/highway/README.chromium b/third_party/highway/README.chromium index 753f481..a99e0fb 100644 --- a/third_party/highway/README.chromium +++ b/third_party/highway/README.chromium
@@ -1,9 +1,9 @@ Name: Highway: C++ library for SIMD Short Name: highway URL: https://github.com/google/highway -Version: 0.12.0 -Date: 2020-04-15 -Revision: ca1a57c342cd815053abfcffa29b44eaead4f20b +Version: 0.12.2 +Date: 2020-05-31 +Revision: 424360251cdcfc314cfc528f53c872ecd63af0f0 License: Apache 2.0 Security Critical: yes CPEPrefix: unknown
diff --git a/third_party/libjxl/LICENSE b/third_party/libjxl/LICENSE index 6b0b127..c66034b 100644 --- a/third_party/libjxl/LICENSE +++ b/third_party/libjxl/LICENSE
@@ -1,203 +1,27 @@ +Copyright (c) the JPEG XL Project Authors. +All rights reserved. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. - 1. Definitions. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libjxl/README.chromium b/third_party/libjxl/README.chromium index 45777cf..2dd6e1b 100644 --- a/third_party/libjxl/README.chromium +++ b/third_party/libjxl/README.chromium
@@ -1,16 +1,15 @@ Name: JPEG XL image decoder library Short Name: libjxl -URL: https://gitlab.com/wg1/jpeg-xl -Version: 0 -Date: 2021-06-14 -Revision: 4a981fd8be383703ca8c5dc78c25411c14a01d9f -License: Apache 2.0 +URL: https://github.com/libjxl/libjxl +Version: 0.5 +Date: 2021-08-02 +Revision: c4e0877f93506e880cd922f6c94644d79ae9adff +License: BSD 3-Clause Security Critical: yes -CPEPrefix: unknown +CPEPrefix: cpe:2.3:a:libjxl_project:libjxl:0.5 Description: The reference implementation for the JPEG XL image encoder/decoder. Local Modifications: None. Only decoder-side is compiled. -
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py index 9beefc6..b9f0200 100755 --- a/tools/cygprofile/orderfile_generator_backend.py +++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -13,7 +13,6 @@ tools/cygprofile/orderfile_generator_backend.py --use-goma --target-arch=arm """ -from __future__ import print_function import argparse import csv @@ -388,7 +387,7 @@ Exception if the hash file does not match the file. NotImplementedError when the commit logic hasn't been overridden. """ - files_to_commit = list(filter(None, files)) + files_to_commit = [_f for _f in files if _f] if files_to_commit: self._CommitStashedFiles(files_to_commit) @@ -964,8 +963,8 @@ elif self._options.manual_symbol_offsets: assert self._options.manual_libname assert self._options.manual_objdir - with file(self._options.manual_symbol_offsets) as f: - symbol_offsets = [int(x) for x in f.xreadlines()] + with open(self._options.manual_symbol_offsets) as f: + symbol_offsets = [int(x) for x in f] processor = process_profiles.SymbolOffsetProcessor( self._compiler.manual_libname) generator = cyglog_to_orderfile.OffsetOrderfileGenerator(
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py index 1068716..0eb9577 100755 --- a/tools/cygprofile/profile_android_startup.py +++ b/tools/cygprofile/profile_android_startup.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (c) 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -10,7 +10,6 @@ to make runs repeatable. """ -from __future__ import print_function import argparse import logging @@ -529,7 +528,7 @@ apk = apk_helper.ApkHelper(args.apk_path) package_info = None - for p in constants.PACKAGE_INFO.itervalues(): + for p in constants.PACKAGE_INFO.items(): if p.package == apk.GetPackageName(): package_info = p break
diff --git a/tools/dump_process_memory/collect_process_dump.py b/tools/dump_process_memory/collect_process_dump.py index 47f4b6e..ba348fa 100755 --- a/tools/dump_process_memory/collect_process_dump.py +++ b/tools/dump_process_memory/collect_process_dump.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index ff9faf82..62499c6 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -206,8 +206,8 @@ }, 'chromium.dawn': { - 'Dawn Linux x64 Builder': 'dawn_tests_release_trybot', - 'Dawn Linux x64 DEPS Builder': 'dawn_tests_release_trybot', + 'Dawn Linux x64 Builder': 'dawn_tests_with_desktop_gl_release_trybot', + 'Dawn Linux x64 DEPS Builder': 'dawn_tests_with_desktop_gl_release_trybot', 'Dawn Mac x64 Builder': 'dawn_tests_release_trybot', 'Dawn Mac x64 DEPS Builder': 'dawn_tests_release_trybot', @@ -962,12 +962,12 @@ }, 'tryserver.chromium.dawn': { - 'dawn-linux-x64-deps-rel': 'dawn_tests_release_trybot', + 'dawn-linux-x64-deps-rel': 'dawn_tests_with_desktop_gl_release_trybot', 'dawn-mac-x64-deps-rel': 'dawn_tests_release_trybot', 'dawn-try-mac-amd-exp': 'dawn_tests_release_trybot', 'dawn-win10-x86-deps-rel': 'dawn_tests_release_trybot_x86', 'dawn-win10-x64-deps-rel': 'dawn_tests_release_trybot', - 'linux-dawn-rel': 'dawn_tests_release_trybot', + 'linux-dawn-rel': 'dawn_tests_with_desktop_gl_release_trybot', 'mac-dawn-rel': 'dawn_tests_release_trybot', 'win-dawn-rel': 'dawn_tests_release_trybot', 'dawn-try-win10-x86-rel': 'dawn_tests_release_trybot_x86', @@ -2022,6 +2022,10 @@ 'dawn_tests', 'release_trybot', 'x86', ], + 'dawn_tests_with_desktop_gl_release_trybot': [ + 'dawn_tests', 'dawn_enable_desktop_gl', 'release_trybot', + ], + 'debug_bot': [ 'debug_bot', ], @@ -3120,7 +3124,11 @@ }, 'dawn_tests': { - 'gn_args': 'use_dawn=true', + 'gn_args': 'use_dawn=true dawn_enable_opengles=true', + }, + + 'dawn_enable_desktop_gl': { + 'gn_args': 'dawn_enable_desktop_gl=true', }, 'dcheck_always_on': {
diff --git a/tools/mb/mb_config_expectations/chromium.dawn.json b/tools/mb/mb_config_expectations/chromium.dawn.json index 9edb80e4..62fc4399 100644 --- a/tools/mb/mb_config_expectations/chromium.dawn.json +++ b/tools/mb/mb_config_expectations/chromium.dawn.json
@@ -2,6 +2,8 @@ "Dawn Linux x64 Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_desktop_gl": true, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -13,6 +15,8 @@ "Dawn Linux x64 DEPS Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_desktop_gl": true, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -24,6 +28,7 @@ "Dawn Mac x64 Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -35,6 +40,7 @@ "Dawn Mac x64 DEPS Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -46,6 +52,7 @@ "Dawn Win10 x64 ASAN Release": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_asan": true, "is_component_build": false, @@ -58,6 +65,7 @@ "Dawn Win10 x64 Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -69,6 +77,7 @@ "Dawn Win10 x64 DEPS Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -80,6 +89,7 @@ "Dawn Win10 x86 Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -92,6 +102,7 @@ "Dawn Win10 x86 DEPS Builder": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json b/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json index 711d4ce..95b3f5de 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json
@@ -2,6 +2,8 @@ "dawn-linux-x64-deps-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_desktop_gl": true, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -13,6 +15,7 @@ "dawn-mac-x64-deps-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -24,6 +27,7 @@ "dawn-try-mac-amd-exp": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -35,6 +39,7 @@ "dawn-try-win10-x64-asan-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_asan": true, "is_component_build": false, @@ -47,6 +52,7 @@ "dawn-try-win10-x86-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -59,6 +65,7 @@ "dawn-win10-x64-deps-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -70,6 +77,7 @@ "dawn-win10-x86-deps-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -82,6 +90,8 @@ "linux-dawn-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_desktop_gl": true, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -93,6 +103,7 @@ "mac-dawn-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false, @@ -104,6 +115,7 @@ "win-dawn-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, + "dawn_enable_opengles": true, "dcheck_always_on": true, "is_component_build": false, "is_debug": false,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7bba660..7c36fe67 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -44447,6 +44447,13 @@ <int value="2" label="BO"/> </enum> +<enum name="LacrosLaunchMode"> + <int value="0" label="Only Ash browser"/> + <int value="1" label="Ash and Lacros browser available"/> + <int value="2" label="Lacros browser is primary"/> + <int value="3" label="Only Lacros browser"/> +</enum> + <enum name="LanguageDetectionModelState"> <int value="0" label="Unknown"/> <int value="1" label="Model File Invalid"/> @@ -45405,6 +45412,20 @@ <int value="11" label="Success: Image is translatable"/> </enum> +<enum name="LensRegionSearchAspectRatio"> + <summary> + Enum describing the aspect ratio of the captured region. The aspect ratios + are defined arbitrarly as follows: SQUARE: [0.8, 1.2] WIDE: (1.2, 1.7] + VERY_WIDE: (1.7, infinity] TALL: [0.3, 0.8) VERY_TALL: [0, 0.3) + </summary> + <int value="0" label="Undefined Aspect Ratio"/> + <int value="1" label="Square Aspect Ratio"/> + <int value="2" label="Wide Aspect Ratio"/> + <int value="3" label="Very Wide Aspect Ratio"/> + <int value="4" label="Tall Aspect Ratio"/> + <int value="5" label="Very Tall Aspect Ratio"/> +</enum> + <enum name="LensRegionSearchCaptureResult"> <summary>Result of Lens Region Search feature.</summary> <int value="0" label="Success"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml index c8229fc..dca8ed9 100644 --- a/tools/metrics/histograms/metadata/accessibility/histograms.xml +++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -1510,7 +1510,7 @@ </histogram> <histogram name="DomDistiller.InfoBarUsage" enum="BooleanUsage" - expires_after="M77"> + expires_after="2022-01-01"> <owner>mdjones@chromium.org</owner> <summary> "Used" is recorded when the user clicks the infobar to enter @@ -1583,7 +1583,7 @@ </histogram> <histogram name="DomDistiller.ReaderShownForPageLoad" enum="Boolean" - expires_after="M77"> + expires_after="2022-01-01"> <owner>mdjones@chromium.org</owner> <summary> Records if the panel became visible at any point after a page was navigated. @@ -1701,7 +1701,7 @@ </histogram> <histogram name="DomDistiller.Time.ViewingReaderModePage" units="ms" - expires_after="M77"> + expires_after="2022-01-01"> <owner>mdjones@chromium.org</owner> <summary> Records the amount of time a user spent on a Reader Mode Page.
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 5770d371..e61c39e9 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1419,6 +1419,17 @@ </summary> </histogram> +<histogram name="Ash.Lacros.Launch.Mode" enum="LacrosLaunchMode" + expires_after="2022-09-01"> + <owner>skuhne@chromium.org</owner> + <owner>lacros-team@google.com</owner> + <summary> + The Lacros operation mode. This will record if Ash is the only browser, both + browsers are running side by side or if Lacros is the only browser. It will + be emitted once when the system (Ash) starts. + </summary> +</histogram> + <histogram name="Ash.Login.Lock.AuthMethod.Switched" enum="AuthMethodSwitchType" expires_after="2022-06-29"> <owner>rsorokin@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml index 882ceeb3..80a0cec 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -8172,14 +8172,6 @@ <affected-histogram name="Media.VideoCaptureManager"/> </histogram_suffixes> -<histogram_suffixes name="MediaVideoCategories" separator="."> - <suffix name="All" label="All media with a video track."/> - <suffix name="EME" label="EME media with a video track."/> - <suffix name="MSE" label="MSE media with a video track."/> - <suffix name="SRC" label="SRC media with a video track."/> - <affected-histogram name="Media.VideoHeight.Initial"/> -</histogram_suffixes> - <histogram_suffixes name="MediaWatchTimeCategories" separator="."> <suffix name="Audio.AC" label="Watch time for all media with only an audio track on AC power."/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 98002db..6c48999 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -4737,14 +4737,20 @@ </summary> </histogram> -<histogram base="true" name="Media.VideoHeight.Initial" units="pixels" - expires_after="2021-08-22"> +<histogram name="Media.VideoHeight.Initial.{PlaybackType}" units="pixels" + expires_after="2022-08-22"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> - The height of the first video frame in an HTML5 video. Reported when the - first video frame is available. + The height of the first video frame in an HTML5 video for {PlaybackType} + playbacks. Reported when the first video frame is available. </summary> + <token key="PlaybackType"> + <variant name="All" summary="all"/> + <variant name="EME"/> + <variant name="MSE"/> + <variant name="SRC"/> + </token> </histogram> <histogram name="Media.VideoPersistence.AttemptResult" @@ -5604,12 +5610,40 @@ <owner>openscreen-eng@google.com</owner> <summary> Counts the number of devices known and populated to the Media Router dialog - three seconds after the dialog loads. Always expected to be non-negative. - This includes data recorded from Clank, which uses Android's MediaRouter - framework. + (or the Global Media Controls' device picker) three seconds after the dialog + loads. Always expected to be non-negative. This includes data recorded from + Clank, which uses Android's MediaRouter framework. </summary> </histogram> +<histogram name="MediaRouter.Ui.Device.Count.{Ui}.{Trigger}.{Mrp}.{State}" + units="units" expires_after="2022-02-01"> + <owner>takumif@chromium.org</owner> + <owner>openscreen-eng@google.com</owner> + <summary> + Counts the number of {Mrp} devices that are shown as {State} in the {Ui} UI + three seconds after the UI was opened via {Trigger}. Always expected to be + non-negative. + </summary> + <token key="Ui"> + <variant name="CastHarmony"/> + <variant name="GlobalMediaControls"/> + </token> + <token key="Trigger"> + <variant name="BrowserUi"/> + <variant name="PresentationApi"/> + </token> + <token key="Mrp"> + <variant name="CAST"/> + <variant name="DIAL"/> + <variant name="WIRED_DISPLAY"/> + </token> + <token key="State"> + <variant name="Available"/> + <variant name="Unavailable"/> + </token> +</histogram> + <histogram name="MediaRouter.Ui.Dialog.ActivationLocationAndCastMode" enum="MediaRouterDialogActivationLocationAndCastMode" expires_after="2022-02-01">
diff --git a/tools/metrics/histograms/metadata/mobile/OWNERS b/tools/metrics/histograms/metadata/mobile/OWNERS index f3014b8..7b2b7d4 100644 --- a/tools/metrics/histograms/metadata/mobile/OWNERS +++ b/tools/metrics/histograms/metadata/mobile/OWNERS
@@ -3,3 +3,4 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. ender@google.com +mthiesse@chromium.org
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index ab9b451..e1111bc9 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -2306,7 +2306,7 @@ </histogram> <histogram name="Net.NetworkErrorLogging.SignedExchangeRequestOutcome" - enum="NetNetworkErrorLoggingRequestOutcome" expires_after="M94"> + enum="NetNetworkErrorLoggingRequestOutcome" expires_after="M99"> <owner>horo@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index a0232d3..9d318e1e 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -12376,7 +12376,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.BodySize" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -12387,7 +12387,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.BodySizeTotal" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -12399,7 +12399,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.Count" units="count" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -12411,7 +12411,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.HeadersSizeTotal" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -14964,7 +14964,7 @@ </histogram> <histogram name="SignedExchange.CertificateFetch.CacheHit" - enum="BooleanCacheHit" expires_after="M94"> + enum="BooleanCacheHit" expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -14975,7 +14975,7 @@ </histogram> <histogram name="SignedExchange.CertVerificationResult" enum="NetErrorCodes" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -14985,7 +14985,7 @@ </histogram> <histogram name="SignedExchange.CTVerificationResult" enum="CTComplianceStatus" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -14995,7 +14995,7 @@ </histogram> <histogram name="SignedExchange.FallbackRedirectLoop" enum="BooleanDetected" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15009,7 +15009,7 @@ </histogram> <histogram name="SignedExchange.LoadResult2" enum="SignedExchangeLoadResult" - expires_after="2022-01-02"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15020,7 +15020,7 @@ </histogram> <histogram name="SignedExchange.OCSPResponseStatus" enum="OCSPResponseStatus" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15031,7 +15031,7 @@ </histogram> <histogram name="SignedExchange.OCSPRevocationStatus" - enum="OCSPRevocationStatus" expires_after="M94"> + enum="OCSPRevocationStatus" expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15043,7 +15043,7 @@ </histogram> <histogram name="SignedExchange.Prefetch.LoadResult2" - enum="SignedExchangeLoadResult" expires_after="M94"> + enum="SignedExchangeLoadResult" expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15054,7 +15054,7 @@ </histogram> <histogram name="SignedExchange.Prefetch.Precision.30Seconds" - enum="BooleanUsage" expires_after="M94"> + enum="BooleanUsage" expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15067,7 +15067,7 @@ </histogram> <histogram name="SignedExchange.Prefetch.Recall.30Seconds" enum="BooleanUsage" - expires_after="M94"> + expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15079,7 +15079,7 @@ </histogram> <histogram name="SignedExchange.SignatureVerificationError.Expired" - units="seconds" expires_after="M94"> + units="seconds" expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15090,7 +15090,7 @@ </histogram> <histogram name="SignedExchange.SignatureVerificationError.NotYetValid" - units="seconds" expires_after="M94"> + units="seconds" expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15101,7 +15101,7 @@ </histogram> <histogram name="SignedExchange.SignatureVerificationResult" - enum="SignedExchangeSignatureVerificationResult" expires_after="2021-10-31"> + enum="SignedExchangeSignatureVerificationResult" expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15112,7 +15112,7 @@ </histogram> <histogram name="SignedExchange.Time.CertificateFetch.Failure" units="ms" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15123,7 +15123,7 @@ </histogram> <histogram name="SignedExchange.Time.CertificateFetch.Success" units="ms" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15134,7 +15134,7 @@ </histogram> <histogram name="SignedExchange.Time.SignatureVerify" units="ms" - expires_after="M94"> + expires_after="M99"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15145,7 +15145,7 @@ </histogram> <histogram name="SignedExchange.TimeUntilExpiration" units="seconds" - expires_after="M94"> + expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15157,7 +15157,7 @@ </histogram> <histogram name="SignedExchange.ValidityPingDuration" units="ms" - expires_after="M94"> + expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -15168,7 +15168,7 @@ </histogram> <histogram name="SignedExchange.ValidityPingResult" - enum="SignedExchangeValidityPingResult" expires_after="M94"> + enum="SignedExchangeValidityPingResult" expires_after="M99"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -16226,7 +16226,7 @@ </histogram> <histogram name="SubresourceWebBundles.ContentLength" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -16236,14 +16236,14 @@ </histogram> <histogram name="SubresourceWebBundles.LoadResult" - enum="SubresourceWebBundleLoadResult" expires_after="M94"> + enum="SubresourceWebBundleLoadResult" expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary>The result of loading subresource web bundles.</summary> </histogram> <histogram name="SubresourceWebBundles.MaxMemoryUsagePerProcess" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -16254,7 +16254,7 @@ </histogram> <histogram name="SubresourceWebBundles.ReceivedSize" units="bytes" - expires_after="M94"> + expires_after="M99"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml index a924569..fc0543ee 100644 --- a/tools/metrics/histograms/metadata/search/histograms.xml +++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -1257,7 +1257,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.Bitmap.Available" - enum="BooleanAvailable" expires_after="M94"> + enum="BooleanAvailable" expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1268,7 +1268,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.Bitmap.FetchDuration" units="ms" - expires_after="M94"> + expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1281,7 +1281,7 @@ </histogram> <histogram name="Search.QueryTiles.Fetcher.FirstFlowDuration" units="hours" - expires_after="M94"> + expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary> @@ -1291,28 +1291,28 @@ </histogram> <histogram name="Search.QueryTiles.Fetcher.Start" units="hours" - expires_after="M94"> + expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary>Records the hour (0-23) when the TileFetcher task starts.</summary> </histogram> <histogram name="Search.QueryTiles.FetcherHttpResponseCode" - enum="HttpResponseCode" expires_after="2021-12-31"> + enum="HttpResponseCode" expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary>Records the HTTP response code get from TileFetcher.</summary> </histogram> <histogram name="Search.QueryTiles.FetcherNetErrorCode" enum="NetErrorCodes" - expires_after="2021-12-31"> + expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary>Records the net error code get from TileFetcher.</summary> </histogram> <histogram name="Search.QueryTiles.Group.PruneReason" - enum="QueryTilesGroupPruneReason" expires_after="M94"> + enum="QueryTilesGroupPruneReason" expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary> @@ -1321,7 +1321,7 @@ </histogram> <histogram name="Search.QueryTiles.GroupStatus" enum="QueryTilesGroupStatus" - expires_after="2021-12-31"> + expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary> @@ -1340,7 +1340,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.NoBitmap.FetchDuration" - units="ms" expires_after="M94"> + units="ms" expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1353,7 +1353,7 @@ </histogram> <histogram name="Search.QueryTiles.NTP.Chip.SearchClicked" units="index" - expires_after="2021-12-31"> + expires_after="2022-04-01"> <owner>shaktisahu@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary> @@ -1363,7 +1363,7 @@ </histogram> <histogram name="Search.QueryTiles.RequestStatus" - enum="QueryTilesRequestStatus" expires_after="M94"> + enum="QueryTilesRequestStatus" expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary> @@ -1373,7 +1373,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.Tile.Clicked" units="index" - expires_after="M95"> + expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1385,7 +1385,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.Tile.Clicked.IsTopLevel" - enum="BooleanIsTopLevel" expires_after="M95"> + enum="BooleanIsTopLevel" expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1394,7 +1394,7 @@ </histogram> <histogram base="true" name="Search.QueryTiles.TileCount" units="tiles" - expires_after="M94"> + expires_after="2022-04-01"> <!-- Name completed by histogram_suffixes name="TileUiSurface" --> <owner>shaktisahu@chromium.org</owner> @@ -1424,7 +1424,7 @@ </histogram> <histogram name="Search.QueryTiles.TrendingTileEvent" enum="TrendingTileEvent" - expires_after="M94"> + expires_after="2022-04-01"> <owner>qinmin@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index d3bf46a..c45fe090 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -9,8 +9,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/win/3f8fabd85f1c3c15a2a98a40fe71e3eb165fba5e/trace_processor_shell.exe" }, "mac": { - "hash": "8452a92a4d2f47b9fe48579afde153ce345fe63a", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/bb09784511ef291082ade44a2d3d05dd3e45d30d/trace_processor_shell" + "hash": "0cfe0976cb4f931833b822104d2c212a1e737f65", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/3f8fabd85f1c3c15a2a98a40fe71e3eb165fba5e/trace_processor_shell" }, "linux_arm64": { "hash": "5074025a2898ec41a872e70a5719e417acb0a380",
diff --git a/tools/security/idn_test_case_generator.py b/tools/security/idn_test_case_generator.py index 1d0eab6..a1c0dd0 100755 --- a/tools/security/idn_test_case_generator.py +++ b/tools/security/idn_test_case_generator.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -9,7 +9,6 @@ from Python shell (see make_case documentation). """ -from __future__ import print_function import argparse import codecs @@ -18,16 +17,16 @@ def str_to_c_string(string): - """Converts a Python str (ASCII) to a C string literal. + """Converts a Python str (ASCII) to a C string literal. >>> str_to_c_string('abc\x8c') '"abc\\\\x8c"' """ - return repr(string).replace("'", '"') + return repr(string).replace("'", '"') def ishexdigit(c): - """ + """ >>> ishexdigit('0') True >>> ishexdigit('9') @@ -49,34 +48,34 @@ >>> ishexdigit('G') False """ - return c.isdigit() or ord('a') <= ord(c.lower()) <= ord('f') + return c.isdigit() or ord('a') <= ord(c.lower()) <= ord('f') def unicode_to_c_wstring(string): - """Converts a Python str or unicode to a C wide-string literal. + """Converts a Python str or unicode to a C wide-string literal. >>> unicode_to_c_wstring(u'b\u00fccher.de') 'L"b\\\\x00fc" L"cher.de"' """ - result = ['L"'] - for c in string: - # If the previous character was \x-escaped, and the next character is a - # hex digit, we need to end and restart the string literal. Otherwise, - # the next character will extend the \x escape sequence. - if result[-1].startswith('\\x') and ishexdigit(c): - result.append('" L"') - escaped = repr(c)[2:-1] - # Convert '\u' to '\x', and also force a minimum of 4 digits (this isn't - # necessary but is preferred style for these test cases). - if escaped[:2] in ('\\x', '\\u'): - escaped = '\\x%04x' % ord(c) - result.append(escaped) - result.append('"') - return ''.join(result) + result = ['L"'] + for c in string: + # If the previous character was \x-escaped, and the next character is a + # hex digit, we need to end and restart the string literal. Otherwise, + # the next character will extend the \x escape sequence. + if result[-1].startswith('\\x') and ishexdigit(c): + result.append('" L"') + escaped = repr(c)[2:-1] + # Convert '\u' to '\x', and also force a minimum of 4 digits (this isn't + # necessary but is preferred style for these test cases). + if escaped[:2] in ('\\x', '\\u'): + escaped = '\\x%04x' % ord(c) + result.append(escaped) + result.append('"') + return ''.join(result) def make_case(unicode_domain, unicode_allowed=True, case_name=None): - """Generates a C++ test case for an IDN domain test. + """Generates a C++ test case for an IDN domain test. This is designed specifically for the IDNTestCase struct in the file components/url_formatter/url_formatter_unittest.cc. It generates a row of @@ -103,45 +102,52 @@ >>> make_case(u'\u210fello', True) {"xn--ello-4xa", L"\\x0127" L"ello", true}, """ - idna_input = codecs.encode(unicode_domain, 'idna') - # Round-trip to ensure normalization. - unicode_output = codecs.decode(idna_input, 'idna') - if case_name: - print(' // %s' % case_name) - print(' {%s, %s, %s},' % - (str_to_c_string(idna_input), unicode_to_c_wstring(unicode_output), - repr(unicode_allowed).lower())) + idna_input = codecs.encode(unicode_domain, 'idna') + # Round-trip to ensure normalization. + unicode_output = codecs.decode(idna_input, 'idna') + if case_name: + print(' // %s' % case_name) + print(' {%s, %s, %s},' % + (str_to_c_string(idna_input), unicode_to_c_wstring(unicode_output), + repr(unicode_allowed).lower())) def main(args=None): - if args is None: - args = sys.argv[1:] + if args is None: + args = sys.argv[1:] - parser = argparse.ArgumentParser(description='Generate an IDN test case.') - parser.add_argument('domain', metavar='DOMAIN', nargs='?', - help='the Unicode domain (not encoded)') - parser.add_argument('--name', metavar='NAME', - help='the name of the test case') - parser.add_argument('--no-unicode', action='store_false', - dest='unicode_allowed', default=True, - help='expect the domain to be Punycoded') - parser.add_argument('--test', action='store_true', dest='run_tests', - help='run unit tests') + parser = argparse.ArgumentParser(description='Generate an IDN test case.') + parser.add_argument('domain', + metavar='DOMAIN', + nargs='?', + help='the Unicode domain (not encoded)') + parser.add_argument('--name', + metavar='NAME', + help='the name of the test case') + parser.add_argument('--no-unicode', + action='store_false', + dest='unicode_allowed', + default=True, + help='expect the domain to be Punycoded') + parser.add_argument('--test', + action='store_true', + dest='run_tests', + help='run unit tests') - args = parser.parse_args(args) + args = parser.parse_args(args) - if args.run_tests: - import doctest - doctest.testmod() - return + if args.run_tests: + import doctest + doctest.testmod() + return - if not args.domain: - parser.error('Required argument: DOMAIN') + if not args.domain: + parser.error('Required argument: DOMAIN') - # Assume stdin.encoding is the encoding used for command-line arguments. - domain = args.domain.decode(sys.stdin.encoding) - make_case(domain, unicode_allowed=args.unicode_allowed, case_name=args.name) + # Assume stdin.encoding is the encoding used for command-line arguments. + domain = args.domain.decode(sys.stdin.encoding) + make_case(domain, unicode_allowed=args.unicode_allowed, case_name=args.name) if __name__ == '__main__': - sys.exit(main()) + sys.exit(main())
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc index 64656ce..d890e03 100644 --- a/ui/accessibility/ax_event_generator.cc +++ b/ui/accessibility/ax_event_generator.cc
@@ -736,10 +736,6 @@ } void AXEventGenerator::OnNodeWillBeDeleted(AXTree* tree, AXNode* node) { - if (AXNode* root = live_region_tracker_->GetLiveRoot(*node)) { - if (root != node) - AddEvent(root, Event::LIVE_REGION_CHANGED); - } live_region_tracker_->OnNodeWillBeDeleted(*node); DCHECK_EQ(tree_, tree); @@ -785,7 +781,7 @@ change.type == NODE_REPARENTED || change.type == SUBTREE_REPARENTED)) { if (change.node->data().HasStringAttribute( ax::mojom::StringAttribute::kContainerLiveStatus)) { - live_region_tracker_->TrackNode(*change.node); + live_region_tracker_->UpdateCachedLiveRootForNode(*change.node); } } @@ -807,6 +803,20 @@ FireActiveDescendantEvents(); + // If we queued any live region change events during node deletion, add them + // here. It's necessary to wait to add these events, because an update might + // destroy and recreate live region roots after OnNodeWillBeDeleted is called. + // TODO(mrobinson): Consider designing AXEventGenerator to have a more + // resilient way to queue up events for nodes that might be destroyed and + // recreated in a single update. + for (auto& id : live_region_tracker_->live_region_roots_with_changes()) { + // If node is null, the live region root with a change was deleted during + // the course of this update and we should not trigger an event. + if (AXNode* node = tree_->GetFromId(id)) { + AddEvent(node, Event::LIVE_REGION_CHANGED); + } + } + live_region_tracker_->OnAtomicUpdateFinished(); PostprocessEvents();
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc index 825edf673..3797cf1 100644 --- a/ui/accessibility/ax_event_generator_unittest.cc +++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -2920,4 +2920,46 @@ HasEventAtNode(AXEventGenerator::Event::NAME_CHANGED, 4))); } +TEST(AXEventGeneratorTest, LiveRootDescendantOfClearedNodeChanged) { + AXTreeUpdate initial_state; + initial_state.root_id = 1; + initial_state.nodes.resize(4); + initial_state.nodes[0].id = 1; + initial_state.nodes[0].child_ids = {2}; + + initial_state.nodes[1].id = 2; + initial_state.nodes[1].child_ids = {3}; + + initial_state.nodes[2].id = 3; + initial_state.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kLiveStatus, "polite"); + initial_state.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[2].child_ids = {4}; + + initial_state.nodes[3].id = 4; + initial_state.nodes[3].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[3].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Live child"); + + AXTree tree(initial_state); + + AXEventGenerator event_generator(&tree); + AXTreeUpdate update = initial_state; + update.node_id_to_clear = 2; + update.nodes[2].child_ids = {}; + update.nodes.resize(3); + + // In this case the live region root is "reparented" because its removed + // when its parent is cleared and then re-added in the update. + EXPECT_TRUE(tree.Unserialize(update)); + EXPECT_THAT( + event_generator, + UnorderedElementsAre( + HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_CHANGED, 3), + HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 3), + HasEventAtNode(AXEventGenerator::Event::PARENT_CHANGED, 3))); +} + } // namespace ui
diff --git a/ui/accessibility/ax_live_region_tracker.cc b/ui/accessibility/ax_live_region_tracker.cc index b5e53f0..a160a00 100644 --- a/ui/accessibility/ax_live_region_tracker.cc +++ b/ui/accessibility/ax_live_region_tracker.cc
@@ -4,6 +4,7 @@ #include "ui/accessibility/ax_live_region_tracker.h" +#include "ui/accessibility/ax_event_generator.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_role_properties.h" @@ -24,21 +25,30 @@ AXLiveRegionTracker::~AXLiveRegionTracker() = default; -void AXLiveRegionTracker::TrackNode(const AXNode& node) { +void AXLiveRegionTracker::UpdateCachedLiveRootForNode(const AXNode& node) { const AXNode* live_root = &node; while (live_root && !IsLiveRegionRoot(*live_root)) live_root = live_root->GetUnignoredParent(); + if (live_root) live_region_node_to_root_id_[node.id()] = live_root->id(); } void AXLiveRegionTracker::OnNodeWillBeDeleted(const AXNode& node) { + if (AXNode* root = GetLiveRoot(node)) + QueueChangeEventForDeletedNode(*root); + live_region_node_to_root_id_.erase(node.id()); deleted_node_ids_.insert(node.id()); } +void AXLiveRegionTracker::QueueChangeEventForDeletedNode(const AXNode& root) { + live_region_roots_with_changes_.insert(root.id()); +} + void AXLiveRegionTracker::OnAtomicUpdateFinished() { deleted_node_ids_.clear(); + live_region_roots_with_changes_.clear(); } AXNode* AXLiveRegionTracker::GetLiveRoot(const AXNode& node) const {
diff --git a/ui/accessibility/ax_live_region_tracker.h b/ui/accessibility/ax_live_region_tracker.h index 8bda6e8..4cc64b2 100644 --- a/ui/accessibility/ax_live_region_tracker.h +++ b/ui/accessibility/ax_live_region_tracker.h
@@ -14,7 +14,9 @@ namespace ui { // Class that works with `AXEventGenerator` to track live regions in -// an `AXTree`. +// an `AXTree`, by maintaining a map from each node to the root of +// its live region. This map is used to trigger events on live region +// roots when a node in a live region changes. class AXLiveRegionTracker { public: static bool IsLiveRegionRoot(const AXNode& node); @@ -24,21 +26,30 @@ AXLiveRegionTracker(const AXLiveRegionTracker& other) = delete; AXLiveRegionTracker& operator=(const AXLiveRegionTracker& other) = delete; - void TrackNode(const AXNode& node); + // Walk upwards in the tree and determine the live root for this node, + // overriding any previously assigned live root. + void UpdateCachedLiveRootForNode(const AXNode& node); + void OnNodeWillBeDeleted(const AXNode& node); void OnAtomicUpdateFinished(); AXNode* GetLiveRoot(const AXNode& node) const; AXNode* GetLiveRootIfNotBusy(const AXNode& node) const; + const std::set<AXNodeID>& live_region_roots_with_changes() const { + return live_region_roots_with_changes_; + } + private: void WalkTreeAndAssignLiveRootsToNodes(const AXNode& node, const AXNode* current_root); + void QueueChangeEventForDeletedNode(const AXNode& root); const AXTree& tree_; // Map from live region node to its live region root ID. std::map<const AXNodeID, AXNodeID> live_region_node_to_root_id_; std::set<AXNodeID> deleted_node_ids_; + std::set<AXNodeID> live_region_roots_with_changes_; }; } // namespace ui
diff --git a/ui/gl/delegated_ink_point_renderer_gpu.h b/ui/gl/delegated_ink_point_renderer_gpu.h index 653ccdd..5fe3b24 100644 --- a/ui/gl/delegated_ink_point_renderer_gpu.h +++ b/ui/gl/delegated_ink_point_renderer_gpu.h
@@ -12,10 +12,10 @@ #include <memory> #include <utility> -#include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" #include "base/trace_event/trace_event.h" #include "mojo/public/cpp/bindings/receiver.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/delegated_ink_metadata.h" #include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" @@ -36,6 +36,17 @@ // of a trail. constexpr int kMaximumNumberOfPoints = 128; +struct DelegatedInkPointCompare { + bool operator()(const gfx::DelegatedInkPoint& lhs, + const gfx::DelegatedInkPoint& rhs) const { + return lhs.timestamp() < rhs.timestamp(); + } +}; + +using DelegatedInkPointTokenMap = base::flat_map<gfx::DelegatedInkPoint, + absl::optional<unsigned int>, + DelegatedInkPointCompare>; + } // namespace // TODO(1171374): Remove this class and remove templates when the types are @@ -87,16 +98,14 @@ return nullptr; } - base::circular_deque<gfx::DelegatedInkPoint> DelegatedInkPointsForTesting() - const { + DelegatedInkPointTokenMap DelegatedInkPointsForTesting() const { NOTREACHED(); - return base::circular_deque<gfx::DelegatedInkPoint>(); + return DelegatedInkPointTokenMap(); } - base::flat_map<base::TimeTicks, unsigned int> InkTrailTokensForTesting() - const { + uint64_t InkTrailTokenCountForTesting() const { NOTREACHED(); - return base::flat_map<base::TimeTicks, unsigned int>(); + return 0u; } bool WaitForNewTrailToDrawForTesting() const { @@ -222,25 +231,38 @@ DCHECK(delegated_ink_trail_); // If a trail has already been started and |metadata| is a point that was - // drawn as part of that trail (meaning it is found in |ink_trail_tokens_|), + // drawn as part of that trail (meaning |delegated_ink_points_| contains a + // key with the same timestamp as |metadata| and it has a valid token), // simply remove all the points up to the point that |metadata| describes. - // The only exception to this is if the color on |metadata| doesn't match - // |metadata_|'s color - then a new trail needs to be started to describe - // the new color. - auto metadata_token = ink_trail_tokens_.find(metadata->timestamp()); + // However, if the colors of |metadata_| and |metadata| don't match or the + // location of the DelegatedInkPoint in |delegated_ink_points_| doesn't + // match |metadata|, then we will need to start a new trail to ensure that + // the color matches or that we are able to draw a new trail in the correct + // location. + auto point_matching_metadata_it = delegated_ink_points_.find( + gfx::DelegatedInkPoint(metadata->point(), metadata->timestamp())); if (metadata_ && metadata->color() == metadata_->color() && - metadata_token != ink_trail_tokens_.end()) { - bool remove_trail_points_failed = TraceEventOnFailure( - delegated_ink_trail_->RemoveTrailPoints(metadata_token->second), - "DelegatedInkPointRendererGpu::SetDelegatedInkTrailStartPoint - " - "Failed to remove trail points."); - if (!remove_trail_points_failed && - UpdateVisualClip(metadata->presentation_area())) { - ink_trail_tokens_.erase(ink_trail_tokens_.begin(), - std::next(metadata_token)); - metadata_ = std::move(metadata); - RemoveSavedPointsOlderThanMetadata(); - return; + point_matching_metadata_it != delegated_ink_points_.end()) { + gfx::DelegatedInkPoint point_matching_metadata = + point_matching_metadata_it->first; + absl::optional<unsigned int> token = point_matching_metadata_it->second; + if (point_matching_metadata.MatchesDelegatedInkMetadata(metadata.get()) && + token) { + bool remove_trail_points_failed = TraceEventOnFailure( + delegated_ink_trail_->RemoveTrailPoints(token.value()), + "DelegatedInkPointRendererGpu::SetDelegatedInkTrailStartPoint - " + "Failed to remove trail points."); + if (!remove_trail_points_failed && + UpdateVisualClip(metadata->presentation_area())) { + // Remove all points up to and including the point that matches + // |metadata|. No need to hold on to the point that matches metadata + // because we've already added it to AddTrailPoints previously, and + // the next valid |metadata| is guaranteed to be after it. + delegated_ink_points_.erase(delegated_ink_points_.begin(), + std::next(point_matching_metadata_it)); + metadata_ = std::move(metadata); + return; + } } } @@ -261,7 +283,6 @@ } wait_for_new_trail_to_draw_ = false; - ink_trail_tokens_.clear(); metadata_ = std::move(metadata); DrawSavedTrailPoints(); } @@ -271,7 +292,8 @@ "delegated ink point", point.ToString()); DCHECK(delegated_ink_points_.empty() || - point.timestamp() > delegated_ink_points_.back().timestamp()); + point.timestamp() > + delegated_ink_points_.rbegin()->first.timestamp()); if (metadata_ && point.timestamp() < metadata_->timestamp()) return; @@ -282,8 +304,8 @@ // we will store, start erasing the oldest ones first. This matches what the // OS compositor does internally when it hits the max number of points. if (delegated_ink_points_.size() == kMaximumNumberOfPoints) - delegated_ink_points_.pop_front(); - delegated_ink_points_.push_back(point); + delegated_ink_points_.erase(delegated_ink_points_.begin()); + delegated_ink_points_.insert({point, absl::nullopt}); DrawDelegatedInkPoint(point); } @@ -299,14 +321,17 @@ return metadata_.get(); } - const base::circular_deque<gfx::DelegatedInkPoint>& - DelegatedInkPointsForTesting() const { - return delegated_ink_points_; + uint64_t InkTrailTokenCountForTesting() const { + uint64_t valid_tokens = 0u; + for (const auto& it : delegated_ink_points_) { + if (it.second) + valid_tokens++; + } + return valid_tokens; } - const base::flat_map<base::TimeTicks, unsigned int>& - InkTrailTokensForTesting() const { - return ink_trail_tokens_; + const DelegatedInkPointTokenMap& DelegatedInkPointsForTesting() const { + return delegated_ink_points_; } bool WaitForNewTrailToDrawForTesting() const { @@ -345,26 +370,50 @@ SUCCEEDED(dcomp_device_->Commit()); } - void RemoveSavedPointsOlderThanMetadata() { - DCHECK(metadata_); - while (!delegated_ink_points_.empty() && - delegated_ink_points_.front().timestamp() < metadata_->timestamp()) { - delegated_ink_points_.pop_front(); - } - } - void DrawSavedTrailPoints() { - RemoveSavedPointsOlderThanMetadata(); + DCHECK(metadata_); - for (const gfx::DelegatedInkPoint& point : delegated_ink_points_) - DrawDelegatedInkPoint(point); + // Remove all points that have a timestamp earlier than |metadata_|'s, since + // we know that we won't need to draw them. This is subtly different than + // the erasing done in SetDelegatedInkTrailStartPoint() - there the point + // matching the metadata is removed, here it is not. The reason for this + // difference is because there we know that it matches |metadata_| and + // therefore it cannot possibly be drawn again, so it is safe to remove. + // Here however, we are erasing all points up to, but not including, the + // first point with a timestamp equal to or greater than |metadata_|'s so + // that we can then check that point to confirm that it matches |metadata_| + // before deciding to draw an ink trail. The point could then be erased + // after it is successfully checked against |metadata_| and drawn, it just + // isn't for simplicity's sake. + delegated_ink_points_.erase( + delegated_ink_points_.begin(), + delegated_ink_points_.lower_bound(gfx::DelegatedInkPoint( + metadata_->point(), metadata_->timestamp()))); + + // Now, the very first point must match |metadata_|, and as long as it does + // we can continue to draw everything else. If at any point something can't + // or fails to draw though, don't attempt to draw anything after it so that + // the trail can match the user's actual stroke. + if (!delegated_ink_points_.empty() && + delegated_ink_points_.begin()->first.MatchesDelegatedInkMetadata( + metadata_.get())) { + for (auto it = delegated_ink_points_.begin(); + it != delegated_ink_points_.end(); ++it) { + if (!DrawDelegatedInkPoint(it->first)) + break; + } + } } - void DrawDelegatedInkPoint(const gfx::DelegatedInkPoint& point) { - if (wait_for_new_trail_to_draw_ || !metadata_ || - !metadata_->presentation_area().Contains(point.point())) { - return; - } + bool DrawDelegatedInkPoint(const gfx::DelegatedInkPoint& point) { + // Always wait for a new trail to be started before attempting to draw + // anything, even if |metadata_| exists. + if (wait_for_new_trail_to_draw_) + return false; + + DCHECK(metadata_); + if (!metadata_->presentation_area().Contains(point.point())) + return false; DCHECK(delegated_ink_trail_); @@ -388,13 +437,11 @@ "DelegatedInkPointRendererGpu::DrawDelegatedInkPoint - Failed to " "add trail point")) { // TODO(1052145): Start predicting points. - return; + return false; } - if (ink_trail_tokens_.size() == kMaximumNumberOfPoints) - ink_trail_tokens_.erase(ink_trail_tokens_.begin()); - - ink_trail_tokens_.insert({point.timestamp(), token}); + delegated_ink_points_[point] = token; + return true; } // The visual within the tree that will contain the delegated ink trail. It @@ -416,25 +463,20 @@ // delegated ink trail that will be drawn. std::unique_ptr<gfx::DelegatedInkMetadata> metadata_; - // All the points that have arrived in StoreDelegatedInkPoint(). These are - // stored in increasing timestamp order, and are not guaranteed to be - // currently drawn to the screen. They are not guaranteed to be currently on - // the screen because all points that arrive are stored, even if no metadata - // has arrived in SetDelegatedInkTrailStartPoint(), the DelegatedInkPoint - // is outside of |metadata_|'s presentation area, or we are waiting for a new - // SetDelegatedInkTrailStartPoint() call. The only exception is if a point - // arrives with a timestamp earlier than |metadata_|'s, then we just bail - // without even saving it. Each time a new trail is started, all points in - // |delegated_ink_points_| are iterated over and either removed from the list - // because their timestamp is earlier than |metadata_|'s, or we send them - // through StoreDelegatedInkPoint() again. - base::circular_deque<gfx::DelegatedInkPoint> delegated_ink_points_; - - // Tokens received when adding points to the trail. The tokens are then later - // used to remove points from the trail. The timestamps should always match - // all the points that are being drawn except the first point of the trail and - // no more. - base::flat_map<base::TimeTicks, unsigned int> ink_trail_tokens_; + // A base::flat_map of all the points that have arrived in + // StoreDelegatedInkPoint() with a timestamp greater than or equal to that of + // |metadata_|, where the key is the DelegatedInkPoint that was received, and + // the value is an optional token. The value will be null until the + // DelegatedInkPoint is added to the trail, at which point the value is the + // token that was returned by AddTrailPoints. The elements of the flat_map are + // sorted by the timestamp of the DelegatedInkPoint. All points are stored in + // here until we receive a |metadata_|, then any DelegatedInkPoints that have + // a timestamp earlier than |metadata_|'s are removed, and any new + // DelegatedInkPoints that may arrive with an earlier timestamp are ignored. + // Then as each new |metadata| arrives in SetDelegatedInkTrailStartPoint(), + // we remove any old elements with earlier timestamps, up to and including the + // element that matches the DelegatedInkMetadata. + DelegatedInkPointTokenMap delegated_ink_points_; // Flag to know if new DelegatedInkPoints that arrive should be drawn // immediately or if they should wait for a new trail to be started. Set to
diff --git a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc index a8a521f..cfa9f0a 100644 --- a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc +++ b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
@@ -31,13 +31,16 @@ return layer_tree()->GetInkRendererForTesting(); } - void SendDelegatedInkPointBasedOnPrevious() { - const base::circular_deque<gfx::DelegatedInkPoint>& ink_points = - ink_renderer()->DelegatedInkPointsForTesting(); - DCHECK(!ink_points.empty()); + void SendDelegatedInkPoint(const gfx::DelegatedInkPoint& point) { + stored_points_.push_back(point); + ink_renderer()->StoreDelegatedInkPoint(point); + } - auto last_point = ink_points.back(); - ink_renderer()->StoreDelegatedInkPoint(gfx::DelegatedInkPoint( + void SendDelegatedInkPointBasedOnPrevious() { + DCHECK(!stored_points_.empty()); + + auto last_point = stored_points_.back(); + SendDelegatedInkPoint(gfx::DelegatedInkPoint( last_point.point() + gfx::Vector2dF(5, 5), last_point.timestamp() + base::TimeDelta::FromMicroseconds(10), last_point.pointer_id())); @@ -49,11 +52,9 @@ } gfx::DelegatedInkMetadata SendMetadataBasedOnStoredPoint(uint64_t point) { - const base::circular_deque<gfx::DelegatedInkPoint>& ink_points = - ink_renderer()->DelegatedInkPointsForTesting(); - EXPECT_GE(ink_points.size(), point); + EXPECT_GE(stored_points_.size(), point); - auto ink_point = ink_points[point]; + auto ink_point = stored_points_[point]; gfx::DelegatedInkMetadata metadata( ink_point.point(), /*diameter=*/3, SK_ColorBLACK, ink_point.timestamp(), gfx::RectF(0, 0, 100, 100), /*hovering=*/false); @@ -143,6 +144,10 @@ HWND parent_window_; scoped_refptr<DirectCompositionSurfaceWin> surface_; scoped_refptr<GLContext> context_; + + // Used as a reference when making DelegatedInkMetadatas based on previously + // sent points. + std::vector<gfx::DelegatedInkPoint> stored_points_; }; // Test to confirm that points and tokens are stored and removed correctly based @@ -152,7 +157,7 @@ return; // Send some points and make sure they are all stored even with no metadata. - ink_renderer()->StoreDelegatedInkPoint( + SendDelegatedInkPoint( gfx::DelegatedInkPoint(gfx::PointF(10, 10), base::TimeTicks::Now(), 1)); const uint64_t kPointsToStore = 5u; for (uint64_t i = 1; i < kPointsToStore; ++i) @@ -160,7 +165,7 @@ EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), kPointsToStore); - EXPECT_TRUE(ink_renderer()->InkTrailTokensForTesting().empty()); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), 0u); EXPECT_FALSE(ink_renderer()->MetadataForTesting()); EXPECT_TRUE(ink_renderer()->WaitForNewTrailToDrawForTesting()); @@ -172,21 +177,19 @@ EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), kPointsToStore); - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), kPointsToStore); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), kPointsToStore); EXPECT_FALSE(ink_renderer()->WaitForNewTrailToDrawForTesting()); StoredMetadataMatchesSentMetadata(metadata); // Now send a metadata that matches a later one of the points. It should - // result in some of the stored points being erased, and one more token erased - // than points erased. This is because we don't need to store the token of the - // point that exactly matches the metadata. + // result in all of the points up to and including the point that matches + // the metadata being erased. Then, all remaining points should be drawn and + // should therefore have tokens associated with them. const uint64_t kPointToSend = 3u; metadata = SendMetadataBasedOnStoredPoint(kPointToSend); EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), - kPointsToStore - kPointToSend); - // Subtract one extra because the token for the point that matches the new - // metadata is erased too. - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), + kPointsToStore - kPointToSend - 1); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), kPointsToStore - kPointToSend - 1); StoredMetadataMatchesSentMetadata(metadata); @@ -194,14 +197,14 @@ // results in all the tokens and stored points being erased because a new // trail is started. gfx::DelegatedInkPoint last_point = - ink_renderer()->DelegatedInkPointsForTesting().back(); + ink_renderer()->DelegatedInkPointsForTesting().rbegin()->first; metadata = gfx::DelegatedInkMetadata( last_point.point() + gfx::Vector2dF(2, 2), /*diameter=*/3, SK_ColorBLACK, last_point.timestamp() + base::TimeDelta::FromMicroseconds(20), gfx::RectF(0, 0, 100, 100), /*hovering=*/false); SendMetadata(metadata); EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), 0u); - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), 0u); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), 0u); StoredMetadataMatchesSentMetadata(metadata); } @@ -221,13 +224,13 @@ const uint64_t kPointsToSend = 5u; for (uint64_t i = 1u; i <= kPointsToSend; ++i) { if (i == 1) { - ink_renderer()->StoreDelegatedInkPoint(gfx::DelegatedInkPoint( + SendDelegatedInkPoint(gfx::DelegatedInkPoint( metadata.point(), metadata.timestamp(), /*pointer_id=*/1)); } else { SendDelegatedInkPointBasedOnPrevious(); } EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), i); - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), i); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), i); } // Now send a point that is outside of the presentation area to ensure that @@ -235,18 +238,18 @@ // arrives with a presentation area that would contain this point, it can // still be drawn. gfx::DelegatedInkPoint last_point = - ink_renderer()->DelegatedInkPointsForTesting().back(); + ink_renderer()->DelegatedInkPointsForTesting().rbegin()->first; gfx::DelegatedInkPoint outside_point( gfx::PointF(5, 5), last_point.timestamp() + base::TimeDelta::FromMicroseconds(10), /*pointer_id=*/1); - EXPECT_FALSE(metadata.presentation_area().Contains((outside_point.point()))); - ink_renderer()->StoreDelegatedInkPoint(outside_point); + EXPECT_FALSE(metadata.presentation_area().Contains(outside_point.point())); + SendDelegatedInkPoint(outside_point); const uint64_t kTotalPointsSent = kPointsToSend + 1u; EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), kTotalPointsSent); - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), kPointsToSend); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), kPointsToSend); // Then send a metadata with a larger presentation area and timestamp earlier // than the above point to confirm it will be the only point drawn, but all @@ -254,8 +257,8 @@ const uint64_t kMetadataToSend = 3u; SendMetadataBasedOnStoredPoint(kMetadataToSend); EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting().size(), - kTotalPointsSent - kMetadataToSend); - EXPECT_EQ(ink_renderer()->InkTrailTokensForTesting().size(), 1u); + kTotalPointsSent - kMetadataToSend - 1); + EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), 1u); } } // namespace
diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc index f070ebd..f78893e4 100644 --- a/ui/gtk/gtk_compat.cc +++ b/ui/gtk/gtk_compat.cc
@@ -7,9 +7,11 @@ #include <dlfcn.h> #include "base/check.h" +#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/debug/leak_annotations.h" #include "base/no_destructor.h" +#include "base/strings/string_number_conversions.h" #include "ui/gfx/color_palette.h" #include "ui/gtk/gtk_stubs.h" @@ -20,6 +22,8 @@ namespace { +const char kGtkVersionFlag[] = "gtk-version"; + struct Gdk3Rgba { gdouble r; gdouble g; @@ -77,8 +81,8 @@ return libgtk3; } -void* GetLibGtk4() { - static void* libgtk4 = DlOpen("libgtk-4.so.1"); +void* GetLibGtk4(bool check = true) { + static void* libgtk4 = DlOpen("libgtk-4.so.1", check); return libgtk4; } @@ -88,26 +92,41 @@ return GetLibGtk3(); } -bool LoadGtkImpl(int gtk_version) { - // Prefer GTK3 for now as the GTK4 ecosystem is still immature. - if (GetLibGtk3(false)) { - ui_gtk::InitializeGdk_pixbuf(GetLibGdkPixbuf()); - ui_gtk::InitializeGdk(GetLibGdk3()); - ui_gtk::InitializeGtk(GetLibGtk3()); - } else { - // In GTK4 mode, we require some newer gio symbols that aren't available in - // Ubuntu Xenial or Debian Stretch. Fortunately, GTK4 itself depends on a - // newer version of glib (which provides gio), so if we're using GTK4, we - // can safely assume the system has the required gio symbols. - ui_gtk::InitializeGio(GetLibGio()); - // In GTK4, libgtk provides all gdk_*, gsk_*, and gtk_* symbols. - ui_gtk::InitializeGdk(GetLibGtk4()); - ui_gtk::InitializeGsk(GetLibGtk4()); - ui_gtk::InitializeGtk(GetLibGtk4()); - } +bool LoadGtk3() { + if (!GetLibGtk3(false)) + return false; + ui_gtk::InitializeGdk_pixbuf(GetLibGdkPixbuf()); + ui_gtk::InitializeGdk(GetLibGdk3()); + ui_gtk::InitializeGtk(GetLibGtk3()); return true; } +bool LoadGtk4() { + if (!GetLibGtk4(false)) + return false; + // In GTK4 mode, we require some newer gio symbols that aren't available + // in Ubuntu Xenial or Debian Stretch. Fortunately, GTK4 itself depends + // on a newer version of glib (which provides gio), so if we're using + // GTK4, we can safely assume the system has the required gio symbols. + ui_gtk::InitializeGio(GetLibGio()); + // In GTK4, libgtk provides all gdk_*, gsk_*, and gtk_* symbols. + ui_gtk::InitializeGdk(GetLibGtk4()); + ui_gtk::InitializeGsk(GetLibGtk4()); + ui_gtk::InitializeGtk(GetLibGtk4()); + return true; +} + +bool LoadGtkImpl() { + auto* cmd = base::CommandLine::ForCurrentProcess(); + unsigned int gtk_version; + if (!base::StringToUint(cmd->GetSwitchValueASCII(kGtkVersionFlag), + >k_version)) { + gtk_version = 0; + } + // Prefer GTK3 for now as the GTK4 ecosystem is still immature. + return gtk_version == 4 ? LoadGtk4() || LoadGtk3() : LoadGtk3() || LoadGtk4(); +} + gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) { return gfx::Insets(border.top, border.left, border.bottom, border.right); } @@ -115,7 +134,7 @@ } // namespace bool LoadGtk() { - static bool loaded = LoadGtkImpl(GTK_MAJOR_VERSION); + static bool loaded = LoadGtkImpl(); return loaded; }
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc index 0048e367..4f25572 100644 --- a/ui/message_center/views/notification_view_md_unittest.cc +++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -11,6 +11,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/event_processor.h" @@ -50,6 +51,22 @@ constexpr char kDefaultNotificationId[] = "notification id"; +SkBitmap CreateSolidColorBitmap(int width, int height, SkColor solid_color) { + SkBitmap bitmap; + bitmap.allocN32Pixels(width, height); + bitmap.eraseColor(solid_color); + return bitmap; +} + +#if BUILDFLAG(IS_CHROMEOS_ASH) +// Returns the same value as AshColorProvider::Get()-> +// GetContentLayerColor(ContentLayerType::kIconColorPrimary). +SkColor GetAshIconColorPrimary(bool is_dark_mode) { + return is_dark_mode ? SkColorSetRGB(0xE8, 0xEA, 0xED) + : SkColorSetRGB(0x5F, 0x63, 0x68); +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + class NotificationTestDelegate : public NotificationDelegate { public: NotificationTestDelegate() = default; @@ -266,10 +283,7 @@ const SkBitmap NotificationViewMDTest::CreateBitmap(int width, int height) const { - SkBitmap bitmap; - bitmap.allocN32Pixels(width, height); - bitmap.eraseColor(kBitmapColor); - return bitmap; + return CreateSolidColorBitmap(width, height, kBitmapColor); } std::vector<ButtonInfo> NotificationViewMDTest::CreateButtons(int number) { @@ -1470,6 +1484,10 @@ NotifierId notifier_id(web_app_url, /*title=*/u"web app title"); + SkBitmap small_bitmap = CreateSolidColorBitmap(16, 16, SK_ColorYELLOW); + // Makes the center area transparent. + small_bitmap.eraseArea(SkIRect::MakeXYWH(4, 4, 8, 8), SK_ColorTRANSPARENT); + RichNotificationData data; data.settings_button_handler = SettingsButtonHandler::INLINE; @@ -1477,7 +1495,7 @@ NOTIFICATION_TYPE_BASE_FORMAT, std::string(kDefaultNotificationId), u"title", u"message", CreateTestImage(80, 80), u"display source", GURL(), notifier_id, data, delegate_); - notification->set_small_image(CreateTestImage(16, 16)); + notification->set_small_image(gfx::Image::CreateFrom1xBitmap(small_bitmap)); notification->set_image(CreateTestImage(320, 240)); notification->set_origin_url(web_app_url); @@ -1486,6 +1504,23 @@ EXPECT_EQ(u"web app title", notification_view()->header_row_->app_name_for_testing()); + + const SkBitmap* app_icon_view = notification_view() + ->header_row_->app_icon_view_for_testing() + ->GetImage() + .bitmap(); + + EXPECT_EQ(color_utils::SkColorToRgbaString(SK_ColorTRANSPARENT), + color_utils::SkColorToRgbaString(app_icon_view->getColor(8, 8))); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + EXPECT_EQ(color_utils::SkColorToRgbaString( + GetAshIconColorPrimary(/*is_dark_mode=*/false)), + color_utils::SkColorToRgbaString(app_icon_view->getColor(0, 0))); +#else + EXPECT_EQ(color_utils::SkColorToRgbaString(SK_ColorYELLOW), + color_utils::SkColorToRgbaString(app_icon_view->getColor(0, 0))); +#endif } TEST_F(NotificationViewMDTest, ShowProgress) {
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc index a24b5b8..bf563aaf 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc +++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -51,7 +51,15 @@ bool IsRotationTransformSupported(gfx::OverlayTransform transform, uint32_t format_fourcc) { #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) - if ((format_fourcc == DRM_FORMAT_NV12 || format_fourcc == DRM_FORMAT_P010) && +#if BUILDFLAG(IS_CHROMEOS_LACROS) + const bool enable_more_rotations = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLacrosUseChromeosProtectedMedia); +#else + const bool enable_more_rotations = true; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + if (enable_more_rotations && + (format_fourcc == DRM_FORMAT_NV12 || format_fourcc == DRM_FORMAT_P010) && (transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 || transform == gfx::OVERLAY_TRANSFORM_ROTATE_270)) { return true;