diff --git a/.eslintrc.js b/.eslintrc.js index 78007a5d..d13be07 100644 --- a/.eslintrc.js +++ b/.eslintrc.js
@@ -24,6 +24,7 @@ 'new-parens': 'error', 'no-array-constructor': 'error', 'no-console': ['error', {allow: ['info', 'warn', 'error', 'assert']}], + 'no-debugger': 'error', 'no-extra-boolean-cast': 'error', 'no-extra-semi': 'error', 'no-new-wrappers': 'error',
diff --git a/DEPS b/DEPS index d444851..3af41afc 100644 --- a/DEPS +++ b/DEPS
@@ -308,11 +308,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '6365d276cb6ee8b2d6992bcc8699f3e1eff7fe3b', + 'src_internal_revision': '5fb766e4a38b8e77fc63d347b829a1903c23a919', # 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': 'b159229f2174800f6655f7b7dbba01d7bd3d5d48', + 'skia_revision': '50ac1117f1597d57faf9ae5360ad95029c515f97', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -320,7 +320,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': '49e434dba2f98a749fe36d44137cee2b8f039800', + 'angle_revision': '6557da03c85eee30448e1fefc2d89bdc348c580d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -403,7 +403,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '8e6c915f32a6c98fe6968eace7a2a9a66589a892', + 'devtools_frontend_revision': '4e11c8801f7a4e8e9f7b94f6acd4155cbe0a5e57', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -427,7 +427,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': '413dfc05c2ba4c5a5d8629b440b17ab9b3ed5c5d', + 'dawn_revision': 'b5d89266d090eb586b756294ea09e4beb0c06bcb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -827,7 +827,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '7fd047c41ca4c77672258cc2644b116844100171', + '8b6ec119f001eb5ad89d77c153fa132bd65801c0', 'condition': 'checkout_android and checkout_src_internal', }, @@ -982,7 +982,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'IMaWheUQ-GmELoiuWqPaUhQt_A4P2dHCf_Wzxa-ULxoC', + 'version': '2mvgH2wtdOI49Je4ZitkDbIq6HHd25YrHrJ-RqzrS0cC', }, ], 'condition': 'checkout_android', @@ -1198,7 +1198,7 @@ Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'b4ea518eb65f83a0f5c4e8f9625b099ec18c07d8', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '120296784c3ee38e176618378479e2d63ab4deaf', 'condition': 'checkout_src_internal', }, @@ -1811,7 +1811,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@35d6b77d10f523580acf18702b28efc2709bc1d2', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ea0fb515f594700d7fc4cbfff49268f596de4984', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -1848,10 +1848,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '11efd3b4ad23b66ed7aa88e84193833dbe5a7150', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3f94329188723ae92fc1bdefbcacd659fed2aa8b', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '181dbebba43f9023754d1f4766e7e4a2516c53a4', + Var('webrtc_git') + '/src.git' + '@' + 'd86c0cdbde7261deefc5771f41a14186bac9fd09', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1963,7 +1963,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/eche_app/app', - 'version': 'adlsj1Xru68irZ1xlmnbIEtZ4jaFfqbhmuDXMhGNpCQC', + 'version': '58FAaGZeYdOt_nscq4CI8EYcnleAGq_UoFn7C_FWgZUC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1985,7 +1985,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': '-E_2mIUEbbKyJWZzHVRIuanUBTuj_qtcDBs4y87tagkC', + 'version': 'W7KDA1fDp311XqHX9sUTPggIOaay2dmUlX3p3W8YNVIC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4125,7 +4125,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'f758ded9acac8b0e8eb6f1638b8fb945c15da69d', + 'ce28903ff84c8484e00400f18816c7dac205a29b', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 65d88bc..709bcf5 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2864,8 +2864,6 @@ "wm/splitview/split_view_controller.h", "wm/splitview/split_view_divider.cc", "wm/splitview/split_view_divider.h", - "wm/splitview/split_view_divider_handler_view.cc", - "wm/splitview/split_view_divider_handler_view.h", "wm/splitview/split_view_divider_view.cc", "wm/splitview/split_view_divider_view.h", "wm/splitview/split_view_drag_indicators.cc",
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc index 7625b5c..ce64251 100644 --- a/ash/accelerators/debug_commands.cc +++ b/ash/accelerators/debug_commands.cc
@@ -252,10 +252,8 @@ } void HandleShowInformedRestore() { - if (features::IsForestFeatureEnabled()) { - Shell::Get() - ->pine_controller() - ->MaybeStartPineOverviewSessionDevAccelerator(); + if (auto* pine_controller = Shell::Get()->pine_controller()) { + pine_controller->MaybeStartPineOverviewSessionDevAccelerator(); } }
diff --git a/ash/capture_mode/capture_mode_pixeltest.cc b/ash/capture_mode/capture_mode_pixeltest.cc index 001e458f..8746fa4 100644 --- a/ash/capture_mode/capture_mode_pixeltest.cc +++ b/ash/capture_mode/capture_mode_pixeltest.cc
@@ -132,7 +132,7 @@ EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( base::StrCat({"screen_capture_popup_notification_", GetDisplayTypeName(GetDisplayType())}), - /*revision_number=*/0, + /*revision_number=*/1, test_api()->GetPopupViewForId(kScreenCaptureNotificationId))); } @@ -164,7 +164,7 @@ EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( base::StrCat({"video_capture_notification_popup_", GetDisplayTypeName(GetDisplayType())}), - /*revision_number=*/3, notification_popup_view)); + /*revision_number=*/4, notification_popup_view)); test_api()->ToggleBubble(); auto* notification_view = @@ -172,7 +172,7 @@ EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( base::StrCat({"video_capture_notification_view_", GetDisplayTypeName(GetDisplayType())}), - /*revision_number=*/3, notification_view)); + /*revision_number=*/4, notification_view)); } } // namespace ash
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc index 07c1925..d0232b13 100644 --- a/ash/capture_mode/capture_mode_unittests.cc +++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -4450,11 +4450,11 @@ controller->PerformCapture(); waiter.Wait(); } - // Click on the notification body. This should take us to the files app. + // Click on the notification body. This should open the default handler. ClickOnNotification(std::nullopt); EXPECT_FALSE(GetPreviewNotification()); histogram_tester.ExpectBucketCount(kQuickActionHistogramName, - CaptureQuickAction::kFiles, 1); + CaptureQuickAction::kOpenDefault, 1); controller = StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kImage);
diff --git a/ash/components/arc/appfuse/OWNERS b/ash/components/arc/appfuse/OWNERS index e1627725..4228552 100644 --- a/ash/components/arc/appfuse/OWNERS +++ b/ash/components/arc/appfuse/OWNERS
@@ -1 +1,2 @@ -hashimoto@chromium.org +youkichihosoi@chromium.org +momohatt@chromium.org
diff --git a/ash/components/arc/disk_quota/OWNERS b/ash/components/arc/disk_quota/OWNERS index e1627725..631b9d62 100644 --- a/ash/components/arc/disk_quota/OWNERS +++ b/ash/components/arc/disk_quota/OWNERS
@@ -1 +1,2 @@ -hashimoto@chromium.org +momohatt@chromium.org +youkichihosoi@chromium.org
diff --git a/ash/components/arc/obb_mounter/OWNERS b/ash/components/arc/obb_mounter/OWNERS index e1627725..4228552 100644 --- a/ash/components/arc/obb_mounter/OWNERS +++ b/ash/components/arc/obb_mounter/OWNERS
@@ -1 +1,2 @@ -hashimoto@chromium.org +youkichihosoi@chromium.org +momohatt@chromium.org
diff --git a/ash/components/arc/volume_mounter/OWNERS b/ash/components/arc/volume_mounter/OWNERS index 09e9f02..cfe73aa31 100644 --- a/ash/components/arc/volume_mounter/OWNERS +++ b/ash/components/arc/volume_mounter/OWNERS
@@ -1,7 +1,5 @@ youkichihosoi@chromium.org - -# Backup reviewers: -hashimoto@chromium.org +momohatt@chromium.org per-file *_mojom_traits*.*=set noparent per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index a0d5d891..a859a5a 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1150,7 +1150,7 @@ // Enable the new notifications for downloaded files and screen captures. BASE_FEATURE(kFileNotificationRevamp, "kFileNotificationRevamp", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables experimental UI features in Files app. BASE_FEATURE(kFilesAppExperimental, @@ -3577,11 +3577,6 @@ return base::FeatureList::IsEnabled(kForceReSyncDrive); } -bool IsForestFeatureEnabled() { - return base::FeatureList::IsEnabled(kForestFeature) && - switches::IsForestSecretKeyMatched(); -} - bool IsFullscreenAfterUnlockAllowed() { return base::FeatureList::IsEnabled(kFullscreenAfterUnlockAllowed); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 66d18b4..fc2fe108 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -1046,7 +1046,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldForceEnableServerSideSpeechRecognitionForDev(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsForceReSyncDriveEnabled(); -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsForestFeatureEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheLauncherEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheLauncherListViewEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/picker/views/picker_image_item_view.cc b/ash/picker/views/picker_image_item_view.cc index 07d0fa15..f7cbfee2 100644 --- a/ash/picker/views/picker_image_item_view.cc +++ b/ash/picker/views/picker_image_item_view.cc
@@ -23,7 +23,8 @@ PickerImageItemView::PickerImageItemView( SelectItemCallback select_item_callback, std::unique_ptr<views::ImageView> image) - : PickerItemView(std::move(select_item_callback)) { + : PickerItemView(std::move(select_item_callback), + FocusIndicatorStyle::kFocusRingWithInsetGap) { SetUseDefaultFillLayout(true); SetCornerRadius(kPickerImageItemCornerRadius);
diff --git a/ash/picker/views/picker_item_view.cc b/ash/picker/views/picker_item_view.cc index 21b2709..7ae99e6 100644 --- a/ash/picker/views/picker_item_view.cc +++ b/ash/picker/views/picker_item_view.cc
@@ -19,9 +19,11 @@ #include "ui/color/color_provider.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_host.h" +#include "ui/gfx/geometry/skia_conversions.h" #include "ui/views/background.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/focus_ring.h" @@ -30,6 +32,13 @@ namespace ash { namespace { +// How much to clip the focused PickerItemView by. Inset by at least the default +// focus ring inset so the clipping is actually visible, then clip by the actual +// desired amount. It would be better to absolute value the halo inset here, but +// to keep this constexpr, also multiply by -1 to keep it positive. +constexpr float kPseudoFocusClipInset = + views::FocusRing::kDefaultHaloInset * -1.0f + 2.0f; + constexpr auto kPickerItemFocusIndicatorMargins = gfx::Insets::VH(6, 0); std::unique_ptr<views::Background> GetPickerItemBackground( @@ -58,6 +67,8 @@ base::TimeDelta()); switch (focus_indicator_style_) { + case FocusIndicatorStyle::kFocusRingWithInsetGap: + [[fallthrough]]; case FocusIndicatorStyle::kFocusRing: views::FocusRing::Get(this)->SetHasFocusPredicate( base::BindRepeating([](const View* view) { @@ -118,6 +129,10 @@ } } +void PickerItemView::OnBoundsChanged(const gfx::Rect& previous_bounds) { + UpdateClipPathForFocusRingWithInsetGap(); +} + void PickerItemView::SetCornerRadius(int corner_radius) { if (corner_radius_ == corner_radius) { return; @@ -141,6 +156,9 @@ item_state_ = item_state; SetBackground(GetPickerItemBackground(item_state_, corner_radius_)); switch (focus_indicator_style_) { + case FocusIndicatorStyle::kFocusRingWithInsetGap: + UpdateClipPathForFocusRingWithInsetGap(); + [[fallthrough]]; case FocusIndicatorStyle::kFocusRing: views::FocusRing::Get(this)->SchedulePaint(); break; @@ -150,6 +168,22 @@ } } +void PickerItemView::UpdateClipPathForFocusRingWithInsetGap() { + if (focus_indicator_style_ != FocusIndicatorStyle::kFocusRingWithInsetGap) { + return; + } + + SkPath clip_path; + if (item_state_ == ItemState::kPseudoFocused) { + gfx::RectF inset_bounds(GetLocalBounds()); + const SkScalar radius = + SkIntToScalar(corner_radius_ - kPseudoFocusClipInset); + inset_bounds.Inset(kPseudoFocusClipInset); + clip_path.addRoundRect(gfx::RectFToSkRect(inset_bounds), radius, radius); + } + SetClipPath(clip_path); +} + BEGIN_METADATA(PickerItemView) END_METADATA
diff --git a/ash/picker/views/picker_item_view.h b/ash/picker/views/picker_item_view.h index 7fa21fb..8d525dd 100644 --- a/ash/picker/views/picker_item_view.h +++ b/ash/picker/views/picker_item_view.h
@@ -36,6 +36,9 @@ enum class FocusIndicatorStyle { // Indicate focus using a rounded rectangular ring around the item. kFocusRing, + // Similar to `kFocusRing`, but clips the PickerItemView with a 1dp border + // as well as adding a rounded rectangular ring. + kFocusRingWithInsetGap, // Indicate focus using a vertical bar with half rounded corners at the left // edge of the item. kFocusBar, @@ -56,6 +59,7 @@ void PaintButtonContents(gfx::Canvas* canvas) override; void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void SelectItem(); @@ -65,6 +69,8 @@ void SetItemState(ItemState item_state); private: + void UpdateClipPathForFocusRingWithInsetGap(); + SelectItemCallback select_item_callback_; ItemState item_state_ = ItemState::kNormal;
diff --git a/ash/public/cpp/resources/ash_public_unscaled_resources.grd b/ash/public/cpp/resources/ash_public_unscaled_resources.grd index bd7c6e1..230b359d 100644 --- a/ash/public/cpp/resources/ash_public_unscaled_resources.grd +++ b/ash/public/cpp/resources/ash_public_unscaled_resources.grd
@@ -59,7 +59,7 @@ <structure type="lottie" name="IDR_PINE_NUDGE_IMAGE_LM" file="unscaled_resources/pine_nudge_lm.json" compress="gzip" /> <structure type="lottie" name="IDR_PINE_ONBOARDING_IMAGE" file="unscaled_resources/pine_onboarding.json" compress="gzip" /> <!-- Focus Mode --> - <structure type="lottie" name="IDR_FOCUS_MODE_EQUALIZER_LIGHT_ANIMATION" file="unscaled_resources/equalizer_light.json" compress="gzip" /> + <structure type="lottie" name="IDR_FOCUS_MODE_EQUALIZER_ANIMATION" file="unscaled_resources/equalizer.json" compress="gzip" /> <!-- Birch --> <structure type="lottie" name="IDR_BIRCH_RELEASE_NOTES_ICON" file="unscaled_resources/birch_release_notes_icon.json" compress="gzip" /> <!-- Mahi -->
diff --git a/ash/public/cpp/resources/unscaled_resources/equalizer.json b/ash/public/cpp/resources/unscaled_resources/equalizer.json new file mode 100644 index 0000000..b529c44 --- /dev/null +++ b/ash/public/cpp/resources/unscaled_resources/equalizer.json
@@ -0,0 +1 @@ +{"v":"5.9.3","fr":60,"ip":709,"op":771,"w":20,"h":20,"nm":"equalizer light","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Adjustment Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10.062,0],"ix":2,"l":2},"a":{"a":0,"k":[7,7,0],"ix":1,"l":2},"s":{"a":0,"k":[28,28,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":771,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"4","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.124,10.25,0],"ix":2,"l":2},"a":{"a":0,"k":[19.812,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":714,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":717,"s":[200,580,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":720,"s":[200,550,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":726,"s":[200,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":729,"s":[200,226,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0.111,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":735,"s":[200,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":743,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":749,"s":[200,160,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":762,"s":[200,100,100]},{"t":771,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0.004,-2.542],[0.011,-2.543],[1.504,-1.042],[1.5,1.41],[0,2.91],[-1.5,1.41],[-1.496,-1.042]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[19.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[13.376,10.25,0],"ix":2,"l":2},"a":{"a":0,"k":[13.938,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":711,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":714,"s":[200,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":717,"s":[200,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":723,"s":[200,240,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":728,"s":[200,112,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,7.209,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[200,230,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":743,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":746,"s":[200,232,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":752,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":758,"s":[200,96,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-24.869,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":761,"s":[200,192,100]},{"t":771,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-7],[0,-7],[1.5,-5.5],[1.5,5.5],[0,7],[-1.5,5.5],[-1.5,-5.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"2","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.188,10.25,0],"ix":2,"l":2},"a":{"a":0,"k":[7.844,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":711,"s":[200,200,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-18.66,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[200,190,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":743,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":746,"s":[200,300,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":755,"s":[200,80,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-1.664,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":761,"s":[200,118,100]},{"t":771,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-4],[0,-4],[1.5,-2.5],[1.5,2.5],[0,4],[-1.5,2.5],[-1.5,-2.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[7.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-10.812,10.25,0],"ix":2,"l":2},"a":{"a":0,"k":[1.844,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":709,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":712,"s":[200,160,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[200,66,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":743,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":752,"s":[200,80,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":756,"s":[200,200,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0.1,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":762,"s":[200,100,100]},{"t":771,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-6],[0,-6],[1.5,-4.5],[1.5,4.5],[0,6],[-1.5,4.5],[-1.5,-4.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/ash/public/cpp/resources/unscaled_resources/equalizer_light.json b/ash/public/cpp/resources/unscaled_resources/equalizer_light.json deleted file mode 100644 index cd28af2..0000000 --- a/ash/public/cpp/resources/unscaled_resources/equalizer_light.json +++ /dev/null
@@ -1 +0,0 @@ -{"v":"5.8.1","fr":60,"ip":709,"op":771,"w":21,"h":21,"nm":"equalizer light","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[19.562,12.125,0],"ix":2,"l":2},"a":{"a":0,"k":[19.812,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":714,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":717,"s":[100,290,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":720,"s":[100,275,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":726,"s":[100,40,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":729,"s":[100,113,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0.111,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":735,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":743,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":749,"s":[100,80,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":762,"s":[100,50,100]},{"t":771,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0.004,-2.542],[0.011,-2.543],[1.504,-1.042],[1.5,1.41],[0,2.91],[-1.5,1.41],[-1.496,-1.042]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803986549,0.917647123337,0.929411828518,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[19.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[13.688,12.125,0],"ix":2,"l":2},"a":{"a":0,"k":[13.938,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":711,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":714,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":717,"s":[100,40,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":723,"s":[100,120,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":728,"s":[100,56,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,7.209,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[100,115,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":743,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":746,"s":[100,116,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":752,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":758,"s":[100,48,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-24.869,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":761,"s":[100,96,100]},{"t":771,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-7],[0,-7],[1.5,-5.5],[1.5,5.5],[0,7],[-1.5,5.5],[-1.5,-5.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.917647063732,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[7.594,12.125,0],"ix":2,"l":2},"a":{"a":0,"k":[7.844,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":711,"s":[100,100,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-18.66,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[100,95,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":743,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":746,"s":[100,150,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":755,"s":[100,40,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,-1.664,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":761,"s":[100,59,100]},{"t":771,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-4],[0,-4],[1.5,-2.5],[1.5,2.5],[0,4],[-1.5,2.5],[-1.5,-2.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.917647063732,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[7.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.594,12.125,0],"ix":2,"l":2},"a":{"a":0,"k":[1.844,7.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":709,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":712,"s":[100,80,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":734,"s":[100,33,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":743,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":752,"s":[100,40,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":756,"s":[100,100,100]},{"i":{"x":[0.86,0.86,0.86],"y":[1,0.1,1]},"o":{"x":[0.66,0.66,0.66],"y":[0,0,0]},"t":762,"s":[100,50,100]},{"t":771,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.828,0],[0,0],[0,-0.828],[0,0],[0.828,0],[0,0.828],[0,0]],"o":[[0,0],[0.828,0],[0,0],[0,0.828],[-0.828,0],[0,0],[0,-0.828]],"v":[[0,-6],[0,-6],[1.5,-4.5],[1.5,4.5],[0,6],[-1.5,4.5],[-1.5,-4.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.917647063732,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"_CrOS_SecondaryColor","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1.75,7.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1769,"st":0,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index af0c4f34..bb09d1f 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -49,6 +49,7 @@ #include "ash/touch/touch_hud_debug.h" #include "ash/touch/touch_hud_projection.h" #include "ash/touch/touch_observer_hud.h" +#include "ash/utility/forest_util.h" #include "ash/wallpaper/views/wallpaper_widget_controller.h" #include "ash/wm/always_on_top_controller.h" #include "ash/wm/bounds_tracker/window_bounds_tracker.h" @@ -846,7 +847,7 @@ ui::MenuSourceType source_type) { // Show birch bar context menu for the primary user in clamshell mode Overview // without a partial split screen. - if (features::IsForestFeatureEnabled() && + if (IsForestFeatureEnabled() && Shell::Get()->session_controller()->IsUserPrimary() && OverviewController::Get()->InOverviewSession() && !split_view_overview_session_) { @@ -1214,7 +1215,7 @@ non_lock_screen_containers); aura::Window* shutdown_screenshot_container = non_lock_screen_containers; - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureFlagEnabled()) { shutdown_screenshot_container = CreateContainer( kShellWindowId_ShutdownScreenshotContainer, "ShutdownScreenshotContainer", non_lock_screen_containers);
diff --git a/ash/shelf/hotseat_widget.cc b/ash/shelf/hotseat_widget.cc index 571d783b..bf1d8a9 100644 --- a/ash/shelf/hotseat_widget.cc +++ b/ash/shelf/hotseat_widget.cc
@@ -499,6 +499,12 @@ // The type of highlight border. views::HighlightBorder::Type border_type_; + + // Tracks whether the forest flag was enabled when entering overview. + // TODO(sammiequon): This is temporary while the secret key exists. After the + // secret key is removed, entering/exiting overview should never need to + // remove/readd blur. + bool was_forest_on_overview_enter_ = false; }; HotseatWidget::DelegateView::~DelegateView() { @@ -716,7 +722,8 @@ void HotseatWidget::DelegateView::OnOverviewModeWillStart() { // Forest uses background blur in overview. - if (IsForestFeatureEnabled()) { + was_forest_on_overview_enter_ = IsForestFeatureEnabled(); + if (was_forest_on_overview_enter_) { return; } DCHECK_LE(blur_lock_, 2); @@ -728,7 +735,8 @@ void HotseatWidget::DelegateView::OnOverviewModeEndingAnimationComplete( bool canceled) { // Forest uses background blur in overview. - if (IsForestFeatureEnabled()) { + if (was_forest_on_overview_enter_) { + was_forest_on_overview_enter_ = false; return; } DCHECK_GT(blur_lock_, 0);
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index 7518c62e..2274146 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -34,6 +34,7 @@ #include "ash/style/ash_color_id.h" #include "ash/style/style_util.h" #include "ash/system/status_area_widget.h" +#include "ash/utility/forest_util.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/work_area_insets.h" #include "base/command_line.h" @@ -489,8 +490,7 @@ const bool in_app = ShelfConfig::Get()->is_in_app(); const bool in_overview_mode = ShelfConfig::Get()->in_overview_mode(); - const bool in_oak_session = - features::IsForestFeatureEnabled() && in_overview_mode; + const bool in_oak_session = IsForestFeatureEnabled() && in_overview_mode; const bool split_view = ShelfConfig::Get()->in_split_view_with_overview(); bool show_opaque_background = (!in_oak_session) && (!tablet_mode || in_app || split_view);
diff --git a/ash/shell.cc b/ash/shell.cc index 549c34b..8bede10 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -197,6 +197,7 @@ #include "ash/tray_action/tray_action.h" #include "ash/user_education/user_education_controller.h" #include "ash/user_education/user_education_delegate.h" +#include "ash/utility/forest_util.h" #include "ash/utility/occlusion_tracker_pauser.h" #include "ash/wallpaper/wallpaper_controller_impl.h" #include "ash/wm/ash_focus_rules.h" @@ -1592,7 +1593,7 @@ // used in its constructor. app_list_controller_ = std::make_unique<AppListControllerImpl>(); - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureFlagEnabled()) { birch_model_ = std::make_unique<BirchModel>(); } @@ -1769,7 +1770,7 @@ projector_controller_ = std::make_unique<ProjectorControllerImpl>(); float_controller_ = std::make_unique<FloatController>(); - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureFlagEnabled()) { pine_controller_ = std::make_unique<PineController>(); } pip_controller_ = std::make_unique<PipController>();
diff --git a/ash/system/focus_mode/sounds/playlist_image_button.cc b/ash/system/focus_mode/sounds/playlist_image_button.cc index 27a30d9..1742c83 100644 --- a/ash/system/focus_mode/sounds/playlist_image_button.cc +++ b/ash/system/focus_mode/sounds/playlist_image_button.cc
@@ -23,7 +23,7 @@ std::unique_ptr<lottie::Animation> GetEqualizerAnimation() { std::optional<std::vector<uint8_t>> lottie_data = ui::ResourceBundle::GetSharedInstance().GetLottieData( - IDR_FOCUS_MODE_EQUALIZER_LIGHT_ANIMATION); + IDR_FOCUS_MODE_EQUALIZER_ANIMATION); CHECK(lottie_data.has_value()); return std::make_unique<lottie::Animation>(
diff --git a/ash/utility/forest_util.cc b/ash/utility/forest_util.cc index ab4f8f4..d3fff78 100644 --- a/ash/utility/forest_util.cc +++ b/ash/utility/forest_util.cc
@@ -12,16 +12,23 @@ namespace ash { +bool IsForestFeatureFlagEnabled() { + return base::FeatureList::IsEnabled(features::kForestFeature); +} + bool IsForestFeatureEnabled() { - if (!base::FeatureList::IsEnabled(features::kForestFeature)) { + if (!IsForestFeatureFlagEnabled()) { return false; } - // TODO(http://b/333952534): Remove the google api DEPS changes. - if (gaia::IsGoogleInternalAccountEmail(Shell::Get() - ->session_controller() - ->GetActiveAccountId() - .GetUserEmail())) { + // The shell may not be created in some unit tests. + Shell* shell = Shell::HasInstance() ? Shell::Get() : nullptr; + + // TODO(http://b/333952534): Remove the google api DEPS changes, and move this + // function back to ash/constants/ash_features. + if (shell && + gaia::IsGoogleInternalAccountEmail( + shell->session_controller()->GetActiveAccountId().GetUserEmail())) { return true; }
diff --git a/ash/utility/forest_util.h b/ash/utility/forest_util.h index 80ca4176..0e63d34e 100644 --- a/ash/utility/forest_util.h +++ b/ash/utility/forest_util.h
@@ -9,6 +9,8 @@ namespace ash { +ASH_EXPORT bool IsForestFeatureFlagEnabled(); + // Checks for the forest feature. This needs a secret key, unless the active // user is a google account. ASH_EXPORT bool IsForestFeatureEnabled();
diff --git a/ash/wallpaper/views/wallpaper_widget_controller.cc b/ash/wallpaper/views/wallpaper_widget_controller.cc index dc06905..109906b 100644 --- a/ash/wallpaper/views/wallpaper_widget_controller.cc +++ b/ash/wallpaper/views/wallpaper_widget_controller.cc
@@ -4,11 +4,11 @@ #include "ash/wallpaper/views/wallpaper_widget_controller.h" -#include "ash/constants/ash_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/style/color_util.h" +#include "ash/utility/forest_util.h" #include "ash/wallpaper/views/wallpaper_view.h" #include "ui/aura/window.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" @@ -140,7 +140,7 @@ } void WallpaperWidgetController::CreateWallpaperUnderlayLayer() { - if (!features::IsForestFeatureEnabled()) { + if (!IsForestFeatureFlagEnabled()) { return; }
diff --git a/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts b/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts index 8b9d4d1..4787592 100644 --- a/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts +++ b/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts
@@ -3,7 +3,9 @@ // found in the LICENSE file. import {assert, assertExists, assertNotReached} from '../assert.js'; +import {Flag} from '../flag.js'; import {Point} from '../geometry.js'; +import * as loadTimeData from '../models/load_time_data.js'; import {DeviceOperator} from '../mojo/device_operator.js'; import * as state from '../state.js'; import {CropRegionRect, Resolution} from '../type.js'; @@ -373,6 +375,7 @@ const deviceOperator = assertExists(DeviceOperator.getInstance()); await deviceOperator.resetCropRegion(this.deviceId); this.ptzSettings = DIGITAL_ZOOM_DEFAULT_SETTINGS; + state.set(state.State.SUPER_RES_ZOOM, false); } async pan(value: number): Promise<void> { @@ -409,6 +412,12 @@ const cropRegion = calculateCropRegion(baseSettings, this.fullCropRegion); await deviceOperator.setCropRegion(this.deviceId, cropRegion); this.ptzSettings = baseSettings; + + state.set(state.State.SUPER_RES_ZOOM, this.isSuperResZoom()); + } + + private isSuperResZoom(): boolean { + return loadTimeData.getChromeFlag(Flag.SUPER_RES); } private isFullFrame({zoom}: PTZSettings): boolean {
diff --git a/ash/webui/camera_app_ui/resources/js/flag.ts b/ash/webui/camera_app_ui/resources/js/flag.ts index 04e6725..b3b09c3 100644 --- a/ash/webui/camera_app_ui/resources/js/flag.ts +++ b/ash/webui/camera_app_ui/resources/js/flag.ts
@@ -8,4 +8,5 @@ export enum Flag { AUTO_QR = 'auto_qr', DIGITAL_ZOOM = 'digital_zoom', + SUPER_RES = 'super_res', }
diff --git a/ash/webui/camera_app_ui/resources/js/js.gni b/ash/webui/camera_app_ui/resources/js/js.gni index bc6a903..aaacb62 100644 --- a/ash/webui/camera_app_ui/resources/js/js.gni +++ b/ash/webui/camera_app_ui/resources/js/js.gni
@@ -47,6 +47,7 @@ "lit/components/index.ts", "lit/components/mode-selector.ts", "lit/components/record-time-chip.ts", + "lit/components/super-res-loading-indicator.ts", "lit/components/svg-wrapper.ts", "lit/components/switch-device-button.ts", "lit/components/text-tooltip.ts",
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts b/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts index 62f51ac..903658b1 100644 --- a/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts +++ b/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts
@@ -2,18 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import './super-res-loading-indicator.js'; + import { classMap, css, html, LitElement, PropertyDeclarations, + styleMap, } from 'chrome://resources/mwc/lit/index.js'; import {CoverPhoto} from '../../cover_photo.js'; import {I18nString} from '../../i18n_string.js'; import {getI18nMessage} from '../../models/load_time_data.js'; +import {State} from '../../state.js'; +import {PerfEvent} from '../../type.js'; import {withTooltip} from '../directives/with_tooltip.js'; +import {StateObserverController} from '../state_observer_controller.js'; import {DEFAULT_STYLE} from '../styles.js'; export class GalleryButton extends LitElement { @@ -41,6 +47,12 @@ display: none; } + #loading-indicator { + height: var(--big-icon); + position: absolute; + width: var(--big-icon); + } + img { height: 100%; object-fit: cover; @@ -63,6 +75,12 @@ return this.shadowRoot?.querySelector('img')?.getAttribute('src') ?? ''; } + private readonly superResZoomState = + new StateObserverController(this, State.SUPER_RES_ZOOM); + + private readonly photoTakingState = + new StateObserverController(this, PerfEvent.PHOTO_TAKING); + override render(): RenderResult { const buttonClasses = { hidden: this.cover === null, @@ -71,6 +89,15 @@ draggable: this.cover?.draggable ?? false, }; return html` + <div> + <div id="loading-indicator" + style=${styleMap({ + visibility: this.superResZoomState.value ? 'visible' : 'hidden', + })}> + <super-res-loading-indicator .photoProcessing=${ + this.photoTakingState.value}> + </super-res-loading-indicator> + </div> <button aria-label=${getI18nMessage(I18nString.GALLERY_BUTTON)} ${withTooltip()} @@ -79,6 +106,7 @@ class=${classMap(imgClasses)} src=${this.cover?.url ?? ''}> </button> + </div> `; } }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts b/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts new file mode 100644 index 0000000..454dd270 --- /dev/null +++ b/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts
@@ -0,0 +1,94 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import { + css, + html, + LitElement, + PropertyDeclarations, +} from 'chrome://resources/mwc/lit/index.js'; + +import {DEFAULT_STYLE} from '../styles.js'; + +export class SuperResLoadingIndicator extends LitElement { + static override styles = [ + DEFAULT_STYLE, + css` + .spin-start circle { + animation: loading 0.5s ease-out forwards; + } + + @keyframes loading { + from { + stroke-dashoffset: 315; + } + to { + stroke-dashoffset: 95; + } + } + + .spin-complete circle { + animation: finish 2s ease-out forwards; + } + + @keyframes finish { + 0% { + stroke-dashoffset: 95; + } + 20% { + stroke-dashoffset: 0; + } + 25% { + stroke-opacity: 1; + } + 40% { + stroke-opacity: 0; + } + 55% { + stroke-opacity: 1; + } + 70% { + stroke-opacity: 0; + } + 85% { + stroke-opacity: 1; + } + 100% { + stroke-opacity: 0; + } + } + `, + ]; + + static override properties: PropertyDeclarations = { + photoProcessing: {type: Boolean}, + }; + + /** + * Whether the photo processing is ongoing. + */ + photoProcessing = false; + + override render(): RenderResult { + return html` + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" + class=${this.photoProcessing ? 'spin-start' : 'spin-complete'}> + <circle stroke-linecap="round" cx="50" cy="50" r="48" + stroke="var(--cros-sys-on_primary_container)" stroke-width="5" + fill="none" stroke-dasharray="315" + transform="rotate(-90,50,50)" /> + </svg> + `; + } +} + +window.customElements.define( + 'super-res-loading-indicator', SuperResLoadingIndicator); + +declare global { + interface HTMLElementTagNameMap { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + 'super-res-loading-indicator': SuperResLoadingIndicator; + } +}
diff --git a/ash/webui/camera_app_ui/resources/js/state.ts b/ash/webui/camera_app_ui/resources/js/state.ts index 842b6ba..5b088ae 100644 --- a/ash/webui/camera_app_ui/resources/js/state.ts +++ b/ash/webui/camera_app_ui/resources/js/state.ts
@@ -55,6 +55,7 @@ SHOULD_HANDLE_INTENT_RESULT = 'should-handle-intent-result', SNAPSHOTTING = 'snapshotting', STREAMING = 'streaming', + SUPER_RES_ZOOM = 'super-res-zoom', SUSPEND = 'suspend', TABLET = 'tablet', TABLET_LANDSCAPE = 'tablet-landscape',
diff --git a/ash/webui/camera_app_ui/resources/utils/cca/commands/dev.py b/ash/webui/camera_app_ui/resources/utils/cca/commands/dev.py index 15ce59a8..f6ab85e 100644 --- a/ash/webui/camera_app_ui/resources/utils/cca/commands/dev.py +++ b/ash/webui/camera_app_ui/resources/utils/cca/commands/dev.py
@@ -92,6 +92,7 @@ "timeLapse": True, "auto_qr": True, "digital_zoom": True, + "super_res": True, } load_time_data.update(self._load_grd_strings()) relative_path = _get_root_relative_path(request_path)
diff --git a/ash/wm/desks/desk_bar_view_base.cc b/ash/wm/desks/desk_bar_view_base.cc index f07fd837..d051db9d 100644 --- a/ash/wm/desks/desk_bar_view_base.cc +++ b/ash/wm/desks/desk_bar_view_base.cc
@@ -21,6 +21,7 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_id.h" #include "ash/style/typography.h" +#include "ash/utility/forest_util.h" #include "ash/wm/desks/desk.h" #include "ash/wm/desks/desk_action_button.h" #include "ash/wm/desks/desk_action_view.h" @@ -125,7 +126,7 @@ auto* layer = view->layer(); layer->SetFillsBoundsOpaquely(false); - if (features::IsForestFeatureEnabled() && !type_is_desk_button) { + if (IsForestFeatureEnabled() && !type_is_desk_button) { // Forests feature needs a transparent desks bar background. Still needs the // view layer to perform animations. return; @@ -623,9 +624,8 @@ height = kDeskBarZeroStateHeight; } else { height = DeskPreviewView::GetHeight(root) + - (features::IsForestFeatureEnabled() - ? kExpandedDeskBarHeightWithOak - : kDeskBarNonPreviewAllocatedHeight); + (IsForestFeatureEnabled() ? kExpandedDeskBarHeightWithOak + : kDeskBarNonPreviewAllocatedHeight); } break; }
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc index e85e60f..563b664 100644 --- a/ash/wm/lock_state_controller.cc +++ b/ash/wm/lock_state_controller.cc
@@ -12,7 +12,6 @@ #include "ash/app_list/app_list_controller_impl.h" #include "ash/cancel_mode.h" #include "ash/capture_mode/capture_mode_controller.h" -#include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" #include "ash/public/cpp/saved_desk_delegate.h" #include "ash/public/cpp/shell_window_ids.h" @@ -21,6 +20,7 @@ #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/shell_delegate.h" +#include "ash/utility/forest_util.h" #include "ash/utility/occlusion_tracker_pauser.h" #include "ash/wallpaper/views/wallpaper_view.h" #include "ash/wallpaper/views/wallpaper_widget_controller.h" @@ -459,7 +459,7 @@ void LockStateController::RequestRestart( power_manager::RequestRestartReason reason, const std::string& description) { - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { restart_reason_ = reason; restart_description_ = description; HideAndMaybeLockCursor(/*lock=*/false); @@ -813,7 +813,7 @@ } void LockStateController::ShutdownOnPine(bool with_pre_animation) { - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { TakePineImageAndShutdown(with_pre_animation); } else { StartShutdownProcess(with_pre_animation);
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index bd2b53aa..5477b124 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -32,6 +32,7 @@ #include "ash/style/rounded_label_widget.h" #include "ash/style/typography.h" #include "ash/system/toast/toast_manager_impl.h" +#include "ash/utility/forest_util.h" #include "ash/wallpaper/wallpaper_controller_impl.h" #include "ash/wm/desks/default_desk_button.h" #include "ash/wm/desks/desk_bar_view_base.h" @@ -537,7 +538,7 @@ // disabled by users. We don't need to worry about showing/hiding the bar // dynamically on primary/secondary user switch because we exit overview when // we switch users. - return features::IsForestFeatureEnabled() && + return IsForestFeatureEnabled() && Shell::Get()->session_controller()->IsUserPrimary() && BirchBarController::Get()->GetShowBirchSuggestions() && !SplitViewController::Get(root_window)->InSplitViewMode(); @@ -545,7 +546,7 @@ bool ShouldShowPineDialog(aura::Window* root_window) { return root_window == Shell::GetPrimaryRootWindow() && - features::IsForestFeatureEnabled() && + IsForestFeatureEnabled() && !!Shell::Get()->pine_controller()->pine_contents_data(); } @@ -682,7 +683,7 @@ MaybeInitBirchBarWidget(); - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { scoped_overview_wallpaper_clipper_ = std::make_unique<ScopedOverviewWallpaperClipper>(this); } @@ -792,7 +793,7 @@ // Create a feedback button that shows even when no items are present (e.g., // for Pine). - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { UpdateFeedbackButton(); } @@ -1659,7 +1660,7 @@ } gfx::Insets OverviewGrid::GetGridHorizontalPaddings() const { - if (!features::IsForestFeatureEnabled()) { + if (!IsForestFeatureEnabled()) { return gfx::Insets(); } @@ -1690,7 +1691,7 @@ } gfx::Insets OverviewGrid::GetGridVerticalPaddings() const { - const bool forest_enabled = features::IsForestFeatureEnabled(); + const bool forest_enabled = IsForestFeatureEnabled(); // Use compact paddings for partial overview. if (forest_enabled && @@ -2296,7 +2297,7 @@ scoped_overview_wallpaper_clipper_->RefreshWallpaperClipBounds(); } - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { UpdateFeedbackButton(); } } @@ -3006,7 +3007,7 @@ void OverviewGrid::MaybeCenterOverviewItems( std::vector<gfx::RectF>& out_window_rects, const base::flat_set<OverviewItemBase*>& ignored_items) { - if (!features::IsForestFeatureEnabled() || out_window_rects.empty()) { + if (!IsForestFeatureEnabled() || out_window_rects.empty()) { return; } @@ -3211,7 +3212,7 @@ } void OverviewGrid::RefreshDesksWidgets(bool visible) { - if (!features::IsForestFeatureEnabled()) { + if (!IsForestFeatureEnabled()) { return; } @@ -3384,7 +3385,7 @@ } void OverviewGrid::UpdateFeedbackButton() { - CHECK(features::IsForestFeatureEnabled()); + CHECK(IsForestFeatureEnabled()); if (SplitViewController::Get(root_window_)->InSplitViewMode()) { feedback_widget_.reset();
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 6ada017..6b572ae 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -8,7 +8,6 @@ #include "ash/accessibility/accessibility_controller.h" #include "ash/app_list/app_list_controller_impl.h" -#include "ash/constants/ash_features.h" #include "ash/frame_throttler/frame_throttling_controller.h" #include "ash/metrics/user_metrics_recorder.h" #include "ash/public/cpp/window_properties.h" @@ -17,6 +16,7 @@ #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/style/rounded_label_widget.h" +#include "ash/utility/forest_util.h" #include "ash/wm/desks/desk.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/legacy_desk_bar_view.h" @@ -204,7 +204,7 @@ } // Create this before the birch bar widget. - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { birch_bar_controller_ = std::make_unique<BirchBarController>( /*from_pine_service=*/enter_exit_overview_type_ == OverviewEnterExitType::kPine); @@ -1588,7 +1588,7 @@ // Entering or exiting splitview is unexpected behavior in a pine overview // session. - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { CHECK(!Shell::Get()->pine_controller()->pine_contents_data()); }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index 0b4f1ae..f193b6b 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -41,6 +41,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test/raster_scale_change_tracker.h" #include "ash/test/test_window_builder.h" +#include "ash/utility/forest_util.h" #include "ash/wallpaper/views/wallpaper_view.h" #include "ash/wallpaper/views/wallpaper_widget_controller.h" #include "ash/wm/desks/desk.h" @@ -5401,7 +5402,7 @@ // it is not true on any of the root windows. bool IsFloatContainerNormalStacked() const { for (aura::Window* root : Shell::GetAllRootWindows()) { - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { // The float container should be the top-most child of the // `ShutdownScreenshotContainer` when the feature `ForestFeature` is // enabled.
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index 8433f06..d2116f1 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -7,7 +7,6 @@ #include <utility> #include "ash/accessibility/accessibility_controller.h" -#include "ash/constants/ash_features.h" #include "ash/public/cpp/shelf_config.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" @@ -15,6 +14,7 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" +#include "ash/utility/forest_util.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/cleanup_animation_observer.h" #include "ash/wm/overview/delayed_animation_observer_impl.h" @@ -261,7 +261,7 @@ const bool show_home_launcher = hotseat_state == HotseatState::kShownHomeLauncher; - const bool forest_enabled = features::IsForestFeatureEnabled(); + const bool forest_enabled = IsForestFeatureEnabled(); // Use the default hotseat size here to avoid the possible re-layout // due to the update in HotseatWidget::is_forced_dense_.
diff --git a/ash/wm/overview/scoped_overview_wallpaper_clipper.cc b/ash/wm/overview/scoped_overview_wallpaper_clipper.cc index 77e5c63a..135821e 100644 --- a/ash/wm/overview/scoped_overview_wallpaper_clipper.cc +++ b/ash/wm/overview/scoped_overview_wallpaper_clipper.cc
@@ -39,6 +39,9 @@ ->wallpaper_widget_controller(); auto* wallpaper_underlay_layer = wallpaper_widget_controller->wallpaper_underlay_layer(); + // TODO(http://b/333952534): Remove this check once `wallpaper_underlay_layer` + // is always created. + CHECK(wallpaper_underlay_layer); wallpaper_underlay_layer->SetVisible(true); auto* wallpaper_view_layer =
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc index 291abce..7358ffc 100644 --- a/ash/wm/snap_group/snap_group_unittest.cc +++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -2310,35 +2310,6 @@ SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w3.get())); } -// TODO(b/326481241): Currently it's not possible to swap windows since -// `SplitViewController` still manages the windows and updates the bounds in a -// `SnapGroup`. This will just check that double tap still works after -// conversion. -TEST_F(SnapGroupTest, DoubleTapDivider) { - std::unique_ptr<aura::Window> w1(CreateAppWindow()); - std::unique_ptr<aura::Window> w2(CreateAppWindow()); - SnapTwoTestWindows(w1.get(), w2.get()); - auto* snap_group = SnapGroupController::Get()->GetTopmostSnapGroup(); - EXPECT_TRUE(snap_group); - auto* new_primary_window = snap_group->window1(); - auto* new_secondary_window = snap_group->window2(); - - // Switch to tablet mode. Test that double tap on the divider swaps the - // windows. - SwitchToTabletMode(); - EXPECT_EQ(new_primary_window, split_view_controller()->primary_window()); - EXPECT_EQ(new_secondary_window, split_view_controller()->secondary_window()); - EXPECT_TRUE(split_view_divider()->divider_widget()); - const gfx::Point divider_center = - split_view_divider() - ->GetDividerBoundsInScreen(/*is_dragging=*/false) - .CenterPoint(); - GetEventGenerator()->GestureTapAt(divider_center); - GetEventGenerator()->GestureTapAt(divider_center); - EXPECT_EQ(new_secondary_window, split_view_controller()->primary_window()); - EXPECT_EQ(new_primary_window, split_view_controller()->secondary_window()); -} - TEST_F(SnapGroupTest, DontAutoSnapNewWindowOutsideSplitViewOverview) { std::unique_ptr<aura::Window> w1(CreateAppWindow()); std::unique_ptr<aura::Window> w2(CreateAppWindow()); @@ -2480,6 +2451,44 @@ using SnapGroupDividerTest = SnapGroupTest; +// Tests that the divider starts with a thin default width +// (`kSplitviewDividerShortSideLength`) in landscape mode, expands to +// `kSplitviewDividerEnlargedShortSideLength` on mouse hover or drag, and +// returns to its default thin width on mouse exit. +TEST_F(SnapGroupDividerTest, HoverToEnlargeDivider) { + std::unique_ptr<aura::Window> w1(CreateAppWindow()); + std::unique_ptr<aura::Window> w2(CreateAppWindow()); + SnapTwoTestWindows(w1.get(), w2.get()); + + SplitViewDivider* divider = snap_group_divider(); + auto* divider_widget = divider->divider_widget(); + ASSERT_TRUE(divider_widget); + + const auto divider_bounds_before_hover = + divider_widget->GetWindowBoundsInScreen(); + EXPECT_EQ(kSplitviewDividerShortSideLength, + divider_bounds_before_hover.width()); + + auto* event_generator = GetEventGenerator(); + + // Shift the hover point so that it is not right on the divider handler view + // to trigger hover to enlarge. + const auto delta_vector = gfx::Vector2d(0, -10); + const gfx::Point hover_point = + divider_bounds_before_hover.CenterPoint() + delta_vector; + event_generator->MoveMouseTo(hover_point); + EXPECT_EQ(kSplitviewDividerEnlargedShortSideLength, + divider_widget->GetWindowBoundsInScreen().width()); + + event_generator->MoveMouseBy(10, 0); + EXPECT_EQ(kSplitviewDividerEnlargedShortSideLength, + divider_widget->GetWindowBoundsInScreen().width()); + + event_generator->MoveMouseTo(gfx::Point(0, 0)); + EXPECT_EQ(kSplitviewDividerShortSideLength, + divider_widget->GetWindowBoundsInScreen().width()); +} + // Tests that the split view divider will be stacked on top of both windows in // the snap group and that on a third window activated the split view divider // will be stacked below the newly activated window. @@ -2491,6 +2500,7 @@ SplitViewDivider* divider = snap_group_divider(); auto* divider_widget = divider->divider_widget(); + ASSERT_TRUE(divider_widget); aura::Window* divider_window = divider_widget->GetNativeWindow(); EXPECT_TRUE(window_util::IsStackedBelow(w2.get(), w1.get())); EXPECT_TRUE(window_util::IsStackedBelow(w1.get(), divider_window)); @@ -2829,6 +2839,35 @@ (cached_divider_center_point + move_vector).x(), /*abs_error=*/1); } +// TODO(b/326481241): Currently it's not possible to swap windows since +// `SplitViewController` still manages the windows and updates the bounds in a +// `SnapGroup`. This will just check that double tap still works after +// conversion. +TEST_F(SnapGroupTest, DoubleTapDividerInTablet) { + std::unique_ptr<aura::Window> w1(CreateAppWindow()); + std::unique_ptr<aura::Window> w2(CreateAppWindow()); + SnapTwoTestWindows(w1.get(), w2.get()); + auto* snap_group = SnapGroupController::Get()->GetTopmostSnapGroup(); + EXPECT_TRUE(snap_group); + auto* new_primary_window = snap_group->window1(); + auto* new_secondary_window = snap_group->window2(); + + // Switch to tablet mode. Test that double tap on the divider swaps the + // windows. + SwitchToTabletMode(); + EXPECT_EQ(new_primary_window, split_view_controller()->primary_window()); + EXPECT_EQ(new_secondary_window, split_view_controller()->secondary_window()); + EXPECT_TRUE(split_view_divider()->divider_widget()); + const gfx::Point divider_center = + split_view_divider() + ->GetDividerBoundsInScreen(/*is_dragging=*/false) + .CenterPoint(); + GetEventGenerator()->GestureTapAt(divider_center); + GetEventGenerator()->GestureTapAt(divider_center); + EXPECT_EQ(new_secondary_window, split_view_controller()->primary_window()); + EXPECT_EQ(new_primary_window, split_view_controller()->secondary_window()); +} + // Tests to verify that when a window is dragged out of a snap group and onto // another display, it snaps correctly with accurate bounds on the destination // display. See regression at http://b/331663949.
diff --git a/ash/wm/splitview/split_view_constants.h b/ash/wm/splitview/split_view_constants.h index d778e97..c0b4b02 100644 --- a/ash/wm/splitview/split_view_constants.h +++ b/ash/wm/splitview/split_view_constants.h
@@ -42,42 +42,12 @@ // The time duration for the window transformation animations. constexpr auto kSplitviewWindowTransformDuration = base::Milliseconds(250); -// The time duration for the `split_view_divider_` animations when dragging -// starts and ends. -constexpr auto kSplitviewDividerSelectionStatusChangeDuration = - base::Milliseconds(250); - -// The time duration for the `split_view_divider_` spawning animation. -constexpr auto kSplitviewDividerSpawnDuration = base::Milliseconds(100); - -// The delay before the `split_view_divider_` spawning animation. -constexpr auto kSplitviewDividerSpawnDelay = base::Milliseconds(183); - // The one-way bouncing animation duration for the `split_view_divider_` when // the to-be-snapped window can't fit in the work area. The actual duration when // used should be doubled to include the "bouncing out and bounding back in" // process. constexpr auto kBouncingAnimationOneWayDuration = base::Milliseconds(250); -// The thickness of the `split_view_divider_`'s handler. -constexpr int kDividerHandlerShortSideLength = 2; - -// The length of the `split_view_divider_`'s handler. -constexpr int kDividerHandlerLongSideLength = 16; - -// The corner radius of the `split_view_divider_`'s handler. -constexpr int kDividerHandlerCornerRadius = 1; - -// The radius of the circular handler when the `split_view_divider_` is being -// dragged. -constexpr int kDividerHandlerRadius = 2; - -// The length of the `split_view_divider_`'s handler when it spawns. -constexpr int kDividerHandlerSpawnLongSideLength = 2; - -// The distance from the `split_view_divider_` to where its handler spawns. -constexpr int kDividerHandlerSpawnUnsignedOffset = 2; - // The opacity of the highlight area. constexpr float kHighlightOpacity = 0.25f;
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index e835041..8045a76 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -1201,29 +1201,9 @@ aura::Window* window = window_state->window(); if (window_state->IsSnapped()) { - bool do_divider_spawn_animation = false; - // Only need to do divider spawn animation if split view is to be active, - // window is not minimized and has an non-identify transform in tablet mode. - // If window|is currently minimized then it will undergo the unminimizing - // animation instead, therefore skip the divider spawn animation if - // the window is minimized. - if (state_ == State::kNoSnap && InTabletMode() && - old_type != WindowStateType::kMinimized && - !window->transform().IsIdentity()) { - // For the divider spawn animation, at the end of the delay, the divider - // shall be visually aligned with an edge of |window|. This effect will - // be more easily achieved after |window| has been snapped and the - // corresponding transform animation has begun. So for now, just set a - // flag to indicate that the divider spawn animation should be done. - do_divider_spawn_animation = true; - } - OnWindowSnapped(window, old_type, window_state->snap_action_source().value_or( WindowSnapActionSource::kNotSpecified)); - if (do_divider_spawn_animation) { - DoSplitDividerSpawnAnimation(window); - } } else if (window_state->IsNormalStateType() || window_state->IsMaximized() || window_state->IsFullscreen() || window_state->IsFloated()) { // End split view, and also overview if overview is active, in these cases: @@ -2655,30 +2635,6 @@ } } -void SplitViewController::DoSplitDividerSpawnAnimation(aura::Window* window) { - DCHECK(window->layer()->GetAnimator()->GetTargetTransform().IsIdentity()); - SnapPosition snap_position = GetPositionOfSnappedWindow(window); - const gfx::Rect bounds = GetSnappedWindowBoundsInScreen( - snap_position, window, window_util::GetSnapRatioForWindow(window), - ShouldConsiderDivider()); - // Get one of the two corners of |window| that meet the divider. - gfx::Point p = IsPhysicalLeftOrTop(snap_position, window) - ? bounds.bottom_right() - : bounds.origin(); - // Apply the transform that |window| will undergo when the divider spawns. - static const double value = gfx::Tween::CalculateValue( - gfx::Tween::FAST_OUT_SLOW_IN, - kSplitviewDividerSpawnDelay / kSplitviewWindowTransformDuration); - p = gfx::TransformAboutPivot( - gfx::PointF(bounds.origin()), - gfx::Tween::TransformValueBetween(value, window->transform(), - gfx::Transform())) - .MapPoint(p); - // Use a coordinate of the transformed |window| corner for spawn_position. - split_view_divider_.DoSpawningAnimation(IsLayoutHorizontal(window) ? p.x() - : p.y()); -} - void SplitViewController::SwapWindowsAndUpdateBounds() { gfx::Rect primary_window_bounds = primary_window_ ? primary_window_->GetBoundsInScreen() : gfx::Rect();
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h index e09307b..3267021 100644 --- a/ash/wm/splitview/split_view_controller.h +++ b/ash/wm/splitview/split_view_controller.h
@@ -550,10 +550,6 @@ const gfx::Point& last_location_in_screen, WindowSnapActionSource snap_action_source); - // Do the split divider spawn animation. It will add a finishing touch to the - // |window| animation that generally accommodates snapping by dragging. - void DoSplitDividerSpawnAnimation(aura::Window* window); - // Called by `SwapWindows()` to swap the window(s) if exist that occupy the // `SnapPosition::kPrimary` and `SnapPosition::kSecondary`. The bounds of the // window(s) will also be updated.
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index 86ed4d6e..5b2f01f 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -4152,8 +4152,11 @@ std::unique_ptr<aura::Window> bottom_window(CreateWindow(bounds)); auto bottom_client = std::make_unique<TestTextInputClient>(bottom_window.get()); - split_view_controller()->SnapWindow(bottom_window.get(), - SnapPosition::kSecondary); + + SplitViewController* split_view_controller = + SplitViewController::Get(Shell::GetPrimaryRootWindow()); + split_view_controller->SnapWindow(bottom_window.get(), + SnapPosition::kSecondary); test_api.SetDisplayRotation(display::Display::ROTATE_270, display::Display::RotationSource::ACTIVE); @@ -4171,18 +4174,23 @@ const int screen_height = screen_bounds.height(); const int limit_y = screen_height * kMinDividerPositionRatio; + gfx::Rect ori_divider_bounds = split_view_controller->split_view_divider() + ->divider_widget() + ->GetWindowBoundsInScreen(); + // Resize divider to a position that when the bottom window is pushed up, its // position will exceeds `1-kMinDividerPositionRatio` of screen height. - split_view_divider()->StartResizeWithDivider(divider_bounds.CenterPoint()); + const auto drag_start_point = divider_bounds.CenterPoint(); + split_view_divider()->StartResizeWithDivider(drag_start_point); + const int drag_end_point_y = screen_height * 0.15f; split_view_divider()->ResizeWithDivider(gfx::Point(0, screen_height * 0.15f)); - const gfx::Rect orig_bottom_bounds = bottom_window->GetBoundsInScreen(); - EXPECT_LT(keyboard_bounds.y() - orig_bottom_bounds.height(), limit_y); + // Adjust the `ori_divider_bounds` with the dragging distance to be used for + // check later. + ori_divider_bounds.Offset(0, drag_end_point_y - drag_start_point.y()); - const gfx::Rect orig_divider_bounds = split_view_controller() - ->split_view_divider() - ->divider_widget() - ->GetWindowBoundsInScreen(); + const gfx::Rect ori_bottom_bounds = bottom_window->GetBoundsInScreen(); + EXPECT_LT(keyboard_bounds.y() - ori_bottom_bounds.height(), limit_y); // Set the caret position in bottom window below the upper bounds of the // virtual keyboard. When the virtual keyboard is enabled, the bottom window @@ -4192,32 +4200,31 @@ keyboard_bounds.y() - limit_y); const gfx::Rect shift_divider_bounds( shift_bottom_bounds.origin() + - gfx::Vector2d(0, -orig_divider_bounds.height()), - orig_divider_bounds.size()); + gfx::Vector2d(0, -ori_divider_bounds.height()), + ori_divider_bounds.size()); bottom_client->set_caret_bounds(gfx::Rect(keyboard_bounds.top_center(), gfx::Size(0, kCaretHeightForTest))); bottom_client->Focus(); EXPECT_TRUE(keyboard_controller()->IsKeyboardVisible()); EXPECT_EQ(shift_bottom_bounds, bottom_window->GetBoundsInScreen()); + // The split view divider will also be shifted and become unadjustable. - EXPECT_EQ(shift_divider_bounds, split_view_controller() - ->split_view_divider() + EXPECT_EQ(shift_divider_bounds, split_view_controller->split_view_divider() ->divider_widget() ->GetWindowBoundsInScreen()); - EXPECT_FALSE(split_view_controller()->split_view_divider()->IsAdjustable()); + EXPECT_FALSE(split_view_controller->split_view_divider()->IsAdjustable()); // Disable the keyboard. The bottom window will restore to original bounds. // The split view divider will also be adjustable and restore to original // bounds. bottom_client->UnFocus(); EXPECT_FALSE(keyboard_controller()->IsKeyboardVisible()); - EXPECT_EQ(orig_bottom_bounds, bottom_window->GetBoundsInScreen()); - EXPECT_EQ(orig_divider_bounds, split_view_controller() - ->split_view_divider() - ->divider_widget() - ->GetWindowBoundsInScreen()); - EXPECT_TRUE(split_view_controller()->split_view_divider()->IsAdjustable()); + EXPECT_EQ(ori_bottom_bounds, bottom_window->GetBoundsInScreen()); + EXPECT_EQ(ori_divider_bounds, split_view_controller->split_view_divider() + ->divider_widget() + ->GetWindowBoundsInScreen()); + EXPECT_TRUE(split_view_controller->split_view_divider()->IsAdjustable()); } // Tests that when the bottom window is pushed up due to the virtual keyboard
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc index db99b742..13353f55 100644 --- a/ash/wm/splitview/split_view_divider.cc +++ b/ash/wm/splitview/split_view_divider.cc
@@ -11,7 +11,6 @@ #include "ash/public/cpp/window_properties.h" #include "ash/screen_util.h" #include "ash/wm/desks/desks_util.h" -#include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_divider_view.h" @@ -86,19 +85,19 @@ } // Returns the widget init params needed to create the widget. -views::Widget::InitParams CreateWidgetInitParams( - aura::Window* parent_window, - const std::string& widget_name) { +views::Widget::InitParams CreateWidgetInitParams(aura::Window* parent_window, + const gfx::Rect& bounds) { views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; params.activatable = views::Widget::InitParams::Activatable::kNo; params.parent = parent_window; + params.bounds = bounds; params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true); // Exclude the divider from getting transformed with its transient parent // window when we are resizing. The divider will set its own transforms. params.init_properties_container.SetProperty( kExcludeFromTransientTreeTransformKey, true); - params.name = widget_name; + params.name = "SplitViewDividerWidget"; return params; } @@ -115,31 +114,25 @@ bool landscape, int divider_position, bool is_dragging) { - const int dragging_diff = (kSplitviewDividerEnlargedShortSideLength - - kSplitviewDividerShortSideLength) / - 2; + const int dragging_diff = is_dragging + ? (kSplitviewDividerEnlargedShortSideLength - + kSplitviewDividerShortSideLength) / + 2 + : 0; if (landscape) { - return is_dragging - ? gfx::Rect(work_area_bounds_in_screen.x() + divider_position - - dragging_diff, - work_area_bounds_in_screen.y(), - kSplitviewDividerEnlargedShortSideLength, - work_area_bounds_in_screen.height()) - : gfx::Rect(work_area_bounds_in_screen.x() + divider_position, - work_area_bounds_in_screen.y(), - kSplitviewDividerShortSideLength, - work_area_bounds_in_screen.height()); + return gfx::Rect( + work_area_bounds_in_screen.x() + divider_position - dragging_diff, + work_area_bounds_in_screen.y(), + is_dragging ? kSplitviewDividerEnlargedShortSideLength + : kSplitviewDividerShortSideLength, + work_area_bounds_in_screen.height()); } else { - return is_dragging - ? gfx::Rect(work_area_bounds_in_screen.x(), - work_area_bounds_in_screen.y() + divider_position - - dragging_diff, - work_area_bounds_in_screen.width(), - kSplitviewDividerEnlargedShortSideLength) - : gfx::Rect(work_area_bounds_in_screen.x(), - work_area_bounds_in_screen.y() + divider_position, - work_area_bounds_in_screen.width(), - kSplitviewDividerShortSideLength); + return gfx::Rect( + work_area_bounds_in_screen.x(), + work_area_bounds_in_screen.y() + divider_position - dragging_diff, + work_area_bounds_in_screen.width(), + is_dragging ? kSplitviewDividerEnlargedShortSideLength + : kSplitviewDividerShortSideLength); } } @@ -216,7 +209,7 @@ } is_resizing_with_divider_ = true; - UpdateDividerBounds(); + EnlargeOrShrinkDivider(/*should_enlarge=*/true); previous_event_location_ = location_in_screen; controller_->StartResizeWithDivider(location_in_screen); @@ -253,6 +246,7 @@ // `LayoutDividerController` will update the window and divider bounds in // `UpdateResizeWithDivider()`. UpdateDividerPosition(modified_location_in_screen); + EnlargeOrShrinkDivider(/*should_enlarge=*/true); controller_->UpdateResizeWithDivider(modified_location_in_screen); previous_event_location_ = modified_location_in_screen; @@ -267,13 +261,16 @@ is_resizing_with_divider_ = false; gfx::Point modified_location_in_screen = GetBoundedPosition( - location_in_screen, - GetWorkAreaBoundsInScreen(divider_widget_->GetNativeWindow())); + location_in_screen, GetWorkAreaBoundsInScreen(GetRootWindow())); // Order here matters: we first update `divider_position_`, then the // `LayoutDividerController` will transform and update the windows bounds in // `EndResizeWithDivider()`. UpdateDividerPosition(modified_location_in_screen); + const gfx::Point cursor_point = + display::Screen::GetScreen()->GetCursorScreenPoint(); + EnlargeOrShrinkDivider( + GetDividerBoundsInScreen(/*is_dragging=*/true).Contains(cursor_point)); // If the delegate is done with resizing, finish resizing and clean up. // Otherwise it will be called later, in @@ -292,10 +289,6 @@ controller_->OnResizeEnded(); } -void SplitViewDivider::DoSpawningAnimation(int spawning_position) { - divider_view_->DoSpawningAnimation(spawning_position); -} - void SplitViewDivider::UpdateDividerBounds() { if (divider_widget_) { divider_widget_->SetBounds(GetDividerBoundsInScreen(/*is_dragging=*/false)); @@ -311,6 +304,15 @@ divider_position_, is_dragging); } +void SplitViewDivider::EnlargeOrShrinkDivider(bool should_enlarge) { + if (!divider_widget_ || !divider_widget_->GetNativeWindow()->IsVisible()) { + return; + } + + divider_widget_->SetBounds(GetDividerBoundsInScreen(should_enlarge)); + divider_view_->RefreshDividerHandler(should_enlarge); +} + void SplitViewDivider::SetAdjustable(bool adjustable) { if (adjustable == IsAdjustable()) { return; @@ -319,7 +321,7 @@ divider_widget_->GetNativeWindow()->SetEventTargetingPolicy( adjustable ? aura::EventTargetingPolicy::kTargetAndDescendants : aura::EventTargetingPolicy::kNone); - divider_view_->SetDividerBarVisible(adjustable); + divider_view_->SetHandlerBarVisible(adjustable); } bool SplitViewDivider::IsAdjustable() const { @@ -543,8 +545,13 @@ CHECK(top_window); parent_container = top_window->parent(); CHECK(parent_container); + + const gfx::Rect initial_divider_bounds = GetDividerBoundsInScreen( + GetWorkAreaBoundsInScreen(observed_windows_[0].get()), + IsLayoutHorizontal(observed_windows_[0].get()), divider_position, + /*is_dragging=*/false); divider_widget_->Init( - CreateWidgetInitParams(parent_container, "SplitViewDivider")); + CreateWidgetInitParams(parent_container, initial_divider_bounds)); divider_widget_->SetVisibilityAnimationTransition( views::Widget::ANIMATE_NONE); divider_view_ = divider_widget_->SetContentsView(
diff --git a/ash/wm/splitview/split_view_divider.h b/ash/wm/splitview/split_view_divider.h index 5dd43d19..49fbc933 100644 --- a/ash/wm/splitview/split_view_divider.h +++ b/ash/wm/splitview/split_view_divider.h
@@ -49,7 +49,7 @@ SplitViewDivider& operator=(const SplitViewDivider&) = delete; ~SplitViewDivider() override; - // static version of GetDividerBoundsInScreen(bool is_dragging) function. + // static static gfx::Rect GetDividerBoundsInScreen( const gfx::Rect& work_area_bounds_in_screen, bool landscape, @@ -61,6 +61,7 @@ int divider_position() const { return divider_position_; } bool is_resizing_with_divider() const { return is_resizing_with_divider_; } + // Does not consider any order of `observed_windows_`. Clients of the divider // are responsible for maintaining the order themselves. const aura::Window::Windows& observed_windows() const { @@ -97,10 +98,6 @@ // external events (split view ending, tablet mode ending, etc.). void CleanUpWindowResizing(); - // Do the divider spawning animation that adds a finishing touch to the - // snapping animation of a window. - void DoSpawningAnimation(int spawn_position); - // Updates `divider_widget_`'s bounds. void UpdateDividerBounds(); @@ -108,6 +105,10 @@ // position. gfx::Rect GetDividerBoundsInScreen(bool is_dragging); + // Provides visual feedback by adjusting `divider_widget_` bounds in response + // to user hover or drag interactions (enlarged on interaction, thin default). + void EnlargeOrShrinkDivider(bool should_enlarge); + // Sets the adjustability of the divider bar. Unadjustable divider does not // receive event and the divider bar view is not visible. When the divider is // moved for the virtual keyboard, the divider will be set unadjustable. @@ -191,7 +192,7 @@ // |<--- divider_position_ --->| // --------------------------------------------------------------- // | | | | - // | primary_window_ | | secondary_window_ | + // | primary window | | secondary window | // | | | | // --------------------------------------------------------------- // Initialized as -1 before `divider_widget_` is created and shown.
diff --git a/ash/wm/splitview/split_view_divider_handler_view.cc b/ash/wm/splitview/split_view_divider_handler_view.cc deleted file mode 100644 index 6e09e56..0000000 --- a/ash/wm/splitview/split_view_divider_handler_view.cc +++ /dev/null
@@ -1,168 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/splitview/split_view_divider_handler_view.h" - -#include "ash/display/screen_orientation_controller.h" -#include "ash/wm/splitview/split_view_constants.h" -#include "ash/wm/splitview/split_view_divider.h" -#include "ash/wm/splitview/split_view_utils.h" -#include "base/memory/raw_ptr.h" -#include "base/timer/timer.h" -#include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/chromeos/styles/cros_tokens_color_mappings.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/views/background.h" - -namespace ash { - -class SplitViewDividerHandlerView::SelectionAnimation - : public gfx::SlideAnimation, - public gfx::AnimationDelegate { - public: - explicit SelectionAnimation(SplitViewDividerHandlerView* white_handler_view) - : gfx::SlideAnimation(this), white_handler_view_(white_handler_view) { - SetSlideDuration(kSplitviewDividerSelectionStatusChangeDuration); - SetTweenType(gfx::Tween::EASE_IN); - } - - SelectionAnimation(const SelectionAnimation&) = delete; - SelectionAnimation& operator=(const SelectionAnimation&) = delete; - - ~SelectionAnimation() override = default; - - void UpdateWhiteHandlerBounds() { - white_handler_view_->SetBounds( - CurrentValueBetween(kDividerHandlerShortSideLength, - kDividerHandlerRadius * 2), - CurrentValueBetween(kDividerHandlerLongSideLength, - kDividerHandlerRadius * 2), - /*signed_offset=*/0); - } - - private: - // gfx::AnimationDelegate: - void AnimationProgressed(const gfx::Animation* animation) override { - UpdateWhiteHandlerBounds(); - white_handler_view_->UpdateCornerRadius(CurrentValueBetween( - kDividerHandlerCornerRadius, kDividerHandlerRadius)); - } - - raw_ptr<SplitViewDividerHandlerView> white_handler_view_; -}; - -class SplitViewDividerHandlerView::SpawningAnimation - : public gfx::SlideAnimation, - public gfx::AnimationDelegate { - public: - SpawningAnimation(SplitViewDividerHandlerView* white_handler_view, - int divider_signed_offset) - : gfx::SlideAnimation(this), - white_handler_view_(white_handler_view), - spawn_signed_offset_(divider_signed_offset + - (divider_signed_offset > 0 - ? kDividerHandlerSpawnUnsignedOffset - : -kDividerHandlerSpawnUnsignedOffset)) { - SetSlideDuration(kSplitviewDividerSpawnDuration); - SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); - } - - SpawningAnimation(const SpawningAnimation&) = delete; - SpawningAnimation& operator=(const SpawningAnimation&) = delete; - - ~SpawningAnimation() override = default; - - void Activate() { - white_handler_view_->SetVisible(false); - delay_timer_.Start(FROM_HERE, kSplitviewDividerSpawnDelay, this, - &SpawningAnimation::StartAnimation); - } - - bool IsActive() const { return delay_timer_.IsRunning() || is_animating(); } - - void UpdateWhiteHandlerBounds() { - DCHECK(IsActive()); - white_handler_view_->SetBounds( - kDividerHandlerShortSideLength, - CurrentValueBetween(kDividerHandlerSpawnLongSideLength, - kDividerHandlerLongSideLength), - CurrentValueBetween(spawn_signed_offset_, 0)); - } - - private: - void StartAnimation() { - DCHECK(!white_handler_view_->GetVisible()); - white_handler_view_->SetVisible(true); - DCHECK(!is_animating()); - Show(); - DCHECK_EQ(0.0, GetCurrentValue()); - UpdateWhiteHandlerBounds(); - } - - // gfx::AnimationDelegate: - void AnimationProgressed(const gfx::Animation* animation) override { - UpdateWhiteHandlerBounds(); - } - - raw_ptr<SplitViewDividerHandlerView> white_handler_view_; - int spawn_signed_offset_; - base::OneShotTimer delay_timer_; -}; - -SplitViewDividerHandlerView::SplitViewDividerHandlerView() - : selection_animation_(std::make_unique<SelectionAnimation>(this)) { - SetPaintToLayer(); - SetBackground(views::CreateThemedRoundedRectBackground( - cros_tokens::kCrosSysOnSecondary, kDividerHandlerCornerRadius)); -} - -SplitViewDividerHandlerView::~SplitViewDividerHandlerView() = default; - -void SplitViewDividerHandlerView::DoSpawningAnimation( - int divider_signed_offset) { - spawning_animation_ = - std::make_unique<SpawningAnimation>(this, divider_signed_offset); - spawning_animation_->Activate(); -} - -void SplitViewDividerHandlerView::Refresh(bool is_resizing) { - spawning_animation_.reset(); - SetVisible(true); - selection_animation_->UpdateWhiteHandlerBounds(); - if (is_resizing) - selection_animation_->Show(); - else - selection_animation_->Hide(); -} - -void SplitViewDividerHandlerView::UpdateCornerRadius(float radius) { - layer()->SetRoundedCornerRadius(gfx::RoundedCornersF{radius}); -} - -void SplitViewDividerHandlerView::SetBounds(int short_length, - int long_length, - int signed_offset) { - const bool landscape = parent()->width() == kSplitviewDividerShortSideLength; - gfx::Rect bounds = landscape ? gfx::Rect(short_length, long_length) - : gfx::Rect(long_length, short_length); - bounds.Offset(parent()->GetLocalBounds().CenterPoint() - - bounds.CenterPoint() + - (landscape ? gfx::Vector2d(signed_offset, 0) - : gfx::Vector2d(0, signed_offset))); - SetBoundsRect(bounds); -} - -void SplitViewDividerHandlerView::OnPaint(gfx::Canvas* canvas) { - views::View::OnPaint(canvas); - // It's needed to avoid artifacts when tapping on the divider quickly. - canvas->DrawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc); - views::View::OnPaint(canvas); -} - -BEGIN_METADATA(SplitViewDividerHandlerView) -END_METADATA - -} // namespace ash
diff --git a/ash/wm/splitview/split_view_divider_handler_view.h b/ash/wm/splitview/split_view_divider_handler_view.h deleted file mode 100644 index 953245c3..0000000 --- a/ash/wm/splitview/split_view_divider_handler_view.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_SPLITVIEW_SPLIT_VIEW_DIVIDER_HANDLER_VIEW_H_ -#define ASH_WM_SPLITVIEW_SPLIT_VIEW_DIVIDER_HANDLER_VIEW_H_ - -#include <memory> - -#include "ui/base/metadata/metadata_header_macros.h" -#include "ui/gfx/canvas.h" -#include "ui/views/view.h" - -namespace ash { - -// The white handler bar in the middle of the divider. -class SplitViewDividerHandlerView : public views::View { - METADATA_HEADER(SplitViewDividerHandlerView, views::View) - - public: - SplitViewDividerHandlerView(); - - SplitViewDividerHandlerView(const SplitViewDividerHandlerView&) = delete; - SplitViewDividerHandlerView& operator=(const SplitViewDividerHandlerView&) = - delete; - - ~SplitViewDividerHandlerView() override; - - // Play the white handler's part in the divider spawn animation. - // |divider_signed_offset| represents the motion of the center of the divider - // during the spawning animation. This parameter is used to make the white - // handler move with the center of the divider, as the two views are siblings - // because if the white handler view were a child of the divider view, then - // the transform that enlarges the divider during dragging would distort the - // white handler. - void DoSpawningAnimation(int divider_signed_offset); - - // If the spawning animation is running, stop it and show the white handler. - // Update bounds. Do the enlarge/shrink animation when starting/ending - // dragging. - void Refresh(bool is_resizing); - - // Updates the corner radius of the handler bar to |radius|. Happens during - // the animation of starting and ending dragging. - void UpdateCornerRadius(float radius); - - private: - class SelectionAnimation; - class SpawningAnimation; - - void SetBounds(int short_length, int long_length, int signed_offset); - - // views::View: - void OnPaint(gfx::Canvas* canvas) override; - - // Handles the animations for starting and ending dragging. - std::unique_ptr<SelectionAnimation> selection_animation_; - - // Handles the spawning animation. - std::unique_ptr<SpawningAnimation> spawning_animation_; -}; - -} // namespace ash - -#endif // ASH_WM_SPLITVIEW_SPLIT_VIEW_DIVIDER_HANDLER_VIEW_H_
diff --git a/ash/wm/splitview/split_view_divider_view.cc b/ash/wm/splitview/split_view_divider_view.cc index 3e73a89..b6ed747 100644 --- a/ash/wm/splitview/split_view_divider_view.cc +++ b/ash/wm/splitview/split_view_divider_view.cc
@@ -4,17 +4,14 @@ #include "ash/wm/splitview/split_view_divider_view.h" -#include "ash/display/screen_orientation_controller.h" #include "ash/public/cpp/window_properties.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/icon_button.h" -#include "ash/wm/snap_group/snap_group.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_divider.h" -#include "ash/wm/splitview/split_view_divider_handler_view.h" #include "ash/wm/splitview/split_view_utils.h" #include "base/functional/callback_helpers.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -25,7 +22,6 @@ #include "ui/events/types/event_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/background.h" -#include "ui/views/highlight_border.h" #include "ui/views/view.h" #include "ui/wm/core/coordinate_conversion.h" @@ -33,6 +29,18 @@ namespace { +// The divider handler's default / enlarged short side length. +constexpr int kDividerHandlerShortSideLength = 2; +constexpr int kDividerHandlerEnlargedShortSideLength = 4; + +// The divider handler's default / enlarged long side length. +constexpr int kDividerHandlerLongSideLength = 16; +constexpr int kDividerHandlerEnlargedLongSideLength = 48; + +// The divider handler's default / enlarged corner radius. +constexpr int kDividerHandlerCornerRadius = 1; +constexpr int kDividerHandlerEnlargedCornerRadius = 2; + // Distance between the bottom / right edge of the feedback button and the // bottom / right of the work area. constexpr int kFeedbackButtonDistanceFromEdge = 58; @@ -46,9 +54,8 @@ } // namespace SplitViewDividerView::SplitViewDividerView(SplitViewDivider* divider) - : divider_handler_view_( - AddChildView(std::make_unique<SplitViewDividerHandlerView>())), - divider_(divider) { + : divider_(divider), + handler_view_(AddChildView(std::make_unique<views::View>())) { SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); SetPaintToLayer(ui::LAYER_TEXTURED); @@ -56,7 +63,7 @@ SetBackground( views::CreateThemedSolidBackground(cros_tokens::kCrosSysSecondary)); - RefreshFeedbackButton(false); + RefreshFeedbackButton(/*visible=*/false); } SplitViewDividerView::~SplitViewDividerView() = default; @@ -65,37 +72,8 @@ divider_ = nullptr; } -void SplitViewDividerView::DoSpawningAnimation(int spawn_position) { - const gfx::Rect bounds = GetBoundsInScreen(); - int divider_signed_offset; - - // To animate the divider scaling up from nothing, animate its bounds rather - // than its transform, mostly because a transform that scales by zero would - // be singular. For that bounds animation, express `spawn_position` in local - // coordinates by subtracting a coordinate of the origin. Compute - // `divider_signed_offset` as described in the comment for - // `SplitViewDividerHandlerView::DoSpawningAnimation`. - if (IsCurrentScreenOrientationLandscape()) { - SetBounds(spawn_position - bounds.x(), 0, 0, bounds.height()); - divider_signed_offset = spawn_position - bounds.CenterPoint().x(); - } else { - SetBounds(0, spawn_position - bounds.y(), bounds.width(), 0); - divider_signed_offset = spawn_position - bounds.CenterPoint().y(); - } - - ui::LayerAnimator* divider_animator = layer()->GetAnimator(); - ui::ScopedLayerAnimationSettings settings(divider_animator); - settings.SetTransitionDuration(kSplitviewDividerSpawnDuration); - settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); - settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); - divider_animator->SchedulePauseForProperties( - kSplitviewDividerSpawnDelay, ui::LayerAnimationElement::BOUNDS); - SetBounds(0, 0, bounds.width(), bounds.height()); - divider_handler_view_->DoSpawningAnimation(divider_signed_offset); -} - -void SplitViewDividerView::SetDividerBarVisible(bool visible) { - divider_handler_view_->SetVisible(visible); +void SplitViewDividerView::SetHandlerBarVisible(bool visible) { + handler_view_->SetVisible(visible); } void SplitViewDividerView::Layout(PassKey) { @@ -109,17 +87,19 @@ } SetBoundsRect(GetLocalBounds()); + RefreshDividerHandler(/*hover=*/false); RefreshFeedbackButtonBounds(); - divider_handler_view_->Refresh(divider_->is_resizing_with_divider()); } void SplitViewDividerView::OnMouseEntered(const ui::MouseEvent& event) { + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/true); + gfx::Point screen_location = event.location(); ConvertPointToScreen(this, &screen_location); + // Show `feedback_button_` on mouse entered. if (!feedback_button_ || !feedback_button_->GetBoundsInScreen().Contains(screen_location)) { - // Show `feedback_button_` on mouse entered. RefreshFeedbackButton(/*visible=*/true); } } @@ -127,6 +107,14 @@ void SplitViewDividerView::OnMouseExited(const ui::MouseEvent& event) { gfx::Point screen_location = event.location(); ConvertPointToScreen(this, &screen_location); + + if (handler_view_ && + !handler_view_->GetBoundsInScreen().Contains(screen_location) && + (!feedback_button_ || + !feedback_button_->GetBoundsInScreen().Contains(screen_location))) { + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/false); + } + // Hide `feedback_button_` on mouse exited. if (feedback_button_ && !feedback_button_->GetBoundsInScreen().Contains(screen_location)) { @@ -143,7 +131,9 @@ bool SplitViewDividerView::OnMouseDragged(const ui::MouseEvent& event) { CHECK(divider_); + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/true); RefreshFeedbackButton(/*visible=*/false); + if (!mouse_move_started_) { // If this is the first mouse drag event, start the resize and reset // `mouse_move_started_`. @@ -178,6 +168,7 @@ // synthetic touch event. return; } + gfx::Point location(event->location()); views::View::ConvertPointToScreen(this, &location); switch (event->type()) { @@ -187,15 +178,29 @@ } break; case ui::ET_GESTURE_TAP_DOWN: + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/true); + RefreshFeedbackButton(/*visible=*/true); + break; + case ui::ET_GESTURE_TAP_CANCEL: + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/false); + RefreshFeedbackButton(/*visible=*/false); break; case ui::ET_GESTURE_SCROLL_BEGIN: StartResizing(location); + RefreshFeedbackButton(/*visible=*/true); break; case ui::ET_GESTURE_SCROLL_UPDATE: divider_->ResizeWithDivider(location); + RefreshFeedbackButton(/*visible=*/true); + break; + case ui::ET_GESTURE_SCROLL_END: + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/false); + RefreshFeedbackButton(/*visible=*/false); break; case ui::ET_GESTURE_END: EndResizing(location, /*swap_windows=*/false); + divider_->EnlargeOrShrinkDivider(/*should_enlarge=*/false); + RefreshFeedbackButton(/*visible=*/true); break; default: @@ -221,49 +226,36 @@ divider_->SwapWindows(); } -void SplitViewDividerView::OnResizeStatusChanged() { - // If split view has ended, the divider widget will be closing. In this case - // no need to update the divider layout and do the animation. - if (!divider_ || !divider_->divider_widget()) { - return; - } - - // If `divider_view_`'s bounds are animating, it is for the divider spawning - // animation. Stop that before animating `divider_view_`'s transform. - ui::LayerAnimator* divider_animator = layer()->GetAnimator(); - divider_animator->StopAnimatingProperty(ui::LayerAnimationElement::BOUNDS); - - // Do the divider enlarge/shrink animation when starting/ending dragging. - const bool is_resizing = divider_->is_resizing_with_divider(); - SetBoundsRect(GetLocalBounds()); - const gfx::Rect old_bounds = - divider_->GetDividerBoundsInScreen(/*is_dragging=*/false); - const gfx::Rect new_bounds = divider_->GetDividerBoundsInScreen(is_resizing); - gfx::Transform transform; - transform.Translate(new_bounds.x() - old_bounds.x(), - new_bounds.y() - old_bounds.y()); - transform.Scale( - static_cast<float>(new_bounds.width()) / old_bounds.width(), - static_cast<float>(new_bounds.height()) / old_bounds.height()); - ui::ScopedLayerAnimationSettings settings(divider_animator); - settings.SetTransitionDuration( - kSplitviewDividerSelectionStatusChangeDuration); - settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN); - settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - SetTransform(transform); - - divider_handler_view_->Refresh(is_resizing); -} - void SplitViewDividerView::StartResizing(gfx::Point location) { CHECK(divider_); - // `StartResizeWithDivider()` may cause this view to be destroyed. - auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); divider_->StartResizeWithDivider(location); - if (weak_ptr) { - OnResizeStatusChanged(); +} + +void SplitViewDividerView::RefreshDividerHandler(bool should_enlarge) { + CHECK(divider_); + + const gfx::Point divider_center = bounds().CenterPoint(); + const int handler_short_side = should_enlarge + ? kDividerHandlerEnlargedShortSideLength + : kDividerHandlerShortSideLength; + const int handler_long_side = should_enlarge + ? kDividerHandlerEnlargedLongSideLength + : kDividerHandlerLongSideLength; + if (IsLayoutHorizontal(divider_->GetRootWindow())) { + handler_view_->SetBounds(divider_center.x() - handler_short_side / 2, + divider_center.y() - handler_long_side / 2, + handler_short_side, handler_long_side); + } else { + handler_view_->SetBounds(divider_center.x() - handler_long_side / 2, + divider_center.y() - handler_short_side / 2, + handler_long_side, handler_short_side); } + + handler_view_->SetBackground(views::CreateThemedRoundedRectBackground( + cros_tokens::kCrosSysOnSecondary, + should_enlarge ? kDividerHandlerEnlargedCornerRadius + : kDividerHandlerCornerRadius)); + handler_view_->SetVisible(true); } void SplitViewDividerView::RefreshFeedbackButton(bool visible) { @@ -322,7 +314,7 @@ if (!weak_ptr) { return; } - OnResizeStatusChanged(); + if (swap_windows) { SwapWindows(); }
diff --git a/ash/wm/splitview/split_view_divider_view.h b/ash/wm/splitview/split_view_divider_view.h index 58a7f45..ae50beb 100644 --- a/ash/wm/splitview/split_view_divider_view.h +++ b/ash/wm/splitview/split_view_divider_view.h
@@ -13,9 +13,20 @@ class IconButton; class SplitViewDivider; -class SplitViewDividerHandlerView; -// A view that acts as the contents view of the split view divider widget. +// A view that acts as the content view within a split view divider widget. +// It hosts two child views: a handler view and a feedback button. Its +// responsibility is to update the bounds and visibility of its child views in +// response to located events. +// | | +// | | +// |||<-----handler_view_ +// ||| +// | | +// +---+ +// | |<----feedback_button_ +// +---+ +// | | class SplitViewDividerView : public views::View, public views::ViewTargeterDelegate { METADATA_HEADER(SplitViewDividerView, views::View) @@ -26,8 +37,7 @@ SplitViewDividerView& operator=(const SplitViewDividerView&) = delete; ~SplitViewDividerView() override; - void DoSpawningAnimation(int spawn_position); - void SetDividerBarVisible(bool visible); + void SetHandlerBarVisible(bool visible); // Called explicitly by SplitViewDivider when the divider widget is closing. void OnDividerClosing(); @@ -49,9 +59,9 @@ IconButton* feedback_button_for_testing() const { return feedback_button_; } private: - void SwapWindows(); + friend class SplitViewDivider; - void OnResizeStatusChanged(); + void SwapWindows(); void StartResizing(gfx::Point location); @@ -59,6 +69,10 @@ // `swap_windows` is true, swaps the windows after resizing. void EndResizing(gfx::Point location, bool swap_windows); + // Refreshes the divider handler's bounds and rounded corners in response to + // changes in the divider's dimensions or display properties. + void RefreshDividerHandler(bool should_enlarge); + // Initializes, refreshes bounds, or updates visibility for the // `feedback_button_` on the divider. void RefreshFeedbackButton(bool visible); @@ -76,9 +90,9 @@ // a resize. bool mouse_move_started_ = false; - raw_ptr<SplitViewDividerHandlerView> divider_handler_view_ = nullptr; raw_ptr<SplitViewDivider> divider_; + raw_ptr<views::View> handler_view_ = nullptr; raw_ptr<IconButton> feedback_button_ = nullptr; base::WeakPtrFactory<SplitViewDividerView> weak_ptr_factory_{this};
diff --git a/ash/wm/window_restore/pine_controller.cc b/ash/wm/window_restore/pine_controller.cc index 5b22e54..838ccc6 100644 --- a/ash/wm/window_restore/pine_controller.cc +++ b/ash/wm/window_restore/pine_controller.cc
@@ -22,6 +22,7 @@ #include "ash/style/dark_light_mode_controller_impl.h" #include "ash/style/system_dialog_delegate_view.h" #include "ash/system/toast/toast_manager_impl.h" +#include "ash/utility/forest_util.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_grid.h" @@ -213,7 +214,7 @@ void PineController::MaybeStartPineOverviewSession( std::unique_ptr<PineContentsData> pine_contents_data) { - CHECK(features::IsForestFeatureEnabled()); + CHECK(IsForestFeatureEnabled()); if (OverviewController::Get()->InOverviewSession()) { return; @@ -267,12 +268,19 @@ void PineController::OnOverviewModeEndingAnimationComplete(bool canceled) { // If `canceled` is true, overview was reentered before the exit animations // were finished. `in_pine_` will be reset the next time overview ends. - if (canceled || !in_pine_ || !features::IsForestFeatureEnabled()) { + if (canceled || !in_pine_) { return; } in_pine_ = false; + // In multi-user scenario, forest may have been available for the user that + // started overview, but not for the current user. (Switching users ends + // overview.) + if (!IsForestFeatureEnabled()) { + return; + } + PrefService* prefs = GetActivePrefService(); if (!prefs) { return;
diff --git a/base/containers/checked_iterators.h b/base/containers/checked_iterators.h index 6f62aa81..59654830 100644 --- a/base/containers/checked_iterators.h +++ b/base/containers/checked_iterators.h
@@ -194,7 +194,7 @@ CHECK_EQ(end_, other.end_); } - // RAW_PTR_EXCLUSION: T can be a STACK_ALLOCATED class. + // RAW_PTR_EXCLUSION: The embedding class is stack-scoped. RAW_PTR_EXCLUSION const T* start_ = nullptr; RAW_PTR_EXCLUSION T* current_ = nullptr; RAW_PTR_EXCLUSION const T* end_ = nullptr;
diff --git a/base/files/file_util.h b/base/files/file_util.h index 73f39bd..3c19ee8 100644 --- a/base/files/file_util.h +++ b/base/files/file_util.h
@@ -525,6 +525,15 @@ #endif // This function will return if the given file is a symlink or not. +// +// IMPORTANT NOTE: This method is subject to race conditions, meaning its +// results might not always accurately reflect the current state of the file +// system by the time they are used. Specifically, the link target could change +// between the time of this check and subsequent operations, leading to +// potential inconsistencies. Therefore, this method should only be used by +// callers that need to know nothing more than whether or not a given directory +// entry is a symlink. When the path to the target is required, callers should +// instead use `base::ReadSymbolicLink()` or `base::ReadSymbolicLinkAbsolute()`. BASE_EXPORT bool IsLink(const FilePath& file_path); // Returns information about the given file path. Also see |File::GetInfo|.
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc index 1421794a..6a92587 100644 --- a/base/files/file_util_unittest.cc +++ b/base/files/file_util_unittest.cc
@@ -99,6 +99,18 @@ const size_t kLargeFileSize = (1 << 16) + 3; +enum class CreateSymbolicLinkResult { + // The symbolic link creation failed because the platform does not support it. + // On Windows, that may be due to the lack of the required privilege. + kUnsupported = -1, + + // The symbolic link creation failed. + kFailed, + + // The symbolic link was created successfully. + kSucceeded, +}; + #if BUILDFLAG(IS_WIN) // Method that wraps the win32 GetShortPathName API. Returns an empty path on // error. @@ -116,8 +128,51 @@ return FilePath(path_short_str); } + +CreateSymbolicLinkResult CreateWinSymbolicLink(const FilePath& target, + const FilePath& symlink) { + // Determine whether the target is a directory. This is necessary because + // creating a symbolic link requires different flags depending on the type + // of the target (file vs. directory). + DWORD attrs = GetFileAttributes(target.value().c_str()); + if (attrs == INVALID_FILE_ATTRIBUTES) { + // Unable to retrieve attributes for the target. It might not exist, or + // there may be a permissions issue. Either way, we cannot proceed. + return CreateSymbolicLinkResult::kFailed; + } + + DWORD flags = + attrs & FILE_ATTRIBUTE_DIRECTORY ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; + + if (!::CreateSymbolicLink( + symlink.value().c_str(), target.value().c_str(), + flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) { + if (::GetLastError() == ERROR_PRIVILEGE_NOT_HELD) { + return CreateSymbolicLinkResult::kUnsupported; + } + return CreateSymbolicLinkResult::kFailed; + } + + return CreateSymbolicLinkResult::kSucceeded; +} #endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX) + +CreateSymbolicLinkResult CreateSymbolicLinkForTesting(const FilePath& target, + const FilePath& symlink) { +#if BUILDFLAG(IS_WIN) + return CreateWinSymbolicLink(target, symlink); +#else + if (!CreateSymbolicLink(target, symlink)) { + return CreateSymbolicLinkResult::kFailed; + } + return CreateSymbolicLinkResult::kSucceeded; +#endif // BUILDFLAG(IS_WIN) +} + +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX) + #if BUILDFLAG(IS_MAC) // Provide a simple way to change the permissions bits on |path| in tests. // ASSERT failures will return, but not stop the test. Caller should wrap @@ -391,6 +446,112 @@ .IsParent(normalized_file_b_path.DirName())); } +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX) + +TEST_F(FileUtilTest, IsLinkCreateSymbolicLinkOnFile) { + FilePath target_file_path; + ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path)); + EXPECT_FALSE(IsLink(target_file_path)); + + base::FilePath symlink_path = + temp_dir_.GetPath().Append(FPL("symlink_to_target")); + + CreateSymbolicLinkResult result = + CreateSymbolicLinkForTesting(target_file_path, symlink_path); + if (result == CreateSymbolicLinkResult::kUnsupported) { + GTEST_SKIP(); + } + ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded); + + EXPECT_TRUE(IsLink(symlink_path)); +} + +TEST_F(FileUtilTest, IsLinkCreateSymbolicLinkOnDirectory) { + FilePath target_path = temp_dir_.GetPath().Append(FPL("target")); + ASSERT_TRUE(CreateDirectory(target_path)); + EXPECT_FALSE(IsLink(target_path)); + + base::FilePath symlink_path = + temp_dir_.GetPath().Append(FPL("symlink_to_target")); + + CreateSymbolicLinkResult result = + CreateSymbolicLinkForTesting(target_path, symlink_path); + if (result == CreateSymbolicLinkResult::kUnsupported) { + GTEST_SKIP(); + } + ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded); + + EXPECT_TRUE(IsLink(symlink_path)); +} + +TEST_F(FileUtilTest, IsLinkMissingFile) { + EXPECT_FALSE(IsLink(FilePath())); +} + +TEST_F(FileUtilTest, IsLinkWithDeletedTargetFile) { + // Set up a symlink pointing to a temporary file. + FilePath target_file_path; + ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path)); + FilePath symlink_path = + temp_dir_.GetPath().Append(FPL("symlink_to_missing_target")); + + CreateSymbolicLinkResult result = + CreateSymbolicLinkForTesting(target_file_path, symlink_path); + if (result == CreateSymbolicLinkResult::kUnsupported) { + GTEST_SKIP(); + } + ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded); + + // Verify that the symlink is recognized correctly. + EXPECT_TRUE(IsLink(symlink_path)); + + // Delete the target file. + ASSERT_TRUE(DeleteFile(target_file_path)); + + // Verify that IsLink still returns true for the symlink, even though its + // target is missing. + EXPECT_TRUE(IsLink(symlink_path)); +} + +TEST_F(FileUtilTest, IsLinkWithDeletedTargetDirectory) { + // Set up a symlink pointing to a temporary file. + FilePath target_path = temp_dir_.GetPath().Append(FPL("target")); + ASSERT_TRUE(CreateDirectory(target_path)); + FilePath symlink_path = + temp_dir_.GetPath().Append(FPL("symlink_to_missing_target")); + + CreateSymbolicLinkResult result = + CreateSymbolicLinkForTesting(target_path, symlink_path); + if (result == CreateSymbolicLinkResult::kUnsupported) { + GTEST_SKIP(); + } + ASSERT_EQ(result, CreateSymbolicLinkResult::kSucceeded); + + // Verify that the symlink is recognized correctly. + EXPECT_TRUE(IsLink(symlink_path)); + + // Delete the target file. + ASSERT_TRUE(DeleteFile(target_path)); + + // Verify that IsLink still returns true for the symlink, even though its + // target is missing. + EXPECT_TRUE(IsLink(symlink_path)); +} + +TEST_F(FileUtilTest, IsLinkWihtoutReparsePointAttributeOnDirectory) { + FilePath target_path = temp_dir_.GetPath().Append(FPL("target")); + ASSERT_TRUE(CreateDirectory(target_path)); + EXPECT_FALSE(IsLink(target_path)); +} + +TEST_F(FileUtilTest, IsLinkWihtoutReparsePointAttributeOnFile) { + FilePath target_file_path; + ASSERT_TRUE(CreateTemporaryFileInDir(temp_dir_.GetPath(), &target_file_path)); + EXPECT_FALSE(IsLink(target_file_path)); +} + +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_POSIX) + #if BUILDFLAG(IS_WIN) TEST_F(FileUtilTest, NormalizeFileEmptyFile) {
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc index 60df40b..8780301b 100644 --- a/base/files/file_util_win.cc +++ b/base/files/file_util_win.cc
@@ -903,10 +903,37 @@ nullptr); } -// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle -// them if we do decide to. bool IsLink(const FilePath& file_path) { - return false; + ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK); + + // Opens the file or directory specified by file_path for querying attributes. + // No access rights are requested (FILE_READ_ATTRIBUTES), as we're only + // interested in the attributes. The file share mode allows other processes to + // read, write, and delete the file while we have it open. The flags + // FILE_FLAG_BACKUP_SEMANTICS and FILE_FLAG_OPEN_REPARSE_POINT are used to + // ensure we can open directories and work with reparse points, respectively. + // + // NOTE: In future, we can consider using GetFileInformationByName(...) + // instead. + win::ScopedHandle file( + ::CreateFile(file_path.value().c_str(), FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + /*hTemplateFile=*/nullptr)); + + if (!file.is_valid()) { + return false; + } + + FILE_ATTRIBUTE_TAG_INFO attr_taginfo; + if (!::GetFileInformationByHandleEx(file.get(), FileAttributeTagInfo, + &attr_taginfo, sizeof(attr_taginfo))) { + return false; + } + + return (attr_taginfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (attr_taginfo.ReparseTag == IO_REPARSE_TAG_SYMLINK); } bool GetFileInfo(const FilePath& file_path, File::Info* results) {
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 425e11f..792548d2 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -116,6 +116,14 @@ # When true, sanitizer warnings will cause test case failures. fail_on_san_warnings = false + + # When true, only builds fuzzer targets that require high end machines to run. + # Otherwise, builds all the targets. + # TODO(paulsemel): once we have everything implemented on the recipe side, we + # can change the behaviour for the false case, and only build the non high-end + # jobs, so that they do not appear in the zip. As for now, this behaviour + # ensures nothing breaks. + high_end_fuzzer_targets = false } declare_args() {
diff --git a/build/config/siso/main.star b/build/config/siso/main.star index e30ba95..7e07066 100644 --- a/build/config/siso/main.star +++ b/build/config/siso/main.star
@@ -53,16 +53,13 @@ "./obj/chrome/browser/browser/chrome_content_browser_client.o", "./obj/chrome/browser/browser/render_view_context_menu.o", "./obj/chrome/browser/ui/ash/holding_space/browser_tests/holding_space_ui_browsertest.o", - "./obj/chrome/test/browser_tests/app_list_client_impl_browsertest.o", "./obj/chrome/test/browser_tests/browser_non_client_frame_view_chromeos_browsertest.o", "./obj/chrome/test/browser_tests/chrome_shelf_controller_browsertest.o", "./obj/chrome/test/browser_tests/device_local_account_browsertest.o", "./obj/chrome/test/browser_tests/file_manager_browsertest_base.o", "./obj/chrome/test/browser_tests/full_restore_app_launch_handler_browsertest.o", - "./obj/chrome/test/browser_tests/remote_apps_manager_browsertest.o", "./obj/chrome/test/browser_tests/safe_browsing_blocking_page_test.o", "./obj/chrome/test/browser_tests/scalable_iph_browsertest.o", - "./obj/chrome/test/browser_tests/spoken_feedback_browsertest.o", "./obj/chrome/test/interactive_ui_tests/local_card_migration_uitest.o", "./obj/chrome/test/interactive_ui_tests/system_web_app_interactive_uitest.o", "./obj/chrome/test/interactive_ui_tests/tab_drag_controller_interactive_uitest.o", @@ -103,6 +100,7 @@ # target_os = "android" # use_remoteexec = true "./android_clang_arm/obj/content/browser/browser/browser_interface_binders.o", + "./obj/content/test/content_unittests__library/auction_runner_unittest.o", # Fallback happens with follwoing args.gn (try/fuchsia-x64-cast-receiver-rel). # Fallback may happen in other build config too.
diff --git a/chrome/MAJOR_BRANCH_DATE b/chrome/MAJOR_BRANCH_DATE index b4fe844..a5f277cf 100644 --- a/chrome/MAJOR_BRANCH_DATE +++ b/chrome/MAJOR_BRANCH_DATE
@@ -1 +1 @@ -MAJOR_BRANCH_DATE=2024-03-19 +MAJOR_BRANCH_DATE=2024-04-16
diff --git a/chrome/VERSION b/chrome/VERSION index 05a34bd9..0c87028f2 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ -MAJOR=125 +MAJOR=126 MINOR=0 -BUILD=6422 +BUILD=6423 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index a539a43..fe9f698 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -2857,6 +2857,7 @@ "//chrome/browser/android/intents:unit_device_javatests", "//chrome/browser/back_press/android:unit_device_javatests", "//chrome/browser/download/internal/android:unit_device_javatests", + "//chrome/browser/history:unit_device_javatests", "//chrome/browser/hub:unit_device_javatests", "//chrome/browser/hub/internal:unit_device_javatests", "//chrome/browser/image_descriptions:unit_device_javatests",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index cf84c67..18b91de5 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4157,6 +4157,10 @@ flag_descriptions::kAudioSuppressSetRTCAudioActiveName, flag_descriptions::kAudioSuppressSetRTCAudioActiveDescription, kOsCrOS, PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootAudioSuppressSetRTCAudioActive")}, + {"cras-processor-dedicated-thread", + flag_descriptions::kCrasProcessorDedicatedThreadName, + flag_descriptions::kCrasProcessorDedicatedThreadDescription, kOsCrOS, + PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootCrasProcessorDedicatedThread")}, {"cras-split-alsa-usb-internal", flag_descriptions::kCrasSplitAlsaUsbInternalName, flag_descriptions::kCrasSplitAlsaUsbInternalDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_preload_service/proto/app_preload.proto b/chrome/browser/apps/app_preload_service/proto/app_preload.proto index 4967ef5..f040482 100644 --- a/chrome/browser/apps/app_preload_service/proto/app_preload.proto +++ b/chrome/browser/apps/app_preload_service/proto/app_preload.proto
@@ -26,16 +26,26 @@ // A list of zero or more apps for APS to install. repeated App apps_to_install = 1; + // The Launcher Configuration. + repeated LauncherConfig launcher_config = 2; + + // The Shelf Configuration. + repeated ShelfConfig shelf_config = 3; + enum InstallReason { // Default for deserialization when an unexpected value is encountered. - // Indicates to the client that the server has a new reason and needs - // the proto file updated. + // Usually indicates to the client that the server has a new reason and + // needs the proto file updated. INSTALL_REASON_UNKNOWN = 0; - // A Default App. + // An app other than an OEM app. This should be pinned in the Launcher at + // the position that matches the PackageId or, if not specified, into the + // end of the "OTHER" position, as defined in the launcher config. INSTALL_REASON_DEFAULT = 1; - // An app installed for an OEM. + // An app installed for an OEM. This should be placed into the "OEM" folder + // defined in the launcher config. + // (note: position in the OEM folder itself does not matter). INSTALL_REASON_OEM = 2; // An app which is being returned by the server for testing purposes. @@ -44,26 +54,12 @@ INSTALL_REASON_TEST = 3; } - message Icon { - // Url to query to get the icon. This will always be from the host - // meltingpot.googleusercontent.com. - optional string url = 1; - - // Width of the icon in pixels. While App icons are typically square - // note there is no guarantee the image provided will be. - optional uint32 width_in_pixels = 2; - - // Mime type of the icon. - optional string mime_type = 3; - - // Whether or not we have permission from the platform to mask the icon. - optional bool is_masking_allowed = 4; - } - // For Android-only metadata. + // Note: Once Unified App Install has been hooked up, this will be deprecated. message AndroidExtras {} // For Web-only metadata. + // Note: Once Unified App Install has been hooked up, this will be deprecated. message WebExtras { // A URL to the web app's manifest in json format. This will always be from // the host meltingpot.googleusercontent.com. @@ -88,17 +84,103 @@ // The App's UTF-8 encoded name in the requested language (or next best). optional string name = 3; - // One or more Icons for this App for the requested language (or next best). - repeated Icon icons = 4; + // Icons (which are not currently used). + reserved 4; // The reason why this app is in the list. optional InstallReason install_reason = 5; + // An optional campaign code for this preload. + optional string campaign_code = 8; + + // The localised folder name that this preload should be placed in. + // Note: this is not populated and should be ignored for OEM preloads. + optional string folder_name = 9; + // Every platform has its own [Platform]Extras message to store platform // specific metadata. + // Note: Once Unified App Install has been hooked up, this will be + // deprecated. oneof extras { AndroidExtras android_extras = 6; WebExtras web_extras = 7; } } + + // Configuration defining the order of apps pinned in the Shelf. + message ShelfConfig { + // The order of the entries in this config. Sort by this value and then + // process in ascending order. + optional uint32 order = 1; + + // An optional feature flag. If specified, evaluate the flag and ignore this + // entry if the feature is not enabled. + optional string feature_flag = 2; + + // The identifier for the app for this slot (usually one). If more than one + // is specified, evaluate the entries in order and place the first app + // detected on the device in this slot. Ignore the remaining entries. + repeated string package_id = 3; + } + + // Indicates the type of Launcher entry. + enum LauncherType { + // Default for deserialization when an unexpected value is encountered. + // Usually Indicates to the client that the server has a new reason and + // needs the proto file updated. + LAUNCHER_TYPE_UNKNOWN = 0; + + // Indicates where the Chrome Browser (Ash or Lacross) should be placed. + // Note: this may be in a folder (see below). + LAUNCHER_TYPE_CHROME = 1; + + // An App with the `package_id` should be placed in this position. + // Note: this may be in a folder (see below). + LAUNCHER_TYPE_APP = 2; + + // All other apps not explicitly listed should be installed in this + // position in the order they are installed (ie. doesn't matter). + // Note: this may be in a folder (see below). + LAUNCHER_TYPE_OTHER = 3; + + // Indicates the position of the OEM folder which should be named with the + // localised string in `folder_name`. Preloads marked "INSTALL_REASON_OEM" + // should be placed in this folder in the order they install (ie. doesn't + // matter). + LAUNCHER_TYPE_FOLDER_OEM = 4; + + // Indicates an arbitrary folder should be created in this position named + // with the string in `folder_name`. This will have a child configuration + // which can only contain Apps (ie. no nested folders). + LAUNCHER_TYPE_FOLDER = 5; + } + + // Configuration defining the order of items pinned in the Launcher. + message LauncherConfig { + // Indicates what type of entry this is in the config (see above). + optional LauncherType type = 1; + + // The order of the entries in this config. Sort by this value and then + // process in ascending order. + optional uint32 order = 2; + + // An optional feature flag. If specified, evaluate the flag and ignore + // this entry if the feature is not enabled. + optional string feature_flag = 3; + + // The identifier for the app for this slot (usually one). If more than one + // is specified, evaluate the entries in order and place the first app + // detected on the device in this slot. Ignore the remaining entries. + repeated string package_id = 4; + + // For LAUNCHER_TYPE_FOLDER_OEM and LAUNCHER_TYPE_FOLDER, the localised name + // to use for the folder. + optional string folder_name = 5; + + // For LAUNCHER_TYPE_FOLDER the nested configuration controlling the + // placement of apps within the folder. + // Note: this is not recursive (ie. only valid for 1 level down). + // Install the child apps in this configuration in the order specified. + repeated LauncherConfig child_config = 6; + } }
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc index fec65ad..fd223e7 100644 --- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -51,7 +51,8 @@ #include "chrome/browser/ash/login/test/device_state_mixin.h" #include "chrome/browser/ash/login/test/login_manager_mixin.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" -#include "chrome/browser/ash/login/wizard_controller.h" +#include "chrome/browser/ash/login/ui/login_display_host.h" +#include "chrome/browser/ash/login/wizard_context.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
diff --git a/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc index 4ba5617..421c76c 100644 --- a/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc +++ b/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc
@@ -56,7 +56,6 @@ #include "chrome/browser/ash/login/test/login_manager_mixin.h" #include "chrome/browser/ash/login/ui/user_adding_screen.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" -#include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_browsertest.h"
diff --git a/chrome/browser/ash/app_restore/full_restore_prefs.cc b/chrome/browser/ash/app_restore/full_restore_prefs.cc index 1024add2..2725f52 100644 --- a/chrome/browser/ash/app_restore/full_restore_prefs.cc +++ b/chrome/browser/ash/app_restore/full_restore_prefs.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/ash/app_restore/full_restore_prefs.h" -#include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" +#include "ash/utility/forest_util.h" #include "ash/wm/window_restore/window_restore_util.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/common/pref_names.h" @@ -24,7 +24,7 @@ static_cast<int>(RestoreOption::kAskEveryTime), user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureFlagEnabled()) { registry->RegisterBooleanPref(prefs::kShouldShowPineOnboarding, true); registry->RegisterIntegerPref(prefs::kPineNudgeShownCount, 0); registry->RegisterTimePref(prefs::kPineNudgeLastShown, base::Time());
diff --git a/chrome/browser/ash/app_restore/full_restore_service.cc b/chrome/browser/ash/app_restore/full_restore_service.cc index a9f8a8a..8954b13c 100644 --- a/chrome/browser/ash/app_restore/full_restore_service.cc +++ b/chrome/browser/ash/app_restore/full_restore_service.cc
@@ -11,6 +11,7 @@ #include "ash/glanceables/post_login_glanceables_metrics_recorder.h" #include "ash/public/cpp/notification_utils.h" #include "ash/shell.h" +#include "ash/utility/forest_util.h" #include "ash/webui/settings/public/constants/routes.mojom.h" #include "ash/webui/settings/public/constants/setting.mojom-shared.h" #include "ash/wm/desks/templates/saved_desk_controller.h" @@ -149,6 +150,7 @@ // A unit test that does not override this default delegate may not have ash // shell. if (Shell::HasInstance()) { + CHECK(Shell::Get()->pine_controller()); Shell::Get()->pine_controller()->MaybeStartPineOverviewSession( std::move(pine_contents_data)); } @@ -158,6 +160,7 @@ // A unit test that does not override this default delegate may not have ash // shell. if (Shell::HasInstance()) { + CHECK(Shell::Get()->pine_controller()); Shell::Get()->pine_controller()->MaybeEndPineOverviewSession(); } } @@ -310,7 +313,7 @@ MaybeInitiateAdminTemplateAutoLaunch(); break; case RestoreOption::kDoNotRestore: - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { MaybeShowPineOnboarding(); } ::full_restore::FullRestoreSaveHandler::GetInstance()->AllowSave(); @@ -503,8 +506,7 @@ } // Do not show the notification if we have no restore data. - if (!features::IsForestFeatureEnabled() && - !app_launch_handler_->HasRestoreData()) { + if (!IsForestFeatureEnabled() && !app_launch_handler_->HasRestoreData()) { return; } @@ -523,7 +525,7 @@ const bool last_session_crashed = id == kRestoreForCrashNotificationId; if (!app_launch_handler_->HasRestoreData()) { - CHECK(features::IsForestFeatureEnabled()); + CHECK(IsForestFeatureEnabled()); MaybeShowPineOnboarding(); return; } @@ -543,7 +545,7 @@ ->RecordPostLoginFullRestoreShown(); } - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { CHECK(delegate_); if (crosapi::browser_util::IsLacrosEnabled()) { @@ -828,10 +830,10 @@ } void FullRestoreService::MaybeShowPineOnboarding() { - CHECK(features::IsForestFeatureEnabled()); if (Shell::HasInstance()) { RestoreOption restore_pref = static_cast<RestoreOption>( profile_->GetPrefs()->GetInteger(prefs::kRestoreAppsAndPagesPrefName)); + CHECK(Shell::Get()->pine_controller()); Shell::Get()->pine_controller()->MaybeShowPineOnboardingMessage( /*restore_on=*/restore_pref == RestoreOption::kAskEveryTime); }
diff --git a/chrome/browser/ash/arc/file_system_watcher/OWNERS b/chrome/browser/ash/arc/file_system_watcher/OWNERS index ede84c12..4228552 100644 --- a/chrome/browser/ash/arc/file_system_watcher/OWNERS +++ b/chrome/browser/ash/arc/file_system_watcher/OWNERS
@@ -1,3 +1,2 @@ -hashimoto@chromium.org -niwa@chromium.org youkichihosoi@chromium.org +momohatt@chromium.org
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc index d2bef94..bd64772 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -425,7 +425,15 @@ TestCase("fileDisplayCheckReadOnlyIconOnFakeDirectory"), TestCase("fileDisplayCheckNoReadOnlyIconOnDownloads"), TestCase("fileDisplayCheckNoReadOnlyIconOnLinuxFiles"), - TestCase("fileDisplayCheckNoReadOnlyIconOnGuestOs"))); + TestCase("fileDisplayCheckNoReadOnlyIconOnGuestOs"), + TestCase("fileDisplayLocalFilesDisabledUnmountRemovable") + .DontMountVolumes() + .NewDirectoryTree() + .EnableSkyVault(), + TestCase("fileDisplayLocalFilesDisableInMyFiles") + .DontMountVolumes() + .NewDirectoryTree() + .EnableSkyVault())); WRAPPED_INSTANTIATE_TEST_SUITE_P( OpenVideoMediaApp, /* open_video_media_app.js */
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc index 436ca99..37a4180 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -98,6 +98,7 @@ #include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/download/download_dir_util.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" #include "chrome/browser/extensions/mixin_based_extension_apitest.h" @@ -2424,6 +2425,12 @@ disabled_features.push_back(ash::features::kFilesNewDirectoryTree); } + if (options.enable_skyvault) { + enabled_features.push_back(features::kSkyVault); + } else { + disabled_features.push_back(features::kSkyVault); + } + // This is destroyed in |TearDown()|. We cannot initialize this in the // constructor due to this feature values' above dependence on virtual // method calls, but by convention subclasses of this fixture may initialize @@ -3411,6 +3418,14 @@ return; } + if (name == "setupSkyVault") { + profile()->GetPrefs()->SetString(prefs::kFilesAppDefaultLocation, + download_dir_util::kLocationGoogleDrive); + g_browser_process->local_state()->SetBoolean(prefs::kLocalUserFilesAllowed, + false); + return; + } + if (name == "setTrashEnabled") { std::optional<bool> enabled = value.FindBool("enabled"); ASSERT_TRUE(enabled.has_value());
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h index 094f9acb..06b0856 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -207,6 +207,9 @@ // Whether to enable new directory tree implementation. bool enable_new_directory_tree = false; + // Whether test should enable the SkyVault feature. + bool enable_skyvault = false; + // Feature IDs associated for mapping test cases and features. std::vector<std::string> feature_ids; };
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc index b93849f..30526cb0 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc
@@ -219,6 +219,11 @@ return *this; } +TestCase& TestCase::EnableSkyVault() { + options.enable_skyvault = true; + return *this; +} + std::string TestCase::GetFullName() const { std::string full_name = name;
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h index 388cf84..b8e7cdd5 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h
@@ -116,6 +116,8 @@ TestCase& EnableCrosComponents(); + TestCase& EnableSkyVault(); + std::string GetFullName() const; const char* const name;
diff --git a/chrome/browser/ash/file_suggest/file_suggest_keyed_service.cc b/chrome/browser/ash/file_suggest/file_suggest_keyed_service.cc index 827b8696..f3c801ac 100644 --- a/chrome/browser/ash/file_suggest/file_suggest_keyed_service.cc +++ b/chrome/browser/ash/file_suggest/file_suggest_keyed_service.cc
@@ -6,6 +6,7 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/app_list/app_list_types.h" +#include "ash/utility/forest_util.h" #include "base/functional/bind.h" #include "chrome/browser/ash/file_manager/fileapi_util.h" #include "chrome/browser/ash/file_suggest/drive_file_suggestion_provider.h" @@ -34,7 +35,7 @@ proto_.Init(); if (features::IsLauncherContinueSectionWithRecentsEnabled() || - features::IsForestFeatureEnabled()) { + IsForestFeatureEnabled()) { drive_file_suggestion_provider_ = std::make_unique<DriveRecentFileSuggestionProvider>( profile, base::BindRepeating(
diff --git a/chrome/browser/ash/input_method/input_method_settings.cc b/chrome/browser/ash/input_method/input_method_settings.cc index fd49d44..170ae6c 100644 --- a/chrome/browser/ash/input_method/input_method_settings.cc +++ b/chrome/browser/ash/input_method/input_method_settings.cc
@@ -12,6 +12,7 @@ #include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" +#include "base/strings/strcat.h" #include "chrome/browser/ash/input_method/autocorrect_enums.h" #include "chrome/browser/ash/input_method/autocorrect_prefs.h" #include "chrome/common/pref_names.h" @@ -346,41 +347,26 @@ ValueOrEmpty(input_method_specific_pref.FindString("zhuyinPageSize"))); return settings; } +} // namespace -const base::Value::Dict& GetPrefsDictionaryForEngineId( +mojom::InputMethodSettingsPtr CreateSettingsFromPrefs( const PrefService& prefs, - const std::string& engine_id, - const base::Value::Dict& fallback_dictionary) { + const std::string& engine_id) { // All input method settings are stored in a single pref whose value is a // dictionary. - const base::Value::Dict& all_input_method_pref = - prefs.GetDict(::prefs::kLanguageInputMethodSpecificSettings); - // For each input method, the dictionary contains an entry, with the key being // a string that identifies the input method, and the value being a // subdictionary with the specific settings for that input method. The // subdictionary structure depends on the type of input method it's for. The // subdictionary may be null if the user hasn't changed any settings for that // input method. - const base::Value::Dict* input_method_specific_pref_or_null = - all_input_method_pref.FindDict(engine_id); + const base::Value::Dict* ime_prefs_ptr = + prefs.GetDict(::prefs::kLanguageInputMethodSpecificSettings) + .FindDict(engine_id); - // For convenience, pass an empty dictionary if there are no settings for this - // input method yet. - return input_method_specific_pref_or_null - ? *input_method_specific_pref_or_null - : fallback_dictionary; -} - -// Port the Prefs sett} // namespace -} // namespace - -mojom::InputMethodSettingsPtr CreateSettingsFromPrefs( - const PrefService& prefs, - const std::string& engine_id) { - base::Value::Dict empty_dictionary; - const auto& input_method_specific_pref = - GetPrefsDictionaryForEngineId(prefs, engine_id, empty_dictionary); + base::Value::Dict default_dict; + const base::Value::Dict& input_method_specific_pref = + ime_prefs_ptr == nullptr ? default_dict : *ime_prefs_ptr; if (IsFstEngine(engine_id)) { return mojom::InputMethodSettings::NewLatinSettings( @@ -414,17 +400,31 @@ return nullptr; } +const base::Value* GetLanguageInputMethodSpecificSetting( + PrefService& prefs, + const std::string& engine_id, + const std::string& preference_name) { + return prefs.GetDict(::prefs::kLanguageInputMethodSpecificSettings) + .FindByDottedPath(base::StrCat({engine_id, ".", preference_name})); +} + void SetLanguageInputMethodSpecificSetting(PrefService& prefs, const std::string& engine_id, const base::Value::Dict& values) { // This creates a dictionary where any changes to the dictionary will notify // the prefs service (and its observers). - ScopedDictPrefUpdate update = ScopedDictPrefUpdate( - &prefs, ::prefs::kLanguageInputMethodSpecificSettings); + ScopedDictPrefUpdate update(&prefs, + ::prefs::kLanguageInputMethodSpecificSettings); - for (const auto [key, value] : values) { - update->FindDict(engine_id)->Set(key, value.Clone()); - } + // The "update" dictionary contains nested dictionaries of engine_id -> Dict. + // This partial dictionary contains all the new updated files set up in the + // same schema so it can be merged. + base::Value::Dict partial_dict; + partial_dict.Set(engine_id, values.Clone()); + + // Does a nested dictionary merge to the "update" dictionary. This does not + // modify any existing values that are not inside the partial_dict. + update->Merge(std::move(partial_dict)); } bool IsAutocorrectSupported(const std::string& engine_id) {
diff --git a/chrome/browser/ash/input_method/input_method_settings.h b/chrome/browser/ash/input_method/input_method_settings.h index b9615d4..cb3dcee8 100644 --- a/chrome/browser/ash/input_method/input_method_settings.h +++ b/chrome/browser/ash/input_method/input_method_settings.h
@@ -21,6 +21,14 @@ const std::string& engine_id, const base::Value::Dict& values); +// Gets a specific settings value that is held under a key for an engine id if +// it exists. +// Will return nullptr if it does not exist. +const base::Value* GetLanguageInputMethodSpecificSetting( + PrefService& prefs, + const std::string& engine_id, + const std::string& preference_name); + // Returns true if Autocorrect is supported for a given engine id. bool IsAutocorrectSupported(const std::string& engine_id);
diff --git a/chrome/browser/ash/input_method/input_method_settings_unittest.cc b/chrome/browser/ash/input_method/input_method_settings_unittest.cc index a080679..e8a2191 100644 --- a/chrome/browser/ash/input_method/input_method_settings_unittest.cc +++ b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
@@ -291,7 +291,29 @@ ASSERT_FALSE(IsAutocorrectSupported("zh-t-i0-pinyin")); } -TEST(InputMethodSettingsTest, SetLanguageSpecificInputMethodSettings) { +TEST(InputMethodSettingsTest, GetLanguageSpecificInputMethodSettings) { + base::Value::Dict dict; + dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".field1"}), "DEFAULT1"); + dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".field2"}), "DEFAULT2"); + dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".field3"}), "DEFAULT3"); + TestingPrefServiceSimple prefs; + RegisterTestingPrefs(prefs, dict); + + base::Value::Dict new_prefs; + new_prefs.Set("field2", "CHANGED"); + EXPECT_EQ( + *GetLanguageInputMethodSpecificSetting(prefs, kZhuyinEngineId, "field1"), + "DEFAULT1"); + EXPECT_EQ( + *GetLanguageInputMethodSpecificSetting(prefs, kZhuyinEngineId, "field2"), + "DEFAULT2"); + EXPECT_EQ( + *GetLanguageInputMethodSpecificSetting(prefs, kZhuyinEngineId, "field3"), + "DEFAULT3"); +} + +TEST(InputMethodSettingsTest, + SetLanguageInputMethodSpecificSettingExistingEngine) { base::Value::Dict dict; dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".field1"}), "DEFAULT"); dict.SetByDottedPath(base::StrCat({kZhuyinEngineId, ".field2"}), "DEFAULT"); @@ -317,6 +339,26 @@ EXPECT_EQ(*prefs_val->GetIfDict(), expected); } +TEST(InputMethodSettingsTest, SetLanguageInputMethodSpecificSettingNewEngine) { + base::Value::Dict dict; + dict.SetByDottedPath("existing-engine.field1", "DEFAULT"); + TestingPrefServiceSimple prefs; + RegisterTestingPrefs(prefs, dict); + + base::Value::Dict new_prefs; + new_prefs.Set("field1", "NEW"); + SetLanguageInputMethodSpecificSetting(prefs, "brand-new-engine", new_prefs); + + const base::Value* prefs_val = + prefs.GetUserPref(::prefs::kLanguageInputMethodSpecificSettings); + + base::Value::Dict expected; + expected.SetByDottedPath("existing-engine.field1", "DEFAULT"); + expected.SetByDottedPath("brand-new-engine.field1", "NEW"); + + EXPECT_EQ(*prefs_val->GetIfDict(), expected); +} + } // namespace } // namespace input_method } // namespace ash
diff --git a/chrome/browser/ash/login/session/user_session_initializer.cc b/chrome/browser/ash/login/session/user_session_initializer.cc index e884373f..76abf61 100644 --- a/chrome/browser/ash/login/session/user_session_initializer.cc +++ b/chrome/browser/ash/login/session/user_session_initializer.cc
@@ -268,10 +268,6 @@ // Ensure that the `HoldingSpaceKeyedService` for `profile` is created. HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(profile); - // Ensure that the `BirchKeyedService` for `profile` is created. It is created - // one per user in a multiprofile session. - BirchKeyedServiceFactory::GetInstance()->GetService(profile); - // Ensure that the `CalendarKeyedService` for `profile` is created. It is // created one per user in a multiprofile session. CalendarKeyedServiceFactory::GetInstance()->GetService(profile); @@ -286,6 +282,10 @@ if (is_primary_user) { DCHECK_EQ(primary_profile_, profile); + // Ensure that the `BirchKeyedService` for `profile` is created. It is + // created one per user in a multiprofile session. + BirchKeyedServiceFactory::GetInstance()->GetService(profile); + // Ensure that PhoneHubManager and EcheAppManager are created for the // primary profile. phonehub::PhoneHubManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/ash/policy/core/device_local_account_external_cache.cc b/chrome/browser/ash/policy/core/device_local_account_external_cache.cc index 7e32f01..418991b 100644 --- a/chrome/browser/ash/policy/core/device_local_account_external_cache.cc +++ b/chrome/browser/ash/policy/core/device_local_account_external_cache.cc
@@ -5,20 +5,19 @@ #include "chrome/browser/ash/policy/core/device_local_account_external_cache.h" #include <memory> +#include <string> +#include <utility> -#include "base/check_is_test.h" +#include "base/check.h" #include "base/files/file_path.h" +#include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" -#include "chrome/browser/ash/crosapi/crosapi_ash.h" -#include "chrome/browser/ash/crosapi/crosapi_manager.h" -#include "chrome/browser/ash/crosapi/device_local_account_extension_service_ash.h" #include "chrome/browser/ash/extensions/external_cache_impl.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" -#include "chrome/browser/extensions/external_loader.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -26,11 +25,13 @@ namespace chromeos { DeviceLocalAccountExternalCache::DeviceLocalAccountExternalCache( + ExtensionListCallback ash_loader, + ExtensionListCallback lacros_loader, const std::string& user_id, const base::FilePath& cache_dir) - : user_id_(user_id), cache_dir_(cache_dir) { - loader_ = base::MakeRefCounted<DeviceLocalAccountExternalPolicyLoader>(); -} + : cache_dir_(cache_dir), + ash_loader_(ash_loader), + lacros_loader_(lacros_loader) {} DeviceLocalAccountExternalCache::~DeviceLocalAccountExternalCache() = default; @@ -63,7 +64,8 @@ } base::Value::Dict empty_prefs; - loader_->OnExtensionListsUpdated(empty_prefs); + ash_loader_.Run(user_id_, empty_prefs.Clone()); + lacros_loader_.Run(user_id_, empty_prefs.Clone()); } bool DeviceLocalAccountExternalCache::IsCacheRunning() const { @@ -72,15 +74,8 @@ void DeviceLocalAccountExternalCache::OnExtensionListsUpdated( const base::Value::Dict& prefs) { - if (crosapi::CrosapiManager::IsInitialized()) { - crosapi::CrosapiManager::Get() - ->crosapi_ash() - ->device_local_account_extension_service() - ->SetForceInstallExtensionsFromCache(user_id_, prefs.Clone()); - } else { - CHECK_IS_TEST(); - } - loader_->OnExtensionListsUpdated(prefs); + lacros_loader_.Run(user_id_, prefs.Clone()); + ash_loader_.Run(user_id_, prefs.Clone()); } bool DeviceLocalAccountExternalCache::IsRollbackAllowed() const { @@ -96,11 +91,6 @@ return true; } -scoped_refptr<extensions::ExternalLoader> -DeviceLocalAccountExternalCache::GetExtensionLoader() { - return loader_; -} - base::Value::Dict DeviceLocalAccountExternalCache::GetCachedExtensions() const { return external_cache_->GetCachedExtensions().Clone(); }
diff --git a/chrome/browser/ash/policy/core/device_local_account_external_cache.h b/chrome/browser/ash/policy/core/device_local_account_external_cache.h index b07656e6..0265d68 100644 --- a/chrome/browser/ash/policy/core/device_local_account_external_cache.h +++ b/chrome/browser/ash/policy/core/device_local_account_external_cache.h
@@ -5,13 +5,15 @@ #ifndef CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_EXTERNAL_CACHE_H_ #define CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_EXTERNAL_CACHE_H_ +#include <memory> +#include <string> + #include "base/files/file_path.h" -#include "base/functional/callback_forward.h" +#include "base/functional/callback.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" #include "chrome/browser/ash/extensions/external_cache_delegate.h" -#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" #include "chrome/browser/extensions/external_loader.h" namespace chromeos { @@ -24,7 +26,14 @@ */ class DeviceLocalAccountExternalCache : public ExternalCacheDelegate { public: - DeviceLocalAccountExternalCache(const std::string& user_id, + // Callback invoked when the list of cached extensions is updated. + using ExtensionListCallback = + base::RepeatingCallback<void(const std::string& user_id, + base::Value::Dict cached_extensions)>; + + DeviceLocalAccountExternalCache(ExtensionListCallback ash_loader, + ExtensionListCallback lacros_loader, + const std::string& user_id, const base::FilePath& cache_dir); ~DeviceLocalAccountExternalCache() override; @@ -41,20 +50,26 @@ // Send the new extension dictionary down to the ExternalCache. void UpdateExtensionsList(base::Value::Dict dict); - // ExternalCacheDelegate: - void OnExtensionListsUpdated(const base::Value::Dict& prefs) override; - bool IsRollbackAllowed() const override; - bool CanRollbackNow() const override; - scoped_refptr<extensions::ExternalLoader> GetExtensionLoader(); base::Value::Dict GetCachedExtensions() const; private: + // `ExternalCacheDelegate`: + void OnExtensionListsUpdated(const base::Value::Dict& prefs) override; + bool IsRollbackAllowed() const override; + bool CanRollbackNow() const override; + const std::string user_id_; const base::FilePath cache_dir_; std::unique_ptr<ExternalCache> external_cache_; - scoped_refptr<DeviceLocalAccountExternalPolicyLoader> loader_; + + // Callback invoked when the list of cached extensions that must be installed + // in Ash is updated. + ExtensionListCallback ash_loader_; + // Callback invoked when the list of cached extensions that must be installed + // in the Lacros browser is updated. + ExtensionListCallback lacros_loader_; }; } // namespace chromeos
diff --git a/chrome/browser/ash/policy/core/device_local_account_external_cache_unittest.cc b/chrome/browser/ash/policy/core/device_local_account_external_cache_unittest.cc index 4904394..d52dc4e 100644 --- a/chrome/browser/ash/policy/core/device_local_account_external_cache_unittest.cc +++ b/chrome/browser/ash/policy/core/device_local_account_external_cache_unittest.cc
@@ -5,31 +5,34 @@ #include "chrome/browser/ash/policy/core/device_local_account_external_cache.h" #include <memory> +#include <set> #include <string> #include <utility> +#include <vector> +#include "base/check_op.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/functional/bind.h" #include "base/functional/callback.h" +#include "base/functional/callback_helpers.h" +#include "base/location.h" +#include "base/memory/scoped_refptr.h" #include "base/path_service.h" #include "base/run_loop.h" +#include "base/sequence_checker.h" #include "base/strings/stringprintf.h" #include "base/task/current_thread.h" #include "base/task/single_thread_task_runner.h" +#include "base/time/time.h" #include "base/values.h" -#include "build/build_config.h" -#include "build/chromeos_buildflags.h" -#include "chrome/browser/ash/crosapi/crosapi_manager.h" -#include "chrome/browser/ash/crosapi/idle_service_ash.h" -#include "chrome/browser/ash/crosapi/test_crosapi_dependency_registry.h" #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h" +#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" #include "chrome/browser/extensions/external_provider_impl.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" -#include "chromeos/ash/components/login/login_state/login_state.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_utils.h" #include "extensions/browser/external_install_info.h" @@ -38,6 +41,7 @@ #include "extensions/browser/updater/extension_update_found_test_observer.h" #include "extensions/common/extension.h" #include "extensions/common/extension_urls.h" +#include "extensions/common/mojom/manifest.mojom-shared.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" @@ -181,8 +185,8 @@ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_)}; base::FilePath test_dir_; - std::unique_ptr<crosapi::CrosapiManager> crosapi_manager_; + scoped_refptr<DeviceLocalAccountExternalPolicyLoader> extension_loader_; std::unique_ptr<DeviceLocalAccountExternalCache> external_cache_; MockExternalPolicyProviderVisitor visitor_; std::unique_ptr<extensions::ExternalProviderImpl> provider_; @@ -203,16 +207,24 @@ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_)); ASSERT_TRUE(testing_profile_manager_.SetUp()); - ash::LoginState::Initialize(); - crosapi::IdleServiceAsh::DisableForTesting(); Profile* profile = testing_profile_manager_.CreateTestingProfile("Default"); - crosapi_manager_ = crosapi::CreateCrosapiManagerWithTestRegistry(); - external_cache_ = - std::make_unique<DeviceLocalAccountExternalCache>(kAccountId, cache_dir_); + extension_loader_ = + base::MakeRefCounted<chromeos::DeviceLocalAccountExternalPolicyLoader>(); + + external_cache_ = std::make_unique<DeviceLocalAccountExternalCache>( + /*ash_loader=*/ + base::BindRepeating( + [](scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader> + loader, + const std::string&, base::Value::Dict cached_extensions) { + loader->OnExtensionListsUpdated(cached_extensions); + }, + extension_loader_), + /*lacros_loader=*/ + base::DoNothing(), kAccountId, cache_dir_); provider_ = std::make_unique<extensions::ExternalProviderImpl>( - &visitor_, external_cache_->GetExtensionLoader(), profile, - ManifestLocation::kExternalPolicy, + &visitor_, extension_loader_, profile, ManifestLocation::kExternalPolicy, ManifestLocation::kExternalPolicyDownload, extensions::Extension::NO_FLAGS); @@ -220,9 +232,7 @@ } void DeviceLocalAccountExternalCacheTest::TearDown() { - crosapi_manager_.reset(); testing_profile_manager_.DeleteAllTestingProfiles(); - ash::LoginState::Shutdown(); TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory(nullptr); } @@ -269,7 +279,7 @@ // is manually requested. TEST_F(DeviceLocalAccountExternalCacheTest, CacheNotStarted) { // Manually request a load. - external_cache_->GetExtensionLoader()->StartLoading(); + extension_loader_->StartLoading(); EXPECT_FALSE(external_cache_->IsCacheRunning()); }
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_broker.cc b/chrome/browser/ash/policy/core/device_local_account_policy_broker.cc index c7c337f..86d09ec 100644 --- a/chrome/browser/ash/policy/core/device_local_account_policy_broker.cc +++ b/chrome/browser/ash/policy/core/device_local_account_policy_broker.cc
@@ -3,26 +3,49 @@ // found in the LICENSE file. #include "chrome/browser/ash/policy/core/device_local_account_policy_broker.h" + #include <memory> +#include <optional> +#include <string> +#include <utility> +#include <vector> #include "ash/constants/ash_paths.h" +#include "base/check_is_test.h" +#include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "base/path_service.h" -#include "base/strings/string_number_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" +#include "chrome/browser/ash/crosapi/crosapi_ash.h" +#include "chrome/browser/ash/crosapi/crosapi_manager.h" +#include "chrome/browser/ash/crosapi/device_local_account_extension_service_ash.h" #include "chrome/browser/ash/policy/core/device_local_account.h" #include "chrome/browser/ash/policy/core/device_local_account_external_cache.h" #include "chrome/browser/ash/policy/core/file_util.h" +#include "chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h" +#include "chrome/browser/ash/policy/invalidation/affiliated_cloud_policy_invalidator.h" +#include "chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider.h" +#include "chrome/browser/ash/settings/device_settings_service.h" +#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" +#include "chrome/browser/extensions/external_loader.h" #include "chrome/browser/extensions/policy_handlers.h" #include "components/policy/core/common/chrome_schema.h" +#include "components/policy/core/common/cloud/cloud_policy_client.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h" +#include "components/policy/core/common/cloud/cloud_policy_store.h" +#include "components/policy/core/common/cloud/component_cloud_policy_service.h" +#include "components/policy/core/common/cloud/device_management_service.h" +#include "components/policy/core/common/cloud/policy_invalidation_scope.h" #include "components/policy/core/common/cloud/resource_cache.h" +#include "components/policy/core/common/policy_namespace.h" #include "components/policy/policy_constants.h" -#include "components/prefs/pref_value_map.h" +#include "components/policy/proto/device_management_backend.pb.h" #include "content/public/browser/network_service_instance.h" -#include "extensions/browser/pref_names.h" +#include "device_local_account_extension_tracker.h" +#include "device_local_account_policy_store.h" #include "services/network/public/cpp/shared_url_loader_factory.h" namespace policy { @@ -68,6 +91,26 @@ return policy_handler.GetPolicyDict(policy_map); } +void SendExtensionsToAsh( + scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader> loader, + const std::string& user_id, + base::Value::Dict cached_extensions) { + loader->OnExtensionListsUpdated(cached_extensions); +} + +void SendExtensionsToLacros(const std::string& user_id, + base::Value::Dict cached_extensions) { + if (crosapi::CrosapiManager::IsInitialized()) { + crosapi::CrosapiManager::Get() + ->crosapi_ash() + ->device_local_account_extension_service() + ->SetForceInstallExtensionsFromCache(user_id, + std::move(cached_extensions)); + } else { + CHECK_IS_TEST(); + } +} + } // namespace DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker( @@ -85,6 +128,8 @@ component_policy_cache_path_(component_policy_cache_path), store_(std::move(store)), external_data_manager_(external_data_manager), + extension_loader_(base::MakeRefCounted< + chromeos::DeviceLocalAccountExternalPolicyLoader>()), core_(dm_protocol::kChromePublicAccountPolicyType, store_->account_id(), store_.get(), @@ -98,7 +143,9 @@ account, store_.get(), &schema_registry_); } external_cache_ = std::make_unique<chromeos::DeviceLocalAccountExternalCache>( - user_id_, + /*ash_loader=*/base::BindRepeating(SendExtensionsToAsh, + extension_loader_), + /*lacros_loader=*/base::BindRepeating(SendExtensionsToLacros), user_id_, base::PathService::CheckedGet(ash::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS) .Append(GetUniqueSubDirectoryForAccountID(account.account_id))); store_->AddObserver(this); @@ -124,6 +171,11 @@ store_->LoadImmediately(); } +scoped_refptr<extensions::ExternalLoader> +DeviceLocalAccountPolicyBroker::extension_loader() const { + return extension_loader_; +} + bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const { return invalidator_ != nullptr; }
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_broker.h b/chrome/browser/ash/policy/core/device_local_account_policy_broker.h index 1079b58..b0336bb 100644 --- a/chrome/browser/ash/policy/core/device_local_account_policy_broker.h +++ b/chrome/browser/ash/policy/core/device_local_account_policy_broker.h
@@ -5,11 +5,16 @@ #ifndef CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_POLICY_BROKER_H_ #define CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_POLICY_BROKER_H_ +#include <memory> #include <string> +#include "base/files/file_path.h" #include "base/functional/callback_forward.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" +#include "build/buildflag.h" #include "chrome/browser/ash/policy/core/device_local_account.h" #include "chrome/browser/ash/policy/core/device_local_account_extension_tracker.h" #include "chrome/browser/ash/policy/core/device_local_account_external_cache.h" @@ -17,12 +22,20 @@ #include "chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h" #include "chrome/browser/ash/policy/invalidation/affiliated_cloud_policy_invalidator.h" #include "chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider.h" +#include "chrome/browser/ash/settings/device_settings_service.h" #include "chrome/browser/extensions/external_loader.h" +#include "components/policy/core/common/cloud/cloud_external_data_manager.h" +#include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/cloud_policy_store.h" #include "components/policy/core/common/cloud/component_cloud_policy_service.h" +#include "components/policy/core/common/cloud/device_management_service.h" static_assert(BUILDFLAG(IS_CHROMEOS_ASH), "For ChromeOS ash-chrome only"); +namespace chromeos { +class DeviceLocalAccountExternalPolicyLoader; +} // namespace chromeos + namespace policy { // The main switching central that downloads, caches, refreshes, etc. policy for @@ -67,9 +80,7 @@ const std::string& account_id() const { return account_id_; } const std::string& user_id() const { return user_id_; } - scoped_refptr<extensions::ExternalLoader> extension_loader() const { - return external_cache_->GetExtensionLoader(); - } + scoped_refptr<extensions::ExternalLoader> extension_loader() const; CloudPolicyCore* core() { return &core_; } const CloudPolicyCore* core() const { return &core_; } @@ -132,6 +143,8 @@ const std::unique_ptr<DeviceLocalAccountPolicyStore> store_; std::unique_ptr<DeviceLocalAccountExtensionTracker> extension_tracker_; scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager_; + scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader> + extension_loader_; std::unique_ptr<chromeos::DeviceLocalAccountExternalCache> external_cache_; CloudPolicyCore core_; std::unique_ptr<ComponentCloudPolicyService> component_policy_service_;
diff --git a/chrome/browser/ash/release_notes/release_notes_notification.cc b/chrome/browser/ash/release_notes/release_notes_notification.cc index 95ceff4..33f2d105 100644 --- a/chrome/browser/ash/release_notes/release_notes_notification.cc +++ b/chrome/browser/ash/release_notes/release_notes_notification.cc
@@ -6,10 +6,10 @@ #include <string> -#include "ash/constants/ash_features.h" #include "ash/constants/notifier_catalogs.h" #include "ash/public/cpp/notification_utils.h" #include "ash/resources/vector_icons/vector_icons.h" +#include "ash/utility/forest_util.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/strings/string_util.h" @@ -39,8 +39,7 @@ void ReleaseNotesNotification::MaybeShowReleaseNotes() { release_notes_storage_ = std::make_unique<ReleaseNotesStorage>(profile_); - if (!release_notes_storage_->ShouldNotify() || - features::IsForestFeatureEnabled()) { + if (!release_notes_storage_->ShouldNotify() || IsForestFeatureEnabled()) { return; } ShowReleaseNotesNotification();
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc index a1f5c3e..b368302 100644 --- a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc +++ b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc
@@ -38,7 +38,6 @@ #include "chrome/browser/ash/app_list/app_list_client_impl.h" #include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h" #include "chrome/browser/ash/login/test/session_manager_state_waiter.h" -#include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h" #include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h" #include "chrome/browser/ash/profiles/profile_helper.h"
diff --git a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc index e7ecab7..2023ace 100644 --- a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc +++ b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc
@@ -327,6 +327,8 @@ ash::features::kCameraAppAutoQRDetection)); source->AddBoolean("digital_zoom", base::FeatureList::IsEnabled( ash::features::kCameraAppDigitalZoom)); + source->AddBoolean("super_res", base::FeatureList::IsEnabled( + ash::features::kCameraSuperResSupported)); const PrefService* prefs = Profile::FromWebUI(web_ui_)->GetPrefs(); source->AddBoolean("video_capture_disallowed",
diff --git a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc index 47aa5f3..b365da9 100644 --- a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc +++ b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.h" #include "ash/constants/ash_features.h" +#include "ash/utility/forest_util.h" #include "base/logging.h" #include "base/version.h" #include "chrome/browser/ash/release_notes/release_notes_notification.h" @@ -66,7 +67,7 @@ features::kReleaseNotesNotificationAlwaysEligible)) { return; } - if (features::IsForestFeatureEnabled()) { + if (IsForestFeatureEnabled()) { return; } ReleaseNotesStorage release_notes_storage(profile_);
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.h b/chrome/browser/autofill/mock_autofill_popup_controller.h index e2d0947..4483ebf 100644 --- a/chrome/browser/autofill/mock_autofill_popup_controller.h +++ b/chrome/browser/autofill/mock_autofill_popup_controller.h
@@ -114,6 +114,10 @@ MOCK_METHOD(void, DisableThresholdForTesting, (bool), (override)); MOCK_METHOD(void, KeepPopupOpenForTesting, (), (override)); MOCK_METHOD(void, + SetViewForTesting, + (base::WeakPtr<AutofillPopupView>), + (override)); + MOCK_METHOD(void, UpdateDataListValues, (base::span<const SelectOption>), (override));
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc index 8f40536e..d77b23e 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc
@@ -413,9 +413,9 @@ if (result) { return result; } - // When extension is newer than the brwowser, extension might pass in a - // routine argument that cannot be recognized by the browser. For better - // developer experience, don't treat it as an invalid union. + // When extension is newer than the browser, extension might pass in a routine + // argument that cannot be recognized by the browser. For better developer + // experience, don't treat it as an invalid union. return crosapi::TelemetryDiagnosticRoutineArgument::NewUnrecognizedArgument( false); } @@ -436,9 +436,9 @@ if (result) { return result; } - // When extension is newer than the brwowser, extension might pass in a - // reply that cannot be recognized by the browser. For better developer - // experience, don't treat it as an invalid union. + // When extension is newer than the browser, extension might pass in a reply + // that cannot be recognized by the browser. For better developer experience, + // don't treat it as an invalid union. return crosapi::TelemetryDiagnosticRoutineInquiryReply::NewUnrecognizedReply( false); }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 6b16529..dffb13a8 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1574,6 +1574,11 @@ "expiry_milestone": 130 }, { + "name": "cras-processor-dedicated-thread", + "owners": ["aaronyu@google.com", "chromeos-audio@google.com" ], + "expiry_milestone": 130 + }, + { "name": "cras-split-alsa-usb-internal", "owners": [ "whalechang@google.com", "chromeos-audio-sw@google.com" ], "expiry_milestone": 125
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 2893c4d98..616c1bf 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2001,6 +2001,11 @@ "When enabled, the audio indicators in the tab strip double as tab audio " "mute controls."; +const char kCrasProcessorDedicatedThreadName[] = + "Run CrasProcessor in a dedicated thread"; +const char kCrasProcessorDedicatedThreadDescription[] = + "Run CrasProcessor in a separate thread out of the audio thread"; + const char kCrasSplitAlsaUsbInternalName[] = "CRAS Split USB/Internal refactor control"; const char kCrasSplitAlsaUsbInternalDescription[] = @@ -8015,9 +8020,7 @@ const char kEnableBoundSessionCredentialsName[] = "Device Bound Session Credentials"; const char kEnableBoundSessionCredentialsDescription[] = - "Enables Google session credentials binding to cryptographic keys that are " - "practically impossible to extract from the user device. This will mostly " - "prevent the usage of bound credentials outside of the user device."; + "Enables Google session credentials binding to cryptographic keys."; const char kEnableBoundSessionCredentialsSoftwareKeysForManualTestingName[] = "Device Bound Session Credentials with software keys";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 7970f47..629f52c5 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1139,6 +1139,9 @@ extern const char kTabAudioMutingName[]; extern const char kTabAudioMutingDescription[]; +extern const char kCrasProcessorDedicatedThreadName[]; +extern const char kCrasProcessorDedicatedThreadDescription[]; + extern const char kCrasSplitAlsaUsbInternalName[]; extern const char kCrasSplitAlsaUsbInternalDescription[];
diff --git a/chrome/browser/history/BUILD.gn b/chrome/browser/history/BUILD.gn index 4041fd029..feffc5c8 100644 --- a/chrome/browser/history/BUILD.gn +++ b/chrome/browser/history/BUILD.gn
@@ -9,19 +9,69 @@ android_library("java") { srcjar_deps = [ ":jni_headers" ] - sources = - [ "java/src/org/chromium/chrome/browser/history/HistoryTabHelper.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/history/AppFilterCoordinator.java", + "java/src/org/chromium/chrome/browser/history/AppFilterMediator.java", + "java/src/org/chromium/chrome/browser/history/AppFilterProperties.java", + "java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java", + "java/src/org/chromium/chrome/browser/history/AppFilterViewBinder.java", + "java/src/org/chromium/chrome/browser/history/HistoryTabHelper.java", + ] deps = [ + ":java_resources", "//base:base_java", "//chrome/browser/tab:java", + "//components/browser_ui/bottomsheet/android:java", "//content/public/android:content_java", "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_recyclerview_recyclerview_java", "//third_party/jni_zero:jni_zero_java", + "//ui/android:ui_full_java", ] + resources_package = "org.chromium.chrome.browser.history" } generate_jni("jni_headers") { sources = [ "java/src/org/chromium/chrome/browser/history/HistoryTabHelper.java" ] } + +android_resources("java_resources") { + sources = [ + "java/res/layout/appfilter_content.xml", + "java/res/layout/appfilter_header.xml", + ] + deps = [ + "//chrome/browser/ui/android/strings:ui_strings_grd", + "//components/browser_ui/widget/android:java_resources", + ] +} + +android_library("unit_device_javatests") { + testonly = true + resources_package = "org.chromium.chrome.browser.history" + + sources = [ "java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java" ] + + deps = [ + ":java", + ":java_resources", + "//base:base_java", + "//base:base_java_test_support", + "//chrome/browser/flags:java", + "//chrome/test/android:chrome_java_unit_test_support", + "//components/browser_ui/bottomsheet/android:factory_java", + "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/bottomsheet/android:manager_java", + "//components/browser_ui/widget/android:java", + "//content/public/test/android:content_java_test_support", + "//third_party/androidx:androidx_test_monitor_java", + "//third_party/androidx:androidx_test_rules_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/junit", + "//ui/android:ui_java", + "//ui/android:ui_java_test_support", + ] +}
diff --git a/chrome/browser/history/java/DEPS b/chrome/browser/history/java/DEPS new file mode 100644 index 0000000..fe3f4c93 --- /dev/null +++ b/chrome/browser/history/java/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+components/browser_ui/bottomsheet/android", + "+ui/android", +]
diff --git a/chrome/browser/history/java/OWNERS b/chrome/browser/history/java/OWNERS new file mode 100644 index 0000000..0edc952 --- /dev/null +++ b/chrome/browser/history/java/OWNERS
@@ -0,0 +1,2 @@ +jinsukkim@chromium.org +katzz@google.com
diff --git a/chrome/browser/history/java/res/layout/appfilter_content.xml b/chrome/browser/history/java/res/layout/appfilter_content.xml new file mode 100644 index 0000000..41aeb57e --- /dev/null +++ b/chrome/browser/history/java/res/layout/appfilter_content.xml
@@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2024 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/list_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/min_touch_target_size" + android:orientation="vertical"> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/appfilter_item_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:scrollbars="vertical" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/> + <View + android:layout_marginEnd="@dimen/list_item_default_margin" + android:layout_marginStart="@dimen/list_item_default_margin" + android:importantForAccessibility="no" + style="@style/HorizontalDivider" /> + <TextView + android:id="@+id/close_button" + android:layout_width="wrap_content" + android:layout_height="@dimen/min_touch_target_size" + android:layout_gravity="center" + android:gravity="center" + android:text="@string/close" + style="@style/TextButton" /> +</LinearLayout>
diff --git a/chrome/browser/history/java/res/layout/appfilter_header.xml b/chrome/browser/history/java/res/layout/appfilter_header.xml new file mode 100644 index 0000000..6ccd1f4 --- /dev/null +++ b/chrome/browser/history/java/res/layout/appfilter_header.xml
@@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2024 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="@dimen/min_touch_target_size" + android:orientation="vertical" + tools:ignore="UseCompoundDrawables"> + <ImageView + android:id="@+id/drag_handlebar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="8dp" + android:importantForAccessibility="no" + android:src="@drawable/drag_handlebar" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_gravity="bottom" + android:textDirection="locale" + android:text="@string/history_app_filter_sheet_header" + style="@style/TextAppearance.TextAccentMediumThick.Primary" /> +</LinearLayout>
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinator.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinator.java new file mode 100644 index 0000000..db6ba57 --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinator.java
@@ -0,0 +1,192 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.VisibleForTesting; +import androidx.recyclerview.widget.RecyclerView; + +import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; +import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; + +import java.util.List; + +/** Coordinator class of the app filter bottom sheet UI for history page. */ +class AppFilterCoordinator implements View.OnLayoutChangeListener { + // Maximum number of app filter items shown on the sheet at once if screen dimension allows. + static final int MAX_VISIBLE_ITEM_COUNT = 5; + + // Maximum ratio of the sheet height against the base view height. + static final float MAX_SHEET_HEIGHT_RATIO = 0.7f; + + private final Context mContext; + private final BottomSheetController mBottomSheetController; + private final AppFilterMediator mMediator; + private final RecyclerView mItemListView; + private final BottomSheetContent mSheetContent; + private final PropertyModel mCloseButtonModel; + + private final View mContentView; + private final View mBaseView; + + private final CloseCallback mCloseCallback; + private final int mAppCount; + + private int mBaseViewHeight; + + /** Data class for individual app item in the filter list. */ + public static class AppInfo { + public final String id; + public final Drawable icon; + public final CharSequence label; + + public AppInfo(String id, Drawable icon, CharSequence label) { + this.id = id; + this.icon = icon; + this.label = label; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + return (o instanceof AppInfo appInfo) ? TextUtils.equals(id, appInfo.id) : false; + } + } + + /** Callback to be invoked when the sheet gets closed with updated app info. */ + public interface CloseCallback { + /** + * @param appInfo {@link AppInfo} containing the app information. May be {@code null} if no + * app is selected. + */ + void onAppUpdated(AppInfo appInfo); + } + + /** + * Constructor. + * + * @param context {@link Context} for resources, views. + * @param baseView Base view on which the sheet is opened. + * @param bottomSheetController {@link BottomSheetController} to open/close the sheet. + * @param closeCallback Callback invoked when the sheet is closed + * @param appInfoList List of the apps to display in the sheet. + */ + AppFilterCoordinator( + Context context, + View baseView, + BottomSheetController bottomSheetController, + CloseCallback closeCallback, + List<AppInfo> appInfoList) { + mContext = context; + mBaseView = baseView; + mBaseViewHeight = mBaseView.getHeight(); + mBottomSheetController = bottomSheetController; + mCloseCallback = closeCallback; + var layoutInflater = LayoutInflater.from(context); + mContentView = layoutInflater.inflate(R.layout.appfilter_content, null); + mItemListView = (RecyclerView) mContentView.findViewById(R.id.appfilter_item_list); + mSheetContent = + new AppFilterSheetContent(context, mContentView, mItemListView, this::destroy); + + ModelList listItems = new ModelList(); + var adapter = new SimpleRecyclerViewAdapter(listItems); + adapter.registerType( + 0, + (parent) -> layoutInflater.inflate(R.layout.modern_list_item_view, parent, false), + AppFilterViewBinder::bind); + mItemListView.setAdapter(adapter); + + // Close button at the bottom. + View closeButton = mContentView.findViewById(R.id.close_button); + mCloseButtonModel = + new PropertyModel.Builder(AppFilterProperties.CLOSE_BUTTON_KEY) + .with( + AppFilterProperties.CLOSE_BUTTON_CALLBACK, + v -> mBottomSheetController.hideContent(mSheetContent, true)) + .build(); + PropertyModelChangeProcessor.create( + mCloseButtonModel, closeButton, AppFilterViewBinder::bind); + + mMediator = new AppFilterMediator(context, listItems, appInfoList, this::closeSheet); + mAppCount = listItems.size(); + } + + @Override + public void onLayoutChange( + View view, + int left, + int top, + int right, + int bottom, + int oldLeft, + int oldTop, + int oldRight, + int oldBottom) { + if (!mBottomSheetController.isSheetOpen()) return; + if (mBaseViewHeight != mBaseView.getHeight()) { + mBaseViewHeight = mBaseView.getHeight(); + updateSheetHeight(); + } + } + + /** Open app filter bottom sheet. */ + public void openSheet() { + updateSheetHeight(); + mBottomSheetController.requestShowContent(mSheetContent, true); + } + + /** + * Update the sheet height. Called before opening it for the first time, or while it is open in + * order to adjust the height if the base view layout change occurs. + */ + private void updateSheetHeight() { + ViewGroup.LayoutParams layoutParams = mItemListView.getLayoutParams(); + if (layoutParams == null) { + layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); + } + + int rowHeight = mContext.getResources().getDimensionPixelSize(R.dimen.list_item_min_height); + layoutParams.height = calculateSheetHeight(rowHeight, mBaseView.getHeight(), mAppCount); + mItemListView.setLayoutParams(layoutParams); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static int calculateSheetHeight(int rowHeight, int baseViewHeight, int rowCount) { + int maxHeight = (int) (baseViewHeight * MAX_SHEET_HEIGHT_RATIO); + int visibleRowCount = Math.min(rowCount, MAX_VISIBLE_ITEM_COUNT); + return Math.min(visibleRowCount * rowHeight, maxHeight); + } + + private void closeSheet(AppInfo appInfo) { + mBottomSheetController.hideContent(mSheetContent, true); + mCloseCallback.onAppUpdated(appInfo); + } + + private void destroy() { + mBaseView.removeOnLayoutChangeListener(this); + } + + void clickItemForTesting(String appId) { + mMediator.clickItemForTesting(appId); // IN-TEST + } + + void clickCloseButtonForTesting() { + mCloseButtonModel.get(AppFilterProperties.CLOSE_BUTTON_CALLBACK).onClick(null); // IN-TEST + } + + void setCurrentAppForTesting(String appId) { + mMediator.setCurrentAppForTesting(appId); // IN-TEST + } +}
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java new file mode 100644 index 0000000..3344341 --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java
@@ -0,0 +1,237 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import static org.junit.Assert.assertEquals; + +import static org.chromium.chrome.browser.history.AppFilterCoordinator.MAX_SHEET_HEIGHT_RATIO; +import static org.chromium.chrome.browser.history.AppFilterCoordinator.MAX_VISIBLE_ITEM_COUNT; +import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.view.ViewGroup; + +import androidx.test.filters.MediumTest; +import androidx.test.filters.SmallTest; +import androidx.test.runner.lifecycle.Stage; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.test.util.ApplicationTestUtils; +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.history.AppFilterCoordinator.AppInfo; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerFactory; +import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.KeyboardVisibilityDelegate; +import org.chromium.ui.test.util.BlankUiTestActivity; + +import java.util.ArrayList; +import java.util.List; + +/** Integration tests for the app filter sheet for history page. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.PER_CLASS) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class AppFilterCoordinatorTest { + /** {@link AppInfo} indicating that no app is selected i.e. full history. */ + private static final AppInfo APP_NOTSELECTED = new AppInfo(null, null, null); + + private static final String APPID_YOUTUBE = "com.google.android.youtube"; + private static final String APPID_CHROME = "com.android.chrome"; + private static final String APPID_CALENDAR = "com.google.android.calendar"; + private static final String APPID_MESSAGE = "com.google.android.apps.messaging"; + + private static final CharSequence APPLABEL_YOUTUBE = "YouTube"; + private static final CharSequence APPLABEL_CHROME = "Chrome"; + private static final CharSequence APPLABEL_CALENDAR = "Calendar"; + private static final CharSequence APPLABEL_MESSAGE = "Message"; + + @Rule + public final BaseActivityTestRule<BlankUiTestActivity> mActivityRule = + new BaseActivityTestRule<>(BlankUiTestActivity.class); + + private BottomSheetController mBottomSheetController; + private AppFilterCoordinator mAppFilterSheet; + private Drawable mIcon; + private String mAppId; + private CharSequence mAppLabel; + + @Before + public void setUp() throws InterruptedException { + mActivityRule.launchActivity(null); + Activity activity = getActivity(); + ApplicationTestUtils.waitForActivityState(activity, Stage.RESUMED); + runOnUiThreadBlocking( + () -> { + mBottomSheetController = createBottomSheetController(); + + mIcon = activity.getResources().getDrawable(R.drawable.ic_devices_16dp); + List<AppInfo> apps = new ArrayList<>(); + apps.add(new AppInfo(APPID_YOUTUBE, mIcon, APPLABEL_YOUTUBE)); + apps.add(new AppInfo(APPID_CHROME, mIcon, APPLABEL_CHROME)); + apps.add(new AppInfo(APPID_CALENDAR, mIcon, APPLABEL_CALENDAR)); + apps.add(new AppInfo(APPID_MESSAGE, mIcon, APPLABEL_MESSAGE)); + mAppFilterSheet = + new AppFilterCoordinator( + activity, + activity.getWindow().getDecorView(), + mBottomSheetController, + this::onAppUpdated, + apps); + }); + } + + private BlankUiTestActivity getActivity() { + return mActivityRule.getActivity(); + } + + private BottomSheetController createBottomSheetController() { + ViewGroup activityContentView = getActivity().findViewById(android.R.id.content); + ScrimCoordinator scrimCoordinator = + new ScrimCoordinator( + getActivity(), + new ScrimCoordinator.SystemUiScrimDelegate() { + @Override + public void setStatusBarScrimFraction(float scrimFraction) {} + + @Override + public void setNavigationBarScrimFraction(float scrimFraction) {} + }, + activityContentView, + Color.WHITE); + return BottomSheetControllerFactory.createBottomSheetController( + () -> scrimCoordinator, + (unused) -> {}, + getActivity().getWindow(), + KeyboardVisibilityDelegate.getInstance(), + () -> activityContentView, + () -> 0); + } + + private void onAppUpdated(AppInfo appInfo) { + mAppId = appInfo != null ? appInfo.id : null; + mAppLabel = appInfo != null ? appInfo.label : null; + } + + private void setCurrentAppInfo(String appId, CharSequence appLabel) { + mAppId = appId; + mAppLabel = appLabel; + mAppFilterSheet.setCurrentAppForTesting(appId); + } + + private int calcSheetHeight(int rowHeight, int baseViewHeight, int rowCount) { + return AppFilterCoordinator.calculateSheetHeight(rowHeight, baseViewHeight, rowCount); + } + + @Test + @SmallTest + public void testSheetSize() { + final int rowHeight = 64; + final int baseHeight = 1200; + final int defaultMaxHeight = rowHeight * MAX_VISIBLE_ITEM_COUNT; + + int rowCount = MAX_VISIBLE_ITEM_COUNT - 1; + assertEquals(rowHeight * rowCount, calcSheetHeight(rowHeight, baseHeight, rowCount)); + + rowCount = MAX_VISIBLE_ITEM_COUNT; + assertEquals(rowHeight * rowCount, calcSheetHeight(rowHeight, baseHeight, rowCount)); + + rowCount = MAX_VISIBLE_ITEM_COUNT + 1; + assertEquals(defaultMaxHeight, calcSheetHeight(rowHeight, baseHeight, rowCount)); + + rowCount = MAX_VISIBLE_ITEM_COUNT * 2; + assertEquals(defaultMaxHeight, calcSheetHeight(rowHeight, baseHeight, rowCount)); + + final int smallBase = 300; + final int maxHeight = (int) (smallBase * MAX_SHEET_HEIGHT_RATIO); + + rowCount = 2; + assertEquals(rowHeight * rowCount, calcSheetHeight(rowHeight, smallBase, rowCount)); + + rowCount = MAX_VISIBLE_ITEM_COUNT; + assertEquals(maxHeight, calcSheetHeight(rowHeight, smallBase, rowCount)); + + rowCount = 100; + assertEquals(maxHeight, calcSheetHeight(rowHeight, smallBase, rowCount)); + } + + @Test + @MediumTest + public void testFullHistoryToApp() { + assertEquals("Selected app is not correct.", null, mAppId); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { + mAppFilterSheet.openSheet(); + mAppFilterSheet.clickItemForTesting(APPID_MESSAGE); + }); + + // Tapping an app selects it. + assertEquals("Chosen app is not correct.", APPID_MESSAGE, mAppId); + assertEquals("Chosen app is not correct.", APPLABEL_MESSAGE, mAppLabel); + } + + @Test + @MediumTest + public void testSelectNewApp() { + setCurrentAppInfo(APPID_CALENDAR, APPLABEL_CALENDAR); + assertEquals("Selected app is not correct.", APPID_CALENDAR, mAppId); + TestThreadUtils.runOnUiThreadBlocking( + () -> { + mAppFilterSheet.openSheet(); + mAppFilterSheet.clickItemForTesting(APPID_CHROME); + }); + + // Tapping an app makes it a newly selected one. + assertEquals("Chosen app is not correct.", APPID_CHROME, mAppId); + assertEquals("Chosen app is not correct.", APPLABEL_CHROME, mAppLabel); + } + + @Test + @MediumTest + public void testUnselectApp() { + setCurrentAppInfo(APPID_CALENDAR, APPLABEL_CALENDAR); + assertEquals("Selected app is not correct.", APPID_CALENDAR, mAppId); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { + mAppFilterSheet.openSheet(); + mAppFilterSheet.clickItemForTesting(APPID_CALENDAR); + }); + + // Tapping the already selected app unselects it. + assertEquals("Chosen app is not correct.", APP_NOTSELECTED.id, mAppId); + assertEquals("Chosen app is not correct.", APP_NOTSELECTED.label, mAppLabel); + } + + @Test + @MediumTest + public void testCloseSheetWithoutSelection() { + setCurrentAppInfo(APPID_CALENDAR, APPLABEL_CALENDAR); + assertEquals("Selected app is not correct.", APPID_CALENDAR, mAppId); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { + mAppFilterSheet.openSheet(); + mAppFilterSheet.clickCloseButtonForTesting(); + }); + + // Closing the sheet preserves the previously selected app. + assertEquals("Chosen app is not correct.", APPID_CALENDAR, mAppId); + assertEquals("Chosen app is not correct.", APPLABEL_CALENDAR, mAppLabel); + } +}
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java new file mode 100644 index 0000000..107eba3 --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java
@@ -0,0 +1,86 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import org.chromium.chrome.browser.history.AppFilterCoordinator.AppInfo; +import org.chromium.chrome.browser.history.AppFilterCoordinator.CloseCallback; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; + +import java.util.List; + +/** Mediator class for history app filter sheet. */ +class AppFilterMediator { + private final ModelList mModelList; + private final CloseCallback mCloseCallback; + + private @Nullable PropertyModel mSelectedModel; + + AppFilterMediator( + Context context, + ModelList modelList, + List<AppInfo> appInfoList, + CloseCallback closeCallback) { + mModelList = modelList; + mCloseCallback = closeCallback; + for (AppInfo info : appInfoList) { + PropertyModel item = generateListItem(info); + mModelList.add(new SimpleRecyclerViewAdapter.ListItem(0, item)); + } + } + + private @Nullable PropertyModel generateListItem(AppInfo info) { + PropertyModel model = + new PropertyModel.Builder(AppFilterProperties.LIST_ITEM_KEYS) + .with(AppFilterProperties.ID, info.id) + .with(AppFilterProperties.ICON, info.icon) + .with(AppFilterProperties.LABEL, info.label) + .with(AppFilterProperties.SELECTED, false) + .build(); + model.set(AppFilterProperties.CLICK_LISTENER, v -> handleClick(model)); + return model; + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + void handleClick(PropertyModel model) { + PropertyModel prevModel = mSelectedModel; + + String appId = model.get(AppFilterProperties.ID); + boolean toFullHistory = prevModel != null && prevModel == model; + + if (prevModel != null) prevModel.set(AppFilterProperties.SELECTED, false); + mSelectedModel = model; + if (toFullHistory) { + mCloseCallback.onAppUpdated(null); + } else { + mSelectedModel.set(AppFilterProperties.SELECTED, true); + AppInfo appInfo = new AppInfo(appId, null, model.get(AppFilterProperties.LABEL)); + mCloseCallback.onAppUpdated(appInfo); + } + } + + private PropertyModel getModelForAppIdForTesting(String appId) { + for (SimpleRecyclerViewAdapter.ListItem item : mModelList) { + if (appId.equals(item.model.get(AppFilterProperties.ID))) { + return item.model; + } + } + return null; + } + + void clickItemForTesting(String appId) { + handleClick(getModelForAppIdForTesting(appId)); + } + + void setCurrentAppForTesting(String appId) { + mSelectedModel = getModelForAppIdForTesting(appId); + } +}
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterProperties.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterProperties.java new file mode 100644 index 0000000..01d949f --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterProperties.java
@@ -0,0 +1,32 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import android.graphics.drawable.Drawable; +import android.view.View; + +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey; +import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; +import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; + +/** Property model properties for app filter sheet UI. */ +class AppFilterProperties { + public static final ReadableObjectPropertyKey<String> ID = new ReadableObjectPropertyKey(); + public static final ReadableObjectPropertyKey<Drawable> ICON = new ReadableObjectPropertyKey(); + public static final ReadableObjectPropertyKey<CharSequence> LABEL = + new ReadableObjectPropertyKey(); + public static final WritableObjectPropertyKey<View.OnClickListener> CLICK_LISTENER = + new WritableObjectPropertyKey(); + public static final WritableBooleanPropertyKey SELECTED = new WritableBooleanPropertyKey(); + public static final ReadableObjectPropertyKey<View.OnClickListener> CLOSE_BUTTON_CALLBACK = + new ReadableObjectPropertyKey(); + + /** Property keys for a list item. */ + public static final PropertyKey[] LIST_ITEM_KEYS = {ID, ICON, LABEL, CLICK_LISTENER, SELECTED}; + + /** Property keys for the close button. */ + public static final PropertyKey[] CLOSE_BUTTON_KEY = {CLOSE_BUTTON_CALLBACK}; +}
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java new file mode 100644 index 0000000..ce5f4cf --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java
@@ -0,0 +1,96 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; + +/** BottomSheetContent implementation for app filter bottom sheet. */ +class AppFilterSheetContent implements BottomSheetContent { + private final View mContentView; + private final View mToolbarView; + private final RecyclerView mListView; + private final Runnable mCloseRunnable; + + /** Construct a new AppFilterSheet. */ + AppFilterSheetContent( + Context context, View contentView, RecyclerView listView, Runnable closeRunnable) { + var layoutInflater = LayoutInflater.from(context); + mToolbarView = layoutInflater.inflate(R.layout.appfilter_header, null); + mContentView = contentView; + mListView = listView; + mCloseRunnable = closeRunnable; + } + + @Override + public View getContentView() { + return mContentView; + } + + @Override + public View getToolbarView() { + return mToolbarView; + } + + @Override + public int getVerticalScrollOffset() { + return mListView.computeVerticalScrollOffset(); + } + + @Override + public void destroy() { + mCloseRunnable.run(); + } + + @Override + public @ContentPriority int getPriority() { + return ContentPriority.HIGH; + } + + @Override + public boolean swipeToDismissEnabled() { + return true; + } + + @Override + public int getPeekHeight() { + return BottomSheetContent.HeightMode.DISABLED; + } + + @Override + public float getHalfHeightRatio() { + return BottomSheetContent.HeightMode.DISABLED; + } + + @Override + public float getFullHeightRatio() { + return BottomSheetContent.HeightMode.WRAP_CONTENT; + } + + @Override + public int getSheetContentDescriptionStringId() { + return R.string.history_app_filter_sheet_description; + } + + @Override + public int getSheetHalfHeightAccessibilityStringId() { + return 0; // disabled + } + + @Override + public int getSheetFullHeightAccessibilityStringId() { + return R.string.history_app_filter_sheet_opened; + } + + @Override + public int getSheetClosedAccessibilityStringId() { + return R.string.history_app_filter_sheet_closed; + } +}
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterViewBinder.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterViewBinder.java new file mode 100644 index 0000000..95390eb --- /dev/null +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterViewBinder.java
@@ -0,0 +1,36 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.history; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel; + +/** Binder object for the appfilter sheet content model and the view. */ +class AppFilterViewBinder { + static void bind(PropertyModel model, View view, PropertyKey key) { + if (AppFilterProperties.ICON == key) { + var icon = (ImageView) view.findViewById(R.id.start_icon); + icon.setImageDrawable(model.get(AppFilterProperties.ICON)); + icon.setScaleType(ImageView.ScaleType.FIT_CENTER); + } else if (AppFilterProperties.LABEL == key) { + ((TextView) view.findViewById(R.id.title)) + .setText(model.get(AppFilterProperties.LABEL)); + view.findViewById(R.id.description).setVisibility(View.GONE); + } else if (AppFilterProperties.SELECTED == key) { + var checkMark = (ImageView) view.findViewById(R.id.end_button); + checkMark.setImageResource(R.drawable.ic_check_googblue_24dp); + boolean selected = model.get(AppFilterProperties.SELECTED); + checkMark.setVisibility(selected ? View.VISIBLE : View.INVISIBLE); + } else if (AppFilterProperties.CLICK_LISTENER == key) { + view.setOnClickListener(model.get(AppFilterProperties.CLICK_LISTENER)); + } else if (AppFilterProperties.CLOSE_BUTTON_CALLBACK == key) { + view.setOnClickListener(model.get(AppFilterProperties.CLOSE_BUTTON_CALLBACK)); + } + } +}
diff --git a/chrome/browser/model_execution/model_manager_impl.cc b/chrome/browser/model_execution/model_manager_impl.cc index e3012692..f9bcc1e 100644 --- a/chrome/browser/model_execution/model_manager_impl.cc +++ b/chrome/browser/model_execution/model_manager_impl.cc
@@ -4,16 +4,23 @@ #include "chrome/browser/model_execution/model_manager_impl.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/functional/bind.h" +#include "base/strings/stringprintf.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "chrome/browser/model_execution/model_execution_session.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/optimization_guide/core/model_execution/feature_keys.h" +#include "components/optimization_guide/core/model_util.h" #include "components/optimization_guide/core/optimization_guide_features.h" -#include "content/public/browser/content_browser_client.h" +#include "components/optimization_guide/core/optimization_guide_switches.h" #include "content/public/browser/render_frame_host.h" -#include "content/public/common/content_client.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h" #include "third_party/blink/public/mojom/model_execution/model_manager.mojom.h" DOCUMENT_USER_DATA_KEY_IMPL(ModelManagerImpl); @@ -34,15 +41,63 @@ model_manager->receiver_.Bind(std::move(receiver)); } +bool ModelManagerImpl::IsModelPathValid(const std::string& model_path_str) { + std::optional<base::FilePath> model_path = + optimization_guide::StringToFilePath(model_path_str); + if (!model_path) { + return false; + } + return base::PathExists(*model_path); +} + void ModelManagerImpl::CanCreateGenericSession( CanCreateGenericSessionCallback callback) { - // TODO(leimy): add the checks after optimization guide component provide more - // method to determine if a session could be started. + // If the `OptimizationGuideKeyedService` cannot be retrieved, return false. + // TODO(https://crbug.com/330819915): add the checks after optimization guide + // component provide more method to determine if a session could be started. content::BrowserContext* browser_context = browser_context_.get(); - std::move(callback).Run( - /*can_create=*/browser_context && - !!OptimizationGuideKeyedServiceFactory::GetForProfile( - Profile::FromBrowserContext(browser_context))); + CHECK(browser_context); + if (!OptimizationGuideKeyedServiceFactory::GetForProfile( + Profile::FromBrowserContext(browser_context))) { + render_frame_host().AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kWarning, + "Unable to create generic session because the service is not running."); + std::move(callback).Run(/*can_create=*/false); + return; + } + + // If the model path is empty or invalid, return false. + auto model_path = + optimization_guide::switches::GetOnDeviceModelExecutionOverride(); + if (!model_path) { + render_frame_host().AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kWarning, + "Unable to create generic session because the model path is not " + "provided."); + std::move(callback).Run(/*can_create=*/false); + return; + } + + // This needs to be done in a task runner with `MayBlock` trait. + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ModelManagerImpl::IsModelPathValid, + base::Unretained(this), model_path.value()), + base::BindOnce( + [](CanCreateGenericSessionCallback callback, + content::RenderFrameHost& rfh, const std::string& model_path, + bool is_valid_path) { + if (!is_valid_path) { + rfh.AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kWarning, + base::StringPrintf("Unable to create generic session because " + "the model path ('%s') is invalid.", + model_path.c_str())); + } + std::move(callback).Run(is_valid_path); + }, + std::move(callback), std::ref(render_frame_host()), + model_path.value())); } void ModelManagerImpl::CreateGenericSession(
diff --git a/chrome/browser/model_execution/model_manager_impl.h b/chrome/browser/model_execution/model_manager_impl.h index 69fccbe..c7967d4c 100644 --- a/chrome/browser/model_execution/model_manager_impl.h +++ b/chrome/browser/model_execution/model_manager_impl.h
@@ -34,6 +34,9 @@ explicit ModelManagerImpl(content::RenderFrameHost* rfh); + // Checks if the model path configured via command line is valid. + bool IsModelPathValid(const std::string& model_path); + // `blink::mojom::ModelManager` implementation. void CanCreateGenericSession( CanCreateGenericSessionCallback callback) override;
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/LocalTabGroupMutationHelper.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/LocalTabGroupMutationHelper.java index 9d1975e..f9a0d3b 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/LocalTabGroupMutationHelper.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/LocalTabGroupMutationHelper.java
@@ -74,7 +74,7 @@ tabs, tabs.get(0), /* isSameGroup= */ true, /* notify= */ false); // Notify sync backend about IDs of the newly created group and tabs. - mTabGroupSyncService.updateLocalTabGroupId(tabGroup.syncId, groupId); + mTabGroupSyncService.updateLocalTabGroupMapping(tabGroup.syncId, groupId); for (String syncTabId : tabIdMappings.keySet()) { mTabGroupSyncService.updateLocalTabId(groupId, syncTabId, tabIdMappings.get(syncTabId)); }
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelper.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelper.java index 3220508..e7a5581 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelper.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelper.java
@@ -98,7 +98,7 @@ Integer localGroupId = idMappingsFromPref.get(syncGroupId); if (localGroupId == null) continue; - mTabGroupSyncService.updateLocalTabGroupId(syncGroupId, localGroupId); + mTabGroupSyncService.updateLocalTabGroupMapping(syncGroupId, localGroupId); } }
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelperUnitTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelperUnitTest.java index dac3ae5..75ff63c 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelperUnitTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/StartupHelperUnitTest.java
@@ -78,7 +78,7 @@ when(mTabGroupModelFilter.getTabGroupSyncId(1)).thenReturn(SYNC_ID_1); when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_ID_1}); mStartupHelper.initializeTabGroupSync(); - verify(mTabGroupSyncService).updateLocalTabGroupId(eq(SYNC_ID_1), eq(1)); + verify(mTabGroupSyncService).updateLocalTabGroupMapping(eq(SYNC_ID_1), eq(1)); } @Test
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java index e767b3f..0379eb1 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java
@@ -88,7 +88,7 @@ .mergeListOfTabsToGroup(anyList(), any(), anyBoolean(), anyBoolean()); verify(mTabGroupModelFilter).setTabGroupColor(anyInt(), anyInt()); verify(mTabGroupModelFilter).setTabGroupTitle(anyInt(), any()); - verify(mTabGroupSyncService).updateLocalTabGroupId(any(), anyInt()); + verify(mTabGroupSyncService).updateLocalTabGroupMapping(any(), anyInt()); verify(mTabGroupSyncService, times(2)).updateLocalTabId(anyInt(), any(), anyInt()); }
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TestTabGroupSyncService.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TestTabGroupSyncService.java index 9c70d8e..d155ee0 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TestTabGroupSyncService.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TestTabGroupSyncService.java
@@ -65,7 +65,10 @@ } @Override - public void updateLocalTabGroupId(String syncId, int localId) {} + public void updateLocalTabGroupMapping(String syncId, int localId) {} + + @Override + public void removeLocalTabGroupMapping(int localId) {} @Override public void updateLocalTabId(int localGroupId, String syncTabId, int localTabId) {}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index ca54ecd..6b31fe6 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -64,6 +64,8 @@ "autofill/autofill_popup_hide_helper.h", "autofill/autofill_popup_view.h", "autofill/autofill_popup_view_delegate.h", + "autofill/autofill_suggestion_controller_utils.cc", + "autofill/autofill_suggestion_controller_utils.h", "autofill/chrome_autofill_client.cc", "autofill/chrome_autofill_client.h", "autofill/next_idle_time_ticks.cc", @@ -953,6 +955,9 @@ "autofill/autofill_bubble_base.h", "autofill/autofill_bubble_controller_base.cc", "autofill/autofill_bubble_controller_base.h", + "autofill/autofill_keyboard_accessory_controller.h", + "autofill/autofill_keyboard_accessory_controller_impl.cc", + "autofill/autofill_keyboard_accessory_controller_impl.h", "autofill/payments/autofill_snackbar_controller.h", "autofill/payments/autofill_snackbar_controller_impl.cc", "autofill/payments/autofill_snackbar_controller_impl.h",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 07b70ad..57538fee 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1720,6 +1720,20 @@ Learn more about <ph name="BEGIN_LINK"><link></ph>how Chrome keeps your data private<ph name="END_LINK"></link></ph> </message> + <!-- History App filter --> + <message name="IDS_HISTORY_APP_FILTER_SHEET_HEADER" desc="Title in the header of history app filter sheet."> + Filter by app + </message> + <message name="IDS_HISTORY_APP_FILTER_SHEET_DESCRIPTION" desc="The content description of history app filter where an app id to filter the history with can be chosen."> + App filter sheet + </message> + <message name="IDS_HISTORY_APP_FILTER_SHEET_OPENED" desc="The accessibility string read when the app filter sheet is fully opened."> + App filter sheet is opened. + </message> + <message name="IDS_HISTORY_APP_FILTER_SHEET_CLOSED" desc="The accessibility string read when the app filter sheet is closed."> + App filter sheet is closed. + </message> + <!-- Safe Browsing standard protection preferences --> <message name="IDS_SAFE_BROWSING_STANDARD_PROTECTION_SUBTITLE" desc="Subtitle for Safe Browsing standard protection mode."> Standard protection:
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_CLOSED.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_CLOSED.png.sha1 new file mode 100644 index 0000000..7342f3d --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_CLOSED.png.sha1
@@ -0,0 +1 @@ +e74641ec28634952df75cb08cf8e423ddd5319a6 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..7342f3d --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +e74641ec28634952df75cb08cf8e423ddd5319a6 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_HEADER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_HEADER.png.sha1 new file mode 100644 index 0000000..7342f3d --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_HEADER.png.sha1
@@ -0,0 +1 @@ +e74641ec28634952df75cb08cf8e423ddd5319a6 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_OPENED.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_OPENED.png.sha1 new file mode 100644 index 0000000..7342f3d --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_HISTORY_APP_FILTER_SHEET_OPENED.png.sha1
@@ -0,0 +1 @@ +e74641ec28634952df75cb08cf8e423ddd5319a6 \ No newline at end of file
diff --git a/chrome/browser/ui/ash/birch/birch_keyed_service_factory.cc b/chrome/browser/ui/ash/birch/birch_keyed_service_factory.cc index 22f23ab4..4d9a10a5 100644 --- a/chrome/browser/ui/ash/birch/birch_keyed_service_factory.cc +++ b/chrome/browser/ui/ash/birch/birch_keyed_service_factory.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "ash/constants/ash_features.h" +#include "ash/utility/forest_util.h" #include "base/no_destructor.h" #include "chrome/browser/ash/file_suggest/file_suggest_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" @@ -39,7 +39,7 @@ content::BrowserContext* context) { return static_cast<BirchKeyedService*>( GetInstance()->GetServiceForBrowserContext( - context, /*create=*/features::IsForestFeatureEnabled())); + context, /*create=*/IsForestFeatureEnabled())); } std::unique_ptr<KeyedService>
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc index 0f5ea7f..9ca791d6 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
@@ -835,14 +835,7 @@ if (target_index < 0 || model_->IsAppPinned(app_id)) return; - ash::ShelfItem item; - item.type = ash::TYPE_PINNED_APP; - item.id = ash::ShelfID(app_id); - - model_->AddAt(target_index, item, - std::make_unique<AppShortcutShelfItemController>(item.id)); - - ReportUpdateShelfIconList(model_); + EnsureAppPinnedInModelAtIndex(app_id, /*current_index=*/-1, target_index); } int ChromeShelfController::PinnedItemIndexByAppID(const std::string& app_id) {
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h index 3d4395f..7f639e7 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h
@@ -250,11 +250,7 @@ void ReplacePinnedItem(const std::string& old_app_id, const std::string& new_app_id); - // This method is only used by ApkWebAppService and tests. This method - // relies on implicit assumptions and is likely unsuitable for other use - // cases. - // - // Pins app with |app_id| at |target_index|. + // Pins app with |app_id| at |target_index| if it is not already pinned. void PinAppAtIndex(const std::string& app_id, int target_index); // Converts |app_id| to shelf_id and calls ShelfModel function ItemIndexbyID
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc index a9022f6d..e6f389c 100644 --- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc
@@ -251,6 +251,11 @@ NOTREACHED(); } +void AutofillKeyboardAccessoryAdapter::SetViewForTesting( + base::WeakPtr<AutofillPopupView> view) { + NOTREACHED(); +} + void AutofillKeyboardAccessoryAdapter::UpdateDataListValues( base::span<const SelectOption> options) { NOTREACHED();
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h index 880aef09..5a0a9d1 100644 --- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h
@@ -132,6 +132,7 @@ AutoselectFirstSuggestion autoselect_first_suggestion) override; void DisableThresholdForTesting(bool disable_threshold) override; void KeepPopupOpenForTesting() override; + void SetViewForTesting(base::WeakPtr<AutofillPopupView> view) override; void UpdateDataListValues(base::span<const SelectOption> options) override; void PinView() override;
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h new file mode 100644 index 0000000..6768ce5 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h
@@ -0,0 +1,18 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_H_ + +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" + +namespace autofill { + +class AutofillKeyboardAccessoryController : public AutofillPopupController { + public: +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_H_
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc new file mode 100644 index 0000000..e22b1f3 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
@@ -0,0 +1,578 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/check_op.h" +#include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_functions.h" +#include "base/notreached.h" +#include "base/time/time.h" +#include "chrome/browser/autofill/personal_data_manager_factory.h" +#include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h" +#include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" +#include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h" +#include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/ui/autofill_popup_delegate.h" +#include "components/autofill/core/browser/ui/popup_hiding_reasons.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/password_manager/core/browser/password_manager_metrics_util.h" +#include "components/password_manager/core/common/password_manager_features.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/l10n/l10n_util.h" + +namespace autofill { + +using FillingSource = ManualFillingController::FillingSource; + +// static +base::WeakPtr<AutofillPopupController> AutofillPopupController::GetOrCreate( + base::WeakPtr<AutofillPopupController> previous, + base::WeakPtr<AutofillPopupDelegate> delegate, + content::WebContents* web_contents, + PopupControllerCommon controller_common, + int32_t form_control_ax_id) { + // All controllers on Android derive from + // `AutofillKeyboardAccessoryControllerImpl`. + if (AutofillKeyboardAccessoryControllerImpl* previous_impl = + static_cast<AutofillKeyboardAccessoryControllerImpl*>(previous.get()); + previous_impl && previous_impl->delegate_.get() == delegate.get() && + previous_impl->container_view() == controller_common.container_view) { + if (previous_impl->self_deletion_weak_ptr_factory_.HasWeakPtrs()) { + previous_impl->self_deletion_weak_ptr_factory_.InvalidateWeakPtrs(); + } + previous_impl->controller_common_ = std::move(controller_common); + previous_impl->suggestions_.clear(); + return previous_impl->GetWeakPtr(); + } + + if (previous) { + previous->Hide(PopupHidingReason::kViewDestroyed); + } + auto* controller = new AutofillKeyboardAccessoryControllerImpl( + delegate, web_contents, std::move(controller_common), + base::BindRepeating(&local_password_migration::ShowWarning)); + return controller->GetWeakPtr(); +} + +AutofillKeyboardAccessoryControllerImpl:: + AutofillKeyboardAccessoryControllerImpl( + base::WeakPtr<AutofillPopupDelegate> delegate, + content::WebContents* web_contents, + PopupControllerCommon controller_common, + ShowPasswordMigrationWarningCallback + show_pwd_migration_warning_callback) + : delegate_(delegate), + web_contents_(web_contents->GetWeakPtr()), + controller_common_(std::move(controller_common)), + show_pwd_migration_warning_callback_( + std::move(show_pwd_migration_warning_callback)) {} + +AutofillKeyboardAccessoryControllerImpl:: + ~AutofillKeyboardAccessoryControllerImpl() = default; + +void AutofillKeyboardAccessoryControllerImpl::Hide(PopupHidingReason reason) { + // If the reason for hiding is only stale data or a user interacting with + // native Chrome UI (kFocusChanged/kEndEditing), the popup might be kept open. + if (is_view_pinned_ && (reason == PopupHidingReason::kStaleData || + reason == PopupHidingReason::kFocusChanged || + reason == PopupHidingReason::kEndEditing)) { + return; // Don't close the popup while waiting for an update. + } + // For tests, keep open when hiding is due to external stimuli. + if (keep_popup_open_for_testing_ && + (reason == PopupHidingReason::kWidgetChanged || + reason == PopupHidingReason::kEndEditing)) { + // Don't close the popup because the browser window is resized or because + // too many fields get focus one after each other (this can happen on + // Desktop, if multiple password forms are present, and they are all + // autofilled by default). + return; + } + + if (delegate_) { + delegate_->ClearPreviewedForm(); + delegate_->OnPopupHidden(); + } + popup_hide_helper_.reset(); + AutofillMetrics::LogAutofillPopupHidingReason(reason); + HideViewAndDie(); +} + +void AutofillKeyboardAccessoryControllerImpl::HideViewAndDie() { + // Invalidates in particular ChromeAutofillClient's WeakPtr to `this`, which + // prevents recursive calls triggered by `view_->Hide()` + // (crbug.com/1267047). + weak_ptr_factory_.InvalidateWeakPtrs(); + + // Mark the popup-like filling sources as unavailable. + // Note: We don't invoke ManualFillingController::Hide() here, as we might + // switch between text input fields. + if (web_contents_) { + if (base::WeakPtr<ManualFillingController> manual_filling_controller = + ManualFillingController::GetOrCreate(web_contents_.get())) { + manual_filling_controller->UpdateSourceAvailability( + FillingSource::AUTOFILL, + /*has_suggestions=*/false); + } + } + + // TODO(crbug.com/1341374, crbug.com/1277218): Move this into the asynchronous + // call? + if (view_) { + view_->Hide(); + view_ = nullptr; + } + + if (self_deletion_weak_ptr_factory_.HasWeakPtrs()) { + return; + } + + // TODO: Examine whether this is really enough or revert to the one from + // the popup controller. + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce( + [](base::WeakPtr<AutofillKeyboardAccessoryControllerImpl> weak_this) { + delete weak_this.get(); + }, + self_deletion_weak_ptr_factory_.GetWeakPtr())); +} + +void AutofillKeyboardAccessoryControllerImpl::ViewDestroyed() { + Hide(PopupHidingReason::kViewDestroyed); +} + +gfx::NativeView AutofillKeyboardAccessoryControllerImpl::container_view() + const { + return controller_common_.container_view; +} + +content::WebContents* AutofillKeyboardAccessoryControllerImpl::GetWebContents() + const { + return web_contents_.get(); +} + +const gfx::RectF& AutofillKeyboardAccessoryControllerImpl::element_bounds() + const { + return controller_common_.element_bounds; +} + +base::i18n::TextDirection +AutofillKeyboardAccessoryControllerImpl::GetElementTextDirection() const { + return controller_common_.text_direction; +} + +void AutofillKeyboardAccessoryControllerImpl::OnSuggestionsChanged() { + // Assume that suggestions are (still) available. If this is wrong, the method + // `HideViewAndDie` will be called soon after and will hide all suggestions. + if (base::WeakPtr<ManualFillingController> manual_filling_controller = + ManualFillingController::GetOrCreate(web_contents_.get())) { + manual_filling_controller->UpdateSourceAvailability( + FillingSource::AUTOFILL, + /*has_suggestions=*/true); + } + if (view_) { + view_->OnSuggestionsChanged(); + } +} + +void AutofillKeyboardAccessoryControllerImpl::SelectSuggestion(int index) { + CHECK_GE(index, 0); + CHECK_LT(index, static_cast<int>(suggestions_.size())); + + if (!IsAcceptablePopupItemId(GetSuggestionAt(index).popup_item_id)) { + UnselectSuggestion(); + return; + } + + delegate_->DidSelectSuggestion(GetSuggestionAt(index)); +} + +void AutofillKeyboardAccessoryControllerImpl::UnselectSuggestion() { + delegate_->ClearPreviewedForm(); +} + +void AutofillKeyboardAccessoryControllerImpl::AcceptSuggestion(int index) { + // Ignore clicks immediately after the popup was shown. This is to prevent + // users accidentally accepting suggestions (crbug.com/1279268). + if (time_view_shown_.value().is_null() && !disable_threshold_for_testing_) { + return; + } + const base::TimeDelta time_elapsed = + base::TimeTicks::Now() - time_view_shown_.value(); + // If `kAutofillPopupImprovedTimingChecksV2` is enabled, then + // `time_view_shown_` will remain null for at least + // `kIgnoreEarlyClicksOnPopupDuration`. Therefore we do not have to check any + // times here. + // TODO(crbug.com/1475902): Once `kAutofillPopupImprovedTimingChecksV2` is + // launched, clean up most of the timing checks. That is: + // - Remove paint checks inside views. + // - Remove `event_time` parameters. + // - Rename `NextIdleTimeTicks` to `IdleDelayBarrier` or something similar + // that indicates that just contains a boolean signaling whether a certain + // delay has (safely) passed. + if (time_elapsed < kIgnoreEarlyClicksOnPopupDuration && + !disable_threshold_for_testing_ && + !base::FeatureList::IsEnabled( + features::kAutofillPopupImprovedTimingChecksV2)) { + base::UmaHistogramCustomTimes( + "Autofill.Popup.AcceptanceDelayThresholdNotMet", time_elapsed, + base::Milliseconds(0), kIgnoreEarlyClicksOnPopupDuration, + /*buckets=*/50); + return; + } + + if (static_cast<size_t>(index) >= suggestions_.size()) { + return; + } + + if (IsPointerLocked(web_contents_.get())) { + Hide(PopupHidingReason::kMouseLocked); + return; + } + + // Use a copy instead of a reference here. Under certain circumstances, + // `DidAcceptSuggestion()` invalidate the reference. + Suggestion suggestion = suggestions_[index]; + if (base::WeakPtr<ManualFillingController> manual_filling_controller = + ManualFillingController::GetOrCreate(web_contents_.get())) { + // Accepting a suggestion should hide all suggestions. To prevent them from + // coming up in Multi-Window mode, mark the source as unavailable. + manual_filling_controller->UpdateSourceAvailability( + FillingSource::AUTOFILL, + /*has_suggestions=*/false); + manual_filling_controller->Hide(); + } + + NotifyIphAboutAcceptedSuggestion(web_contents_->GetBrowserContext(), + suggestion); + if (suggestion.acceptance_a11y_announcement && view_) { + view_->AxAnnounce(*suggestion.acceptance_a11y_announcement); + } + + delegate_->DidAcceptSuggestion( + suggestion, AutofillPopupDelegate::SuggestionPosition{.row = index}); + + if (suggestion.popup_item_id == PopupItemId::kPasswordEntry && + base::FeatureList::IsEnabled( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsMigrationWarning)) { + show_pwd_migration_warning_callback_.Run( + web_contents_->GetTopLevelNativeWindow(), + Profile::FromBrowserContext(web_contents_->GetBrowserContext()), + password_manager::metrics_util::PasswordMigrationWarningTriggers:: + kKeyboardAcessoryBar); + } +} + +void AutofillKeyboardAccessoryControllerImpl::PerformButtonActionForSuggestion( + int index) { + NOTREACHED() << "Button actions do not exist for the keyboard accessory."; +} + +bool AutofillKeyboardAccessoryControllerImpl::RemoveSuggestion( + int index, + AutofillMetrics::SingleEntryRemovalMethod removal_method) { + CHECK_EQ(removal_method, + AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory); + + // This function might be called in a callback, so ensure the list index is + // still in bounds. If not, terminate the removing and consider it failed. + // TODO(crbug.com/1209792): Replace these checks with a stronger identifier. + if (index < 0 || static_cast<size_t>(index) >= suggestions_.size()) { + return false; + } + + if (!delegate_->RemoveSuggestion(suggestions_[index])) { + return false; + } + PopupItemId suggestion_type = suggestions_[index].popup_item_id; + switch (GetFillingProductFromPopupItemId(suggestion_type)) { + case FillingProduct::kAddress: + AutofillMetrics::LogDeleteAddressProfileFromKeyboardAccessory(); + break; + case FillingProduct::kAutocomplete: + AutofillMetrics::OnAutocompleteSuggestionDeleted(removal_method); + if (view_) { + view_->AxAnnounce(l10n_util::GetStringFUTF16( + IDS_AUTOFILL_AUTOCOMPLETE_ENTRY_DELETED_A11Y_HINT, + suggestions_[index].main_text.value)); + } + break; + case FillingProduct::kCreditCard: + // TODO(1509457): Add metrics for credit cards. + break; + case FillingProduct::kNone: + case FillingProduct::kMerchantPromoCode: + case FillingProduct::kIban: + case FillingProduct::kPassword: + case FillingProduct::kCompose: + case FillingProduct::kPlusAddresses: + break; + } + + // Remove the deleted element. + suggestions_.erase(suggestions_.begin() + index); + + if (HasSuggestions()) { + delegate_->ClearPreviewedForm(); + OnSuggestionsChanged(); + } else { + Hide(PopupHidingReason::kNoSuggestions); + } + + return true; +} + +int AutofillKeyboardAccessoryControllerImpl::GetLineCount() const { + return suggestions_.size(); +} + +std::vector<Suggestion> +AutofillKeyboardAccessoryControllerImpl::GetSuggestions() const { + return suggestions_; +} + +const Suggestion& AutofillKeyboardAccessoryControllerImpl::GetSuggestionAt( + int row) const { + return suggestions_[row]; +} + +std::u16string AutofillKeyboardAccessoryControllerImpl::GetSuggestionMainTextAt( + int row) const { + return suggestions_[row].main_text.value; +} + +std::u16string +AutofillKeyboardAccessoryControllerImpl::GetSuggestionMinorTextAt( + int row) const { + return suggestions_[row].minor_text.value; +} + +std::vector<std::vector<Suggestion::Text>> +AutofillKeyboardAccessoryControllerImpl::GetSuggestionLabelsAt(int row) const { + return suggestions_[row].labels; +} + +bool AutofillKeyboardAccessoryControllerImpl::GetRemovalConfirmationText( + int index, + std::u16string* title, + std::u16string* body) { + const std::u16string& value = suggestions_[index].main_text.value; + const PopupItemId popup_item_id = suggestions_[index].popup_item_id; + const Suggestion::BackendId backend_id = + suggestions_[index].GetPayload<Suggestion::BackendId>(); + + if (popup_item_id == PopupItemId::kAutocompleteEntry) { + if (title) { + title->assign(value); + } + if (body) { + body->assign(l10n_util::GetStringUTF16( + IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY)); + } + return true; + } + + if (popup_item_id != PopupItemId::kAddressEntry && + popup_item_id != PopupItemId::kCreditCardEntry) { + return false; + } + PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext( + web_contents_->GetBrowserContext()); + + if (const CreditCard* credit_card = pdm->GetCreditCardByGUID( + absl::get<Suggestion::Guid>(backend_id).value())) { + if (!CreditCard::IsLocalCard(credit_card)) { + return false; + } + if (title) { + title->assign(credit_card->CardNameAndLastFourDigits()); + } + if (body) { + body->assign(l10n_util::GetStringUTF16( + IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY)); + } + return true; + } + + if (const AutofillProfile* profile = pdm->GetProfileByGUID( + absl::get<Suggestion::Guid>(backend_id).value())) { + if (title) { + std::u16string street_address = profile->GetRawInfo(ADDRESS_HOME_CITY); + if (!street_address.empty()) { + title->swap(street_address); + } else { + title->assign(value); + } + } + if (body) { + body->assign(l10n_util::GetStringUTF16( + IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY)); + } + + return true; + } + + return false; // The ID was valid. The entry may have been deleted in a race. +} + +FillingProduct AutofillKeyboardAccessoryControllerImpl::GetMainFillingProduct() + const { + return delegate_->GetMainFillingProduct(); +} + +bool AutofillKeyboardAccessoryControllerImpl:: + ShouldIgnoreMouseObservedOutsideItemBoundsCheck() const { + return false; +} + +base::WeakPtr<AutofillPopupController> +AutofillKeyboardAccessoryControllerImpl::OpenSubPopup( + const gfx::RectF& anchor_bounds, + std::vector<Suggestion> suggestions, + AutoselectFirstSuggestion autoselect_first_suggestion) { + NOTREACHED_NORETURN() << "Sub-popups do not exist in the keyboard accessory."; +} + +void AutofillKeyboardAccessoryControllerImpl::HideSubPopup() { + NOTREACHED() << "Sub-popups do not exist in the keyboard accessory."; +} + +std::optional<AutofillClient::PopupScreenLocation> +AutofillKeyboardAccessoryControllerImpl::GetPopupScreenLocation() const { + return std::nullopt; +} + +void AutofillKeyboardAccessoryControllerImpl::Show( + std::vector<Suggestion> suggestions, + AutofillSuggestionTriggerSource trigger_source, + AutoselectFirstSuggestion autoselect_first_suggestion) { + if (auto* rwhv = web_contents_->GetRenderWidgetHostView(); + !rwhv || !rwhv->HasFocus()) { + return; + } + + // The focused frame may be a different frame than the one the delegate is + // associated with. This happens in two scenarios: + // - With frame-transcending forms: the focused frame is subframe, whose + // form has been flattened into an ancestor form. + // - With race conditions: while Autofill parsed the form, the focused may + // have moved to another frame. + // We support the case where the focused frame is a descendant of the + // `delegate_`'s frame. We observe the focused frame's RenderFrameDeleted() + // event. + content::RenderFrameHost* rfh = web_contents_->GetFocusedFrame(); + if (!rfh || !delegate_ || + !IsAncestorOf(GetRenderFrameHost(*delegate_), rfh)) { + Hide(PopupHidingReason::kNoFrameHasFocus); + return; + } + + if (IsPointerLocked(web_contents_.get())) { + Hide(PopupHidingReason::kMouseLocked); + return; + } + + AutofillPopupHideHelper::HidingParams hiding_params = { + // Currently, this is only relevant for Compose on Desktop. + .hide_on_text_field_change = false, + .hide_on_web_contents_lost_focus = true}; + AutofillPopupHideHelper::HidingCallback hiding_callback = base::BindRepeating( + &AutofillKeyboardAccessoryControllerImpl::Hide, base::Unretained(this)); + AutofillPopupHideHelper::PictureInPictureDetectionCallback + pip_detection_callback = base::BindRepeating( + [](base::WeakPtr<AutofillKeyboardAccessoryControllerImpl> + controller) { + return controller && controller->view_ && + controller->view_->OverlapsWithPictureInPictureWindow(); + }, + GetWeakPtr()); + popup_hide_helper_.emplace( + web_contents_.get(), rfh->GetGlobalId(), std::move(hiding_params), + std::move(hiding_callback), std::move(pip_detection_callback)); + + suggestions_ = std::move(suggestions); + trigger_source_ = trigger_source; + + if (view_) { + OnSuggestionsChanged(); + } else { + view_ = AutofillPopupView::Create(GetWeakPtr()); + // It is possible to fail to create the popup. + if (!view_) { + Hide(PopupHidingReason::kViewDestroyed); + return; + } + + if (base::WeakPtr<ManualFillingController> manual_filling_controller = + ManualFillingController::GetOrCreate(web_contents_.get())) { + manual_filling_controller->UpdateSourceAvailability( + FillingSource::AUTOFILL, !suggestions_.empty()); + } + if (!view_ || !view_->Show(autoselect_first_suggestion)) { + return; + } + } + + time_view_shown_ = base::FeatureList::IsEnabled( + features::kAutofillPopupImprovedTimingChecksV2) + ? NextIdleTimeTicks::CaptureNextIdleTimeTicksWithDelay( + kIgnoreEarlyClicksOnPopupDuration) + : NextIdleTimeTicks::CaptureNextIdleTimeTicks(); +} + +void AutofillKeyboardAccessoryControllerImpl::DisableThresholdForTesting( + bool disable_threshold) { + disable_threshold_for_testing_ = disable_threshold; +} + +void AutofillKeyboardAccessoryControllerImpl::KeepPopupOpenForTesting() { + keep_popup_open_for_testing_ = true; +} + +void AutofillKeyboardAccessoryControllerImpl::SetViewForTesting( + base::WeakPtr<AutofillPopupView> view) { + view_ = std::move(view); + time_view_shown_ = NextIdleTimeTicks::CaptureNextIdleTimeTicks(); +} + +void AutofillKeyboardAccessoryControllerImpl::UpdateDataListValues( + base::span<const SelectOption> options) { + UpdateSuggestionsFromDataList(options, suggestions_); + if (HasSuggestions()) { + OnSuggestionsChanged(); + } else { + Hide(PopupHidingReason::kNoSuggestions); + } +} + +void AutofillKeyboardAccessoryControllerImpl::PinView() { + is_view_pinned_ = true; +} + +bool AutofillKeyboardAccessoryControllerImpl::HasSuggestions() const { + if (suggestions_.empty()) { + return false; + } + PopupItemId popup_item_id = suggestions_[0].popup_item_id; + return base::Contains(kItemsTriggeringFieldFilling, popup_item_id) || + popup_item_id == PopupItemId::kScanCreditCard; +} + +base::WeakPtr<AutofillKeyboardAccessoryControllerImpl> +AutofillKeyboardAccessoryControllerImpl::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + +} // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h new file mode 100644 index 0000000..b638aab --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
@@ -0,0 +1,158 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_H_ + +#include <optional> +#include <string> +#include <vector> + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h" +#include "chrome/browser/ui/autofill/autofill_popup_hide_helper.h" +#include "chrome/browser/ui/autofill/next_idle_time_ticks.h" +#include "chrome/browser/ui/autofill/popup_controller_common.h" +#include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/metrics/autofill_metrics.h" +#include "components/autofill/core/browser/ui/suggestion.h" +#include "components/password_manager/core/browser/password_manager_metrics_util.h" + +namespace content { +class WebContents; +} // namespace content + +class Profile; + +namespace autofill { + +class AutofillPopupDelegate; +class AutofillPopupView; +struct Suggestion; + +class AutofillKeyboardAccessoryControllerImpl + : public AutofillKeyboardAccessoryController { + public: + using ShowPasswordMigrationWarningCallback = base::RepeatingCallback<void( + gfx::NativeWindow, + Profile*, + password_manager::metrics_util::PasswordMigrationWarningTriggers)>; + + AutofillKeyboardAccessoryControllerImpl( + base::WeakPtr<AutofillPopupDelegate> delegate, + content::WebContents* web_contents, + PopupControllerCommon controller_common, + ShowPasswordMigrationWarningCallback show_pwd_migration_warning_callback); + + AutofillKeyboardAccessoryControllerImpl( + const AutofillKeyboardAccessoryControllerImpl&) = delete; + AutofillKeyboardAccessoryControllerImpl& operator=( + const AutofillKeyboardAccessoryControllerImpl&) = delete; + + ~AutofillKeyboardAccessoryControllerImpl() override; + + // AutofillPopupViewDelegate: + void Hide(PopupHidingReason reason) override; + void ViewDestroyed() override; + gfx::NativeView container_view() const override; + content::WebContents* GetWebContents() const override; + const gfx::RectF& element_bounds() const override; + base::i18n::TextDirection GetElementTextDirection() const override; + + // AutofillPopupController: + void OnSuggestionsChanged() override; + void SelectSuggestion(int index) override; + void UnselectSuggestion() override; + void AcceptSuggestion(int index) override; + void PerformButtonActionForSuggestion(int index) override; + bool RemoveSuggestion( + int index, + AutofillMetrics::SingleEntryRemovalMethod removal_method) override; + int GetLineCount() const override; + std::vector<Suggestion> GetSuggestions() const override; + const Suggestion& GetSuggestionAt(int row) const override; + std::u16string GetSuggestionMainTextAt(int row) const override; + std::u16string GetSuggestionMinorTextAt(int row) const override; + std::vector<std::vector<Suggestion::Text>> GetSuggestionLabelsAt( + int row) const override; + bool GetRemovalConfirmationText(int index, + std::u16string* title, + std::u16string* body) override; + FillingProduct GetMainFillingProduct() const override; + bool ShouldIgnoreMouseObservedOutsideItemBoundsCheck() const override; + base::WeakPtr<AutofillPopupController> OpenSubPopup( + const gfx::RectF& anchor_bounds, + std::vector<Suggestion> suggestions, + AutoselectFirstSuggestion autoselect_first_suggestion) override; + void HideSubPopup() override; + std::optional<AutofillClient::PopupScreenLocation> GetPopupScreenLocation() + const override; + void Show(std::vector<Suggestion> suggestions, + AutofillSuggestionTriggerSource trigger_source, + AutoselectFirstSuggestion autoselect_first_suggestion) override; + void DisableThresholdForTesting(bool disable_threshold) override; + void KeepPopupOpenForTesting() override; + void SetViewForTesting(base::WeakPtr<AutofillPopupView> view) override; + void UpdateDataListValues(base::span<const SelectOption> options) override; + void PinView() override; + + base::WeakPtr<AutofillKeyboardAccessoryControllerImpl> GetWeakPtr(); + + private: + friend class AutofillPopupController; + + // Returns true if the popup has entries that are not "Manage ...". + bool HasSuggestions() const; + + // Hides the view and asynchronously deletes itself. + void HideViewAndDie(); + + base::WeakPtr<AutofillPopupDelegate> delegate_; + base::WeakPtr<content::WebContents> web_contents_; + PopupControllerCommon controller_common_; + base::WeakPtr<AutofillPopupView> view_; + + // A helper that detects events that should hide the popup. + std::optional<AutofillPopupHideHelper> popup_hide_helper_; + + // The suggestions to be shown in the Keyboard Accessory. + std::vector<Suggestion> suggestions_; + + // The trigger source of the `suggestions_`. + AutofillSuggestionTriggerSource trigger_source_ = + AutofillSuggestionTriggerSource::kUnspecified; + + // The time the view was shown the last time. It is used to safeguard against + // accepting suggestions too quickly after a the popup view was shown (see the + // `show_threshold` parameter of `AcceptSuggestion`). + NextIdleTimeTicks time_view_shown_; + + // An override to suppress minimum show thresholds. It should only be set + // during tests that cannot mock time (e.g. the autofill interactive + // browsertests). + bool disable_threshold_for_testing_ = false; + + // If set to true, the popup will never be hidden because of stale data or if + // the user interacts with native UI. + bool is_view_pinned_ = false; + + // If set to true, the popup will stay open regardless of external changes on + // the machine that would normally cause the popup to be hidden. + bool keep_popup_open_for_testing_ = false; + + // Callback invoked to try to show the password migration warning on Android. + // Used to facilitate testing. + // TODO(crbug.com/1454469): Remove when the warning isn't needed anymore. + ShowPasswordMigrationWarningCallback show_pwd_migration_warning_callback_; + + base::WeakPtrFactory<AutofillKeyboardAccessoryControllerImpl> + self_deletion_weak_ptr_factory_{this}; + + base::WeakPtrFactory<AutofillKeyboardAccessoryControllerImpl> + weak_ptr_factory_{this}; +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_H_
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h index ab0f4ec..27b0f3f 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -24,6 +24,7 @@ namespace autofill { +class AutofillPopupView; struct PopupControllerCommon; // This interface provides data to an AutofillPopupView. @@ -137,8 +138,11 @@ // set during tests that cannot mock time (e.g. the autofill interactive // browsertests). virtual void DisableThresholdForTesting(bool disable_threshold) = 0; + virtual void KeepPopupOpenForTesting() = 0; + virtual void SetViewForTesting(base::WeakPtr<AutofillPopupView> view) = 0; + // Updates the data list values currently shown with the popup. virtual void UpdateDataListValues(base::span<const SelectOption> options) = 0;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 13acd71..a5f5e52 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -13,7 +13,6 @@ #include "base/check_op.h" #include "base/command_line.h" #include "base/functional/bind.h" -#include "base/functional/overloaded.h" #include "base/i18n/rtl.h" #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_functions.h" @@ -23,11 +22,10 @@ #include "build/build_config.h" #include "chrome/browser/accessibility/accessibility_state_utils.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" -#include "chrome/browser/feature_engagement/tracker_factory.h" #include "chrome/browser/ui/autofill/autofill_popup_view.h" +#include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h" #include "chrome/browser/ui/autofill/next_idle_time_ticks.h" #include "chrome/browser/ui/autofill/popup_controller_common.h" -#include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/filling_product.h" #include "components/autofill/core/browser/metrics/autofill_metrics.h" @@ -38,9 +36,6 @@ #include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/common/autofill_features.h" #include "components/compose/core/browser/config.h" -#include "components/feature_engagement/public/feature_constants.h" -#include "components/feature_engagement/public/tracker.h" -#include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_process_host.h" @@ -68,54 +63,17 @@ #include "components/compose/core/browser/compose_features.h" #endif -using base::WeakPtr; - namespace autofill { -namespace { - -// Returns true if the given id refers to an element that can be accepted. -bool CanAccept(PopupItemId id) { - return id != PopupItemId::kSeparator && - id != PopupItemId::kInsecureContextPaymentDisabledMessage && - id != PopupItemId::kMixedFormMessage && id != PopupItemId::kTitle; -} - -content::RenderFrameHost* GetRenderFrameHost(AutofillPopupDelegate& delegate) { - return absl::visit( - base::Overloaded{ - [](AutofillDriver* driver) { - return static_cast<ContentAutofillDriver*>(driver) - ->render_frame_host(); - }, - [](password_manager::PasswordManagerDriver* driver) { - return static_cast<password_manager::ContentPasswordManagerDriver*>( - driver) - ->render_frame_host(); - }}, - delegate.GetDriver()); -} - -bool IsAncestorOf(content::RenderFrameHost* ancestor, - content::RenderFrameHost* descendant) { - for (auto* rfh = descendant; rfh; rfh = rfh->GetParent()) { - if (rfh == ancestor) { - return true; - } - } - return false; -} - -} // namespace - -#if !BUILDFLAG(IS_MAC) +#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID) // static -WeakPtr<AutofillPopupController> AutofillPopupController::GetOrCreate( - WeakPtr<AutofillPopupController> previous, - WeakPtr<AutofillPopupDelegate> delegate, +base::WeakPtr<AutofillPopupController> AutofillPopupController::GetOrCreate( + base::WeakPtr<AutofillPopupController> previous, + base::WeakPtr<AutofillPopupDelegate> delegate, content::WebContents* web_contents, PopupControllerCommon controller_common, int32_t form_control_ax_id) { + // All controllers on Desktop derive from `AutofillPopupControllerImpl`. if (AutofillPopupControllerImpl* previous_impl = static_cast<AutofillPopupControllerImpl*>(previous.get()); previous_impl && previous_impl->delegate_.get() == delegate.get() && @@ -132,16 +90,9 @@ if (previous) { previous->Hide(PopupHidingReason::kViewDestroyed); } -#if BUILDFLAG(IS_ANDROID) - auto* controller = new AutofillPopupControllerImpl( - delegate, web_contents, std::move(controller_common), form_control_ax_id, - base::BindRepeating(&local_password_migration::ShowWarning), - /*parent=*/std::nullopt); -#else auto* controller = new AutofillPopupControllerImpl( delegate, web_contents, std::move(controller_common), form_control_ax_id, base::DoNothing(), /*parent=*/std::nullopt); -#endif return controller->GetWeakPtr(); } #endif @@ -195,7 +146,7 @@ return; } - if (IsPointerLocked()) { + if (IsPointerLocked(web_contents_.get())) { Hide(PopupHidingReason::kMouseLocked); return; } @@ -307,47 +258,12 @@ void AutofillPopupControllerImpl::UpdateDataListValues( base::span<const SelectOption> options) { - // Remove all the old data list values, which should always be at the top of - // the list if they are present. - while (!suggestions_.empty() && - suggestions_[0].popup_item_id == PopupItemId::kDatalistEntry) { - suggestions_.erase(suggestions_.begin()); + UpdateSuggestionsFromDataList(options, suggestions_); + if (HasSuggestions()) { + OnSuggestionsChanged(); + } else { + Hide(PopupHidingReason::kNoSuggestions); } - - // If there are no new data list values, exit (clearing the separator if there - // is one). - if (options.empty()) { - if (!suggestions_.empty() && - suggestions_[0].popup_item_id == PopupItemId::kSeparator) { - suggestions_.erase(suggestions_.begin()); - } - - // The popup contents have changed, so either update the bounds or hide it. - if (HasSuggestions()) - OnSuggestionsChanged(); - else - Hide(PopupHidingReason::kNoSuggestions); - - return; - } - - // Add a separator if there are any other values. - if (!suggestions_.empty() && - suggestions_[0].popup_item_id != PopupItemId::kSeparator) { - suggestions_.insert(suggestions_.begin(), - Suggestion(PopupItemId::kSeparator)); - } - - // Prepend the parameters to the suggestions we already have. - suggestions_.insert(suggestions_.begin(), options.size(), Suggestion()); - for (size_t i = 0; i < options.size(); i++) { - suggestions_[i].main_text = - Suggestion::Text(options[i].value, Suggestion::Text::IsPrimary(true)); - suggestions_[i].labels = {{Suggestion::Text(options[i].content)}}; - suggestions_[i].popup_item_id = PopupItemId::kDatalistEntry; - } - - OnSuggestionsChanged(); } void AutofillPopupControllerImpl::PinView() { @@ -453,7 +369,7 @@ return; } - if (IsPointerLocked()) { + if (IsPointerLocked(web_contents_.get())) { Hide(PopupHidingReason::kMouseLocked); return; } @@ -480,29 +396,10 @@ } #endif - if (suggestion.popup_item_id == PopupItemId::kVirtualCreditCardEntry) { - std::string event_name = - suggestion.feature_for_iph == - &feature_engagement::kIPHAutofillVirtualCardCVCSuggestionFeature - ? "autofill_virtual_card_cvc_suggestion_accepted" - : "autofill_virtual_card_suggestion_accepted"; - feature_engagement::TrackerFactory::GetForBrowserContext( - web_contents_->GetBrowserContext()) - ->NotifyEvent(event_name); - } - - if (suggestion.feature_for_iph == - &feature_engagement:: - kIPHAutofillExternalAccountProfileSuggestionFeature) { - feature_engagement::TrackerFactory::GetForBrowserContext( - web_contents_->GetBrowserContext()) - ->NotifyEvent("autofill_external_account_profile_suggestion_accepted"); - } - - std::optional<std::u16string> announcement = - suggestion.acceptance_a11y_announcement; - if (announcement && view_) { - view_->AxAnnounce(*announcement); + NotifyIphAboutAcceptedSuggestion(web_contents_->GetBrowserContext(), + suggestion); + if (suggestion.acceptance_a11y_announcement && view_) { + view_->AxAnnounce(*suggestion.acceptance_a11y_announcement); } delegate_->DidAcceptSuggestion( @@ -607,6 +504,7 @@ int list_index, std::u16string* title, std::u16string* body) { + // TODO(crbug.com/333316034): Remove - this is not relevant on Desktop. const std::u16string& value = suggestions_[list_index].main_text.value; const PopupItemId popup_item_id = suggestions_[list_index].popup_item_id; const Suggestion::BackendId backend_id = @@ -669,7 +567,7 @@ bool AutofillPopupControllerImpl::RemoveSuggestion( int list_index, AutofillMetrics::SingleEntryRemovalMethod removal_method) { - if (IsPointerLocked()) { + if (IsPointerLocked(web_contents_.get())) { Hide(PopupHidingReason::kMouseLocked); return false; } @@ -739,14 +637,15 @@ } void AutofillPopupControllerImpl::SelectSuggestion(int index) { + CHECK_GE(index, 0); CHECK_LT(index, static_cast<int>(suggestions_.size())); - if (IsPointerLocked()) { + if (IsPointerLocked(web_contents_.get())) { Hide(PopupHidingReason::kMouseLocked); return; } - if (!CanAccept(GetSuggestionAt(index).popup_item_id)) { + if (!IsAcceptablePopupItemId(GetSuggestionAt(index).popup_item_id)) { UnselectSuggestion(); return; } @@ -782,7 +681,8 @@ suggestions_ = std::move(suggestions); } -WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { +base::WeakPtr<AutofillPopupControllerImpl> +AutofillPopupControllerImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } @@ -828,20 +728,13 @@ base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce( - [](WeakPtr<AutofillPopupControllerImpl> weak_this) { + [](base::WeakPtr<AutofillPopupControllerImpl> weak_this) { if (weak_this) delete weak_this.get(); }, self_deletion_weak_ptr_factory_.GetWeakPtr())); } -bool AutofillPopupControllerImpl::IsPointerLocked() const { - content::RenderFrameHost* rfh; - content::RenderWidgetHostView* rwhv; - return web_contents_ && (rfh = web_contents_->GetFocusedFrame()) && - (rwhv = rfh->GetView()) && rwhv->IsPointerLocked(); -} - base::WeakPtr<AutofillPopupView> AutofillPopupControllerImpl::CreateSubPopupView( base::WeakPtr<AutofillPopupController> controller) { @@ -948,4 +841,10 @@ handler_ = content::RenderWidgetHost::KeyPressEventCallback(); } +void AutofillPopupControllerImpl::SetViewForTesting( + base::WeakPtr<AutofillPopupView> view) { + view_ = std::move(view); + time_view_shown_ = NextIdleTimeTicks::CaptureNextIdleTimeTicks(); +} + } // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h index eb840af..551fb3c 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -117,10 +117,9 @@ void UpdateDataListValues(base::span<const SelectOption> options) override; void PinView() override; - void SetViewForTesting(base::WeakPtr<AutofillPopupView> view) { - view_ = std::move(view); - time_view_shown_ = NextIdleTimeTicks::CaptureNextIdleTimeTicks(); - } + base::WeakPtr<AutofillPopupControllerImpl> GetWeakPtr(); + + void SetViewForTesting(base::WeakPtr<AutofillPopupView> view) override; protected: AutofillPopupControllerImpl( @@ -133,7 +132,8 @@ Profile*, password_manager::metrics_util::PasswordMigrationWarningTriggers)> show_pwd_migration_warning_callback, - std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent); + std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent = + std::nullopt); ~AutofillPopupControllerImpl() override; gfx::NativeView container_view() const override; @@ -148,8 +148,6 @@ // without showing the popup. void SetSuggestions(std::vector<Suggestion> suggestions); - base::WeakPtr<AutofillPopupControllerImpl> GetWeakPtr(); - // Raise an accessibility event to indicate the controls relation of the // form control of the popup and popup itself has changed based on the popup's // show or hide action. @@ -169,11 +167,6 @@ // when the popup is reused it doesn't leak values between uses. void ClearState(); - // Returns true iff the focused frame has a pointer lock, which may be used to - // trick the user into accepting some suggestion (crbug.com/1239496). In such - // a case, we should hide the popup. - bool IsPointerLocked() const; - // ExpandablePopupParentControllerImpl: base::WeakPtr<AutofillPopupView> CreateSubPopupView( base::WeakPtr<AutofillPopupController> controller) override;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc index 44899f04..a5c427e 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
@@ -31,10 +31,10 @@ using ::testing::AllOf; using ::testing::Field; using ::testing::Matcher; +using ::testing::Mock; using ::testing::NiceMock; using ::testing::Return; -#if !BUILDFLAG(IS_ANDROID) Matcher<const AutofillPopupDelegate::SuggestionPosition&> EqualsSuggestionPosition(AutofillPopupDelegate::SuggestionPosition position) { return AllOf( @@ -42,13 +42,11 @@ Field(&AutofillPopupDelegate::SuggestionPosition::sub_popup_level, position.sub_popup_level)); } -#endif // !BUILDFLAG(IS_ANDROID) } // namespace using AutofillPopupControllerImplTest = AutofillPopupControllerTestBase<>; -#if !BUILDFLAG(IS_ANDROID) TEST_F(AutofillPopupControllerImplTest, SubPopupIsCreatedWithViewFromParent) { base::WeakPtr<AutofillPopupController> sub_controller = client().popup_controller(manager()).OpenSubPopup( @@ -115,7 +113,6 @@ task_environment()->FastForwardBy(base::Milliseconds(1000)); sub_controller->AcceptSuggestion(/*index=*/0); } -#endif // !BUILDFLAG(IS_ANDROID) TEST_F(AutofillPopupControllerImplTest, ManualFallBackTriggerSource_IgnoresClickOutsideCheck) { @@ -132,6 +129,74 @@ .ShouldIgnoreMouseObservedOutsideItemBoundsCheck()); } +// Tests that the popup controller queries the view for its screen location. +TEST_F(AutofillPopupControllerImplTest, GetPopupScreenLocationCallsView) { + ShowSuggestions(manager(), {PopupItemId::kCompose}); + + using PopupScreenLocation = AutofillClient::PopupScreenLocation; + constexpr gfx::Rect kSampleRect = gfx::Rect(123, 234); + EXPECT_CALL(client().popup_view(), GetPopupScreenLocation) + .WillOnce(Return(PopupScreenLocation{.bounds = kSampleRect})); + EXPECT_THAT(client().popup_controller(manager()).GetPopupScreenLocation(), + Optional(Field(&PopupScreenLocation::bounds, kSampleRect))); +} + +// Tests that a change to a text field hides a popup with a Compose suggestion. +TEST_F(AutofillPopupControllerImplTest, HidesOnFieldChangeForComposeEntries) { + ShowSuggestions(manager(), {PopupItemId::kCompose}); + EXPECT_CALL(client().popup_controller(manager()), + Hide(PopupHidingReason::kFieldValueChanged)); + manager().NotifyObservers( + &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(), + FieldGlobalId()); +} + +// Tests that Compose saved state notification popup gets hidden after 2 +// seconds, but not after 1 second. +TEST_F(AutofillPopupControllerImplTest, + TimedHideComposeSavedStateNotification) { + ShowSuggestions(manager(), {PopupItemId::kComposeSavedStateNotification}); + test::GenerateTestAutofillPopup(&manager().external_delegate()); + ::testing::MockFunction<void()> check; + { + ::testing::InSequence s; + EXPECT_CALL(check, Call); + EXPECT_CALL(client().popup_controller(manager()), + Hide(PopupHidingReason::kFadeTimerExpired)); + } + task_environment()->FastForwardBy(base::Seconds(1)); + check.Call(); + task_environment()->FastForwardBy(base::Seconds(1)); + Mock::VerifyAndClearExpectations(&client().popup_controller(manager())); +} + +TEST_F(AutofillPopupControllerImplTest, + RemoveAutocompleteSuggestion_IgnoresClickOutsideCheck) { + ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry, + PopupItemId::kAutocompleteEntry}); + + // Generate a popup, so it can be hidden later. It doesn't matter what the + // external_delegate thinks is being shown in the process, since we are just + // testing the popup here. + test::GenerateTestAutofillPopup(&manager().external_delegate()); + + EXPECT_CALL(manager().external_delegate(), + RemoveSuggestion(Field(&Suggestion::popup_item_id, + PopupItemId::kAutocompleteEntry))) + .WillOnce(Return(true)); + // Remove the first entry. The popup should be redrawn since its size has + // changed. + EXPECT_CALL(client().popup_view(), OnSuggestionsChanged()); + EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( + 0, + AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + Mock::VerifyAndClearExpectations(&client().popup_view()); + + EXPECT_TRUE(client() + .popup_controller(manager()) + .ShouldIgnoreMouseObservedOutsideItemBoundsCheck()); +} + #if !BUILDFLAG(IS_CHROMEOS_ASH) namespace { @@ -152,6 +217,7 @@ using AutofillPopupControllerForPopupTest:: AutofillPopupControllerForPopupTest; + using AutofillPopupControllerForPopupTest::FireControlsChangedEvent; MOCK_METHOD(ui::AXPlatformNode*, GetRootAXPlatformNodeForWebContents, (),
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc index 8ce9d3b..4a04c3a4 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc
@@ -25,17 +25,18 @@ void(gfx::NativeWindow, Profile*, password_manager::metrics_util::PasswordMigrationWarningTriggers)> - show_pwd_migration_warning_callback, - std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent) - : AutofillPopupControllerImpl( + show_pwd_migration_warning_callback) + : AutofillPopupControllerForPopupTestBase( external_delegate, web_contents, PopupControllerCommon(element_bounds, base::i18n::UNKNOWN_DIRECTION, nullptr), +#if !BUILDFLAG(IS_ANDROID) /*form_control_ax_id=*/0, - std::move(show_pwd_migration_warning_callback), - parent) {} +#endif + std::move(show_pwd_migration_warning_callback)) { +} AutofillPopupControllerForPopupTest::~AutofillPopupControllerForPopupTest() = default;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h index 90969935..2f6e2a7 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h
@@ -38,6 +38,7 @@ #include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h" #include "chrome/browser/keyboard_accessory/test_utils/android/mock_credit_card_accessory_controller.h" #include "chrome/browser/keyboard_accessory/test_utils/android/mock_password_accessory_controller.h" +#include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h" #endif // BUILDFLAG(IS_ANDROID) namespace autofill { @@ -332,7 +333,15 @@ show_pwd_migration_warning_callback_; }; -class AutofillPopupControllerForPopupTest : public AutofillPopupControllerImpl { +using AutofillPopupControllerForPopupTestBase = +#if BUILDFLAG(IS_ANDROID) + AutofillKeyboardAccessoryControllerImpl; +#else + AutofillPopupControllerImpl; +#endif + +class AutofillPopupControllerForPopupTest + : public AutofillPopupControllerForPopupTestBase { public: AutofillPopupControllerForPopupTest( base::WeakPtr<AutofillExternalDelegate> external_delegate, @@ -342,27 +351,24 @@ gfx::NativeWindow, Profile*, password_manager::metrics_util::PasswordMigrationWarningTriggers)> - show_pwd_migration_warning_callback, - std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent = - std::nullopt); + show_pwd_migration_warning_callback); ~AutofillPopupControllerForPopupTest() override; // Making protected functions public for testing - using AutofillPopupControllerImpl::AcceptSuggestion; - using AutofillPopupControllerImpl::element_bounds; - using AutofillPopupControllerImpl::FireControlsChangedEvent; - using AutofillPopupControllerImpl::GetLineCount; - using AutofillPopupControllerImpl::GetSuggestionAt; - using AutofillPopupControllerImpl::GetSuggestionLabelsAt; - using AutofillPopupControllerImpl::GetSuggestionMainTextAt; - using AutofillPopupControllerImpl::GetWeakPtr; - using AutofillPopupControllerImpl::PerformButtonActionForSuggestion; - using AutofillPopupControllerImpl::RemoveSuggestion; - using AutofillPopupControllerImpl::SelectSuggestion; + using AutofillPopupControllerForPopupTestBase::AcceptSuggestion; + using AutofillPopupControllerForPopupTestBase::element_bounds; + using AutofillPopupControllerForPopupTestBase::GetLineCount; + using AutofillPopupControllerForPopupTestBase::GetSuggestionAt; + using AutofillPopupControllerForPopupTestBase::GetSuggestionLabelsAt; + using AutofillPopupControllerForPopupTestBase::GetSuggestionMainTextAt; + using AutofillPopupControllerForPopupTestBase:: + PerformButtonActionForSuggestion; + using AutofillPopupControllerForPopupTestBase::RemoveSuggestion; + using AutofillPopupControllerForPopupTestBase::SelectSuggestion; MOCK_METHOD(void, Hide, (PopupHidingReason reason), (override)); void DoHide(PopupHidingReason reason = PopupHidingReason::kTabGone) { - AutofillPopupControllerImpl::Hide(reason); + AutofillPopupControllerForPopupTestBase::Hide(reason); } };
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index 050b3599..59e6caf 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -108,6 +108,15 @@ return simulator->GetFinalRenderFrameHost(); } +// Returns an `AutofillMetrics::SingleEntryRemovalMethod` that is appropriate +// for the OS this test is run on. +AutofillMetrics::SingleEntryRemovalMethod GetDefaultRemovalMethod() { + if constexpr (BUILDFLAG(IS_ANDROID)) { + return AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory; + } + return AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed; +} + content::RenderFrameHost* NavigateAndCommitFrame(content::RenderFrameHost* rfh, const GURL& url) { std::unique_ptr<content::NavigationSimulator> simulator = @@ -138,8 +147,7 @@ // changed. EXPECT_CALL(client().popup_view(), OnSuggestionsChanged()); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); Mock::VerifyAndClearExpectations(&client().popup_view()); // Remove the next entry. The popup should then be hidden since there are @@ -147,8 +155,7 @@ EXPECT_CALL(client().popup_controller(manager()), Hide(PopupHidingReason::kNoSuggestions)); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); } // Regression test for (crbug.com/1513574): Showing an Autofill Compose @@ -172,35 +179,7 @@ EXPECT_CALL(client().popup_view(), AxAnnounce(Eq(u"Entry main text has been deleted"))); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); -} - -TEST_F(AutofillPopupControllerTest, - RemoveAutocompleteSuggestion_IgnoresClickOutsideCheck) { - ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry, - PopupItemId::kAutocompleteEntry}); - - // Generate a popup, so it can be hidden later. It doesn't matter what the - // external_delegate thinks is being shown in the process, since we are just - // testing the popup here. - test::GenerateTestAutofillPopup(&manager().external_delegate()); - - EXPECT_CALL(manager().external_delegate(), - RemoveSuggestion(Field(&Suggestion::popup_item_id, - PopupItemId::kAutocompleteEntry))) - .WillOnce(Return(true)); - // Remove the first entry. The popup should be redrawn since its size has - // changed. - EXPECT_CALL(client().popup_view(), OnSuggestionsChanged()); - EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); - Mock::VerifyAndClearExpectations(&client().popup_view()); - - EXPECT_TRUE(client() - .popup_controller(manager()) - .ShouldIgnoreMouseObservedOutsideItemBoundsCheck()); + 0, GetDefaultRemovalMethod())); } TEST_F(AutofillPopupControllerTest, @@ -214,12 +193,10 @@ .WillOnce(Return(false)); EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); histogram_tester.ExpectUniqueSample( "Autofill.Autocomplete.SingleEntryRemovalMethod", - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed, - 0); + GetDefaultRemovalMethod(), 0); histogram_tester.ExpectUniqueSample( "Autocomplete.Events2", AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0); @@ -236,12 +213,10 @@ .WillOnce(Return(true)); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); histogram_tester.ExpectUniqueSample( "Autofill.Autocomplete.SingleEntryRemovalMethod", - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed, - 1); + GetDefaultRemovalMethod(), 1); histogram_tester.ExpectUniqueSample( "Autocomplete.Events2", AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 1); @@ -253,7 +228,7 @@ } TEST_F(AutofillPopupControllerTest, - RemoveAddressSuggestion_ShiftDelete_NoMetricsEmittedOnFail) { + RemoveAddressSuggestion_NoMetricsEmittedOnFail) { base::HistogramTester histogram_tester; ShowSuggestions(manager(), {PopupItemId::kAddressEntry}); test::GenerateTestAutofillPopup(&manager().external_delegate()); @@ -263,8 +238,7 @@ .WillOnce(Return(false)); EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0); histogram_tester.ExpectUniqueSample( "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0); @@ -272,7 +246,7 @@ } TEST_F(AutofillPopupControllerTest, - RemoveAddressSuggestion_ShiftDelete_MetricsEmittedOnSuccess) { + RemoveAddressSuggestion_MetricsEmittedOnSuccess) { base::HistogramTester histogram_tester; ShowSuggestions(manager(), {PopupItemId::kAddressEntry}); test::GenerateTestAutofillPopup(&manager().external_delegate()); @@ -282,61 +256,21 @@ .WillOnce(Return(true)); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); - histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 1); + 0, GetDefaultRemovalMethod())); histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1); - // Also no autocomplete or keyboard accessory metrics are emitted. - histogram_tester.ExpectUniqueSample( - "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0); + if constexpr (BUILDFLAG(IS_ANDROID)) { + histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0); + histogram_tester.ExpectUniqueSample( + "Autofill.ProfileDeleted.KeyboardAccessory", 1, 1); + } else { + histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0); + } + // No autocomplete deletion metrics are emitted. histogram_tester.ExpectUniqueSample( "Autofill.Autocomplete.SingleEntryRemovalMethod", - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed, - 0); - histogram_tester.ExpectUniqueSample( - "Autocomplete.Events2", - AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0); -} - -TEST_F(AutofillPopupControllerTest, - RemoveAddressSuggestion_KeyboardAccessory_NoMetricsEmittedOnFail) { - base::HistogramTester histogram_tester; - ShowSuggestions(manager(), {PopupItemId::kAddressEntry}); - test::GenerateTestAutofillPopup(&manager().external_delegate()); - EXPECT_CALL(manager().external_delegate(), - RemoveSuggestion(Field(&Suggestion::popup_item_id, - PopupItemId::kAddressEntry))) - .WillOnce(Return(false)); - - EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion( - 0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory)); - histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0); - histogram_tester.ExpectUniqueSample( - "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0); - histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0); -} - -TEST_F(AutofillPopupControllerTest, - RemoveAddressSuggestion_KeyboardAccessory_MetricsEmittedOnSuccess) { - base::HistogramTester histogram_tester; - ShowSuggestions(manager(), {PopupItemId::kAddressEntry}); - test::GenerateTestAutofillPopup(&manager().external_delegate()); - EXPECT_CALL(manager().external_delegate(), - RemoveSuggestion(Field(&Suggestion::popup_item_id, - PopupItemId::kAddressEntry))) - .WillOnce(Return(true)); - - EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory)); - histogram_tester.ExpectUniqueSample( - "Autofill.ProfileDeleted.KeyboardAccessory", 1, 1); - histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1); - // Also no autocomplete or shift+delete metrics are emitted. - histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0); - histogram_tester.ExpectUniqueSample( - "Autofill.Autocomplete.SingleEntryRemovalMethod", - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed, - 0); + GetDefaultRemovalMethod(), 0); histogram_tester.ExpectUniqueSample( "Autocomplete.Events2", AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0); @@ -353,12 +287,10 @@ .WillOnce(Return(true)); EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion( - 0, - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed)); + 0, GetDefaultRemovalMethod())); histogram_tester.ExpectUniqueSample( "Autofill.Autocomplete.SingleEntryRemovalMethod", - AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed, - 0); + GetDefaultRemovalMethod(), 0); histogram_tester.ExpectUniqueSample( "Autocomplete.Events2", AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0); @@ -552,7 +484,7 @@ PopupItemId::kAutocompleteEntry}); // Now show a new popup with the same controller, but with fewer items. - WeakPtr<AutofillPopupController> controller = + base::WeakPtr<AutofillPopupController> controller = AutofillPopupController::GetOrCreate( client().popup_controller(manager()).GetWeakPtr(), manager().external_delegate().GetWeakPtrForTest(), nullptr, @@ -858,28 +790,6 @@ #endif // BUILDFLAG(IS_ANDROID) -// Tests that the popup controller queries the view for its screen location. -TEST_F(AutofillPopupControllerTest, GetPopupScreenLocationCallsView) { - ShowSuggestions(manager(), {PopupItemId::kCompose}); - - using PopupScreenLocation = AutofillClient::PopupScreenLocation; - constexpr gfx::Rect kSampleRect = gfx::Rect(123, 234); - EXPECT_CALL(client().popup_view(), GetPopupScreenLocation) - .WillOnce(Return(PopupScreenLocation{.bounds = kSampleRect})); - EXPECT_THAT(client().popup_controller(manager()).GetPopupScreenLocation(), - Optional(Field(&PopupScreenLocation::bounds, kSampleRect))); -} - -// Tests that a change to a text field hides a popup with a Compose suggestion. -TEST_F(AutofillPopupControllerTest, HidesOnFieldChangeForComposeEntries) { - ShowSuggestions(manager(), {PopupItemId::kCompose}); - EXPECT_CALL(client().popup_controller(manager()), - Hide(PopupHidingReason::kFieldValueChanged)); - manager().NotifyObservers( - &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(), - FieldGlobalId()); -} - // Tests that a change to a text field does not hide a popup with an // Autocomplete suggestion. TEST_F(AutofillPopupControllerTest, @@ -1015,25 +925,6 @@ NavigateAndCommitFrame(main_frame(), GURL("https://bar.com/")); } -// Tests that Compose saved state notification popup gets hidden after 2 -// seconds, but not after 1 second. -TEST_F(AutofillPopupControllerTestHidingLogic, - TimedHideComposeSavedStateNotification) { - ShowSuggestions(manager(), {PopupItemId::kComposeSavedStateNotification}); - test::GenerateTestAutofillPopup(&manager().external_delegate()); - ::testing::MockFunction<void()> check; - { - ::testing::InSequence s; - EXPECT_CALL(check, Call); - EXPECT_CALL(client().popup_controller(manager()), - Hide(PopupHidingReason::kFadeTimerExpired)); - } - task_environment()->FastForwardBy(base::Seconds(1)); - check.Call(); - task_environment()->FastForwardBy(base::Seconds(1)); - Mock::VerifyAndClearExpectations(&client().popup_controller(manager())); -} - #if !BUILDFLAG(IS_ANDROID) // Tests that if the popup is shown in the *main frame*, changing the zoom hides // the popup.
diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc new file mode 100644 index 0000000..f0fb5e5 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc
@@ -0,0 +1,121 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h" + +#include <string> +#include <vector> + +#include "base/functional/overloaded.h" +#include "chrome/browser/feature_engagement/tracker_factory.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/core/browser/ui/popup_item_ids.h" +#include "components/autofill/core/browser/ui/suggestion.h" +#include "components/autofill/core/common/dense_set.h" +#include "components/autofill/core/common/form_field_data.h" +#include "components/feature_engagement/public/feature_constants.h" +#include "components/feature_engagement/public/tracker.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" + +namespace autofill { + +bool IsAcceptablePopupItemId(PopupItemId id) { + using enum PopupItemId; + static constexpr auto kUnacceptableItemIds = + DenseSet({kSeparator, kInsecureContextPaymentDisabledMessage, + kMixedFormMessage, kTitle}); + return !kUnacceptableItemIds.contains(id); +} + +content::RenderFrameHost* GetRenderFrameHost(AutofillPopupDelegate& delegate) { + return absl::visit( + base::Overloaded{ + [](AutofillDriver* driver) { + return static_cast<ContentAutofillDriver*>(driver) + ->render_frame_host(); + }, + [](password_manager::PasswordManagerDriver* driver) { + return static_cast<password_manager::ContentPasswordManagerDriver*>( + driver) + ->render_frame_host(); + }}, + delegate.GetDriver()); +} + +bool IsAncestorOf(content::RenderFrameHost* ancestor, + content::RenderFrameHost* descendant) { + for (auto* rfh = descendant; rfh; rfh = rfh->GetParent()) { + if (rfh == ancestor) { + return true; + } + } + return false; +} + +bool IsPointerLocked(content::WebContents* web_contents) { + content::RenderFrameHost* rfh; + content::RenderWidgetHostView* rwhv; + return web_contents && (rfh = web_contents->GetFocusedFrame()) && + (rwhv = rfh->GetView()) && rwhv->IsPointerLocked(); +} + +void NotifyIphAboutAcceptedSuggestion(content::BrowserContext* browser_context, + const Suggestion& suggestion) { + if (suggestion.popup_item_id == PopupItemId::kVirtualCreditCardEntry) { + feature_engagement::TrackerFactory::GetForBrowserContext(browser_context) + ->NotifyEvent(suggestion.feature_for_iph == + &feature_engagement:: + kIPHAutofillVirtualCardCVCSuggestionFeature + ? "autofill_virtual_card_cvc_suggestion_accepted" + : "autofill_virtual_card_suggestion_accepted"); + } + + if (suggestion.feature_for_iph == + &feature_engagement:: + kIPHAutofillExternalAccountProfileSuggestionFeature) { + feature_engagement::TrackerFactory::GetForBrowserContext(browser_context) + ->NotifyEvent("autofill_external_account_profile_suggestion_accepted"); + } +} + +void UpdateSuggestionsFromDataList(base::span<const SelectOption> options, + std::vector<Suggestion>& suggestions) { + // Remove all the old data list values, which should always be at the top of + // the list if they are present. + std::erase_if(suggestions, [](const Suggestion& suggestion) { + return suggestion.popup_item_id == PopupItemId::kDatalistEntry; + }); + + // If there are no new data list values, exit (clearing the separator if there + // is one). + if (options.empty()) { + if (!suggestions.empty() && + suggestions[0].popup_item_id == PopupItemId::kSeparator) { + suggestions.erase(suggestions.begin()); + } + + return; + } + + // Add a separator if there are any other values. + if (!suggestions.empty() && + suggestions[0].popup_item_id != PopupItemId::kSeparator) { + suggestions.insert(suggestions.begin(), + Suggestion(PopupItemId::kSeparator)); + } + + // Prepend the parameters to the suggestions we already have. + suggestions.insert(suggestions.begin(), options.size(), Suggestion()); + for (size_t i = 0; i < options.size(); i++) { + suggestions[i].main_text = + Suggestion::Text(options[i].value, Suggestion::Text::IsPrimary(true)); + suggestions[i].labels = {{Suggestion::Text(options[i].content)}}; + suggestions[i].popup_item_id = PopupItemId::kDatalistEntry; + } +} + +} // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h new file mode 100644 index 0000000..5d50b03 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h
@@ -0,0 +1,49 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_SUGGESTION_CONTROLLER_UTILS_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_SUGGESTION_CONTROLLER_UTILS_H_ + +#include <vector> + +#include "base/containers/span.h" +#include "components/autofill/core/browser/ui/popup_item_ids.h" + +namespace content { +class BrowserContext; +class RenderFrameHost; +class WebContents; +} // namespace content + +namespace autofill { + +class AutofillPopupDelegate; +struct SelectOption; +struct Suggestion; + +// Returns whether this `PopupItemId` can, in principle, be accepted. Note that +// even if this is true, the suggestion itself may still not be acceptable. +bool IsAcceptablePopupItemId(PopupItemId id); + +// Returns the RenderFrameHost` corresponding to an `AutofillPopupDelegate`. +content::RenderFrameHost* GetRenderFrameHost(AutofillPopupDelegate& delegate); + +// Returns whether `descendendant` is a `descendant` of `ancestor`. +bool IsAncestorOf(content::RenderFrameHost* ancestor, + content::RenderFrameHost* descendant); + +// Returns whether the pointer is locked in `web_contents`. +bool IsPointerLocked(content::WebContents* web_contents); + +// Informs the IPH trackers about an accepted suggestion if the suggestion had +// relevance for IPH. +void NotifyIphAboutAcceptedSuggestion(content::BrowserContext* browser_context, + const Suggestion& suggestion); + +void UpdateSuggestionsFromDataList(base::span<const SelectOption> options, + std::vector<Suggestion>& suggestions); + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_SUGGESTION_CONTROLLER_UTILS_H_
diff --git a/chrome/browser/ui/browser_tab_strip_tracker.h b/chrome/browser/ui/browser_tab_strip_tracker.h index 8669d461..badfcf3 100644 --- a/chrome/browser/ui/browser_tab_strip_tracker.h +++ b/chrome/browser/ui/browser_tab_strip_tracker.h
@@ -14,6 +14,15 @@ // BrowserTabStripTracker attaches a TabStripModelObserver to a subset of // pre-existing and future Browsers. The subset of Browsers that are tracked is // determined by an optional BrowserTabStripTrackerDelegate. +// +// This class is typically not the right helper to use. Its primary purpose is +// to hook up a TabStripModelObserver across multiple TabStripModels. As per the +// documentation for TabStripModelObserver, only features that need to interact +// with the tab strip like tab groups and tab search should use +// TabStripModelObserver. Other features should use TabInterface and +// TabFeatures. Furthermore, this class mixes state across multiple +// TabStripModels. This is typically not desirable and instead features should +// hold state on a per-browser-window basis, using BrowserWindowFeatures. class BrowserTabStripTracker : public BrowserListObserver { public: // |tab_strip_model_observer| is a non-nullptr TabStripModelObserver
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.h b/chrome/browser/ui/tabs/tab_strip_model_observer.h index d19aae1..07caa90 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_observer.h +++ b/chrome/browser/ui/tabs/tab_strip_model_observer.h
@@ -29,6 +29,13 @@ // // TabStripModelChange / TabStripSelectionChange // +// This observer is not appropriate for most use cases. It's primarily used for +// features that must directly interface with the tab strip, for example: tab +// groups, tab search, etc. +// Most features in Chrome need to hold state on a per-tab basis. In that case, +// add a controller to TabFeatures and use TabInterface to observe for the tab +// events. +// // The following class and structures are used to inform TabStripModelObservers // of changes to: // 1) selection model
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc index 3494adc..8aec76a 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
@@ -57,6 +57,14 @@ return std::nullopt; } +bool IsShowingFrame(bool use_custom_frame, + ui::PlatformWindowState window_state) { + return use_custom_frame && + window_state != ui::PlatformWindowState::kMaximized && + window_state != ui::PlatformWindowState::kMinimized && + !ui::IsPlatformWindowStateFullscreen(window_state); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -188,34 +196,31 @@ void BrowserDesktopWindowTreeHostLinux::UpdateFrameHints() { auto* window = platform_window(); + auto window_state = window->GetPlatformWindowState(); float scale = device_scale_factor(); auto* view = static_cast<BrowserNonClientFrameView*>(browser_frame_->GetFrameView()); - bool showing_frame = - browser_frame_->native_browser_frame()->UseCustomFrame() && - !view->IsFrameCondensed() && !view->frame()->IsMinimized(); const gfx::Size widget_size = view->GetWidget()->GetWindowBoundsInScreen().size(); if (SupportsClientFrameShadow()) { - // Set the frame decoration insets. - const gfx::Insets insets_dip = view->MirroredFrameBorderInsets(); - const gfx::Insets insets_px = gfx::ScaleToCeiledInsets(insets_dip, scale); - window->SetDecorationInsets(showing_frame ? &insets_px : nullptr); - - // Set the input region. - gfx::Rect input_bounds(widget_size); - input_bounds.Inset(insets_dip - view->GetInputInsets()); - input_bounds = gfx::ScaleToEnclosingRect(input_bounds, scale); - window->SetInputRegion( - showing_frame ? std::optional<std::vector<gfx::Rect>>({input_bounds}) - : std::nullopt); + auto insets = CalculateInsetsInDIP(window_state); + if (insets.IsEmpty()) { + window->SetInputRegion(std::nullopt); + } else { + gfx::Rect input_bounds(widget_size); + input_bounds.Inset(insets - view->GetInputInsets()); + input_bounds = gfx::ScaleToEnclosingRect(input_bounds, scale); + window->SetInputRegion( + std::optional<std::vector<gfx::Rect>>({input_bounds})); + } } if (ui::OzonePlatform::GetInstance()->IsWindowCompositingSupported()) { // Set the opaque region. std::vector<gfx::Rect> opaque_region; - if (showing_frame) { + if (IsShowingFrame(browser_frame_->native_browser_frame()->UseCustomFrame(), + window_state)) { // The opaque region is a list of rectangles that contain only fully // opaque pixels of the window. We need to convert the clipping // rounded-rect into this format. @@ -326,6 +331,18 @@ x11_extension->CanResetOverrideRedirect(); } +gfx::Insets BrowserDesktopWindowTreeHostLinux::CalculateInsetsInDIP( + ui::PlatformWindowState window_state) const { + // If we are not showing frame, the insets should be zero. + if (!IsShowingFrame(browser_frame_->native_browser_frame()->UseCustomFrame(), + window_state)) { + return gfx::Insets(); + } + + return static_cast<BrowserNonClientFrameView*>(browser_frame_->GetFrameView()) + ->MirroredFrameBorderInsets(); +} + void BrowserDesktopWindowTreeHostLinux::OnBoundsChanged( const BoundsChange& change) { DesktopWindowTreeHostLinux::OnBoundsChanged(change);
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.h index b52acac..213ff5bd 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.h +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.h
@@ -88,6 +88,8 @@ bool IsOverrideRedirect() const override; // ui::PlatformWindowDelegate + gfx::Insets CalculateInsetsInDIP( + ui::PlatformWindowState window_state) const override; void OnBoundsChanged(const BoundsChange& change) override; void OnWindowStateChanged(ui::PlatformWindowState old_state, ui::PlatformWindowState new_state) override;
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 9b4b1af..37c8554 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1713225556-0014a6d0c9887bed01444e78dfb49cc516874d85-a6f44326964cd416e2c0899245ba5db3de538fb6.profdata +chrome-android32-main-1713247156-e21c1c6a1aad09116cec86d7ad696d195b1f1fb9-050b5f225e98d132a97d05816bf94319f003398d.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index a559d63..fda17d4 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1713203948-2f75700a84a0d0b4b2cc6e4b1ba0ca06e9826d5b-6634c2892d4249eaa2432bedc1ea607e23df50c1.profdata +chrome-linux-main-1713247156-94d76bd2db3dbb00e47e33f8bed1e818a56115ed-050b5f225e98d132a97d05816bf94319f003398d.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 365c2ee..238c643e 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1713225556-148617ef6de999b69bce717b2ada3384aaea0a60-a6f44326964cd416e2c0899245ba5db3de538fb6.profdata +chrome-win-arm64-main-1713247156-74fa95ddd60c5b1b34c0b8f1d3d985c18b2fe1ad-050b5f225e98d132a97d05816bf94319f003398d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 119b6aa..ec65dc3 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1713214724-f52b1d687c54d7fea32d4239bd9f6ff7e1c25ea2-dc3fec1593e34a66d148c068a5b78f5e421c98e9.profdata +chrome-win32-main-1713236188-2d0952c6240f2a255998613bfc59c3da8fdab717-224f55c0f0a227b0da6c08269564115e48562fe8.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 46d7797..3b1e15e 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1713214724-7e0f7844b86444d8bbcf8c70b81af7354523d6c0-dc3fec1593e34a66d148c068a5b78f5e421c98e9.profdata +chrome-win64-main-1713236188-bd3cb4bc0986851fb18963d696a924b288e7b189-224f55c0f0a227b0da6c08269564115e48562fe8.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 2af71eb..86d7a71 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -6494,7 +6494,6 @@ "../browser/translate/translate_service_unittest.cc", "../browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_unittest.cc", "../browser/ui/autofill/autofill_client_provider_unittest.cc", - "../browser/ui/autofill/autofill_popup_controller_impl_unittest.cc", "../browser/ui/autofill/autofill_popup_controller_unittest.cc", "../browser/ui/autofill/chrome_autofill_client_unittest.cc", "../browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc", @@ -6567,6 +6566,7 @@ "../browser/search_engine_choice/search_engine_choice_dialog_service_unittest.cc", "../browser/segmentation_platform/client_util/local_tab_handler_unittest.cc", "../browser/ssl/generated_https_first_mode_pref_unittest.cc", + "../browser/ui/autofill/autofill_popup_controller_impl_unittest.cc", "../browser/ui/download/download_bubble_row_list_view_info_unittest.cc", "../browser/ui/download/download_bubble_row_view_info_unittest.cc", "../browser/ui/download/download_bubble_security_view_info_unittest.cc",
diff --git a/chrome/test/data/webui/test_util.ts b/chrome/test/data/webui/test_util.ts index 04d9ece..f629f18c4 100644 --- a/chrome/test/data/webui/test_util.ts +++ b/chrome/test/data/webui/test_util.ts
@@ -139,6 +139,7 @@ await new Promise<void>(res => { window.setTimeout(() => res(), timeout); }); + /* eslint-disable-next-line no-debugger */ debugger; }
diff --git a/chrome/test/enterprise/e2e/.vpython3 b/chrome/test/enterprise/e2e/.vpython3 index d3e1ce8..ff9fcf9 100644 --- a/chrome/test/enterprise/e2e/.vpython3 +++ b/chrome/test/enterprise/e2e/.vpython3
@@ -7,43 +7,47 @@ # # More information: # https://chromium.googlesource.com/infra/infra/+/main/doc/users/vpython.md -python_version: "3.8" +python_version: "3.11" +# The default set of platforms vpython checks for does not yet include mac-arm64. +# Setting `verify_pep425_tag` to the list of platforms we explicitly must support +# allows us to ensure that vpython specs stay mac-arm64-friendly verify_pep425_tag: [ - {python: "cp38", abi: "cp38", platform: "manylinux1_x86_64"}, - {python: "cp38", abi: "cp38", platform: "linux_arm64"}, + {python: "cp311", abi: "cp311", platform: "manylinux1_x86_64"}, + {python: "cp311", abi: "cp311", platform: "linux_arm64"}, - {python: "cp38", abi: "cp38", platform: "macosx_10_10_intel"}, - {python: "cp38", abi: "cp38", platform: "macosx_11_0_arm64"}, + {python: "cp311", abi: "cp311", platform: "macosx_10_10_intel"}, + {python: "cp311", abi: "cp311", platform: "macosx_11_0_arm64"}, - {python: "cp38", abi: "cp38", platform: "win32"}, - {python: "cp38", abi: "cp38", platform: "win_amd64"} + {python: "cp311", abi: "cp311", platform: "win32"}, + {python: "cp311", abi: "cp311", platform: "win_amd64"} ] wheel: < name: "infra/celab/celab/windows-amd64" - # Source: https://ci.chromium.org/ui/p/celab/builders/ci/Windows/b8750922101336036641 - version: "EOOjjcFkcpSYVHrlcfgxHwBEhIAqwWKNgwX20BvUB8YC" + # Source: https://ci.chromium.org/ui/p/celab/builders/ci/Windows/b8750569502072854417 + version: "j16S6jSsbiySxDfowruIiMXN-3WZ8GB80b8uEys-KpwC" > # googleapiclient wheel: < - name: "infra/python/wheels/google-api-python-client-py2_py3" - version: "version:1.12.8" + name: "infra/python/wheels/google-api-python-client-py3" + version: "version:2.111.0" > # googleapiclient's dependencies wheel: < - name: "infra/python/wheels/cachetools-py2_py3" - version: "version:2.0.1" + name: "infra/python/wheels/cachetools-py3" + version: "version:5.3.2" > + wheel: < name: "infra/python/wheels/google-api-core-py3" - version: "version:1.31.5" + version: "version:2.14.0" > wheel: < name: "infra/python/wheels/google-auth-py2_py3" - version: "version:1.35.0" + version: "version:2.23.4" > wheel: < name: "infra/python/wheels/google-auth-httplib2-py2_py3" @@ -51,7 +55,7 @@ > wheel: < name: "infra/python/wheels/httplib2-py3" - version: "version:0.19.1" + version: "version:0.22.0" > wheel: < name: "infra/python/wheels/oauth2client-py2_py3" @@ -106,8 +110,13 @@ version: "version:1.16.0" > wheel: < - name: "infra/python/wheels/uritemplate-py2_py3" - version: "version:3.0.0" + name: "infra/python/wheels/uritemplate-py3" + version: "version:4.1.1" +> + +wheel: < + name: "infra/python/wheels/grpcio-status-py3" + version: "version:1.57.0" > # google.cloud pubsub @@ -138,8 +147,8 @@ # google.protobuf wheel: < - name: "infra/python/wheels/protobuf-py2_py3" - version: "version:3.18.1" + name: "infra/python/wheels/protobuf-py3" + version: "version:4.25.1" > # iam.admin.v1 @@ -156,12 +165,12 @@ wheel: < name: "infra/python/wheels/googleapis-common-protos-py2_py3" - version: "version:1.52.0" + version: "version:1.61.0" > wheel: < name: "infra/python/wheels/grpcio/${vpython_platform}" - version: "version:1.44.0" + version: "version:1.57.0" > wheel: < @@ -175,8 +184,8 @@ > wheel: < - name: "infra/python/wheels/absl-py-py2_py3" - version: "version:0.7.1" + name: "infra/python/wheels/absl-py-py3" + version: "version:0.11.0" > wheel: < @@ -191,6 +200,6 @@ # attrs for simple dataclass wheel: < - name: "infra/python/wheels/attrs-py2_py3" - version: "version:21.4.0" + name: "infra/python/wheels/attrs-py3" + version: "version:23.1.0" >
diff --git a/chrome/test/fuzzing/in_process_fuzzer.gni b/chrome/test/fuzzing/in_process_fuzzer.gni index 49b9038..1dc9f89 100644 --- a/chrome/test/fuzzing/in_process_fuzzer.gni +++ b/chrome/test/fuzzing/in_process_fuzzer.gni
@@ -23,6 +23,8 @@ target_type = "fuzzer_test" } target(target_type, target_name) { + # Those tests are big, they need a lot of resources. + high_end_job_required = true deps = [ "//chrome/test/fuzzing:in_process_fuzzer_runner" ] if (defined(invoker.deps)) { deps += invoker.deps
diff --git a/clank b/clank index 7fd047c4..8b6ec11 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 7fd047c41ca4c77672258cc2644b116844100171 +Subproject commit 8b6ec119f001eb5ad89d77c153fa132bd65801c0
diff --git a/components/browser_ui/styles/android/java/res/values/styles.xml b/components/browser_ui/styles/android/java/res/values/styles.xml index e0861e7..42a8323 100644 --- a/components/browser_ui/styles/android/java/res/values/styles.xml +++ b/components/browser_ui/styles/android/java/res/values/styles.xml
@@ -117,6 +117,10 @@ <item name="android:textColor">@color/default_text_color_list</item> </style> + <style name="TextAppearance.TextAccentMediumThick.Primary"> + <item name="android:textColor">@color/default_text_color_list</item> + </style> + <style name="TextAppearance.TextLarge.Primary"> <item name="android:textColor">@color/default_text_color_list</item> </style>
diff --git a/components/prefs/android/pref_service_android.cc b/components/prefs/android/pref_service_android.cc index 79d7dd4..2c2b248 100644 --- a/components/prefs/android/pref_service_android.cc +++ b/components/prefs/android/pref_service_android.cc
@@ -8,11 +8,24 @@ #include "components/prefs/android/jni_headers/PrefService_jni.h" #include "components/prefs/pref_service.h" +#include "components/prefs/prefs_export.h" using base::android::JavaParamRef; +using base::android::JavaRef; using base::android::ScopedJavaLocalRef; using jni_zero::AttachCurrentThread; +namespace jni_zero { + +template <> +COMPONENTS_PREFS_EXPORT PrefService* FromJniType<PrefService*, jobject>( + JNIEnv* env, + const JavaRef<jobject>& obj) { + return PrefServiceAndroid::FromPrefServiceAndroid(obj); +} + +} // namespace jni_zero + PrefServiceAndroid::PrefServiceAndroid(PrefService* pref_service) : pref_service_(pref_service) {} @@ -25,7 +38,7 @@ // static PrefService* PrefServiceAndroid::FromPrefServiceAndroid( - const JavaParamRef<jobject>& obj) { + const JavaRef<jobject>& obj) { if (obj.is_null()) { return nullptr; }
diff --git a/components/prefs/android/pref_service_android.h b/components/prefs/android/pref_service_android.h index 73cf688..f40f2105 100644 --- a/components/prefs/android/pref_service_android.h +++ b/components/prefs/android/pref_service_android.h
@@ -25,7 +25,7 @@ // Returns the native counterpart of a Java `PrefService`. static PrefService* FromPrefServiceAndroid( - const base::android::JavaParamRef<jobject>& obj); + const base::android::JavaRef<jobject>& obj); base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
diff --git a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncService.java b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncService.java index b581ec22..cbc1a08 100644 --- a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncService.java +++ b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncService.java
@@ -159,7 +159,14 @@ * @param syncId The remote tab group ID. * @param localId The local tab group ID. */ - void updateLocalTabGroupId(String syncId, int localId); + void updateLocalTabGroupMapping(String syncId, int localId); + + /** + * Removes the in-memory mapping between sync and local tab group IDs. + * + * @param localId The local tab group ID whose mapping is to be forgotten. + */ + void removeLocalTabGroupMapping(int localId); /** * Updates the in-memory mapping between sync and local IDs for a given tab.
diff --git a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceAndroidUnitTest.java b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceAndroidUnitTest.java index 62e105c..a2b07be 100644 --- a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceAndroidUnitTest.java +++ b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceAndroidUnitTest.java
@@ -132,8 +132,13 @@ } @CalledByNative - public void testUpdateLocalTabGroupId(String syncId, int localId) { - mService.updateLocalTabGroupId(syncId, localId); + public void testUpdateLocalTabGroupMapping(String syncId, int localId) { + mService.updateLocalTabGroupMapping(syncId, localId); + } + + @CalledByNative + public void testRemoveLocalTabGroupMapping(int localId) { + mService.removeLocalTabGroupMapping(localId); } @CalledByNative
diff --git a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceImpl.java b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceImpl.java index 83150dc..05fa0cf 100644 --- a/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceImpl.java +++ b/components/saved_tab_groups/android/java/src/org/chromium/components/tab_group_sync/TabGroupSyncServiceImpl.java
@@ -107,9 +107,16 @@ } @Override - public void updateLocalTabGroupId(String syncId, int localId) { + public void updateLocalTabGroupMapping(String syncId, int localId) { if (mNativePtr == 0) return; - TabGroupSyncServiceImplJni.get().updateLocalTabGroupId(mNativePtr, this, syncId, localId); + TabGroupSyncServiceImplJni.get() + .updateLocalTabGroupMapping(mNativePtr, this, syncId, localId); + } + + @Override + public void removeLocalTabGroupMapping(int localId) { + if (mNativePtr == 0) return; + TabGroupSyncServiceImplJni.get().removeLocalTabGroupMapping(mNativePtr, this, localId); } @Override @@ -212,12 +219,15 @@ TabGroupSyncServiceImpl caller, int localGroupId); - void updateLocalTabGroupId( + void updateLocalTabGroupMapping( long nativeTabGroupSyncServiceAndroid, TabGroupSyncServiceImpl caller, String syncId, int localId); + void removeLocalTabGroupMapping( + long nativeTabGroupSyncServiceAndroid, TabGroupSyncServiceImpl caller, int localId); + void updateLocalTabId( long nativeTabGroupSyncServiceAndroid, TabGroupSyncServiceImpl caller,
diff --git a/components/saved_tab_groups/android/tab_group_sync_service_android.cc b/components/saved_tab_groups/android/tab_group_sync_service_android.cc index 497be6b0..f64ef93 100644 --- a/components/saved_tab_groups/android/tab_group_sync_service_android.cc +++ b/components/saved_tab_groups/android/tab_group_sync_service_android.cc
@@ -214,14 +214,22 @@ return TabGroupSyncConversionsBridge::CreateGroup(env, group.value()); } -void TabGroupSyncServiceAndroid::UpdateLocalTabGroupId( +void TabGroupSyncServiceAndroid::UpdateLocalTabGroupMapping( JNIEnv* env, const JavaParamRef<jobject>& j_caller, const JavaParamRef<jstring>& j_sync_id, jint j_local_id) { auto sync_id = JavaStringToUuid(env, j_sync_id); auto local_id = FromJavaTabGroupId(j_local_id); - tab_group_sync_service_->UpdateLocalTabGroupId(sync_id, local_id); + tab_group_sync_service_->UpdateLocalTabGroupMapping(sync_id, local_id); +} + +void TabGroupSyncServiceAndroid::RemoveLocalTabGroupMapping( + JNIEnv* env, + const JavaParamRef<jobject>& j_caller, + jint j_local_id) { + auto local_id = FromJavaTabGroupId(j_local_id); + tab_group_sync_service_->RemoveLocalTabGroupMapping(local_id); } void TabGroupSyncServiceAndroid::UpdateLocalTabId(
diff --git a/components/saved_tab_groups/android/tab_group_sync_service_android.h b/components/saved_tab_groups/android/tab_group_sync_service_android.h index c75ee020..33b5df6d 100644 --- a/components/saved_tab_groups/android/tab_group_sync_service_android.h +++ b/components/saved_tab_groups/android/tab_group_sync_service_android.h
@@ -90,10 +90,13 @@ jint j_group_id); // Book-keeping methods to maintain in-memory mapping of sync and local IDs. - void UpdateLocalTabGroupId(JNIEnv* env, - const JavaParamRef<jobject>& j_caller, - const JavaParamRef<jstring>& j_sync_id, - jint j_local_id); + void UpdateLocalTabGroupMapping(JNIEnv* env, + const JavaParamRef<jobject>& j_caller, + const JavaParamRef<jstring>& j_sync_id, + jint j_local_id); + void RemoveLocalTabGroupMapping(JNIEnv* env, + const JavaParamRef<jobject>& j_caller, + jint j_local_id); void UpdateLocalTabId(JNIEnv* env, const JavaParamRef<jobject>& j_caller, jint j_group_id,
diff --git a/components/saved_tab_groups/android/tab_group_sync_service_android_unittest.cc b/components/saved_tab_groups/android/tab_group_sync_service_android_unittest.cc index 9b30562..3324772 100644 --- a/components/saved_tab_groups/android/tab_group_sync_service_android_unittest.cc +++ b/components/saved_tab_groups/android/tab_group_sync_service_android_unittest.cc
@@ -58,8 +58,9 @@ MOCK_METHOD(std::optional<SavedTabGroup>, GetGroup, (LocalTabGroupID&)); MOCK_METHOD(void, - UpdateLocalTabGroupId, + UpdateLocalTabGroupMapping, (const base::Uuid&, const LocalTabGroupID&)); + MOCK_METHOD(void, RemoveLocalTabGroupMapping, (const LocalTabGroupID&)); MOCK_METHOD(void, UpdateLocalTabId, (const LocalTabGroupID&, const base::Uuid&, const LocalTabID&)); @@ -226,15 +227,21 @@ env, j_test_, j_uuid1, j_uuid2); } -TEST_F(TabGroupSyncServiceAndroidTest, UpdateLocalTabGroupId) { +TEST_F(TabGroupSyncServiceAndroidTest, UpdateLocalTabGroupMapping) { auto* env = AttachCurrentThread(); base::Uuid group_id = base::Uuid::GenerateRandomV4(); auto j_group_id = UuidToJavaString(env, group_id); + // Update the mapping. EXPECT_CALL(tab_group_sync_service_, - UpdateLocalTabGroupId(Eq(group_id), Eq(4))); - Java_TabGroupSyncServiceAndroidUnitTest_testUpdateLocalTabGroupId( + UpdateLocalTabGroupMapping(Eq(group_id), Eq(4))); + Java_TabGroupSyncServiceAndroidUnitTest_testUpdateLocalTabGroupMapping( AttachCurrentThread(), j_test_, j_group_id, 4); + + // Remove the mapping. + EXPECT_CALL(tab_group_sync_service_, RemoveLocalTabGroupMapping(Eq(4))); + Java_TabGroupSyncServiceAndroidUnitTest_testRemoveLocalTabGroupMapping( + AttachCurrentThread(), j_test_, 4); } TEST_F(TabGroupSyncServiceAndroidTest, UpdateLocalTabId) {
diff --git a/components/saved_tab_groups/tab_group_sync_service.h b/components/saved_tab_groups/tab_group_sync_service.h index 6e9382b5..18c26f4b 100644 --- a/components/saved_tab_groups/tab_group_sync_service.h +++ b/components/saved_tab_groups/tab_group_sync_service.h
@@ -114,8 +114,9 @@ virtual std::optional<SavedTabGroup> GetGroup(LocalTabGroupID& local_id) = 0; // Book-keeping methods to maintain in-memory mapping of sync and local IDs. - virtual void UpdateLocalTabGroupId(const base::Uuid& sync_id, - const LocalTabGroupID& local_id) = 0; + virtual void UpdateLocalTabGroupMapping(const base::Uuid& sync_id, + const LocalTabGroupID& local_id) = 0; + virtual void RemoveLocalTabGroupMapping(const LocalTabGroupID& local_id) = 0; virtual void UpdateLocalTabId(const LocalTabGroupID& local_group_id, const base::Uuid& sync_tab_id, const LocalTabID& local_tab_id) = 0;
diff --git a/components/saved_tab_groups/tab_group_sync_service_impl.cc b/components/saved_tab_groups/tab_group_sync_service_impl.cc index d28d418..e3191788 100644 --- a/components/saved_tab_groups/tab_group_sync_service_impl.cc +++ b/components/saved_tab_groups/tab_group_sync_service_impl.cc
@@ -142,12 +142,17 @@ : std::nullopt; } -void TabGroupSyncServiceImpl::UpdateLocalTabGroupId( +void TabGroupSyncServiceImpl::UpdateLocalTabGroupMapping( const base::Uuid& sync_id, const LocalTabGroupID& local_id) { model_->OnGroupOpenedInTabStrip(sync_id, local_id); } +void TabGroupSyncServiceImpl::RemoveLocalTabGroupMapping( + const LocalTabGroupID& local_id) { + model_->OnGroupClosedInTabStrip(local_id); +} + void TabGroupSyncServiceImpl::UpdateLocalTabId( const LocalTabGroupID& local_group_id, const base::Uuid& sync_tab_id,
diff --git a/components/saved_tab_groups/tab_group_sync_service_impl.h b/components/saved_tab_groups/tab_group_sync_service_impl.h index 21059cc7..0f806ff 100644 --- a/components/saved_tab_groups/tab_group_sync_service_impl.h +++ b/components/saved_tab_groups/tab_group_sync_service_impl.h
@@ -57,8 +57,9 @@ std::vector<SavedTabGroup> GetAllGroups() override; std::optional<SavedTabGroup> GetGroup(const base::Uuid& guid) override; std::optional<SavedTabGroup> GetGroup(LocalTabGroupID& local_id) override; - void UpdateLocalTabGroupId(const base::Uuid& sync_id, - const LocalTabGroupID& local_id) override; + void UpdateLocalTabGroupMapping(const base::Uuid& sync_id, + const LocalTabGroupID& local_id) override; + void RemoveLocalTabGroupMapping(const LocalTabGroupID& local_id) override; void UpdateLocalTabId(const LocalTabGroupID& local_group_id, const base::Uuid& sync_tab_id, const LocalTabID& local_tab_id) override;
diff --git a/components/saved_tab_groups/tab_group_sync_service_unittest.cc b/components/saved_tab_groups/tab_group_sync_service_unittest.cc index 9ec5718..8750b9c 100644 --- a/components/saved_tab_groups/tab_group_sync_service_unittest.cc +++ b/components/saved_tab_groups/tab_group_sync_service_unittest.cc
@@ -208,10 +208,10 @@ EXPECT_EQ(group->color(), visual_data.color()); } -TEST_F(TabGroupSyncServiceTest, UpdateLocalTabGroupId) { +TEST_F(TabGroupSyncServiceTest, UpdateLocalTabGroupMapping) { LocalTabGroupID local_id_2 = test::GenerateRandomTabGroupID(); - tab_group_sync_service_->UpdateLocalTabGroupId(group_1_.saved_guid(), - local_id_2); + tab_group_sync_service_->UpdateLocalTabGroupMapping(group_1_.saved_guid(), + local_id_2); auto retrieved_group = tab_group_sync_service_->GetGroup(local_id_2); EXPECT_TRUE(retrieved_group.has_value());
diff --git a/components/supervised_user/android/java/src/org/chromium/components/supervised_user/SupervisedUserPreferences.java b/components/supervised_user/android/java/src/org/chromium/components/supervised_user/SupervisedUserPreferences.java index b2cedf4f..002e724 100644 --- a/components/supervised_user/android/java/src/org/chromium/components/supervised_user/SupervisedUserPreferences.java +++ b/components/supervised_user/android/java/src/org/chromium/components/supervised_user/SupervisedUserPreferences.java
@@ -4,6 +4,7 @@ package org.chromium.components.supervised_user; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.components.prefs.PrefService; @@ -17,6 +18,6 @@ @NativeMethods public interface Natives { - boolean isSubjectToParentalControls(PrefService prefService); + boolean isSubjectToParentalControls(@JniType("PrefService*") PrefService prefService); } }
diff --git a/components/supervised_user/core/browser/supervised_user_preferences.cc b/components/supervised_user/core/browser/supervised_user_preferences.cc index 302df37..c7127a8 100644 --- a/components/supervised_user/core/browser/supervised_user_preferences.cc +++ b/components/supervised_user/core/browser/supervised_user_preferences.cc
@@ -17,7 +17,9 @@ #include "components/supervised_user/core/common/supervised_user_constants.h" #if BUILDFLAG(IS_ANDROID) -#include "components/prefs/android/pref_service_android.h" +#include "components/prefs/pref_service.h" + +// Must come after other includes, because FromJniType() uses PrefService. #include "components/supervised_user/android/supervised_user_preferences_jni_headers/SupervisedUserPreferences_jni.h" #endif @@ -216,8 +218,7 @@ #if BUILDFLAG(IS_ANDROID) static jboolean JNI_SupervisedUserPreferences_IsSubjectToParentalControls( JNIEnv* env, - const base::android::JavaParamRef<jobject>& jprefs) { - PrefService* prefs = PrefServiceAndroid::FromPrefServiceAndroid(jprefs); + PrefService* prefs) { return prefs && supervised_user::IsSubjectToParentalControls(*prefs); } #endif
diff --git a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc index 68fd5a7..bd99796a 100644 --- a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc +++ b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
@@ -307,7 +307,15 @@ // Tests the composited vs main thread scrolling histogram in the presence of // passive event handlers. These should behave the same as the case without any // event handlers at all. -IN_PROC_BROWSER_TEST_P(CompositedScrollingMetricTest, PassiveEventHandlers) { + +// TODO(crbug.com/335028963): Re-enable this test +#if BUILDFLAG(IS_MAC) +#define MAYBE_PassiveEventHandlers DISABLED_PassiveEventHandlers +#else +#define MAYBE_PassiveEventHandlers PassiveEventHandlers +#endif +IN_PROC_BROWSER_TEST_P(CompositedScrollingMetricTest, + MAYBE_PassiveEventHandlers) { LoadURL(R"HTML( data:text/html;charset=utf-8, <!DOCTYPE html>
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 5b2a0a5..aadf013 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -5713,12 +5713,6 @@ common_params_->should_replace_current_entry = ShouldReplaceCurrentEntryForFailedNavigation(); - // Set |origin_to_commit| for the renderer; error pages should always commit - // in an opaque origin (with the precursor reflecting the destination URL). - DCHECK(!commit_params_->origin_to_commit); - commit_params_->origin_to_commit = GetOriginToCommit(); - DCHECK(commit_params_->origin_to_commit->opaque()); - // Don't pass the base url in a failed navigation. common_params_->initiator_base_url = std::nullopt; @@ -7801,8 +7795,15 @@ did_receive_early_hints_before_cross_origin_redirect_); } - // TODO(https://crbug.com/888079) Take sandbox into account. - std::optional<url::Origin> origin_to_commit = GetOriginToCommit(); + // Calculate origin in which this navigation would commit so it can be + // compared with what is generated by the renderer process and the browser + // process at commit time. + // TODO(https://crbug.com/888079): Consider using this cached value everywhere + // we currently call `GetOriginToCommit()`, to prevent nonce mismatches. + browser_side_origin_to_commit_with_debug_info_ = + GetOriginToCommitWithDebugInfo(); + std::optional<url::Origin> origin_to_commit = + browser_side_origin_to_commit_with_debug_info_.first; same_origin_ = (previous_render_frame_host->GetLastCommittedOrigin() == origin_to_commit); @@ -7810,26 +7811,24 @@ commit_params_->is_load_data_with_base_url = IsLoadDataWithBaseURL(); - // Calculate origin in which this navigation would commit so it can be - // compared with what is generated by the renderer process and the browser - // process at commit time. - browser_side_origin_to_commit_with_debug_info_ = - GetOriginToCommitWithDebugInfo(); - - // Set origin_to_commit for data: URLs. Set it here because otherwise the - // origin (and hence the nonce) is separately calculated on the renderer side - // and sent with DidCommit. At that point the origin used to create the - // SiteInstance will differ from the one committed in the renderer. A - // consistent nonce across the browser and renderer can be used to determine - // which data: URL SiteInstance should be used in - // RenderFrameProxyHost::OpenURL. + // Set origin_to_commit for: + // 1) Error pages, which should always commit in an opaque origin (with the + // precursor reflecting the destination URL). + // 2) data: URLs, which should also be opaque. + // Set the origin here because otherwise the origin (and hence the nonce) is + // separately calculated on the renderer side and sent with DidCommit. At that + // point the origin used to create the SiteInstance will differ from the one + // committed in the renderer. For data: URLs, a consistent nonce across the + // browser and renderer can be used to determine which data: URL SiteInstance + // should be used in RenderFrameProxyHost::OpenURL. // We do not need to set it for LoadDataWithBaseURL cases, because it will not // lead to ambiguous cases where multiple data: SiteInstances will be in the // same group. However, when the base URL is empty, LoadDataWithBaseURL is // treated like a regular data: URL. - if (common_params_->url.SchemeIs(url::kDataScheme) && - !IsLoadDataWithBaseURL()) { + if (is_error || (common_params_->url.SchemeIs(url::kDataScheme) && + !IsLoadDataWithBaseURL())) { commit_params_->origin_to_commit = origin_to_commit; + CHECK(!is_error || commit_params_->origin_to_commit->opaque()); } if (!IsSameDocument()) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 983778c..b16c0c8 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -756,7 +756,7 @@ const url::Origin& renderer_side_origin = params.origin; std::pair<std::optional<url::Origin>, std::string> browser_side_origin_and_debug_info = - navigation_request->GetOriginToCommitWithDebugInfo(); + navigation_request->browser_side_origin_to_commit_with_debug_info(); if (renderer_side_origin.scheme() == url::kContentScheme && browser_side_origin_and_debug_info.first->opaque()) { return; @@ -767,10 +767,21 @@ bool origins_match = (browser_side_origin_and_debug_info.first.value() == renderer_side_origin); - // For opaque origins, we say the browser and renderer calculated origins - // match if their precursor origins match (their nonces might not match). + // For opaque origins, we can check for equality if the opaque origin is not + // newly created in the renderer. If the opaque origin can be known by the + // browser, e.g. if the opaque origin is inherited/copied from another + // document, or is from the browser-sent `origin_to_commit`, then the browser + // calculated origin must match the one used by the renderer in the end. On + // the other hand, if the opaque origin is newly created, e.g. a new sandboxed + // opaque origin, we can only match the precursor origin. The renderer will + // tell us if the origin is newly created in the renderer or not through + // appending "is_newly_created" in the end of `origin_calculation_debug_info`. + // See also `DocumentLoader::CalculateOrigin()`. + // TODO(https://crbug.com/888079): Consider adding a separate boolean that + // tracks this instead of piggybacking `origin_calculation_debug_info`. if (renderer_side_origin.opaque() && - browser_side_origin_and_debug_info.first->opaque()) { + browser_side_origin_and_debug_info.first->opaque() && + params.origin_calculation_debug_info.ends_with("is_newly_created")) { origins_match = (renderer_side_origin.GetTupleOrPrecursorTupleIfOpaque() == browser_side_origin_and_debug_info.first ->GetTupleOrPrecursorTupleIfOpaque()); @@ -14108,8 +14119,12 @@ DCHECK_EQ(net::OK, navigation_request->GetNetErrorCode()); // `origin_to_commit` is currently only set only on failed navigations or // data: URL navigations. - DCHECK(!commit_params->origin_to_commit || - common_params->url.SchemeIs(url::kDataScheme)); + if (commit_params->origin_to_commit) { + DCHECK(common_params->url.SchemeIs(url::kDataScheme)); + CHECK_EQ(commit_params->origin_to_commit.value(), + navigation_request->browser_side_origin_to_commit_with_debug_info() + .first.value()); + } IncreaseCommitNavigationCounter(); mojo::PendingRemote<blink::mojom::CodeCacheHost> code_cache_host; mojo::PendingRemote<blink::mojom::CodeCacheHost> @@ -14274,6 +14289,9 @@ blink::mojom::PolicyContainerPtr policy_container) { // `origin_to_commit` must be set on failed navigations. DCHECK(commit_params->origin_to_commit); + CHECK_EQ(commit_params->origin_to_commit.value(), + navigation_request->browser_side_origin_to_commit_with_debug_info() + .first.value()); DCHECK(navigation_client && navigation_request); DCHECK_NE(GURL(), common_params->url); DCHECK_NE(net::OK, error_code);
diff --git a/content/public/browser/on_device_model_service_instance.cc b/content/public/browser/on_device_model_service_instance.cc index 95227a3..ee42377da 100644 --- a/content/public/browser/on_device_model_service_instance.cc +++ b/content/public/browser/on_device_model_service_instance.cc
@@ -10,23 +10,29 @@ namespace content { +namespace { +void InitOnDeviceModelService( + mojo::Remote<on_device_model::mojom::OnDeviceModelService>& + service_remote) { + auto receiver = service_remote.BindNewPipeAndPassReceiver(); + service_remote.reset_on_disconnect(); + ServiceProcessHost::Launch<on_device_model::mojom::OnDeviceModelService>( + std::move(receiver), ServiceProcessHost::Options() + .WithDisplayName("On-Device Model Service") + .Pass()); +} +} // namespace + // static const mojo::Remote<on_device_model::mojom::OnDeviceModelService>& GetRemoteOnDeviceModelService() { static base::NoDestructor< mojo::Remote<on_device_model::mojom::OnDeviceModelService>> - service_remote([]() { - mojo::Remote<on_device_model::mojom::OnDeviceModelService> - service_remote; - auto receiver = service_remote.BindNewPipeAndPassReceiver(); - service_remote.reset_on_disconnect(); - ServiceProcessHost::Launch< - on_device_model::mojom::OnDeviceModelService>( - std::move(receiver), ServiceProcessHost::Options() - .WithDisplayName("On-Device Model Service") - .Pass()); - return service_remote; - }()); + service_remote; + + if (!*service_remote) { + InitOnDeviceModelService(*service_remote); + } return *service_remote; }
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 1c618b7..f92f89a 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -1231,11 +1231,11 @@ "MacAllowBackgroundingRenderProcesses", base::FEATURE_DISABLED_BY_DEFAULT); -// Enables a fix for a macOS IME Live Conversion issue. crbug.com/1328530 and -// crbug.com/1342551 +// Enables a fix for a macOS IME Live Conversion issue. crbug.com/40226470 and +// crbug.com/40060200 BASE_FEATURE(kMacImeLiveConversionFix, "MacImeLiveConversionFix", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kMacSyscallSandbox, "MacSyscallSandbox",
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 34da5b74..045a2a27 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
@@ -818,7 +818,6 @@ crbug.com/angleproject/3684 [ android angle-opengles ] conformance2/renderbuffers/multisample-with-full-sample-counts.html [ Failure ] crbug.com/1521117 [ android android-pixel-4 angle-opengles passthrough ] deqp/functional/gles3/multisample/fbo_4_samples.html [ RetryOnFailure ] -crbug.com/1521117 [ android android-pixel-4 angle-opengles passthrough ] deqp/functional/gles3/multisample/fbo_max_samples.html [ RetryOnFailure ] #####################
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc index 0e87c46..e0be162 100644 --- a/content/test/navigation_simulator_impl.cc +++ b/content/test/navigation_simulator_impl.cc
@@ -1588,7 +1588,9 @@ if (same_document) { params->origin = current_rfh->GetLastCommittedOrigin(); } else { - params->origin = origin_.value_or(request_->GetOriginToCommit().value()); + params->origin = origin_.value_or( + request_->browser_side_origin_to_commit_with_debug_info() + .first.value()); } if (same_document) {
diff --git a/docs/testing/chromeos_integration/crosier_metadata.md b/docs/testing/chromeos_integration/crosier_metadata.md new file mode 100644 index 0000000..15ee6f3 --- /dev/null +++ b/docs/testing/chromeos_integration/crosier_metadata.md
@@ -0,0 +1,58 @@ +# Metadata for Crosier tests + +## Create a yaml file with test case details + +Create a yaml file in the same location of your test source file. Example of +such yaml file: + +```yaml +--- +name: "LockScreen" +harness: "crosier" +category: "integration" +owners: + - email: "test-owner-email@google.com" + - email: "chromeos-sw-engprod@google.com" +hw_agnostic: False +criteria: | + Tests that dbus messages for lid close trigger screen lock. This only tests + the "lock on lid close" pref state. +cases: + - id: "CloseLidDbusIntegration" + tags: ["crosier:crosierdemosuite", "crosier:cq"] + - id: "CloseLidPref" + tags: ["crosier:crosierdemosuite", "crosier:cq", "crosier:informational"] +... +``` + +Pay specifal attention to the list of `tags` for each test case. Using these +tags, tests are being allocated to ChromeOS CI/CQ scheduling suites. + +Following tags are recognized and supported: + +* `crosier:crosierdemosuite` - test case will run daily in a dedicated, +non-critical test suite for stability and regression monitoring. +* `crosier:cq` - test case will run in global CQ and post-submit snapshot +builds. +* `crosier:informational` - test case will be considered as non-critical, i.e. +not included in the critical CQ test suite. + +## Include new yaml file in Crosier binary build + +The link to all yaml files should be added to the `crosier_metadata` rules that +is included by the Crosier `chromeos_integration_tests` rule of the +[BUILD.gn](https://chromium.googlesource.com/chromium/src/+/main/chrome/test/BUILD.gn) +file: + +``` +copy("crosier_metadata") { + sources = [ + ... + "../browser/ash/login/lock/lock_screen_integration_test.yaml", + ... + ... + ] + outputs = [ "$root_out_dir/crosier_metadata/{{source_file_part}}" ] +} + +```
diff --git a/docs/testing/chromeos_integration/development_guide.md b/docs/testing/chromeos_integration/development_guide.md index e08dbde..9b8e4fd4 100644 --- a/docs/testing/chromeos_integration/development_guide.md +++ b/docs/testing/chromeos_integration/development_guide.md
@@ -1,4 +1,4 @@ -# Development Guide +# Crosier Development Guide This doc assumes you're already familiar with ChromeOS on-device development. If not, please follow @@ -21,6 +21,13 @@ See the [demo test](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/base/chromeos/crosier/demo_integration_test.cc;l=19) for instructions +## Test metadata + +Each Crosier test being added should include test metadata in `yaml` format. + +See [Crosier metadata guide](https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/chromeos_integration/crosier_metadata.md) +for more information on how to add it. + ## Continuous builders Currently the test binary runs against both Ash and Lacros on CI only.
diff --git a/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json b/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json index 71c43f9..7294a8b 100644 --- a/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json +++ b/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json
@@ -54,7 +54,8 @@ "$build/siso": { "configs": [ "builder", - "remote-library-link" + "remote-library-link", + "remote-exec-link" ], "enable_cloud_profiler": true, "enable_cloud_trace": true,
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index c299769..ef3f1d5 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -6440,7 +6440,7 @@ name: "Comparison ios (reclient)" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" - dimensions: "cpu:x86-64" + dimensions: "cpu:arm64" dimensions: "free_space:standard" dimensions: "os:Mac-13|Mac-14" dimensions: "pool:luci.chromium.ci"
diff --git a/infra/config/subprojects/build/build.star b/infra/config/subprojects/build/build.star index 840c40f..e4d7dc7c 100644 --- a/infra/config/subprojects/build/build.star +++ b/infra/config/subprojects/build/build.star
@@ -352,8 +352,6 @@ category = "cros", short_name = "siso", ), - # TODO: b/329399631#comment39 - Enable remote-exec-link after resolving the Segmentation fault issue. - siso_configs = ["builder", "remote-library-link"], ) cq_build_perf_builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 699cbe0..5362982 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1412,6 +1412,7 @@ }, builderless = True, cores = None, + cpu = cpu.ARM64, console_view_entry = consoles.console_view_entry( category = "ios", short_name = "cmp",
diff --git a/internal b/internal index 6365d27..5fb766e 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 6365d276cb6ee8b2d6992bcc8699f3e1eff7fe3b +Subproject commit 5fb766e4a38b8e77fc63d347b829a1903c23a919
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index c12a6d6..81c096b 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -906,47 +906,57 @@ // _chromeMain.reset() is a blocking call that regularly causes // applicationWillTerminate to fail after a 5s delay. Experiment with skipping // this shutdown call. See: crbug.com/1328891 - // TODO(crbug.com/325597817): Update this logic for multiple browser states. if (base::FeatureList::IsEnabled(kFastApplicationWillTerminate)) { - // Expected number of time the `completionBlock` defined below needs to + // Expected number of time the `closure` defined below needs to // be called before it signal the semaphore. This corresponds to the // number of services that needs to be waited for. - uint32_t expected_count = 1; + uint32_t expectedCount = 0; - ChromeBrowserState* browserState = self.appState.mainBrowserState; - if (browserState->HasOffTheRecordChromeBrowserState()) { - expected_count += 1; - } - + // MetricsService doesn't depend on a browser state. metrics::MetricsService* metrics = GetApplicationContext()->GetMetricsService(); if (metrics) { - expected_count += 1; + expectedCount += 1; } + std::vector<ChromeBrowserState*> loadedBrowserStates = + GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetLoadedBrowserStates(); + for (ChromeBrowserState* browserState : loadedBrowserStates) { + expectedCount += 1; + if (browserState->HasOffTheRecordChromeBrowserState()) { + expectedCount += 1; + } + } + + // `dispatch_semaphore_signal` is called only once when `closure` is called + // `expectedCount` times. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); base::RepeatingClosure closure = - ExpectNCall(expected_count, base::BindRepeating(^{ + ExpectNCall(expectedCount, base::BindRepeating(^{ dispatch_semaphore_signal(semaphore); })); - SessionRestorationServiceFactory::GetForBrowserState(browserState) - ->InvokeClosureWhenBackgroundProcessingDone(closure); - - if (browserState->HasOffTheRecordChromeBrowserState()) { - ChromeBrowserState* otrBrowserState = - browserState->GetOffTheRecordChromeBrowserState(); - SessionRestorationServiceFactory::GetForBrowserState(otrBrowserState) + for (ChromeBrowserState* browserState : loadedBrowserStates) { + SessionRestorationServiceFactory::GetForBrowserState(browserState) ->InvokeClosureWhenBackgroundProcessingDone(closure); + + if (browserState->HasOffTheRecordChromeBrowserState()) { + ChromeBrowserState* otrBrowserState = + browserState->GetOffTheRecordChromeBrowserState(); + SessionRestorationServiceFactory::GetForBrowserState(otrBrowserState) + ->InvokeClosureWhenBackgroundProcessingDone(closure); + } } if (metrics) { metrics->Stop(); - // MetricsService::Stop() depends on a committed local state, and does so - // asynchronously. To avoid losing metrics, this minimum wait is required. - // This will introduce a wait that will likely be the source of a number - // of watchdog kills, but it should still be fewer than the number of - // kills `_chromeMain.reset()` is responsible for. + // MetricsService::Stop() depends on a committed local state, and does + // so asynchronously. To avoid losing metrics, this minimum wait is + // required. This will introduce a wait that will likely be the source + // of a number of watchdog kills, but it should still be fewer than the + // number of kills `_chromeMain.reset()` is responsible for. GetApplicationContext()->GetLocalState()->CommitPendingWrite({}, closure); }
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.h b/ios/chrome/browser/ui/settings/settings_table_view_controller.h index 27daa3b..77c3ce1 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.h +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.h
@@ -5,15 +5,10 @@ #ifndef IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_TABLE_VIEW_CONTROLLER_H_ #define IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_TABLE_VIEW_CONTROLLER_H_ -#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" +#import "ios/chrome/browser/ui/settings/settings_controller_protocol.h" #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h" -@protocol ApplicationCommands; class Browser; -@protocol BrowserCommands; -@protocol BrowsingDataCommands; -@class SigninInteractionController; -@protocol SnackbarCommands; // This class is the TableView for the application settings. @interface SettingsTableViewController
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 632bbf2..66143b9d 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/ui/settings/settings_table_view_controller.h" -#import <MaterialComponents/MaterialSnackbar.h> #import <memory> #import "base/apple/foundation_util.h" @@ -65,11 +64,9 @@ #import "ios/chrome/browser/shared/model/prefs/pref_names.h" #import "ios/chrome/browser/shared/model/utils/first_run_util.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" -#import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h" #import "ios/chrome/browser/shared/public/commands/show_signin_command.h" -#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/public/features/system_flags.h" #import "ios/chrome/browser/shared/ui/symbols/buildflags.h" @@ -190,7 +187,6 @@ NotificationsCoordinatorDelegate, PrivacyCoordinatorDelegate, SafetyCheckCoordinatorDelegate, - SettingsControllerProtocol, SearchEngineObserving, SyncObserverModelBridge> { // The browser where the settings are being displayed. @@ -295,10 +291,6 @@ @property(nonatomic, strong, readonly) TableViewInfoButtonItem* managedFeedSettingsItem; -@property(nonatomic, readonly, weak) - id<ApplicationCommands, BrowserCommands, BrowsingDataCommands> - dispatcher; - // YES if the default browser settings row is currently showing the notification // dot. @property(nonatomic, assign) BOOL showingDefaultBrowserNotificationDot;
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm index 4d66faf..f24c6eb9 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm
@@ -29,6 +29,7 @@ #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/browsing_data_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" +#import "ios/chrome/browser/shared/public/commands/settings_commands.h" #import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_detail_icon_item.h"
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm index 3a51f7b..c6955f45 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm
@@ -419,9 +419,7 @@ return; } - if (detachChange.group()) { - [self updateCellGroup:detachChange.group()]; - } else { + if (!detachChange.group()) { // Get the identifier to remove. web::WebState* detachedWebState = detachChange.detached_web_state(); GridItemIdentifier* identifierToRemove = @@ -510,10 +508,16 @@ // The activation is handled after this switch statement. break; } - case WebStateListChange::Type::kDetach: - // Do nothing when a WebState is detached, as this is already handled in + case WebStateListChange::Type::kDetach: { + const WebStateListChangeDetach& detachChange = + change.As<WebStateListChangeDetach>(); + if (detachChange.group()) { + [self updateCellGroup:detachChange.group()]; + } + // Do not manage other case scenarios as this is already handled in // `-willChangeWebStateList:change:status:` function. break; + } case WebStateListChange::Type::kMove: { const WebStateListChangeMove& moveChange = change.As<WebStateListChangeMove>();
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_groups_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_groups_egtest.mm index 64d5857..8301dec 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_groups_egtest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_groups_egtest.mm
@@ -110,8 +110,7 @@ } // Tests that creates a tab group and opens the grouped tab. -// TODO(crbug.com/333892967): The test fails on bots. -- (void)DISABLED_testCompleteTabGroupCreation { +- (void)testCompleteTabGroupCreation { [ChromeEarlGreyUI openTabGrid]; // Open the creation view.
diff --git a/ios_internal b/ios_internal index f758ded..ce28903 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit f758ded9acac8b0e8eb6f1638b8fb945c15da69d +Subproject commit ce28903ff84c8484e00400f18816c7dac205a29b
diff --git a/media/gpu/test/video_player/decoder_wrapper.cc b/media/gpu/test/video_player/decoder_wrapper.cc index cbd9f0ae..d4ec9bb36 100644 --- a/media/gpu/test/video_player/decoder_wrapper.cc +++ b/media/gpu/test/video_player/decoder_wrapper.cc
@@ -369,9 +369,7 @@ // should (naively moving this task there doesn't work because it prevents the // V4L2VideoDecoder backend from polling the device driver). #if BUILDFLAG(USE_V4L2_CODEC) - delay = base::FeatureList::IsEnabled(kV4L2FlatStatefulVideoDecoder) - ? base::Milliseconds(5) - : base::Milliseconds(1); + delay = base::Milliseconds(1); static bool log_delay_message = true; if (log_delay_message) { LOG(INFO) << "Using a delay of " << delay
diff --git a/services/webnn/tflite/graph_builder.cc b/services/webnn/tflite/graph_builder.cc index dccaee07..569d05d 100644 --- a/services/webnn/tflite/graph_builder.cc +++ b/services/webnn/tflite/graph_builder.cc
@@ -386,6 +386,9 @@ case mojom::Operation::Tag::kTranspose: operator_offset = SerializeTranspose(*op.get_transpose()); break; + case mojom::Operation::Tag::kWhere: + operator_offset = SerializeWhere(*op.get_where()); + break; case mojom::Operation::Tag::kBatchNormalization: return base::unexpected("batchNormalization is not implemented"); case mojom::Operation::Tag::kExpand: @@ -416,8 +419,6 @@ return base::unexpected("softsign is not implemented"); case mojom::Operation::Tag::kTriangular: return base::unexpected("triangular is not implemented"); - case mojom::Operation::Tag::kWhere: - return base::unexpected("where is not implemented"); } operators_.emplace_back(operator_offset); @@ -1594,4 +1595,44 @@ transpose.permutation); } +auto GraphBuilder::SerializeWhere(const mojom::Where& where) -> OperatorOffset { + // The data type of WebNN condition operand is uint8, but TFLite requires the + // condition operand to be of type bool, so a cast operation need to be + // inserted before the operation to convert uint8 to bool for the condition + // operand. + const mojom::Operand& condition_operand = + GetOperand(where.condition_operand_id); + // The shape of condition operand has been validated to not overflow before + // creating tensor. + const auto signed_condition_dimensions = + ToSignedDimensions(condition_operand.dimensions); + CHECK(signed_condition_dimensions.has_value()); + const int32_t condition_bool_tensor_index = + base::checked_cast<int32_t>(tensors_.size()); + tensors_.emplace_back(::tflite::CreateTensor( + builder_, builder_.CreateVector<int32_t>(*signed_condition_dimensions), + ::tflite::TensorType_BOOL)); + + CHECK_EQ(condition_operand.data_type, mojom::Operand::DataType::kUint8); + operators_.emplace_back(SerializeCastOperation( + operand_to_index_map_.at(where.condition_operand_id), + /*input_tensor_type=*/::tflite::TensorType_UINT8, + condition_bool_tensor_index, + /*output_tensor_type=*/::tflite::TensorType_BOOL)); + + // TFLite SELECT_V2 builtin operator supports broadcastable shapes between + // `condition`, `true` and `false` operand. + const uint32_t operator_code_index = + GetOperatorCodeIndex(::tflite::BuiltinOperator_SELECT_V2); + const std::array<int32_t, 3> op_inputs = { + condition_bool_tensor_index, + operand_to_index_map_.at(where.true_value_operand_id), + operand_to_index_map_.at(where.false_value_operand_id)}; + const std::array<int32_t, 1> op_outputs = { + operand_to_index_map_.at(where.output_operand_id)}; + return ::tflite::CreateOperator(builder_, operator_code_index, + builder_.CreateVector<int32_t>(op_inputs), + builder_.CreateVector<int32_t>(op_outputs)); +} + } // namespace webnn::tflite
diff --git a/services/webnn/tflite/graph_builder.h b/services/webnn/tflite/graph_builder.h index 786dc00..b68ae4a2 100644 --- a/services/webnn/tflite/graph_builder.h +++ b/services/webnn/tflite/graph_builder.h
@@ -186,6 +186,7 @@ const mojom::Split& split); OperatorOffset SerializeTanh(const mojom::Tanh& tanh); OperatorOffset SerializeTranspose(const mojom::Transpose& transpose); + OperatorOffset SerializeWhere(const mojom::Where& where); // No further methods may be called on this class after calling this method // because the buffer of `buffer_` is now owned by the detached buffer.
diff --git a/services/webnn/tflite/op_resolver.cc b/services/webnn/tflite/op_resolver.cc index 3aa8fce..2f093a1 100644 --- a/services/webnn/tflite/op_resolver.cc +++ b/services/webnn/tflite/op_resolver.cc
@@ -165,6 +165,8 @@ ::tflite::ops::builtin::Register_RESIZE_NEAREST_NEIGHBOR(), /* min_version = */ 1, /* max_version = */ 3); + AddBuiltin(::tflite::BuiltinOperator_SELECT_V2, + ::tflite::ops::builtin::Register_SELECT_V2()); AddBuiltin(::tflite::BuiltinOperator_SIN, ::tflite::ops::builtin::Register_SIN()); AddBuiltin(::tflite::BuiltinOperator_SLICE,
diff --git a/testing/libfuzzer/fuzzer_test.gni b/testing/libfuzzer/fuzzer_test.gni index 226db68..097f327 100644 --- a/testing/libfuzzer/fuzzer_test.gni +++ b/testing/libfuzzer/fuzzer_test.gni
@@ -32,6 +32,8 @@ # - seed_corpus_deps - dependencies for generating the seed corpus. # - grammar_options - defines a grammar used by a grammar based mutator. # - exclude_main - if you're going to provide your own 'main' function +# - high_end_job_required - whether the fuzzer requires bigger machines to run. +# Optional argument. # # If use_libfuzzer gn flag is defined, then proper fuzzer would be build. # Without use_libfuzzer or use_afl a unit-test style binary would be built on @@ -42,7 +44,19 @@ # config (.options file) file would be generated or modified in root output # dir (next to test). template("fuzzer_test") { - if (!disable_libfuzzer && use_fuzzing_engine) { + _high_end_job_required = false + if (defined(invoker.high_end_job_required)) { + _high_end_job_required = invoker.high_end_job_required + } + + # If the job is a high_end job and that we are currently building a high_end + # target, we should compile this fuzzer_test in. Otherwise, for now, we just + # compile everything in. + # TODO(crbug.com/333831251): Once CF supports high end jobs, do not compile + # high end targets except for high end jobs. + _should_build = (_high_end_job_required || !high_end_fuzzer_targets) && + !disable_libfuzzer && use_fuzzing_engine + if (_should_build) { assert(defined(invoker.sources), "Need sources in $target_name.") test_deps = [] @@ -315,6 +329,12 @@ # noop on unsupported platforms. # mark attributes as used. not_needed(invoker, "*") + not_needed(invoker, + [ + "deps", + "seed_corpus", + "sources", + ]) group(target_name) { }
diff --git a/testing/test.gni b/testing/test.gni index 9b057e7..5f92dd5c 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -146,34 +146,51 @@ # don't have issues. import("//third_party/jni_zero/jni_zero.gni") } - target(invoker.target_type, target_name) { - forward_variables_from(invoker, - "*", - TESTONLY_AND_VISIBILITY + _rs_vars + [ "fuzztests" ]) - forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) - sources = _cc_sources - if (!defined(deps)) { - deps = [] - } - if (!defined(ldflags)) { - ldflags = [] - } - if (_rs_sources != []) { - deps += [ ":${_rust_target_name}" ] + _building_fuzztest_fuzzer = + defined(invoker.fuzztests) && use_fuzzing_engine && is_linux + + # Fuzz tests are small fuzzers that do not require particularly-powerful + # machines to run, so we do not build them when `high_end_fuzzer_targets` + # is true and we are building fuzztests in fuzzing mode. + if (_building_fuzztest_fuzzer && high_end_fuzzer_targets) { + not_needed(invoker, "*") + not_needed("*") + + # We still want a reachable target, so make it a no-op empty group. This + # will let the fuzzer builders crawl the build graph and invoke ninja in + # the same way regardless of GN args. + group(target_name) { } - if (defined(invoker.fuzztests)) { - deps += [ "//third_party/fuzztest" ] + } else { + target(invoker.target_type, target_name) { + forward_variables_from( + invoker, + "*", + TESTONLY_AND_VISIBILITY + _rs_vars + [ "fuzztests" ]) + forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) + sources = _cc_sources + if (!defined(deps)) { + deps = [] + } + if (!defined(ldflags)) { + ldflags = [] + } + + if (_rs_sources != []) { + deps += [ ":${_rust_target_name}" ] + } + if (defined(invoker.fuzztests)) { + deps += [ "//third_party/fuzztest" ] + } } } - if (defined(invoker.fuzztests) && use_fuzzing_engine && is_linux) { + if (_building_fuzztest_fuzzer && !high_end_fuzzer_targets) { # This test contains fuzztests. We want to package them up in a way # which ClusterFuzz knows how to extract. We need to: # 1) make an executable for each individual fuzz test; - # 2) name the main executable something specific so that ClusterFuzz - # knows how to extract it - # 3) check that the fuzztests variable is correct. + # 2) check that the fuzztests variable is correct. # At present, all this is likely to work only if invoker.target_type # is 'executable', since we generate a wrapper script that assumes so. # At the moment, we aim to fuzz these fuzztests only on Linux so that's
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 761f25ae..d7413509 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -11737,12 +11737,13 @@ ], "experiments": [ { - "name": "LowDeadline", + "name": "Deadline1500_20240415_M124+", "params": { - "MinorModeRestrictionsFetchDeadlineMs": "1000" + "MinorModeRestrictionsFetchDeadlineMs": "1500" }, "enable_features": [ - "MinorModeRestrictionsForHistorySyncOptIn" + "MinorModeRestrictionsForHistorySyncOptIn", + "UseSystemCapabilitiesForMinorModeRestrictions" ] } ] @@ -17751,6 +17752,21 @@ ] } ], + "SearchEnginePromoDialogRewrite": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "SearchEnginePromoDialogRewrite" + ] + } + ] + } + ], "SearchEnginesPromoV3": [ { "platforms": [ @@ -22172,6 +22188,24 @@ ] } ], + "WebRTC-LibvpxVp9Encoder-SvcFrameDropConfig": [ + { + "platforms": [ + "android", + "android_webview", + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled,layer_drop_mode:1,max_consec_drop:2,_20240416" + } + ] + } + ], "WebRTC-PaddingMode-RecentLargePacket": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index 49e434db..6557da0 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 49e434dba2f98a749fe36d44137cee2b8f039800 +Subproject commit 6557da03c85eee30448e1fefc2d89bdc348c580d
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 4861831..740bc1c 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -1303,6 +1303,11 @@ const base::FeatureParam<int> kLCPCriticalPathPredictorMaxElementLocatorLength{ &kLCPCriticalPathPredictor, "lcpp_max_element_locator_length", 1024}; +const base::FeatureParam<bool> + kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost{ + &kLCPCriticalPathPredictor, + "lcpp_adjust_image_load_priority_override_first_n_boost", false}; + const base::FeatureParam<LcppRecordedLcpElementTypes>::Option lcpp_recorded_element_types[] = { {LcppRecordedLcpElementTypes::kAll, "all"},
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 3b4e6d8f..abb9762 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -729,6 +729,11 @@ BLINK_COMMON_EXPORT extern const base::FeatureParam<int> kLCPCriticalPathPredictorMaxElementLocatorLength; +// If true, LCP critical path predictor mechanism overrides the first N image +// prioritization when there is LCP hint. +BLINK_COMMON_EXPORT extern const base::FeatureParam<bool> + kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost; + // The type of LCP elements recorded by LCPP. enum class LcppRecordedLcpElementTypes { kAll,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 7eaeedf7..35b9f0a 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -1738,9 +1738,19 @@ return false; } +namespace { + +CSSValue* ConsumeColorInternal(CSSParserTokenRange&, + const CSSParserContext&, + bool accept_quirky_colors, + AllowedColors); + +} // namespace + // https://www.w3.org/TR/css-color-5/#color-mix static CSSValue* ConsumeColorMixFunction(CSSParserTokenRange& range, - const CSSParserContext& context) { + const CSSParserContext& context, + AllowedColors allowed_colors) { DCHECK(range.Peek().FunctionId() == CSSValueID::kColorMix); context.Count(WebFeature::kCSSColorMixFunction); @@ -1759,12 +1769,16 @@ return nullptr; } - CSSValue* color1 = ConsumeColor(args, context); + const bool no_quirky_colors = false; + + CSSValue* color1 = + ConsumeColorInternal(args, context, no_quirky_colors, allowed_colors); CSSPrimitiveValue* p1 = ConsumePercent(args, context, CSSPrimitiveValue::ValueRange::kAll); // Color can come after the percentage if (!color1) { - color1 = ConsumeColor(args, context); + color1 = ConsumeColorInternal(args, context, no_quirky_colors, + allowed_colors); if (!color1) { return nullptr; } @@ -1779,12 +1793,14 @@ return nullptr; } - CSSValue* color2 = ConsumeColor(args, context); + CSSValue* color2 = + ConsumeColorInternal(args, context, no_quirky_colors, allowed_colors); CSSPrimitiveValue* p2 = ConsumePercent(args, context, CSSPrimitiveValue::ValueRange::kAll); // Color can come after the percentage if (!color2) { - color2 = ConsumeColor(args, context); + color2 = ConsumeColorInternal(args, context, no_quirky_colors, + allowed_colors); if (!color2) { return nullptr; } @@ -1878,13 +1894,17 @@ } // namespace CSSValue* ConsumeColorContrast(CSSParserTokenRange& range, - const CSSParserContext& context) { + const CSSParserContext& context, + AllowedColors allowed_colors) { DCHECK_EQ(range.Peek().FunctionId(), CSSValueID::kColorContrast); CSSParserTokenRange range_copy = range; CSSParserTokenRange args = ConsumeFunction(range_copy); - CSSValue* background_color = ConsumeColor(args, context); + const bool no_quirky_colors = false; + + CSSValue* background_color = + ConsumeColorInternal(args, context, no_quirky_colors, allowed_colors); if (!background_color) { return nullptr; } @@ -1895,7 +1915,8 @@ VectorOf<CSSValue> colors_to_compare_against; do { - CSSValue* color = ConsumeColor(args, context); + CSSValue* color = ConsumeColorInternal(args, context, no_quirky_colors, + allowed_colors); if (!color) { return nullptr; } @@ -1997,14 +2018,14 @@ CSSValue* ConsumeColorInternal(CSSParserTokenRange& range, const CSSParserContext& context, bool accept_quirky_colors, - AllowedColorKeywords allowed_keywords) { + AllowedColors allowed_colors) { if (RuntimeEnabledFeatures::CSSColorContrastEnabled() && range.Peek().FunctionId() == CSSValueID::kColorContrast) { - return ConsumeColorContrast(range, context); + return ConsumeColorContrast(range, context, allowed_colors); } if (range.Peek().FunctionId() == CSSValueID::kColorMix) { - CSSValue* color = ConsumeColorMixFunction(range, context); + CSSValue* color = ConsumeColorMixFunction(range, context, allowed_colors); return color; } @@ -2017,8 +2038,9 @@ if (!isValueAllowedInMode(id, context.Mode())) { return nullptr; } - if (allowed_keywords != AllowedColorKeywords::kAllowSystemColor && - (StyleColor::IsSystemColorIncludingDeprecated(id) || + if (allowed_colors == AllowedColors::kAbsolute && + (id == CSSValueID::kCurrentcolor || + StyleColor::IsSystemColorIncludingDeprecated(id) || StyleColor::IsSystemColor(id))) { return nullptr; } @@ -2046,8 +2068,9 @@ } } - if (IsUASheetBehavior(context.Mode()) || - RuntimeEnabledFeatures::CSSLightDarkColorsEnabled()) { + if ((IsUASheetBehavior(context.Mode()) || + RuntimeEnabledFeatures::CSSLightDarkColorsEnabled()) && + allowed_colors == AllowedColors::kAll) { return ConsumeLightDark(ConsumeColor, range, context); } return nullptr; @@ -2059,19 +2082,19 @@ const CSSParserContext& context) { return ConsumeColorInternal(range, context, IsQuirksModeBehavior(context.Mode()), - AllowedColorKeywords::kAllowSystemColor); + AllowedColors::kAll); } CSSValue* ConsumeColor(CSSParserTokenRange& range, const CSSParserContext& context) { return ConsumeColorInternal(range, context, false /* accept_quirky_colors */, - AllowedColorKeywords::kAllowSystemColor); + AllowedColors::kAll); } CSSValue* ConsumeAbsoluteColor(CSSParserTokenRange& range, const CSSParserContext& context) { return ConsumeColorInternal(range, context, false /* accept_quirky_colors */, - AllowedColorKeywords::kNoSystemColor); + AllowedColors::kAbsolute); } CSSValue* ConsumeLineWidth(CSSParserTokenRange& range, @@ -7030,7 +7053,7 @@ return ConsumeAppearanceAutoBaseSelectColor(range, context); } return ConsumeColorInternal(range, context, allow_quirky_colors, - AllowedColorKeywords::kAllowSystemColor); + AllowedColors::kAll); } CSSValue* ConsumeBorderWidth(CSSParserTokenRange& range,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h index 64c88cd..d2717c9 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -61,7 +61,7 @@ }; enum class UnitlessQuirk { kAllow, kForbid }; enum class AllowCalcSize { kAllowWithAuto, kAllowWithoutAuto, kForbid }; -enum class AllowedColorKeywords { kAllowSystemColor, kNoSystemColor }; +enum class AllowedColors { kAll, kAbsolute }; enum class EmptyPathStringHandling { kFailure, kTreatAsNone }; using ConsumeAnimationItemValue = CSSValue* (*)(CSSPropertyID,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc index cd49dee1..e6c1217b 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
@@ -228,7 +228,6 @@ CSSParserContext* context = MakeContext(); return func(range, *context); }; - using css_parsing_utils::AllowedColorKeywords; struct { STACK_ALLOCATED(); @@ -249,6 +248,8 @@ nullptr}, {"WindowText", CSSIdentifierValue::Create(CSSValueID::kWindowtext), nullptr}, + {"currentcolor", CSSIdentifierValue::Create(CSSValueID::kCurrentcolor), + nullptr}, }; for (auto& expectation : expectations) { EXPECT_EQ(ConsumeColorForTest(expectation.css_text,
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.h b/third_party/blink/renderer/core/dom/layout_tree_builder.h index d6993d80..cc76bd4 100644 --- a/third_party/blink/renderer/core/dom/layout_tree_builder.h +++ b/third_party/blink/renderer/core/dom/layout_tree_builder.h
@@ -87,6 +87,10 @@ auto* const parent = next->Parent(); if (!IsAnonymousInline(parent)) return next; + // Should return a normal result for display:ruby though it can be + // an anonymous inline. + if (UNLIKELY(parent->IsInlineRuby())) + return next; if (!LIKELY(parent->IsLayoutTextCombine())) { return parent; }
diff --git a/third_party/blink/renderer/core/html/resources/permission.css b/third_party/blink/renderer/core/html/resources/permission.css index 75ca5e1f..5847fc9 100644 --- a/third_party/blink/renderer/core/html/resources/permission.css +++ b/third_party/blink/renderer/core/html/resources/permission.css
@@ -27,20 +27,22 @@ } permission::-internal-permission-text { - display: inherit; - font-family: Arial, Helvetica, sans-serif !important; + align-items: center; + display: flex; + font-family: Arial, Helvetica, sans-serif; font-size: inherit; font-style: inherit; font-weight: inherit; height: 100%; - hyphenate-character: auto !important; - line-height: inherit; + hyphenate-character: auto; + line-height: normal; + margin: auto; min-height: inherit; outline: none; - user-select:none !important; + user-select:none; vertical-align: inherit; - white-space:nowrap !important; - width: fit-content !important; - word-wrap: normal !important; + white-space:nowrap; + width: fit-content; + word-wrap: normal; word-spacing: inherit; }
diff --git a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc index 6d77e9bf..f61a35c 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
@@ -435,8 +435,10 @@ container_builder_.SetBfcLineOffset(bfc_line_offset); } - // Force an editable empty line to have metrics, so that is has a height. - if (UNLIKELY(line_info->HasLineEvenIfEmpty())) { + // Force an editable empty line or a line with ruby annotations to have + // metrics, so that is has a height. + if (UNLIKELY(line_info->HasLineEvenIfEmpty() || + !box_states_->RubyColumnList().empty())) { box_states_->LineBoxState().EnsureTextMetrics( line_info->LineStyle(), *box_states_->LineBoxState().font, baseline_type_);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node.cc b/third_party/blink/renderer/core/layout/inline/inline_node.cc index fd5b961..023ff76 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_node.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_node.cc
@@ -1994,7 +1994,7 @@ // fragment (line) that we cannot compute max-content from // min-content. !line_breaker.HasClonedBoxDecorations() && - !line_breaker.MayHaveRubyOverhang(); + !line_info.MayHaveRubyOverhang(); if (can_compute_max_size_from_min_size) max_size_from_min_size.ComputeFromMinSize(line_info); } else {
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.cc b/third_party/blink/renderer/core/layout/inline/line_breaker.cc index 4e787be..82503161 100644 --- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc +++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -733,7 +733,6 @@ hyphen_index_.reset(); has_any_hyphens_ = false; resume_block_in_inline_in_same_flow_ = false; - may_have_ruby_overhang_ = false; // Use 'text-indent' as the initial position. This lets tab positions to align // regardless of 'text-indent'. @@ -3036,6 +3035,9 @@ data->base_line = base_line_info; data->base_line.SetIsRubyBase(); data->base_line.UpdateTextAlign(); + if (data->base_line.MayHaveRubyOverhang()) { + line_info.SetMayHaveRubyOverhang(); + } line_info.SetHaveTextCombineOrRubyItem(); data->annotation_line_list = annotation_line_list; @@ -3057,7 +3059,7 @@ column_result->can_break_after = CanBreakAfterRubyColumn(*column_result); if (base_line_info.Width() < ruby_size) { - may_have_ruby_overhang_ = true; + line_info.SetMayHaveRubyOverhang(); AnnotationOverhang overhang = GetOverhang(*column_result); if (overhang.end > LayoutUnit()) {
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.h b/third_party/blink/renderer/core/layout/inline/line_breaker.h index aed1a956..3f7ffcd 100644 --- a/third_party/blink/renderer/core/layout/inline/line_breaker.h +++ b/third_party/blink/renderer/core/layout/inline/line_breaker.h
@@ -61,9 +61,6 @@ // True if the last line has `box-decoration-break: clone`, which affected the // size. bool HasClonedBoxDecorations() const { return has_cloned_box_decorations_; } - // True if the last processed line might contain ruby overhang. It affects - // min-max computation. - bool MayHaveRubyOverhang() const { return may_have_ruby_overhang_; } // Compute the next line break point and produces InlineItemResults for // the line. @@ -363,8 +360,6 @@ // True if the resultant line contains a RubyColumn with inline-end overhang. bool maybe_have_end_overhang_ = false; - // True if the last processed line might contain ruby overhang. - bool may_have_ruby_overhang_ = false; // True if ShouldCreateNewSvgSegment() should be called. bool needs_svg_segmentation_ = false;
diff --git a/third_party/blink/renderer/core/layout/inline/line_info.cc b/third_party/blink/renderer/core/layout/inline/line_info.cc index 475231d..7ae168dc 100644 --- a/third_party/blink/renderer/core/layout/inline/line_info.cc +++ b/third_party/blink/renderer/core/layout/inline/line_info.cc
@@ -67,6 +67,7 @@ is_ruby_base_ = false; is_ruby_text_ = false; may_have_text_combine_or_ruby_item_ = false; + may_have_ruby_overhang_ = false; allow_hang_for_alignment_ = false; }
diff --git a/third_party/blink/renderer/core/layout/inline/line_info.h b/third_party/blink/renderer/core/layout/inline/line_info.h index b49e239d..eb31f41 100644 --- a/third_party/blink/renderer/core/layout/inline/line_info.h +++ b/third_party/blink/renderer/core/layout/inline/line_info.h
@@ -229,6 +229,11 @@ may_have_text_combine_or_ruby_item_ = true; } + // True if the line might contain ruby overhang. It affects min-max + // computation. + bool MayHaveRubyOverhang() const { return may_have_ruby_overhang_; } + void SetMayHaveRubyOverhang() { may_have_ruby_overhang_ = true; } + // Returns annotation block start adjustment base on annotation and initial // letter. LayoutUnit ComputeAnnotationBlockOffsetAdjustment() const; @@ -321,6 +326,8 @@ // Note: To avoid scanning |InlineItemResults|, this variable is true // when |InlineItemResult| to |results_|. bool may_have_text_combine_or_ruby_item_ = false; + // True if the last processed line might contain ruby overhang. + bool may_have_ruby_overhang_ = false; bool allow_hang_for_alignment_ = false; // When adding fields, pelase ensure `Reset()` is in sync.
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 7ae08b8..c7fa7a9 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -2168,6 +2168,11 @@ Document* owner_document) { scoped_refptr<SecurityOrigin> origin; StringBuilder debug_info_builder; + // Whether the origin is newly created within this call, instead of copied + // from an existing document's origin or from `origin_to_commit_`. If this is + // true, we won't try to compare the nonce of this origin (if it's opaque) to + // the browser-calculated origin later on. + bool origin_is_newly_created = false; if (origin_to_commit_) { // Origin to commit is specified by the browser process, it must be taken // and used directly. It is currently supplied only for failed navigations @@ -2244,6 +2249,7 @@ // initiator origin as the precursor. origin = SecurityOrigin::CreateWithReferenceOrigin(url_, requestor_origin_.get()); + origin_is_newly_created = true; } if ((policy_container_->GetPolicies().sandbox_flags & @@ -2291,6 +2297,7 @@ } } origin = sandbox_origin; + origin_is_newly_created = true; } if (commit_reason_ == CommitReason::kInitialization && @@ -2335,7 +2342,14 @@ debug_info_builder.Append(", is_potentially_trustworthy"); } } - + if (origin_is_newly_created) { + // This information will be used by the browser side to figure out if it can + // do browser vs renderer calculated origin equality check. Note that this + // information must be the last part of the debug info string. + // TODO(https://crbug.com/888079): Consider adding a separate boolean that + // tracks this instead of piggybacking `origin_calculation_debug_info_`. + debug_info_builder.Append(", is_newly_created"); + } origin_calculation_debug_info_ = debug_info_builder.ToAtomicString(); return origin; }
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc index 6b37b2b..96bfeb8 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -550,6 +550,18 @@ return lcpp->HasAnyHintData(); } +bool FrameFetchContext::DoesLCPPHaveLcpElementLocatorHintData() { + if (GetResourceFetcherProperties().IsDetached()) { + return false; + } + + LCPCriticalPathPredictor* lcpp = GetFrame()->GetLCPP(); + if (!lcpp) { + return false; + } + return !lcpp->lcp_element_locators().empty(); +} + void FrameFetchContext::SetFirstPartyCookie(ResourceRequest& request) { // Set the first party for cookies url if it has not been set yet (new // requests). This value will be updated during redirects, consistent with
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h index 0c185cd3..82839b6 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.h +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -105,6 +105,8 @@ bool DoesLCPPHaveAnyHintData() override; + bool DoesLCPPHaveLcpElementLocatorHintData() override; + // Exposed for testing. void ModifyRequestForCSP(ResourceRequest&); void AddClientHintsIfNecessary(const std::optional<float> resource_width,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc index 35049da..e5f9ae7 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -962,8 +962,7 @@ auto conv2d_attributes = ConvertToConv2dAttributes(options); if (!conv2d_attributes.has_value()) { - exception_state.ThrowDOMException(DOMExceptionCode::kDataError, - conv2d_attributes.error()); + exception_state.ThrowTypeError(conv2d_attributes.error()); return nullptr; } @@ -971,9 +970,7 @@ ConvertToComponentOperand(input), ConvertToComponentOperand(filter), std::move(conv2d_attributes.value())); if (!validated_output.has_value()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kDataError, - WTF::String::FromUTF8(validated_output.error())); + exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; } // Create conv2d operator and its output operand. Connect the conv2d operator @@ -985,8 +982,7 @@ this, ComponentOperandTypeToBlink(validated_output.value().data_type), Vector<uint32_t>(validated_output.value().dimensions), conv2d); if (!output.has_value()) { - exception_state.ThrowDOMException(DOMExceptionCode::kDataError, - output.error()); + exception_state.ThrowTypeError(output.error()); return nullptr; } conv2d->Connect(std::move(inputs), {output.value()}); @@ -1011,8 +1007,7 @@ auto convTranspose2d_attributes = ConvertToConvTranspose2dAttributes(options); if (!convTranspose2d_attributes.has_value()) { - exception_state.ThrowDOMException(DOMExceptionCode::kDataError, - convTranspose2d_attributes.error()); + exception_state.ThrowTypeError(convTranspose2d_attributes.error()); return nullptr; } @@ -1020,9 +1015,7 @@ ConvertToComponentOperand(input), ConvertToComponentOperand(filter), std::move(convTranspose2d_attributes.value())); if (!validated_output.has_value()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kDataError, - WTF::String::FromUTF8(validated_output.error())); + exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; } // Create convTranspose2d operator and its output operand. Connect the @@ -1034,8 +1027,7 @@ this, ComponentOperandTypeToBlink(validated_output.value().data_type), Vector<uint32_t>(validated_output.value().dimensions), convTranspose2d); if (!output.has_value()) { - exception_state.ThrowDOMException(DOMExceptionCode::kDataError, - output.error()); + exception_state.ThrowTypeError(output.error()); return nullptr; } convTranspose2d->Connect(std::move(inputs), {output.value()}); @@ -1716,8 +1708,7 @@ auto validated_output = webnn::ValidateMatmulAndInferOutput( ConvertToComponentOperand(a), ConvertToComponentOperand(b)); if (!validated_output.has_value()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kDataError, + exception_state.ThrowTypeError( WTF::String::FromUTF8(validated_output.error())); return nullptr; } @@ -1729,8 +1720,7 @@ this, ComponentOperandTypeToBlink(validated_output.value().data_type), Vector<uint32_t>(validated_output.value().dimensions), matmul); if (!output.has_value()) { - exception_state.ThrowDOMException(DOMExceptionCode::kDataError, - output.error()); + exception_state.ThrowTypeError(output.error()); return nullptr; } matmul->Connect(std::move(inputs), {output.value()});
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc index c8b55ef0..bbe952c 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
@@ -588,1322 +588,6 @@ return output; } -TEST_F(MLGraphBuilderTest, Conv2dTest) { - V8TestingScope scope; - auto* builder = - CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(), - scope.GetExceptionState()); - { - // Test conv2d with default options. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - EXPECT_FALSE(options->hasBias()); - EXPECT_FALSE(options->hasDilations()); - EXPECT_FALSE(options->hasActivation()); - EXPECT_TRUE(options->hasFilterLayout()); - EXPECT_EQ(options->filterLayout(), - V8MLConv2dFilterOperandLayout::Enum::kOihw); - EXPECT_TRUE(options->hasInputLayout()); - EXPECT_EQ(options->inputLayout(), V8MLInputOperandLayout::Enum::kNchw); - EXPECT_TRUE(options->hasGroups()); - EXPECT_EQ(options->groups(), 1u); - EXPECT_FALSE(options->hasPadding()); - EXPECT_FALSE(options->hasStrides()); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with padding=1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 5, 5})); - } - { - // Test conv2d with strides=2 and padding=1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with strides=2 and asymmetric padding. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 4, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setPadding({1, 2, 0, 1}); - options->setStrides({2, 2}); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test depthwise conv2d by setting groups to input channels. - auto* input = BuildInput(builder, "input", {1, 4, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {4, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setGroups(4); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 4, 1, 1})); - } - { - // Test depthwise conv2d with groups=4, inputLayout="nhwc" and - // filterLayout="ihwo". - auto* input = BuildInput(builder, "input", {1, 2, 2, 4}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 2, 4}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setGroups(4); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 1, 4})); - } - { - // Test conv2d with dilations=4, inputLayout="nhwc" and - // filterLayout="ihwo". - auto* input = BuildInput(builder, "input", {1, 65, 65, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - options->setDilations({4, 4}); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 57, 57, 1})); - } - { - // Test conv2d with inputLayout="nchw" and filterLayout="oihw". - auto* input = BuildInput(builder, "input", {1, 2, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOihw); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with inputLayout="nchw" and filterLayout="hwio". - auto* input = BuildInput(builder, "input", {1, 2, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {3, 3, 2, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kHwio); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with inputLayout="nchw" and filterLayout="ohwi". - auto* input = BuildInput(builder, "input", {1, 2, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 3, 3, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with inputLayout="nchw" and filterLayout="ihwo". - auto* input = BuildInput(builder, "input", {1, 2, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {2, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 3, 3})); - } - { - // Test conv2d with inputLayout="nhwc" and filterLayout="oihw". - auto* input = BuildInput(builder, "input", {1, 5, 5, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOihw); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 3, 1})); - } - { - // Test conv2d with inputLayout="nhwc" and filterLayout="hwio". - auto* input = BuildInput(builder, "input", {1, 5, 5, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {3, 3, 2, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kHwio); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 3, 1})); - } - { - // Test conv2d with inputLayout="nhwc" and filterLayout="ohwi". - auto* input = BuildInput(builder, "input", {1, 5, 5, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 3, 3, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 3, 1})); - } - { - // Test conv2d with inputLayout="nhwc" and filterLayout="ihwo". - auto* input = BuildInput(builder, "input", {1, 5, 5, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {2, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - auto* output = BuildConv2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 3, 1})); - } - { - // Test throwing exception if the output operand's number of elements is too - // large. - // Set the input and filter dimensions that let the output's number of - // lements be 2 * SIZE_MAX. - auto* input = BuildInput( - builder, "input", - {1, 1, kSquareRootOfSizeMax / 2, kSquareRootOfSizeMax / 2}, - V8MLOperandDataType::Enum::kFloat32, scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {8, 1, 1, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = builder->conv2d(input, filter, MLConv2dOptions::Create(), - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Invalid operand descriptor: The number of elements is too large."); - } - { - // Test throwing exception if the output operand's byte length is too large. - // Set the dimensions and data type of input and filter that let the - // output's byte length be 4 * SIZE_MAX. - auto* input = BuildInput( - builder, "input", - {1, 1, kSquareRootOfSizeMax / 2, kSquareRootOfSizeMax / 2}, - V8MLOperandDataType::Enum::kFloat32, scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {4, 1, 1, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = builder->conv2d(input, filter, MLConv2dOptions::Create(), - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "Invalid operand descriptor: The byte length is too large."); - } - { - // Test throwing exception when the input is not a 4-D tensor. - auto* input = BuildInput(builder, "input", {1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 2, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The input should be a 4-D tensor."); - } - { - // Test throwing exception when the filter is not a 4-D tensor. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = - BuildConstant(builder, {2, 2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The filter should be a 4-D tensor."); - } - { - // Test throwing exception when the filter data type doesn't match the input - // data type. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = - BuildConstant(builder, {1, 1, 2, 2}, V8MLOperandDataType::Enum::kInt32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The filter data type doesn't match the input data type."); - } - { - // Test throwing exception when the length of padding is not 4. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setPadding({2, 2}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of padding should be 4."); - } - { - // Test throwing exception when the length of strides is not 2. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setStrides({2}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of strides should be 2."); - } - { - // Test throwing exception when one stride value is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setStrides({1, 0}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "All strides should be greater than 0."); - } - { - // Test throwing exception when the length of dilations is not 2. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({1}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of dilations should be 2."); - } - { - // Test throwing exception when the one dilation value is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({1, 0}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "All dilations should be greater than 0."); - } - { - // Test throwing exception when input_channels % groups() != 0. - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setGroups(3); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The groups must evenly divide the input " - "channels to filter input channels."); - } - { - // Test throwing exception when filter_input_channels != input_channels / - // groups(). - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setGroups(2); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The groups must evenly divide the input " - "channels to filter input channels."); - } - { - // Test throwing exception when the groups is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setGroups(0); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The groups should be greater than 0."); - } - { - // Test throwing exception due to overflow when calculating the effective - // filter height. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 434983, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({328442, 1}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Failed to calculate the output height: The effective filter size is " - "too large."); - } - { - // Test throwing exception due to overflow when calculating the effective - // filter width. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 234545}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({2, 843452}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Failed to calculate the output width: The effective filter size is " - "too large."); - } - { - // Test throwing exception due to underflow when calculating the output - // height. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 4, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({4, 1}); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "Failed to calculate the output height: The input size is too " - "small to fill the window."); - } - { - // Test throwing exception due to underflow when calculating the output - // width. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 8}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - options->setDilations({1, 4}); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "Failed to calculate the output width: The input size is too " - "small to fill the window."); - } - { - // Test throwing exception when the bias is not a 1-D tensor. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* bias = - BuildConstant(builder, {1, 2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias should be a 1-D tensor."); - } - { - // Test throwing exception when the bias shape is not equal to - // [output_channels]. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* bias = - BuildConstant(builder, {2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias shape should be [1]."); - } - { - // Test throwing exception when the bias data type doesn't match input data - // type. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConv2dOptions::Create(); - auto* bias = BuildConstant(builder, {1}, V8MLOperandDataType::Enum::kInt32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = - builder->conv2d(input, filter, options, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias data type doesn't match input data type."); - } -} - -MLOperand* BuildConvTranspose2d(V8TestingScope& scope, - MLGraphBuilder* builder, - const MLOperand* input, - const MLOperand* filter, - const MLConvTranspose2dOptions* options) { - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::NotNull()); - EXPECT_EQ(output->Kind(), webnn::mojom::blink::Operand::Kind::kOutput); - EXPECT_EQ(output->DataType(), input->DataType()); - auto* convTranspose2d = output->Operator(); - EXPECT_THAT(convTranspose2d, testing::NotNull()); - EXPECT_EQ(convTranspose2d->Kind(), - webnn::mojom::blink::Operation::Tag::kConv2d); - EXPECT_EQ(convTranspose2d->SubKind<webnn::mojom::blink::Conv2d::Kind>(), - webnn::mojom::blink::Conv2d::Kind::kTransposed); - EXPECT_TRUE(convTranspose2d->IsConnected()); - EXPECT_THAT(convTranspose2d->Options(), testing::NotNull()); - return output; -} - -TEST_F(MLGraphBuilderTest, ConvTranspose2dTest) { - V8TestingScope scope; - auto* builder = - CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(), - scope.GetExceptionState()); - { - // Test convTranspose2d with default options. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - EXPECT_FALSE(options->hasBias()); - EXPECT_FALSE(options->hasDilations()); - EXPECT_FALSE(options->hasActivation()); - EXPECT_TRUE(options->hasFilterLayout()); - EXPECT_EQ(options->filterLayout(), - V8MLConvTranspose2dFilterOperandLayout::Enum::kIohw); - EXPECT_TRUE(options->hasInputLayout()); - EXPECT_EQ(options->inputLayout(), V8MLInputOperandLayout::Enum::kNchw); - EXPECT_TRUE(options->hasGroups()); - EXPECT_EQ(options->groups(), 1u); - EXPECT_FALSE(options->hasPadding()); - EXPECT_FALSE(options->hasStrides()); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 5, 5})); - } - { - // Test convTranspose2d with inputLayout="nchw" and filterLayout="hwoi". - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {3, 3, 2, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kHwoi); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 5, 5})); - } - { - // Test convTranspose2d with inputLayout="nchw" and filterLayout="ohwi". - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {2, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNchw); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 5, 5})); - } - { - // Test convTranspose2d with inputLayout="nhwc" and filterLayout="iohw". - auto* input = BuildInput(builder, "input", {1, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kIohw); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 5, 5, 2})); - } - { - // Test convTranspose2d with inputLayout="nhwc" and filterLayout="hwoi". - auto* input = BuildInput(builder, "input", {1, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {3, 3, 2, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kHwoi); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 5, 5, 2})); - } - { - // Test convTranspose2d with inputLayout="nhwc" and filterLayout="ohwi". - auto* input = BuildInput(builder, "input", {1, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {2, 3, 3, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 5, 5, 2})); - } - { - // Test convTranspose2d with strides=[3, 2], outputSizes=[10, 8]. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({3, 2}); - options->setOutputSizes({10, 8}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 10, 8})); - } - { - // Test convTranspose2d with strides=[3, 2], outputPadding=[1, 1]. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({3, 2}); - options->setOutputPadding({1, 1}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 10, 8})); - } - { - // Test convTranspose2d with padding=1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 5, 5})); - } - { - // Test convTranspose2d with padding=1, groups=3. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - options->setGroups(3); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 5, 5})); - } - { - // Test convTranspose2d with strides=2. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({2, 2}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 7, 7})); - } - { - // Test convTranspose2d with strides=2 and padding=1. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 5, 5})); - } - { - // Test convTranspose2d with outputSizes and outputPadding. When the output - // sizes are explicitly specified, the output padding values are ignored. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({3, 2}); - options->setOutputPadding({1, 1}); - options->setOutputSizes({10, 8}); - auto* output = BuildConvTranspose2d(scope, builder, input, filter, options); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 2, 10, 8})); - } - { - // Test throwing exception if the output operand's number of elements is too - // large. - // Set the input and filter dimensions that let the output's number of - // lements be 2 * SIZE_MAX. - auto* input = BuildInput( - builder, "input", - {1, 1, kSquareRootOfSizeMax / 2, kSquareRootOfSizeMax / 2}, - V8MLOperandDataType::Enum::kFloat32, scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 8, 1, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Invalid operand descriptor: The number of elements is too large."); - } - { - // Test throwing exception if the output operand's byte length is too large. - // Set the dimensions and data type of input and filter that let the - // output's byte length be 4 * SIZE_MAX. - auto* input = BuildInput( - builder, "input", - {1, 1, kSquareRootOfSizeMax / 2, kSquareRootOfSizeMax / 2}, - V8MLOperandDataType::Enum::kFloat32, scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 4, 1, 1}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "Invalid operand descriptor: The byte length is too large."); - } - { - // Test throwing exception when the input is not a 4-D tensor. - auto* input = BuildInput(builder, "input", {1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The input should be a 4-D tensor."); - } - { - // Test throwing exception when the filter is not a 4-D tensor. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = - BuildConstant(builder, {2, 2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The filter should be a 4-D tensor."); - } - { - // Test throwing exception when the filter data type doesn't match the input - // data type. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = - BuildConstant(builder, {1, 1, 2, 2}, V8MLOperandDataType::Enum::kInt32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The filter data type doesn't match the input data type."); - } - { - // Test throwing exception when the length of padding is not 4. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({2, 2}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of padding should be 4."); - } - { - // Test throwing exception when the length of strides is not 2. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({2}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of strides should be 2."); - } - { - // Test throwing exception when one stride value is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({1, 0}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "All strides should be greater than 0."); - } - { - // Test throwing exception when the length of dilations is not 2. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setDilations({1}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of dilations should be 2."); - } - { - // Test throwing exception when the one dilation value is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setDilations({1, 0}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "All dilations should be greater than 0."); - } - { - // Test throwing exception when the input channels is not equal to the - // filter input channels. - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setGroups(3); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The input channels should equal to filter input channels."); - } - { - // Test throwing exception when output channels is too large. - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {4, 2, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setGroups(std::numeric_limits<uint32_t>::max()); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The output channels is too large."); - } - { - // Test throwing exception when the groups is smaller than 1. - auto* input = BuildInput(builder, "input", {1, 4, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setGroups(0); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The groups should be greater than 0."); - } - { - // Test throwing exception due to overflow when calculating the effective - // filter height. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 434983, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setDilations({328442, 1}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Failed to calculate the output height: The effective filter size is " - "too large."); - } - { - // Test throwing exception due to overflow when calculating the effective - // filter width. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 234545}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setDilations({2, 843452}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ( - scope.GetExceptionState().Message(), - "Failed to calculate the output width: The effective filter size is " - "too large."); - } - { - // Test throwing exception when the bias is not a 1-D tensor. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* bias = - BuildConstant(builder, {1, 2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias should be a 1-D tensor."); - } - { - // Test throwing exception when the bias shape is not equal to - // [output_channels]. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* bias = - BuildConstant(builder, {2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias shape should be [1]."); - } - { - // Test throwing exception when the bias data type doesn't match input data - // type. - auto* input = BuildInput(builder, "input", {1, 1, 5, 5}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - auto* bias = BuildConstant(builder, {1}, V8MLOperandDataType::Enum::kInt32, - scope.GetExceptionState()); - options->setBias(bias); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The bias data type doesn't match input data type."); - } - { - // Test throwing exception when the outputPadding is not a sequence of - // length 2. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({3, 2}); - options->setOutputPadding({1, 1, 1, 1}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of output padding should be 2."); - } - { - // Test throwing exception when the outputPadding is greater than stride - // along the same dimension. - auto* input = BuildInput(builder, "input", {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({0, 0, 3, 3}); - options->setStrides({2, 2}); - options->setOutputPadding({0, 2}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The output padding must be smaller than the stride along the " - "same dimension."); - } - { - // Test throwing exception when the outputSizes is not a sequence of - // length 2. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 2, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setStrides({3, 2}); - options->setOutputSizes({1, 2, 10, 8}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The length of output sizes should be 2."); - } - { - // Test throwing exception due to underflow when calculating the output - // height. - auto* input = BuildInput(builder, "input", {1, 1, 2, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({4, 4, 0, 0}); - options->setStrides({2, 2}); - options->setOutputPadding({1, 0}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "Failed to calculate the output height: The stride is too large " - "or the input size is too small for padding."); - } - { - // Test throwing exception due to outputSizes values are smaller than the - // output sizes calculated by not using outputPadding. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - options->setOutputSizes({4, 4}); - options->setOutputPadding({1, 1}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The height of output sizes is invalid."); - } - { - // Test throwing exception due to outputSizes values are greater than the - // output sizes calculated by not using outputPadding. - auto* input = BuildInput(builder, "input", {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* filter = BuildConstant(builder, {1, 1, 3, 3}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* options = MLConvTranspose2dOptions::Create(); - options->setPadding({1, 1, 1, 1}); - options->setStrides({2, 2}); - options->setOutputSizes({6, 8}); - options->setOutputPadding({1, 1}); - auto* output = builder->convTranspose2d(input, filter, options, - scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The width of output sizes is invalid."); - } -} - TEST_F(MLGraphBuilderTest, PReluTest) { V8TestingScope scope; auto* builder = @@ -4261,146 +2945,6 @@ } } -MLOperand* BuildMatmul(V8TestingScope& scope, - MLGraphBuilder* builder, - const MLOperand* a, - const MLOperand* b) { - auto* output = builder->matmul(a, b, scope.GetExceptionState()); - EXPECT_THAT(output, testing::NotNull()); - EXPECT_EQ(output->Kind(), webnn::mojom::blink::Operand::Kind::kOutput); - EXPECT_EQ(output->DataType(), a->DataType()); - auto* matmul = output->Operator(); - EXPECT_THAT(matmul, testing::NotNull()); - EXPECT_EQ(matmul->Kind(), webnn::mojom::blink::Operation::Tag::kMatmul); - EXPECT_TRUE(matmul->IsConnected()); - EXPECT_THAT(matmul->Options(), testing::IsNull()); - return output; -} - -TEST_F(MLGraphBuilderTest, MatmulTest) { - V8TestingScope scope; - auto* builder = - CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(), - scope.GetExceptionState()); - { - // Test throwing exception when the rank of input is smaller than 2. - auto* a = BuildInput(builder, "a", {2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = BuildInput(builder, "b", {2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = builder->matmul(a, b, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The rank of input must be larger than or equal to 2."); - } - { - // Test building matmul with 2-D * 4-D inputs. - auto* a = - BuildInput(builder, "a", {1, 4}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = BuildInput(builder, "b", {2, 2, 4, 2}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = BuildMatmul(scope, builder, a, b); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({2, 2, 1, 2})); - } - { - // Test building matmul with 2-D * 2-D inputs. - auto* a = - BuildInput(builder, "a", {4, 2}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {2, 3}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = BuildMatmul(scope, builder, a, b); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({4, 3})); - } - { - // Test building matmul with 3-D * 3-D inputs using broadcast. - auto* a = - BuildInput(builder, "a", {2, 3, 4}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {1, 4, 1}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = BuildMatmul(scope, builder, a, b); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({2, 3, 1})); - } - { - // Test building matmul with 4-D * 3-D inputs using broadcast. - auto* a = BuildInput(builder, "a", {2, 2, 3, 4}, - V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {1, 4, 5}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = BuildMatmul(scope, builder, a, b); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({2, 2, 3, 5})); - } - { - // Test building matmul with 3-D * 3-D inputs. - auto* a = - BuildInput(builder, "a", {2, 3, 4}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {2, 4, 5}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = BuildMatmul(scope, builder, a, b); - EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({2, 3, 5})); - } - { - // Test throwing exception when the data types of first two inputs don't - // match. - auto* a = - BuildInput(builder, "a", {2, 3}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {3, 4}, V8MLOperandDataType::Enum::kInt32, - scope.GetExceptionState()); - auto* output = builder->matmul(a, b, scope.GetExceptionState()); - ; - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The data types of first two inputs don't match."); - } - { - // Test throwing exception when the number of columns in first matrix - // mismatches with the number of rows in second matrix. - auto* a = - BuildInput(builder, "a", {2, 3}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {2, 4}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = builder->matmul(a, b, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The number of columns (3) in the first matrix isn't equal to " - "the number of rows (2) in the second matrix."); - } - { - // Test throwing exception when the input shapes are not broadcastable. - auto* a = - BuildInput(builder, "a", {3, 3, 4}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* b = - BuildInput(builder, "b", {2, 4, 1}, V8MLOperandDataType::Enum::kFloat32, - scope.GetExceptionState()); - auto* output = builder->matmul(a, b, scope.GetExceptionState()); - EXPECT_THAT(output, testing::IsNull()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kDataError); - EXPECT_EQ(scope.GetExceptionState().Message(), - "The matmul input shapes are not broadcastable."); - } -} - class FakeMLGraphBackend final : public MLGraph { public: // Create and build a FakeMLGraphBackend object. Resolve the promise with
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h index b3f88e3a..0e873d8e 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_batch_normalization_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_transpose_2d_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_elu_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gemm_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gru_options.h" @@ -68,13 +67,6 @@ const MLOperand* filter, const MLConv2dOptions* options = MLConv2dOptions::Create()); -MLOperand* BuildConvTranspose2d(V8TestingScope& scope, - MLGraphBuilder* builder, - const MLOperand* input, - const MLOperand* filter, - const MLConvTranspose2dOptions* options = - MLConvTranspose2dOptions::Create()); - MLOperand* BuildLeakyRelu( V8TestingScope& scope, MLGraphBuilder* builder,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc index a61d2d3..d3cd4e4 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
@@ -1408,493 +1408,6 @@ } } -struct Conv2dTester { - OperandInfoBlink input; - OperandInfoBlink filter; - struct Conv2dOptions { - std::optional<Vector<uint32_t>> padding; - std::optional<Vector<uint32_t>> strides; - std::optional<Vector<uint32_t>> dilations; - std::optional<uint32_t> groups; - std::optional<blink::V8MLInputOperandLayout::Enum> input_layout; - std::optional<blink::V8MLConv2dFilterOperandLayout::Enum> filter_layout; - std::optional<OperandInfoBlink> bias; - std::optional<Activation> activation; - }; - struct Conv2dAttributes { - Vector<uint32_t> padding = {0, 0, 0, 0}; - Vector<uint32_t> strides = {1, 1}; - Vector<uint32_t> dilations = {1, 1}; - uint32_t groups = 1; - blink_mojom::InputOperandLayout input_layout = - blink_mojom::InputOperandLayout::kChannelsFirst; - std::optional<OperandInfoMojo> bias; - std::optional<Activation> activation; - }; - Conv2dOptions options; - OperandInfoMojo expected_operand; - Conv2dAttributes expected_attributes; - - void Test(MLGraphTestMojo& helper, - V8TestingScope& scope, - MLGraphBuilder* builder) { - // Build the graph. - auto* input_operand = - BuildInput(builder, "input", input.dimensions, input.data_type, - scope.GetExceptionState()); - auto* filter_operand = - BuildInput(builder, "filter", filter.dimensions, filter.data_type, - scope.GetExceptionState()); - MLConv2dOptions* ml_conv2d_options = MLConv2dOptions::Create(); - if (options.padding) { - ml_conv2d_options->setPadding(options.padding.value()); - } - if (options.strides) { - ml_conv2d_options->setStrides(options.strides.value()); - } - if (options.dilations) { - ml_conv2d_options->setDilations(options.dilations.value()); - } - if (options.groups) { - ml_conv2d_options->setGroups(options.groups.value()); - } - if (options.input_layout) { - ml_conv2d_options->setInputLayout(options.input_layout.value()); - } - if (options.filter_layout) { - ml_conv2d_options->setFilterLayout(options.filter_layout.value()); - } - if (options.bias) { - ml_conv2d_options->setBias( - BuildInput(builder, "bias", options.bias->dimensions, - options.bias->data_type, scope.GetExceptionState())); - } - if (options.activation) { - auto* activation = - CreateActivation(scope, builder, options.activation.value()); - CHECK(activation); - ml_conv2d_options->setActivation(activation); - } - auto* output_operand = - builder->conv2d(input_operand, filter_operand, ml_conv2d_options, - scope.GetExceptionState()); - auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); - ASSERT_THAT(graph, testing::NotNull()); - - auto graph_info = helper.GetGraphInfo(); - // Verify the graph information of mojo are as expected. - ASSERT_EQ(graph_info->operations.size(), 1u); - auto& operation = graph_info->operations[0]; - EXPECT_TRUE(operation->is_conv2d()); - auto& conv2d = operation->get_conv2d(); - // Validate explicit padding. - auto& expected_padding = expected_attributes.padding; - EXPECT_EQ(conv2d->padding->beginning->height, expected_padding[0]); - EXPECT_EQ(conv2d->padding->ending->height, expected_padding[1]); - EXPECT_EQ(conv2d->padding->beginning->width, expected_padding[2]); - EXPECT_EQ(conv2d->padding->ending->width, expected_padding[3]); - // Validate strides - EXPECT_EQ(conv2d->strides->height, expected_attributes.strides[0]); - EXPECT_EQ(conv2d->strides->width, expected_attributes.strides[1]); - // Validate dilations. - EXPECT_EQ(conv2d->dilations->height, expected_attributes.dilations[0]); - EXPECT_EQ(conv2d->dilations->width, expected_attributes.dilations[1]); - EXPECT_EQ(conv2d->groups, expected_attributes.groups); - EXPECT_EQ(conv2d->input_layout, expected_attributes.input_layout); - if (options.bias) { - auto bias_operand_iter = - graph_info->id_to_operand_map.find(conv2d->bias_operand_id.value()); - ASSERT_TRUE(bias_operand_iter != graph_info->id_to_operand_map.end()); - EXPECT_EQ(bias_operand_iter->value->data_type, - expected_attributes.bias->data_type); - EXPECT_EQ(bias_operand_iter->value->dimensions, - expected_attributes.bias->dimensions); - } - if (options.activation) { - CHECK(expected_attributes.activation); - CheckActivation(conv2d->activation, - expected_attributes.activation.value()); - } - EXPECT_EQ(graph_info->output_operands.size(), 1u); - auto output_operand_id = graph_info->output_operands[0]; - auto output_operand_iter = - graph_info->id_to_operand_map.find(output_operand_id); - ASSERT_TRUE(output_operand_iter != graph_info->id_to_operand_map.end()); - EXPECT_EQ(output_operand_iter->value->data_type, - expected_operand.data_type); - EXPECT_EQ(output_operand_iter->value->dimensions, - expected_operand.dimensions); - } -}; - -TEST_P(MLGraphTestMojo, Conv2dTest) { - V8TestingScope scope; - // Bind fake WebNN Context in the service for testing. - ScopedWebNNServiceBinder scoped_setup_binder(*this, scope); - - auto* options = MLContextOptions::Create(); - // Create WebNN Context with GPU device type. - options->setDeviceType(V8MLDeviceType::Enum::kGpu); - auto* builder = CreateGraphBuilder(scope, options); - ASSERT_THAT(builder, testing::NotNull()); - { - // Test conv2d with default options. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = {.padding = {0, 0, 0, 0}, - .strides = {1, 1}, - .dilations = {1, 1}, - .groups = 1}} - .Test(*this, scope, builder); - } - { - // Test conv2d with strides=2 and padding=1. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.padding = Vector<uint32_t>({1, 1, 1, 1}), - .strides = Vector<uint32_t>({2, 2})}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = {.padding = {1, 1, 1, 1}, - .strides = {2, 2}, - .dilations = {1, 1}, - .groups = 1}} - .Test(*this, scope, builder); - } - { - // Test depthwise conv2d by setting groups to input channels. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 4, 2, 2}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {4, 1, 2, 2}}, - .options = {.groups = 4}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 4, 1, 1}}, - .expected_attributes = {.padding = {0, 0, 0, 0}, - .strides = {1, 1}, - .dilations = {1, 1}, - .groups = 4}} - .Test(*this, scope, builder); - } - { - // Test conv2d with clamp activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = - webnn::mojom::blink::Activation::Tag::kClamp, - .clamp_options = - ClampTester::ClampOptions{.min_value = 1.0, - .max_value = 6.0}}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kClamp, - .clamp_options = - ClampTester::ClampOptions{.min_value = 1.0, - .max_value = 6.0}}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with elu activation with default options. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = - webnn::mojom::blink::Activation::Tag::kElu}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{.kind = webnn::mojom::blink::Activation::Tag::kElu, - .elu_alpha = 1.0}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with elu activation with given alpha. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kElu, - .elu_alpha = 0.5}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{.kind = webnn::mojom::blink::Activation::Tag::kElu, - .elu_alpha = 0.5}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with hardSigmoid activation with default alpha = 0.1 and beta - // = -1.0. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kHardSigmoid, - .hard_sigmoid_alpha = 0.1, - .hard_sigmoid_beta = -1.0}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kHardSigmoid, - .hard_sigmoid_alpha = 0.1, - .hard_sigmoid_beta = -1.0}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with leaky relu activation with default options. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kLeakyRelu}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kLeakyRelu, - .leaky_relu_alpha = 0.01}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with leaky relu activation with given alpha. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kLeakyRelu, - .leaky_relu_alpha = 0.02}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kLeakyRelu, - .leaky_relu_alpha = 0.02}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with relu activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = - webnn::mojom::blink::Activation::Tag::kRelu}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{.kind = - webnn::mojom::blink::Activation::Tag::kRelu}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with sigmoid activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSigmoid}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSigmoid}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with softmax activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSoftmax}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSoftmax}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with softplus activation with steepness = 2.0. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = - webnn::mojom::blink::Activation::Tag::kSoftplus, - .softplus_steepness = 2.0}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSoftplus, - .softplus_steepness = 2.0}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with softsign activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .options = - {.activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSoftsign}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat16, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{ - .kind = webnn::mojom::blink::Activation::Tag::kSoftsign}}} - .Test(*this, scope, builder); - } - { - // Test conv2d with tanh activation. - Conv2dTester{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 5, 5}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .options = {.activation = - Activation{ - .kind = - webnn::mojom::blink::Activation::Tag::kTanh}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {1, 1, 3, 3}}, - .expected_attributes = - {.padding = Vector<uint32_t>({0, 0, 0, 0}), - .strides = Vector<uint32_t>({1, 1}), - .dilations = Vector<uint32_t>({1, 1}), - .groups = 1, - .activation = - Activation{.kind = - webnn::mojom::blink::Activation::Tag::kTanh}}} - .Test(*this, scope, builder); - } -} - struct ElementWiseBinaryTester { OperandInfoBlink lhs; OperandInfoBlink rhs; @@ -3393,101 +2906,6 @@ } } -struct MatmulTester { - OperandInfoBlink a; - OperandInfoBlink b; - OperandInfoMojo expected_operand; - - void Test(MLGraphTestMojo& helper, - V8TestingScope& scope, - MLGraphBuilder* builder) { - // Build the graph. - auto* a_operand = BuildInput(builder, "a", a.dimensions, a.data_type, - scope.GetExceptionState()); - auto* b_operand = BuildInput(builder, "b", b.dimensions, b.data_type, - scope.GetExceptionState()); - auto* output_operand = - builder->matmul(a_operand, b_operand, scope.GetExceptionState()); - auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); - ASSERT_THAT(graph, testing::NotNull()); - - auto graph_info = helper.GetGraphInfo(); - // Verify the graph information of mojo are as expected. - EXPECT_EQ(graph_info->id_to_operand_map.size(), 3u); - EXPECT_EQ(graph_info->input_operands.size(), 2u); - // Verify the a `mojo::Operand`. - auto a_operand_id = graph_info->input_operands[0]; - auto a_operand_iter = graph_info->id_to_operand_map.find(a_operand_id); - ASSERT_TRUE(a_operand_iter != graph_info->id_to_operand_map.end()); - EXPECT_EQ(a_operand_iter->value->kind, blink_mojom::Operand::Kind::kInput); - EXPECT_EQ(a_operand_iter->value->data_type, expected_operand.data_type); - EXPECT_EQ(a_operand_iter->value->dimensions, a.dimensions); - EXPECT_EQ(a_operand_iter->value->name, "a"); - // Verify the b `mojo::Operand`. - auto b_operand_id = graph_info->input_operands[1]; - auto b_operand_iter = graph_info->id_to_operand_map.find(b_operand_id); - ASSERT_TRUE(b_operand_iter != graph_info->id_to_operand_map.end()); - EXPECT_EQ(b_operand_iter->value->kind, blink_mojom::Operand::Kind::kInput); - EXPECT_EQ(b_operand_iter->value->data_type, expected_operand.data_type); - EXPECT_EQ(b_operand_iter->value->dimensions, b.dimensions); - EXPECT_EQ(b_operand_iter->value->name, "b"); - // Verify the output `mojo::Operand`. - ASSERT_EQ(graph_info->output_operands.size(), 1u); - auto output_operand_id = graph_info->output_operands[0]; - auto output_operand_iter = - graph_info->id_to_operand_map.find(output_operand_id); - ASSERT_TRUE(output_operand_iter != graph_info->id_to_operand_map.end()); - EXPECT_EQ(output_operand_iter->value->data_type, - expected_operand.data_type); - EXPECT_EQ(output_operand_iter->value->dimensions, - expected_operand.dimensions); - EXPECT_EQ(output_operand_iter->value->data_type, - expected_operand.data_type); - EXPECT_EQ(output_operand_iter->value->name, "output"); - // Verify the `mojo::Operator`. - ASSERT_EQ(graph_info->operations.size(), 1u); - auto& operation = graph_info->operations[0]; - EXPECT_TRUE(operation->is_matmul()); - } -}; - -TEST_P(MLGraphTestMojo, MatmulTest) { - V8TestingScope scope; - // Bind fake WebNN Context in the service for testing. - ScopedWebNNServiceBinder scoped_setup_binder(*this, scope); - - auto* options = MLContextOptions::Create(); - // Create WebNN Context with GPU device type. - options->setDeviceType(V8MLDeviceType::Enum::kGpu); - auto* builder = CreateGraphBuilder(scope, options); - ASSERT_THAT(builder, testing::NotNull()); - { - // Test building matmul with 2-D * 2-D. - MatmulTester{ - .a = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {2, 3}}, - .b = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3, 4}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat32, - .dimensions = {2, 4}}} - .Test(*this, scope, builder); - } - { - // Test building matmul with 3-D * 4-D using broadcasting. - MatmulTester{ - .a = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {2, 2, 3}}, - .b = {.data_type = V8MLOperandDataType::Enum::kFloat16, - .dimensions = {3, 1, 3, 4}}, - .expected_operand = {.data_type = - blink_mojom::Operand::DataType::kFloat16, - .dimensions = {3, 2, 2, 4}}} - .Test(*this, scope, builder); - } -} - struct PadTester { OperandInfoBlink input; Vector<uint32_t> beginning_padding;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc index eced28c..5589ab5 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -6,8 +6,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_transpose_2d_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_leaky_relu_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pad_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_reduce_options.h" @@ -944,362 +942,6 @@ } template <typename T> -struct Conv2dTester { - OperandInfo<T> input; - OperandInfo<T> filter; - std::optional<OperandInfo<T>> bias = std::nullopt; - Vector<T> expected; - - void Test(MLGraphTest& helper, - V8TestingScope& scope, - MLGraphBuilder* builder, - MLConv2dOptions* options = MLConv2dOptions::Create()) { - // Build the graph. - auto* input_operand = - BuildInput(builder, "input", input.dimensions, input.data_type, - scope.GetExceptionState()); - auto* filter_operand = - BuildConstant(builder, filter.dimensions, filter.data_type, - filter.values, scope.GetExceptionState()); - if (bias) { - options->setBias(BuildConstant( - builder, bias.value().dimensions, bias.value().data_type, - bias.value().values, scope.GetExceptionState())); - } - auto* output_operand = - BuildConv2d(scope, builder, input_operand, filter_operand, options); - auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); - ASSERT_THAT(graph, testing::NotNull()); - - // Compute the graph. - MLNamedArrayBufferViews inputs( - {{"input", - CreateArrayBufferViewForOperand(input_operand, input.values)}}); - MLNamedArrayBufferViews outputs( - {{"output", CreateArrayBufferViewForOperand(output_operand)}}); - std::tie(error_name, error_message) = - helper.ComputeGraph(scope, graph, inputs, outputs); - EXPECT_TRUE(error_name.IsNull()); - auto results = GetArrayBufferViewValues<T>(outputs[0].second); - EXPECT_EQ(results, expected); - } -}; - -TEST_P(MLGraphTest, Conv2dTest) { - V8TestingScope scope; - auto* builder = - CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(), - scope.GetExceptionState()); - { - // Test conv2d operator for nhwc input layout and ohwi filter layout. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 3, 3}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, - 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3, 1, 1, 3}, - .values = {1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0}}, - .expected = {30.0, 36.0, 42.0, 66.0, 81.0, 96.0, 102.0, 126.0, 150.0, - 138.0, 171.0, 204.0, 174.0, 216.0, 258.0, 210.0, 261.0, - 312.0}} - .Test(*this, scope, builder, options); - } - { - // Test conv2d operator for explicit padding are not same as the calculated - // padding with kSameUpper, input, filter size, stride and dilation that - // are used by CalculateConv2dPadding function. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi); - // The paddings are {1, 1, 1, 1} with calculating by CalculateConv2dPadding - // function. - options->setPadding({2, 2, 1, 1}); - options->setStrides({2, 2}); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 7, 5, 1}, - .values = Vector<float>(35, 1.0)}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = Vector<float>(9, 1.0)}, - .expected = {2.0, 3.0, 2.0, 6.0, 9.0, 6.0, 6.0, 9.0, 6.0, 6.0, 9.0, 6.0, - 2.0, 3.0, 2.0}} - .Test(*this, scope, builder, options); - } - { - // Test fused conv2d operator for nhwc input layout and ohwi filter - // layout, fusing with bias operand and relu activation. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi); - options->setActivation(builder->relu(scope.GetExceptionState())); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 3, 3}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, - 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3, 1, 1, 3}, - .values = {1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0}}, - .bias = - OperandInfo<float>{.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3}, - .values = {-6000.0, -7000.0, 8000.0}}, - .expected = {0.0, 0.0, 8042.0, 0.0, 0.0, 8096.0, 0.0, 0.0, 8150.0, 0.0, - 0.0, 8204.0, 0.0, 0.0, 8258.0, 0.0, 0.0, 8312.0}} - .Test(*this, scope, builder, options); - } - { - // Test depthwise conv2d operator by setting groups to input channels, - // nhwc input layout, ihwo filter layout. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - options->setGroups(4); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {10.0, 21.0, 10.0, 0.0, 10.0, 22.0, 20.0, 0.0, 10.0, - 23.0, 30.0, 0.0, 10.0, 24.0, 40.0, 0.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {0.25, 0.0, 10.0, 50.0, 0.25, 1.0, 20.0, 50.0, - 0.25, 0.0, 30.0, 50.0, 0.25, 1.0, 40.0, 50.0}}, - .expected = {10.0, 46.0, 3000.0, 0.0}} - .Test(*this, scope, builder, options); - } - { - // Test fused depthwise conv2d operator by setting groups to input - // channels, nhwc input layout, ihwo filter layout, fusing with bias - // operand and relu activation. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - options->setGroups(4); - options->setActivation(builder->relu(scope.GetExceptionState())); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {10.0, 21.0, 10.0, 0.0, 10.0, 22.0, 20.0, 0.0, 10.0, - 23.0, 30.0, 0.0, 10.0, 24.0, 40.0, 0.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {0.25, 0.0, 10.0, 50.0, 0.25, 1.0, 20.0, 50.0, - 0.25, 0.0, 30.0, 50.0, 0.25, 1.0, 40.0, 50.0}}, - .bias = - OperandInfo<float>{.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {4}, - .values = {-6000.0, -7000.0, 8000.0, 9000.0}}, - .expected = {0.0, 0.0, 11000.0, 9000.0}} - .Test(*this, scope, builder, options); - } - { - // Test fused depthwise conv2d operator by setting groups to input - // channels, nhwc input layout, ihwo filter layout, fusing with bias - // operand and clamp activation. - auto* options = MLConv2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kIhwo); - options->setGroups(4); - auto* clamp_options = MLClampOptions::Create(); - clamp_options->setMinValue(0.0); - clamp_options->setMaxValue(6.0); - options->setActivation( - builder->clamp(clamp_options, scope.GetExceptionState())); - Conv2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {10.0, 21.0, 10.0, 0.0, 10.0, 22.0, 20.0, 0.0, 10.0, - 23.0, 30.0, 0.0, 10.0, 24.0, 40.0, 0.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 2, 2, 4}, - .values = {0.25, 0.0, 10.0, 50.0, 0.25, 1.0, 20.0, 50.0, - 0.25, 0.0, 30.0, 50.0, 0.25, 1.0, 40.0, 50.0}}, - .bias = - OperandInfo<float>{.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {4}, - .values = {-6000.0, -7000.0, 8000.0, 9000.0}}, - .expected = {0.0, 0.0, 6.0, 6.0}} - .Test(*this, scope, builder, options); - } -} - -template <typename T> -struct ConvTranspose2dTester { - OperandInfo<T> input; - OperandInfo<T> filter; - std::optional<OperandInfo<T>> bias = std::nullopt; - Vector<T> expected; - - void Test( - MLGraphTest& helper, - V8TestingScope& scope, - MLGraphBuilder* builder, - MLConvTranspose2dOptions* options = MLConvTranspose2dOptions::Create()) { - // Build the graph. - auto* input_operand = - BuildInput(builder, "input", input.dimensions, input.data_type, - scope.GetExceptionState()); - auto* filter_operand = - BuildConstant(builder, filter.dimensions, filter.data_type, - filter.values, scope.GetExceptionState()); - if (bias) { - options->setBias(BuildConstant( - builder, bias.value().dimensions, bias.value().data_type, - bias.value().values, scope.GetExceptionState())); - } - auto* output_operand = BuildConvTranspose2d(scope, builder, input_operand, - filter_operand, options); - auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); - ASSERT_THAT(graph, testing::NotNull()); - - // Compute the graph. - MLNamedArrayBufferViews inputs( - {{"input", - CreateArrayBufferViewForOperand(input_operand, input.values)}}); - MLNamedArrayBufferViews outputs( - {{"output", CreateArrayBufferViewForOperand(output_operand)}}); - std::tie(error_name, error_message) = - helper.ComputeGraph(scope, graph, inputs, outputs); - EXPECT_TRUE(error_name.IsNull()); - auto results = GetArrayBufferViewValues<T>(outputs[0].second); - EXPECT_EQ(results, expected); - } -}; - -TEST_P(MLGraphTest, ConvTranspose2dTest) { - V8TestingScope scope; - auto* builder = - CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(), - scope.GetExceptionState()); - { - // Test convTranspose2d operator for nhwc input layout and ohwi filter - // layout. - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - ConvTranspose2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0}}, - .expected = {1.0, 5.0, 14.0, 19.0, 15.0, 11.0, 40.0, - 82.0, 74.0, 36.0, 39.0, 114.0, 195.0, 165.0, - 81.0, 65.0, 163.0, 235.0, 173.0, 66.0, 28.0, - 74.0, 140.0, 118.0, 72.0}} - .Test(*this, scope, builder, options); - } - { - // Test fused convTranspose2d operator for nhwc input layout and ohwi filter - // layout, fusing with bias operand and relu activation. - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - options->setActivation(builder->relu(scope.GetExceptionState())); - ConvTranspose2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3, 3, 3, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, - 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}}, - .bias = - OperandInfo<float>{.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {3}, - .values = {-6000.0, -7000.0, 8000.0}}, - .expected = {0.0, 0.0, 8001.0, 0.0, 0.0, 8004.0, 0.0, 0.0, 8010.0, - 0.0, 0.0, 8012.0, 0.0, 0.0, 8009.0, 0.0, 0.0, 8008.0, - 0.0, 0.0, 8026.0, 0.0, 0.0, 8056.0, 0.0, 0.0, 8054.0, - 0.0, 0.0, 8036.0, 0.0, 0.0, 8030.0, 0.0, 0.0, 8084.0, - 0.0, 0.0, 8165.0, 0.0, 0.0, 8144.0, 0.0, 0.0, 8090.0, - 0.0, 0.0, 8056.0, 0.0, 0.0, 8134.0, 0.0, 0.0, 8236.0, - 0.0, 0.0, 8186.0, 0.0, 0.0, 8108.0, 0.0, 0.0, 8049.0, - 0.0, 0.0, 8112.0, 0.0, 0.0, 8190.0, 0.0, 0.0, 8144.0, - 0.0, 0.0, 8081.0}} - .Test(*this, scope, builder, options); - } - { - // Test convTranspose2d operator by setting padding=1. - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - options->setPadding({1, 1, 1, 1}); - ConvTranspose2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 5, 5, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0}}, - .expected = {48.0, 100.0, 127.0, 145.0, 101.0, 126.0, 186.0, - 231.0, 213.0, 132.0, 132.0, 249.0, 285.0, 267.0, - 153.0, 156.0, 231.0, 213.0, 177.0, 147.0, 129.0, - 217.0, 217.0, 199.0, 95.0}} - .Test(*this, scope, builder, options); - } - { - // Test convTranspose2d operator by setting strides=2, padding=1. - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - options->setStrides({2, 2}); - options->setPadding({1, 1, 1, 1}); - ConvTranspose2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0}}, - .expected = {9.0, 16.0, 18.0, 25.0, 27.0, 18.0, 41.0, 27.0, 59.0, - 36.0, 36.0, 43.0, 45.0, 52.0, 54.0, 45.0, 95.0, 54.0, - 113.0, 63.0, 63.0, 70.0, 72.0, 79.0, 81.0}} - .Test(*this, scope, builder, options); - } - { - // Test convTranspose2d by setting outputSizes={1, 8, 8, 1}. - auto* options = MLConvTranspose2dOptions::Create(); - options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc); - options->setFilterLayout( - V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi); - options->setStrides({2, 2}); - options->setOutputSizes({8, 8}); - ConvTranspose2dTester<float>{ - .input = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}}, - .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32, - .dimensions = {1, 3, 3, 1}, - .values = {1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0}}, - .expected = {1.0, 3.0, 7.0, 6.0, 13.0, 9.0, 15.0, 0.0, - 7.0, 9.0, 16.0, 18.0, 25.0, 27.0, 6.0, 0.0, - 8.0, 18.0, 41.0, 27.0, 59.0, 36.0, 54.0, 0.0, - 28.0, 36.0, 43.0, 45.0, 52.0, 54.0, 12.0, 0.0, - 23.0, 45.0, 95.0, 54.0, 113.0, 63.0, 93.0, 0.0, - 49.0, 63.0, 70.0, 72.0, 79.0, 81.0, 18.0, 0.0, - 28.0, 42.0, 88.0, 48.0, 100.0, 54.0, 72.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}} - .Test(*this, scope, builder, options); - } -} - -template <typename T> struct GemmTester { OperandInfo<T> a; OperandInfo<T> b;
diff --git a/third_party/blink/renderer/modules/model_execution/exception_helpers.cc b/third_party/blink/renderer/modules/model_execution/exception_helpers.cc index 65f1d4f..51c9c81 100644 --- a/third_party/blink/renderer/modules/model_execution/exception_helpers.cc +++ b/third_party/blink/renderer/modules/model_execution/exception_helpers.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/modules/model_execution/exception_helpers.h" +#include "third_party/blink/public/mojom/model_execution/model_session.mojom-shared.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" namespace blink { @@ -19,4 +21,59 @@ DOMException::GetErrorName(DOMExceptionCode::kOperationError))); } +DOMException* ConvertModelStreamingResponseErrorToDOMException( + ModelStreamingResponseStatus error) { + switch (error) { + case ModelStreamingResponseStatus::kErrorUnknown: + return DOMException::Create( + "An unknown error occurred.", + DOMException::GetErrorName(DOMExceptionCode::kUnknownError)); + case ModelStreamingResponseStatus::kErrorInvalidRequest: + return DOMException::Create( + "The request was invalid.", + DOMException::GetErrorName(DOMExceptionCode::kNotSupportedError)); + case ModelStreamingResponseStatus::kErrorRequestThrottled: + return DOMException::Create( + "The request was throttled.", + DOMException::GetErrorName(DOMExceptionCode::kQuotaExceededError)); + case ModelStreamingResponseStatus::kErrorPermissionDenied: + return DOMException::Create( + "A user permission error occurred, such as not signed-in or not " + "allowed to execute model.", + DOMException::GetErrorName(DOMExceptionCode::kNotAllowedError)); + case ModelStreamingResponseStatus::kErrorGenericFailure: + return DOMException::Create( + "Other generic failure occurred.", + DOMException::GetErrorName(DOMExceptionCode::kUnknownError)); + case ModelStreamingResponseStatus::kErrorRetryableError: + return DOMException::Create( + "A retryable error occurred in the server.", + DOMException::GetErrorName(DOMExceptionCode::kNotReadableError)); + case ModelStreamingResponseStatus::kErrorNonRetryableError: + return DOMException::Create( + "A non-retryable error occurred in the server.", + DOMException::GetErrorName(DOMExceptionCode::kNotReadableError)); + case ModelStreamingResponseStatus::kErrorUnsupportedLanguage: + return DOMException::Create( + "The language was unsupported.", + DOMException::GetErrorName(DOMExceptionCode::kNotSupportedError)); + case ModelStreamingResponseStatus::kErrorFiltered: + return DOMException::Create( + "The execution yielded a bad response.", + DOMException::GetErrorName(DOMExceptionCode::kNotReadableError)); + case ModelStreamingResponseStatus::kErrorDisabled: + return DOMException::Create( + "The response was disabled.", + DOMException::GetErrorName(DOMExceptionCode::kNotReadableError)); + case ModelStreamingResponseStatus::kErrorCancelled: + return DOMException::Create( + "The request was cancelled.", + DOMException::GetErrorName(DOMExceptionCode::kAbortError)); + case ModelStreamingResponseStatus::kOngoing: + case ModelStreamingResponseStatus::kComplete: + NOTREACHED(); + return nullptr; + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/model_execution/exception_helpers.h b/third_party/blink/renderer/modules/model_execution/exception_helpers.h index 9a5edda..880fdef7 100644 --- a/third_party/blink/renderer/modules/model_execution/exception_helpers.h +++ b/third_party/blink/renderer/modules/model_execution/exception_helpers.h
@@ -5,15 +5,21 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MODEL_EXECUTION_EXCEPTION_HELPERS_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MODEL_EXECUTION_EXCEPTION_HELPERS_H_ +#include "third_party/blink/public/mojom/model_execution/model_session.mojom-blink-forward.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" namespace blink { +using mojom::blink::ModelStreamingResponseStatus; + void ThrowInvalidContextException(ExceptionState& exception_state); void RejectPromiseWithInternalError(ScriptPromiseResolverBase* resolver); +DOMException* ConvertModelStreamingResponseErrorToDOMException( + ModelStreamingResponseStatus error); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MODEL_EXECUTION_EXCEPTION_HELPERS_H_
diff --git a/third_party/blink/renderer/modules/model_execution/model_generic_session.cc b/third_party/blink/renderer/modules/model_execution/model_generic_session.cc index 3643214..860f7c8 100644 --- a/third_party/blink/renderer/modules/model_execution/model_generic_session.cc +++ b/third_party/blink/renderer/modules/model_execution/model_generic_session.cc
@@ -30,41 +30,6 @@ using mojom::blink::ModelStreamingResponseStatus; -// TODO(crbug.com/1520700): update this to different DOMException once the -// list finalized. -const char* ConvertModelStreamingResponseErrorToString( - ModelStreamingResponseStatus error) { - switch (error) { - case ModelStreamingResponseStatus::kErrorUnknown: - return "Unknown error."; - case ModelStreamingResponseStatus::kErrorInvalidRequest: - return "The request was invalid."; - case ModelStreamingResponseStatus::kErrorRequestThrottled: - return "The request was throttled."; - case ModelStreamingResponseStatus::kErrorPermissionDenied: - return "User permission errors such as not signed-in or not allowed to " - "execute model."; - case ModelStreamingResponseStatus::kErrorGenericFailure: - return "Other generic failures."; - case ModelStreamingResponseStatus::kErrorRetryableError: - return "Retryable error occurred in server."; - case ModelStreamingResponseStatus::kErrorNonRetryableError: - return "Non-retryable error occurred in server."; - case ModelStreamingResponseStatus::kErrorUnsupportedLanguage: - return "Unsupported."; - case ModelStreamingResponseStatus::kErrorFiltered: - return "Bad response."; - case ModelStreamingResponseStatus::kErrorDisabled: - return "Response was disabled."; - case ModelStreamingResponseStatus::kErrorCancelled: - return "The request was cancelled."; - case ModelStreamingResponseStatus::kOngoing: - case ModelStreamingResponseStatus::kComplete: - NOTREACHED(); - return ""; - } -} - // Implementation of blink::mojom::blink::ModelStreamingResponder that // handles the streaming output of the model execution, and returns the full // result through a promise. @@ -107,7 +72,8 @@ if (status == ModelStreamingResponseStatus::kComplete) { resolver_->Resolve(response_); } else { - resolver_->Reject(ConvertModelStreamingResponseErrorToString(status)); + resolver_->Reject( + ConvertModelStreamingResponseErrorToDOMException(status)); } // Record the per execution metrics and run the complete callback. base::UmaHistogramCounts1M( @@ -189,9 +155,8 @@ if (status == ModelStreamingResponseStatus::kComplete) { Controller()->Close(); } else { - Controller()->Error(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kNotReadableError, - ConvertModelStreamingResponseErrorToString(status))); + Controller()->Error( + ConvertModelStreamingResponseErrorToDOMException(status)); } // Record the per execution metrics and run the complete callback. base::UmaHistogramCounts1M(
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h index ceecd88..1100c30 100644 --- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h +++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -189,6 +189,10 @@ // Returns true iff we have LCPP hint data for the fetch context. virtual bool DoesLCPPHaveAnyHintData() { return false; } + // Returns true iff we have LCP element locator hint data for the fetch + // context. + virtual bool DoesLCPPHaveLcpElementLocatorHintData() { return false; } + // Returns the origin of the top frame in the document or the dedicated // worker. This returns nullptr for Shared Workers and Service Workers. virtual scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 58fb3aa..0cb5c2bd 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -666,6 +666,19 @@ } } + // The following code disables AdjustImagePriority when there is LCPP + // LcpElementLocator hint data. The reason why not to early return from this + // function is that we want to record UMA with following + // MaybeRecordBoostImagePriorityReason() function even when we disables + // AdjustImagePriority. + if (base::FeatureList::IsEnabled(features::kLCPCriticalPathPredictor) && + features::kLCPCriticalPathAdjustImageLoadPriority.Get() && + features::kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost + .Get() && + context_->DoesLCPPHaveLcpElementLocatorHintData()) { + new_priority = priority_so_far; + } + // Only records HTTP family URLs (e.g. Exclude data URLs). if (resource_request.Url().ProtocolIsInHTTPFamily()) { MaybeRecordBoostImagePriorityReason(priority_so_far != new_priority,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 7ae026c..a1fd2e1 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1558,6 +1558,10 @@ status: "test", }, { + // crbug.com/333630754 + name: "FasterMinContent", + }, + { name: "FastPositionIterator", // Not enabled due to a RTL issue. crbug.com/1421016. },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e51f3b5..4114736 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2814,7 +2814,6 @@ crbug.com/626703 external/wpt/css/css-text/text-justify/text-justify-word-separators.html [ Failure ] crbug.com/626703 external/wpt/svg/pservers/reftests/gradient-color-interpolation.svg [ Failure ] crbug.com/626703 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/arg_min_max.https.any.html [ Skip Timeout ] -crbug.com/626703 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/arg_min_max.https.any.worker.html [ Crash ] crbug.com/626703 external/wpt/css/css-page/page-orientation-on-landscape-001-print.html [ Failure ] crbug.com/626703 external/wpt/css/css-page/page-orientation-on-portrait-001-print.html [ Failure ] crbug.com/626703 external/wpt/css/css-page/page-orientation-on-square-001-print.html [ Failure ] @@ -7260,43 +7259,33 @@ crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/empty-ruby-text-container-abs.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-break-around-ruby-001.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-spacing.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/nested-ruby-pairing-001.html [ Crash Failure Timeout ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-001.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-001a.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-002.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-002a.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-base-container-float.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-bidi-003.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-intra-level-whitespace-001.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-line-breaking-002.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/after-doesnt-crash.html [ Crash Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/before-doesnt-crash.html [ Crash Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/float-overhang-from-ruby-text.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/line-break-ruby.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/nested-ruby.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-horizontal.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-vertical.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/percentage-height-child-crash.html [ Crash ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-7.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-combined.html [ Crash Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-position-modern-japanese-fonts.html [ Crash Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-position-modern-japanese-fonts.html [ Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-text2.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/select-ruby.html [ Failure ] # RubyLineBreakable; NeedsRebaseline +crbug.com/324111880 virtual/ruby-lb/fast/ruby/after-doesnt-crash.html [ Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/before-doesnt-crash.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/float-object-doesnt-crash.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/modify-positioned-ruby-text-crash.html [ Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/percentage-height-child-crash.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/position-after.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-column-break.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-columns-spans.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-columns.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-empty-rt.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-first-letter.html [ Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-7.html [ Failure ] +crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-combined.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-length.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-text-before-after-content.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-trailing.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-1.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-2.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-3.html [ Failure ] -crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-text2.html [ Failure ] crbug.com/324111880 virtual/ruby-lb/fast/ruby/split-ruby-column-percentage-height-descendant.html [ Failure ] # line-clamp @@ -7389,3 +7378,7 @@ # Gardener 2024-04-11 crbug.com/333739617 [ Mac ] fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html [ Timeout ] crbug.com/333501264 virtual/fenced-frame-mparch/external/wpt/fenced-frame/setting-null-config-navigates-to-about-blank.https.html [ Failure Pass ] + +# Gardener 2024-04-16 +crbug.com/335003887 [ Mac14 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/arg_min_max.https.any.worker.html [ Failure Pass ] +crbug.com/335003887 [ Win11 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/arg_min_max.https.any.worker.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html index 2056055f..b93a48fb 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html
@@ -115,13 +115,33 @@ @font-palette-values --A { override-colors: 0 canvas; } + +/* 19 */ +@font-palette-values --A { + override-colors: 0 currentcolor; +} + +/* 20 */ +@font-palette-values --A { + override-colors: 0 light-dark(white, black); +} + +/* 21 */ +@font-palette-values --A { + override-colors: 0 color-mix(in lch, red, canvas); +} + +/* 22 */ +@font-palette-values --A { + override-colors: 0 light-dark(white, currentcolor); +} </style> </head> <body> <script> let rules = document.getElementById("style").sheet.cssRules; test(function() { - assert_equals(rules.length, 19); + assert_equals(rules.length, 23); }); test(function() { @@ -283,6 +303,34 @@ assert_equals(rule.basePalette, ""); assert_equals(rule.overrideColors, ""); }); + +test(function() { + let text = rules[19].cssText; + let rule = rules[19]; + assert_equals(text.indexOf("override-colors"), -1); + assert_equals(rule.overrideColors, ""); +}); + +test(function() { + let text = rules[20].cssText; + let rule = rules[20]; + assert_equals(text.indexOf("override-colors"), -1); + assert_equals(rule.overrideColors, ""); +}); + +test(function() { + let text = rules[21].cssText; + let rule = rules[21]; + assert_equals(text.indexOf("override-colors"), -1); + assert_equals(rule.overrideColors, ""); +}); + +test(function() { + let text = rules[22].cssText; + let rule = rules[22]; + assert_equals(text.indexOf("override-colors"), -1); + assert_equals(rule.overrideColors, ""); +}); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html index 3c0c0626..99fceff2 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html
@@ -103,6 +103,11 @@ @font-palette-values --P { font-family: foo, bar, baz; } + +/* 17 */ +@font-palette-values --Q { + override-colors: 0 color-mix(in lch, red, blue); +} </style> </head> <body> @@ -385,6 +390,14 @@ assert_equals(rule.basePalette, ""); assert_equals(rule.overrideColors, ""); }); + +test(function() { + let rule = rules[17]; + assert_equals(rule.name, "--Q"); + assert_equals(rule.fontFamily, ""); + assert_equals(rule.basePalette, ""); + assert_equals(rule.overrideColors, "0 color-mix(in lch, red, blue)"); +}); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005-ref.html index 03e5cab..79a19130 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005-ref.html
@@ -11,3 +11,12 @@ <p><rb>a</rb><rt>x</rt><rb>b</rb><rt>y</rt></p> <p><rbc><span>a</span><rb></rb>b</rbc><rt>x</rt><rt></rt><rt>y</rt></p> <p><rb>a</rb><rb></rb><rb>b</rb><rtc><span>x</span><rt></rt>y</rtc></p> + +<p>'a' and 'b c' should be paired with 'x' and 'y z' repectively:</p> +<p><ruby>a <rt>x</rt><span style="display:block">b</span> c<rt>y z</ruby></p> + +<p>'a b' and 'c' should be paired with 'x y' and 'z' repectively:</p> +<p><ruby>a <span style="display:block">b</span> <rt>x y</rt><span>c</span><rt>z</ruby></p> + +<p>'a b' and 'c d' should be paired with 'w x' and 'y z' repectively:</p> +<p><ruby>a <span style="display:block">b</span> <rt>w x</rt><span>c</span> <span style="display:block">d</span><rt>y z</ruby>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005.html index a684d66..66f7dbd 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-insertion-005.html
@@ -20,3 +20,12 @@ <p><rbc><span data-insert="after" data-tag="rb">a</span>b</rbc><rt>x</rt><rt></rt><rt>y</rt></p> <!-- pseudo ruby text --> <p><rb>a</rb><rb></rb><rb>b</rb><rtc><span data-insert="after" data-tag="rt">x</span>y</rtc></p> + +<p>'a' and 'b c' should be paired with 'x' and 'y z' repectively:</p> +<p><ruby>a <span style="display:block" data-insert="before" data-tag="rt" data-text="x">b</span> c<rt>y z</ruby></p> + +<p>'a b' and 'c' should be paired with 'x y' and 'z' repectively:</p> +<p><ruby>a <span style="display:block">b</span> <span data-insert="before" data-tag="rt" data-text="x y">c</span><rt>z</ruby></p> + +<p>'a b' and 'c d' should be paired with 'w x' and 'y z' repectively:</p> +<p><ruby>a <span style="display:block">b</span> <span data-insert="before" data-tag="rt" data-text="w x">c</span> <span style="display:block">d</span><rt>y z</ruby>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003-ref.html index 0067c014..113598e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003-ref.html
@@ -18,3 +18,8 @@ <p><rbc>ab</rbc><rt>xy</rt></p> <p><rb>ab</rb><rtc style="letter-spacing: 1px">xy</rtc></p> + +<p>'a b c' should be paried with 'x y z':</p> +<p><ruby>a b <span style="display:block">c</span><rt>x y z</ruby> +<p><ruby>a <span style="display:block">b</span> c<rt>x y z</ruby> +<p><ruby><span style="display:block">a</span> b <span style="display:block">c</span><rt>x y z</ruby>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003.html index d35b2b9..ff6c0b4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-dynamic-removal-003.html
@@ -31,3 +31,9 @@ <!-- pseudo ruby text --> <!-- letter-spacing is added here to avoid fuzzy on Windows. See bug 1111891 --> <p><rb>ab</rb><rtc style="letter-spacing: 1px">x<rt class="remove"></rt>y</rtc></p> + +<p>'a b c' should be paried with 'x y z':</p> +<!-- merge --> +<p><ruby>a <rt class="remove">w</rt><span>b</span> <span style="display:block">c</span><rt>x y z</ruby> +<p><ruby>a <span style="display:block">b</span> <rt class="remove">w</rt><span>c</span><rt>x y z</ruby> +<p><ruby><span style="display:block">a</span> <rt class="remove">w</rt><span>b</span> <span style="display:block">c</span><rt>x y z</ruby>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/conv2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/conv2d.https.any.js index ffc9c2c..44d5f14 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/conv2d.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/conv2d.https.any.js
@@ -55,3 +55,482 @@ const filter = builder.input('filter', kExampleFilterDescriptor); assert_throws_js(TypeError, () => builder.conv2d(input, filter, options)); }, '[conv2d] throw if activation option is from another builder'); + +const tests = [ + { + name: '[conv2d] Test with default options.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with padding.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + }, + output: {dataType: 'float32', dimensions: [1, 1, 5, 5]} + }, + { + name: '[conv2d] Test with strides and padding.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + strides: [2, 2], + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with strides and asymmetric padding.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 4, 2]}, + options: { + padding: [1, 2, 0, 1], + strides: [2, 2], + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test depthwise conv2d by setting groups to input channels.', + input: {dataType: 'float32', dimensions: [1, 4, 2, 2]}, + filter: {dataType: 'float32', dimensions: [4, 1, 2, 2]}, + options: { + groups: 4, + }, + output: {dataType: 'float32', dimensions: [1, 4, 1, 1]} + }, + { + name: + '[conv2d] Test depthwise conv2d with groups, inputLayout="nhwc" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 2, 2, 4]}, + filter: {dataType: 'float32', dimensions: [1, 2, 2, 4]}, + options: { + groups: 4, + inputLayout: 'nhwc', + filterLayout: 'ihwo', + }, + output: {dataType: 'float32', dimensions: [1, 1, 1, 4]} + }, + { + name: + '[conv2d] Test with dilations, inputLayout="nhwc" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 65, 65, 1]}, + filter: {dataType: 'float32', dimensions: [1, 3, 3, 1]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'ihwo', + dilations: [4, 4], + }, + output: {dataType: 'float32', dimensions: [1, 57, 57, 1]} + }, + { + name: '[conv2d] Test with inputLayout="nchw" and filterLayout="oihw".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + inputLayout: 'nchw', + filterLayout: 'oihw', + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with inputLayout="nchw" and filterLayout="hwio".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + inputLayout: 'nchw', + filterLayout: 'hwio', + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with inputLayout="nchw" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + options: { + inputLayout: 'nchw', + filterLayout: 'ohwi', + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with inputLayout="nchw" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + inputLayout: 'nchw', + filterLayout: 'ihwo', + }, + output: {dataType: 'float32', dimensions: [1, 1, 3, 3]} + }, + { + name: '[conv2d] Test with inputLayout="nhwc" and filterLayout="oihw".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'oihw', + }, + output: {dataType: 'float32', dimensions: [1, 3, 3, 1]} + }, + { + name: '[conv2d] Test with inputLayout="nhwc" and filterLayout="hwio".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'hwio', + }, + output: {dataType: 'float32', dimensions: [1, 3, 3, 1]} + }, + { + name: '[conv2d] Test with inputLayout="nhwc" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'ohwi', + }, + output: {dataType: 'float32', dimensions: [1, 3, 3, 1]} + }, + { + name: '[conv2d] Test with inputLayout="nhwc" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'ihwo', + }, + output: {dataType: 'float32', dimensions: [1, 3, 3, 1]} + }, + { + name: + '[conv2d] Throw if the output operand\'s number of elements is too large.', + input: { + dataType: 'float32', + dimensions: [1, 1, kMaxUnsignedLong / 2, kMaxUnsignedLong / 2] + }, + filter: {dataType: 'float32', dimensions: [8, 1, 1, 1]}, + }, + { + name: '[conv2d] Throw if the input is not a 4-D tensor.', + input: {dataType: 'float32', dimensions: [1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 2, 1]}, + }, + { + name: '[conv2d] Throw if the filter is not a 4-D tensor.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 2]}, + }, + { + name: + '[conv2d] Throw if the filter data type doesn\'t match the input data type.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'int32', dimensions: [1, 1, 2, 2]}, + }, + { + name: '[conv2d] Throw if the length of padding is not 4.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + padding: [2, 2], + }, + }, + { + name: '[conv2d] Throw if the length of strides is not 2.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + strides: [2], + }, + }, + { + name: '[conv2d] Throw if strideHeight is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + strides: [0, 1], + }, + }, + { + name: '[conv2d] Throw if strideWidth is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + strides: [1, 0], + }, + }, + { + name: '[conv2d] Throw if the length of dilations is not 2.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + dilations: [1], + }, + }, + { + name: '[conv2d] Throw if dilationHeight is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + dilations: [0, 1], + }, + }, + { + name: '[conv2d] Throw if dilationWidth is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + dilations: [1, 0], + }, + }, + { + name: '[conv2d] Throw if inputChannels % groups is not 0.', + input: {dataType: 'float32', dimensions: [1, 4, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + groups: 3, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels.', + input: {dataType: 'float32', dimensions: [1, 4, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + groups: 2, + }, + }, + { + name: '[conv2d] Throw if the groups is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 4, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + groups: 0, + }, + }, + { + name: + '[conv2d] Throw due to overflow when calculating the effective filter height.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 434983, 2]}, + options: { + dilations: [328442, 1], + }, + }, + { + name: + '[conv2d] Throw due to overflow when calculating the effective filter width.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 234545]}, + options: { + dilations: [2, 843452], + }, + }, + { + name: '[conv2d] Throw due to overflow when dilation height is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + dilations: [kMaxUnsignedLong, 1], + }, + }, + { + name: '[conv2d] Throw due to overflow when dilation width is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + dilations: [1, kMaxUnsignedLong], + }, + }, + { + name: '[conv2d] Throw due to underflow when calculating the output height.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 4, 2]}, + options: { + dilations: [4, 1], + padding: [1, 1, 1, 1], + strides: [2, 2], + }, + }, + { + name: '[conv2d] Throw due to underflow when calculating the output width.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 8]}, + options: { + dilations: [1, 4], + padding: [1, 1, 1, 1], + strides: [2, 2], + }, + }, + { + name: '[conv2d] Throw if the bias is not a 1-D tensor.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + bias: {dataType: 'float32', dimensions: [1, 2]}, + }, + }, + { + name: + '[conv2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="oihw".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[conv2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="hwio".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 2, 1, 1]}, + options: { + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[conv2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 2, 1]}, + options: { + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[conv2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 2, 1]}, + options: { + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[conv2d] Throw if the bias data type doesn\'t match input data type.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + bias: {dataType: 'int32', dimensions: [1]}, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nchw" and filterLayout="oihw".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + inputLayout: 'nchw', + filterLayout: 'oihw', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nchw" and filterLayout="hwio".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + inputLayout: 'nchw', + filterLayout: 'hwio', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nchw" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + options: { + inputLayout: 'nchw', + filterLayout: 'ohwi', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nchw" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 2, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + inputLayout: 'nchw', + filterLayout: 'ihwo', + groups: 2, + }, + + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nhwc" and filterLayout="oihw".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'oihw', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nhwc" and filterLayout="hwio".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'hwio', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nhwc" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'ohwi', + groups: 2, + }, + }, + { + name: + '[conv2d] Throw if inputChannels / groups is not equal to filterInputChannels with inputLayout="nhwc" and filterLayout="ihwo".', + input: {dataType: 'float32', dimensions: [1, 5, 5, 2]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + inputLayout: 'nhwc', + filterLayout: 'ihwo', + groups: 2, + }, + }, +]; + +tests.forEach( + test => promise_test(async t => { + const input = builder.input( + 'input', + {dataType: test.input.dataType, dimensions: test.input.dimensions}); + const filter = builder.input( + 'filter', + {dataType: test.filter.dataType, dimensions: test.filter.dimensions}); + + if (test.options && test.options.bias) { + test.options.bias = builder.input('bias', { + dataType: test.options.bias.dataType, + dimensions: test.options.bias.dimensions + }); + } + + if (test.output) { + const output = builder.conv2d(input, filter, test.options); + assert_equals(output.dataType(), test.output.dataType); + assert_array_equals(output.shape(), test.output.dimensions); + } else { + assert_throws_js( + TypeError, () => builder.conv2d(input, filter, test.options)); + } + }, test.name));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/convTranspose2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/convTranspose2d.https.any.js index c14f445b..3c3c49566 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/convTranspose2d.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/convTranspose2d.https.any.js
@@ -57,3 +57,467 @@ assert_throws_js( TypeError, () => builder.convTranspose2d(input, filter, options)); }, '[convTranspose2d] throw if activation option is from another builder'); + +const tests = [ + { + name: '[convTranspose2d] Test with default options.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + output: {dataType: 'float32', dimensions: [1, 1, 5, 5]} + }, + { + name: + '[convTranspose2d] Test with inputLayout="nchw" and filterLayout="hwoi".', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + filterLayout: 'hwoi', + inputLayout: 'nchw', + }, + output: {dataType: 'float32', dimensions: [1, 2, 5, 5]} + }, + { + name: + '[convTranspose2d] Test with inputLayout="nchw" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + filterLayout: 'ohwi', + inputLayout: 'nchw', + }, + output: {dataType: 'float32', dimensions: [1, 2, 5, 5]} + }, + { + name: + '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="iohw".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 1]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + filterLayout: 'iohw', + inputLayout: 'nhwc', + }, + output: {dataType: 'float32', dimensions: [1, 5, 5, 2]} + }, + { + name: + '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="hwoi".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 1]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + filterLayout: 'hwoi', + inputLayout: 'nhwc', + }, + output: {dataType: 'float32', dimensions: [1, 5, 5, 2]} + }, + { + name: + '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 1]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + filterLayout: 'ohwi', + inputLayout: 'nhwc', + }, + output: {dataType: 'float32', dimensions: [1, 5, 5, 2]} + }, + { + name: '[convTranspose2d] Test with strides=[3, 2], outputSizes=[10, 8].', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + strides: [3, 2], + outputSizes: [10, 8], + }, + output: {dataType: 'float32', dimensions: [1, 2, 10, 8]} + }, + { + name: '[convTranspose2d] Test with strides=[3, 2], outputPadding=[1, 1].', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + strides: [3, 2], + outputPadding: [1, 1], + }, + output: {dataType: 'float32', dimensions: [1, 2, 10, 8]} + }, + { + name: '[convTranspose2d] Test with padding=1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + }, + output: {dataType: 'float32', dimensions: [1, 1, 5, 5]} + }, + { + name: '[convTranspose2d] Test with padding=1, groups=3.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + groups: 3, + }, + output: {dataType: 'float32', dimensions: [1, 3, 5, 5]} + }, + { + name: '[convTranspose2d] Test with strides=2.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + strides: [2, 2], + }, + output: {dataType: 'float32', dimensions: [1, 2, 7, 7]} + }, + { + name: '[convTranspose2d] Test with strides=2 and padding=1.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + strides: [2, 2], + }, + output: {dataType: 'float32', dimensions: [1, 1, 5, 5]} + }, + { + name: + '[convTranspose2d] Test when the output sizes are explicitly specified, the output padding values are ignored though padding value is not smaller than stride along the same axis.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + outputPadding: [3, 3], + strides: [3, 2], + outputSizes: [10, 8], + }, + output: {dataType: 'float32', dimensions: [1, 2, 10, 8]} + }, + { + name: '[convTranspose2d] Throw if the input is not a 4-D tensor.', + input: {dataType: 'float32', dimensions: [1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + }, + { + name: '[convTranspose2d] Throw if the filter is not a 4-D tensor.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 2]}, + }, + { + name: + '[convTranspose2d] Throw if the filter data type doesn\'t match the input data type.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'int32', dimensions: [1, 1, 2, 2]}, + }, + { + name: '[convTranspose2d] Throw if the length of padding is not 4.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + padding: [2, 2], + }, + }, + { + name: '[convTranspose2d] Throw if the length of strides is not 2.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + strides: [2], + }, + }, + { + name: '[convTranspose2d] Throw if one stride value is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + strides: [1, 0], + }, + }, + { + name: '[convTranspose2d] Throw if the length of dilations is not 2.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + dilations: [1], + }, + }, + { + name: + '[convTranspose2d] Throw if the one dilation value is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + dilations: [1, 0], + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="iohw".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + filterLayout: 'iohw', + inputLayout: 'nchw', + groups: 1, + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="hwoi".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 3]}, + filter: {dataType: 'float32', dimensions: [3, 1, 2, 1]}, + options: { + filterLayout: 'hwoi', + inputLayout: 'nchw', + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + filterLayout: 'ohwi', + inputLayout: 'nchw', + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nhwc" and filterLayout="iohw".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + filterLayout: 'iohw', + inputLayout: 'nhwc', + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels inputLayout="nhwc" and filterLayout="hwoi".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + filter: {dataType: 'float32', dimensions: [3, 3, 2, 1]}, + options: { + filterLayout: 'hwoi', + inputLayout: 'nhwc', + }, + }, + { + name: + '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nhwc" and filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 3, 3, 2]}, + filter: {dataType: 'float32', dimensions: [2, 3, 3, 1]}, + options: { + filterLayout: 'ohwi', + inputLayout: 'nhwc', + }, + }, + { + name: '[convTranspose2d] Throw if output channels is too large.', + input: {dataType: 'float32', dimensions: [1, 4, 5, 5]}, + filter: {dataType: 'float32', dimensions: [4, 2, 2, 2]}, + options: { + groups: kMaxUnsignedLong, + }, + }, + { + name: '[convTranspose2d] Throw if the groups is smaller than 1.', + input: {dataType: 'float32', dimensions: [1, 4, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + groups: 0, + }, + }, + { + name: + '[convTranspose2d] Throw due to overflow when calculating the effective filter height.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 434983, 2]}, + options: { + dilations: [328443, 1], + }, + }, + { + name: + '[convTranspose2d] Throw due to overflow when calculating the effective filter width.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 234545]}, + options: { + dilations: [2, 843452], + }, + }, + { + name: + '[convTranspose2d] Throw due to overflow when dilation height is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 2]}, + options: { + dilations: [kMaxUnsignedLong, 1], + }, + }, + { + name: + '[convTranspose2d] Throw due to overflow when dilation width is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 2]}, + options: { + dilations: [1, kMaxUnsignedLong], + }, + }, + { + name: '[convTranspose2d] Throw if the bias is not a 1-D tensor.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + bias: {dataType: 'float32', dimensions: [1, 2]}, + }, + }, + { + name: + '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="iohw".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + filterLayout: 'iohw', + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="hwoi".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [2, 2, 1, 1]}, + options: { + filterLayout: 'hwoi', + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="ohwi".', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 2, 2, 1]}, + options: { + filterLayout: 'ohwi', + bias: {dataType: 'float32', dimensions: [2]}, + }, + }, + { + name: + '[convTranspose2d] Throw if the bias data type doesn\'t match input data type.', + input: {dataType: 'float32', dimensions: [1, 1, 5, 5]}, + filter: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + options: { + bias: {dataType: 'int32', dimensions: [1]}, + }, + }, + { + name: + '[convTranspose2d] Throw if the outputPadding is not a sequence of length 2.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + strides: [3, 2], + outputPadding: [1, 1, 1, 1], + }, + }, + { + name: + '[convTranspose2d] Throw if the outputPadding is not smaller than stride along the width dimension.', + input: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [0, 0, 3, 3], + strides: [2, 2], + outputPadding: [0, 2], + }, + }, + { + name: + '[convTranspose2d] Throw if the outputPadding is not smaller than stride along the height dimension.', + input: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [0, 0, 3, 3], + strides: [2, 2], + outputPadding: [2, 0], + }, + }, + { + name: + '[convTranspose2d] Throw if the outputSizes is not a sequence of length 2.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 2, 3, 3]}, + options: { + strides: [3, 2], + outputSizes: [1, 2, 10, 8], + }, + }, + { + name: '[convTranspose2d] Throw if the padding height is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [4, 4, 0, 0], + strides: [2, 2], + outputPadding: [1, 0], + }, + }, + { + name: '[convTranspose2d] Throw if the padding width is too large.', + input: {dataType: 'float32', dimensions: [1, 1, 2, 2]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [0, 0, 4, 4], + strides: [2, 2], + outputPadding: [0, 1], + }, + }, + { + name: + '[convTranspose2d] Throw due to outputSizes values are smaller than the output sizes calculated by not using outputPadding.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + strides: [2, 2], + outputSizes: [4, 4], + outputPadding: [1, 1], + }, + }, + { + name: + '[convTranspose2d] Throw due to outputSizes values are greater than the output sizes calculated by not using outputPadding.', + input: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + filter: {dataType: 'float32', dimensions: [1, 1, 3, 3]}, + options: { + padding: [1, 1, 1, 1], + strides: [2, 2], + outputSizes: [6, 8], + outputPadding: [1, 1], + }, + }, +]; + +tests.forEach( + test => promise_test(async t => { + const input = builder.input( + 'input', + {dataType: test.input.dataType, dimensions: test.input.dimensions}); + const filter = builder.input( + 'filter', + {dataType: test.filter.dataType, dimensions: test.filter.dimensions}); + + if (test.options && test.options.bias) { + test.options.bias = builder.input('bias', { + dataType: test.options.bias.dataType, + dimensions: test.options.bias.dimensions + }); + } + + if (test.output) { + const output = builder.convTranspose2d(input, filter, test.options); + assert_equals(output.dataType(), test.output.dataType); + assert_array_equals(output.shape(), test.output.dimensions); + } else { + assert_throws_js( + TypeError, + () => builder.convTranspose2d(input, filter, test.options)); + } + }, test.name));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/matmul.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/matmul.https.any.js index 03616ddb..6ce0d87 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/matmul.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/matmul.https.any.js
@@ -5,3 +5,109 @@ 'use strict'; validateTwoInputsFromMultipleBuilders('matmul'); + +const tests = [ + { + name: '[matmul] Throw if first input\'s rank is less than 2', + inputs: { + a: {dataType: 'float32', dimensions: [2]}, + b: {dataType: 'float32', dimensions: [2, 2]} + } + }, + { + name: '[matmul] Throw if second input\'s rank is less than 2', + inputs: { + a: {dataType: 'float32', dimensions: [2, 2]}, + b: {dataType: 'float32', dimensions: [2]} + } + }, + { + name: '[matmul] Test with 2-D input and 4-D input', + inputs: { + a: {dataType: 'float32', dimensions: [1, 4]}, + b: {dataType: 'float32', dimensions: [2, 2, 4, 2]} + }, + output: {dataType: 'float32', dimensions: [2, 2, 1, 2]} + }, + { + name: '[matmul] Test with 2-D input and 2-D input', + inputs: { + a: {dataType: 'float32', dimensions: [4, 2]}, + b: {dataType: 'float32', dimensions: [2, 3]} + }, + output: {dataType: 'float32', dimensions: [4, 3]} + }, + { + // batchShape is a clone of inputShape with the spatial dimensions + // (last 2 items) removed. + name: + '[matmul] Test with 3-D input and 3-D input of broadcastable batchShape', + inputs: { + a: {dataType: 'float32', dimensions: [2, 3, 4]}, + b: {dataType: 'float32', dimensions: [1, 4, 1]} + }, + output: {dataType: 'float32', dimensions: [2, 3, 1]} + }, + { + // batchShape is a clone of inputShape with the spatial dimensions + // (last 2 items) removed. + name: + '[matmul] Test with 4-D input and 3-D input of broadcastable batchShape', + inputs: { + a: {dataType: 'float32', dimensions: [2, 2, 3, 4]}, + b: {dataType: 'float32', dimensions: [1, 4, 5]} + }, + output: {dataType: 'float32', dimensions: [2, 2, 3, 5]} + }, + { + name: '[matmul] Test with 3-D input and 3-D input', + inputs: { + a: {dataType: 'float32', dimensions: [2, 3, 4]}, + b: {dataType: 'float32', dimensions: [2, 4, 5]} + }, + output: {dataType: 'float32', dimensions: [2, 3, 5]} + }, + { + name: '[matmul] Throw if data type of two inputs don\'t match', + inputs: { + a: {dataType: 'float32', dimensions: [2, 3, 4]}, + b: {dataType: 'int32', dimensions: [2, 4, 5]} + } + }, + { + name: + '[matmul] Throw if columns of first input\'s shape doesn\'t match the rows of second input\'s shape', + inputs: { + a: {dataType: 'float32', dimensions: /* [rows, columns] */[2, 3]}, + b: {dataType: 'float32', dimensions: /* [rows, columns] */[2, 4]} + }, + }, + { + // batchShape is a clone of inputShape with the spatial dimensions + // (last 2 items) removed. + name: '[matmul] Throw if batchShapes aren\'t bidirectionally broadcastable', + inputs: { + a: {dataType: 'float32', dimensions: [3, 3, 4]}, + b: {dataType: 'float32', dimensions: [2, 4, 1]} + }, + }, +]; + +tests.forEach(test => promise_test(async t => { + const inputA = builder.input('a', { + dataType: test.inputs.a.dataType, + dimensions: test.inputs.a.dimensions + }); + const inputB = builder.input('b', { + dataType: test.inputs.b.dataType, + dimensions: test.inputs.b.dimensions + }); + if (test.output) { + const output = builder.matmul(inputA, inputB); + assert_equals(output.dataType(), test.output.dataType); + assert_array_equals(output.shape(), test.output.dimensions); + } else { + assert_throws_js( + TypeError, () => builder.matmul(inputA, inputB)); + } + }, test.name));
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1-expected.txt deleted file mode 100644 index e1a6ba5..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -textnew ruby textblock more textruby text
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1.html deleted file mode 100644 index 661bd94..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-1.html +++ /dev/null
@@ -1,28 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var block = document.getElementById('D'); - var newRT = document.createElement('rt'); - var newRTText = document.createTextNode('new ruby text'); - newRT.appendChild(newRTText); - ruby.insertBefore(newRT, block); -} -</script> -</head> -<!-- Inserting a <rt> element, causing a split of block flow to inline flow and block flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">text <div id="D">block</div> more text<rt>ruby text</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2-expected.txt deleted file mode 100644 index 953fed7..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -text blocknew ruby textmore textruby text
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2.html deleted file mode 100644 index 020731b..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-2.html +++ /dev/null
@@ -1,28 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var span = document.getElementById('S'); - var newRT = document.createElement('rt'); - var newRTText = document.createTextNode('new ruby text'); - newRT.appendChild(newRTText); - ruby.insertBefore(newRT, span); -} -</script> -</head> -<!-- Inserting a <rt> element, causing a split of block flow to block flow and inline flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">text <div>block</div> <span id="S">more</span> text<rt>ruby text</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3-expected.txt deleted file mode 100644 index 953fed7..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -text blocknew ruby textmore textruby text
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3.html deleted file mode 100644 index ab52d1aa..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-insert-rt-block-3.html +++ /dev/null
@@ -1,28 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var span = document.getElementById('S'); - var newRT = document.createElement('rt'); - var newRTText = document.createTextNode('new ruby text'); - newRT.appendChild(newRTText); - ruby.insertBefore(newRT, span); -} -</script> -</head> -<!-- Inserting a <rt> element, causing a split of block flow to block flow and block flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">text <div>block</div> <span id="S">more</span> <div>text</div><rt>ruby text</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1-expected.txt deleted file mode 100644 index 6e69928..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -some textmore text and a blockruby text 2
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1.html deleted file mode 100644 index a1da9e9..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-1.html +++ /dev/null
@@ -1,25 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var rt = document.getElementById('RT'); - ruby.removeChild(rt); -} -</script> -</head> -<!-- Removing a <rt> element, causing a merge of inline flow and block flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">some text<rt id="RT">ruby text 1</rt><span>more text</span> <div>and a block</div><rt>ruby text 2</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2-expected.txt deleted file mode 100644 index 299eaa80..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -text block more textruby text 2
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2.html deleted file mode 100644 index c1e3f137..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-2.html +++ /dev/null
@@ -1,25 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var rt = document.getElementById('RT'); - ruby.removeChild(rt); -} -</script> -</head> -<!-- Removing a <rt> element, causing a merge of block flow and inline flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">text <div>block</div> <rt id="RT">ruby text 1</rt><span>more</span> text<rt>ruby text 2</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3-expected.txt b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3-expected.txt deleted file mode 100644 index 299eaa80..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -SUCCESS! - - - -text block more textruby text 2
diff --git a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3.html b/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3.html deleted file mode 100644 index 0945826c..0000000 --- a/third_party/blink/web_tests/fast/ruby/rubyDOM-remove-rt-block-3.html +++ /dev/null
@@ -1,25 +0,0 @@ -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<script> -function test() -{ - if (window.testRunner) - testRunner.dumpAsText(); - document.getElementById("result").firstChild.data = 'SUCCESS!'; - - var ruby = document.getElementById('R'); - var rt = document.getElementById('RT'); - ruby.removeChild(rt); -} -</script> -</head> -<!-- Removing a <rt> element, causing a merge of block flow and block flow --> -<!-- As this is a malformed example we don't care about the exact rendering output, only that it doesn't crash --> -<body onload="test()"> -<div id="result">FAILED!</p> -<br> -<br> -<ruby id="R">text <div>block</div> <rt id="RT">ruby text 1</rt><span>more</span> <div>text</div><rt>ruby text 2</rt></ruby> -</body> -</html>
diff --git a/third_party/blink/web_tests/http/tests/security/base-url-data-expected.txt b/third_party/blink/web_tests/http/tests/security/base-url-data-expected.txt index adaa6ad..b375d51 100644 --- a/third_party/blink/web_tests/http/tests/security/base-url-data-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/base-url-data-expected.txt
@@ -1,4 +1,6 @@ CONSOLE ERROR: 'data' URLs may not be used as base URLs for a document. This is a testharness.js-based test. +[FAIL] 'data:' is an invalid base URL. + assert_equals: expected "data:/,This%20is%20a%20data%20URL." but got "data:/,This is a data URL." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/http/tests/security/base-url-data.html b/third_party/blink/web_tests/http/tests/security/base-url-data.html index 9bab9fa..64d4c3d5 100644 --- a/third_party/blink/web_tests/http/tests/security/base-url-data.html +++ b/third_party/blink/web_tests/http/tests/security/base-url-data.html
@@ -14,7 +14,9 @@ img.onload = t.step_func_done(_ => { assert_equals(img.naturalWidth, 76, "Image loaded correctly."); assert_equals(img.src, "http://127.0.0.1:8000/security/resources/abe.png"); - assert_equals(base.href, 'data:/,This is a data URL.'); + // Fails unless kStandardCompliantNonSpecialSchemeURLParsing is enabled. + // See https://crbug.com/40063064. + assert_equals(base.href, 'data:/,This%20is%20a%20data%20URL.'); }); img.onerror = t.unreached_func("Image should have loaded.");
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/http/tests/security/base-url-data-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/http/tests/security/base-url-data-expected.txt index 168e4aa..adaa6ad 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/http/tests/security/base-url-data-expected.txt +++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/http/tests/security/base-url-data-expected.txt
@@ -1,6 +1,4 @@ CONSOLE ERROR: 'data' URLs may not be used as base URLs for a document. This is a testharness.js-based test. -[FAIL] 'data:' is an invalid base URL. - assert_equals: expected "data:/,This is a data URL." but got "data:/,This%20is%20a%20data%20URL." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any-expected.txt deleted file mode 100644 index bbb8c93a4..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] where float32 0D scalars - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 1D constant tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 1D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 2D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 3D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 5D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 0D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 1D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 2D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 3D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast trueValues 2D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast trueValues 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast falseValues 3D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast falseValues 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors all broadcast 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any.worker-expected.txt deleted file mode 100644 index bbb8c93a4..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/webnn-service-without-gpu/external/wpt/webnn/conformance_tests/gpu/where.https.any.worker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] where float32 0D scalars - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 1D constant tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 1D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 2D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 3D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 5D tensors - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 0D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 1D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 2D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 3D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast condition 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast trueValues 2D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast trueValues 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast falseValues 3D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors only broadcast falseValues 4D to 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -[FAIL] where float32 4D tensors all broadcast 4D - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': where is not implemented" -Harness: the test ran to completion. -
diff --git a/third_party/dawn b/third_party/dawn index 413dfc0..b5d8926 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 413dfc05c2ba4c5a5d8629b440b17ab9b3ed5c5d +Subproject commit b5d89266d090eb586b756294ea09e4beb0c06bcb
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index b4ea518..1202967 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit b4ea518eb65f83a0f5c4e8f9625b099ec18c07d8 +Subproject commit 120296784c3ee38e176618378479e2d63ab4deaf
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 8e6c915..4e11c88 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 8e6c915f32a6c98fe6968eace7a2a9a66589a892 +Subproject commit 4e11c8801f7a4e8e9f7b94f6acd4155cbe0a5e57
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock index d1baab6..ffe03e96 100644 --- a/third_party/rust/chromium_crates_io/Cargo.lock +++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -285,7 +285,7 @@ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "anyhow",
diff --git a/third_party/rust/chromium_crates_io/supply-chain/audits.toml b/third_party/rust/chromium_crates_io/supply-chain/audits.toml index 00b1259..e5f924c 100644 --- a/third_party/rust/chromium_crates_io/supply-chain/audits.toml +++ b/third_party/rust/chromium_crates_io/supply-chain/audits.toml
@@ -724,6 +724,11 @@ criteria = ["safe-to-run", "does-not-implement-crypto", "ub-risk-0"] version = "0.12.3" +[[audits.prost-derive]] +who = "Adrian Taylor <adetaylor@chromium.org>" +criteria = ["safe-to-run", "does-not-implement-crypto"] +delta = "0.12.3 -> 0.12.4" + [[audits.qr_code]] who = "Lukasz Anforowicz <lukasza@chromium.org>" criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-0"]
diff --git a/third_party/rust/chromium_crates_io/supply-chain/config.toml b/third_party/rust/chromium_crates_io/supply-chain/config.toml index db602ef4..cc831cf 100644 --- a/third_party/rust/chromium_crates_io/supply-chain/config.toml +++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -146,7 +146,7 @@ [policy."proc-macro2:1.0.80"] criteria = ["does-not-implement-crypto", "safe-to-deploy", "ub-risk-2"] -[policy."prost-derive:0.12.3"] +[policy."prost-derive:0.12.4"] criteria = ["does-not-implement-crypto", "safe-to-run"] [policy."prost:0.12.3"]
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/.cargo_vcs_info.json deleted file mode 100644 index 5e7c6b1b..0000000 --- a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/.cargo_vcs_info.json +++ /dev/null
@@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "907e9f6fbf72262f52333459bbfb27224da1ad72" - }, - "path_in_vcs": "prost-derive" -} \ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/.cargo-checksum.json similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/.cargo-checksum.json rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/.cargo-checksum.json
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/.cargo_vcs_info.json new file mode 100644 index 0000000..2f45cd3d88 --- /dev/null +++ b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/.cargo_vcs_info.json
@@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "38a00d89527728b6d50736d2ede49b5963abc2fd" + }, + "path_in_vcs": "prost-derive" +} \ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml similarity index 94% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml index 029894d..7e2db46 100644 --- a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml +++ b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml
@@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.60" +rust-version = "1.70" name = "prost-derive" -version = "0.12.3" +version = "0.12.4" authors = [ "Dan Burkert <dan@danburkert.com>", "Lucio Franco <luciofranco14@gmail.com>", @@ -32,7 +32,7 @@ version = "1.0.1" [dependencies.itertools] -version = ">=0.10, <0.12" +version = ">=0.10, <=0.12" features = ["use_alloc"] default-features = false
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml.orig similarity index 80% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml.orig rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml.orig index 45d5cb464..d4f7b8d2 100644 --- a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/Cargo.toml.orig +++ b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/Cargo.toml.orig
@@ -1,6 +1,6 @@ [package] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" authors = [ "Dan Burkert <dan@danburkert.com>", "Lucio Franco <luciofranco14@gmail.com>", @@ -12,14 +12,14 @@ readme = "README.md" description = "A Protocol Buffers implementation for the Rust Language." edition = "2021" -rust-version = "1.60" +rust-version = "1.70" [lib] proc_macro = true [dependencies] anyhow = "1.0.1" -itertools = { version = ">=0.10, <0.12", default-features = false, features = ["use_alloc"] } +itertools = { version = ">=0.10, <=0.12", default-features = false, features = ["use_alloc"] } proc-macro2 = "1" quote = "1" syn = { version = "2", features = [ "extra-traits" ] }
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/LICENSE b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/LICENSE similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/LICENSE rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/LICENSE
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/README.md b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/README.md similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/README.md rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/README.md
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/group.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/group.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/group.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/group.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/map.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/map.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/map.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/map.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/message.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/message.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/message.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/message.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/mod.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/mod.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/mod.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/mod.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/oneof.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/oneof.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/oneof.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/oneof.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/scalar.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/scalar.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/scalar.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/scalar.rs
diff --git a/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/lib.rs similarity index 100% rename from third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/lib.rs rename to third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/lib.rs
diff --git a/third_party/rust/prost_derive/v0_12/BUILD.gn b/third_party/rust/prost_derive/v0_12/BUILD.gn index 3425302..2ac54c8 100644 --- a/third_party/rust/prost_derive/v0_12/BUILD.gn +++ b/third_party/rust/prost_derive/v0_12/BUILD.gn
@@ -12,21 +12,21 @@ crate_name = "prost_derive" epoch = "0.12" crate_type = "proc-macro" - crate_root = "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/lib.rs" + crate_root = "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/lib.rs" sources = [ - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/group.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/map.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/message.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/mod.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/oneof.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/field/scalar.rs", - "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/src/lib.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/group.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/map.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/message.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/mod.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/oneof.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/field/scalar.rs", + "//third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/src/lib.rs", ] inputs = [] build_native_rust_unit_tests = false edition = "2021" - cargo_pkg_version = "0.12.3" + cargo_pkg_version = "0.12.4" cargo_pkg_authors = "Dan Burkert <dan@danburkert.com>, Lucio Franco <luciofranco14@gmail.com>, Tokio Contributors <team@tokio.rs>" cargo_pkg_name = "prost-derive" cargo_pkg_description =
diff --git a/third_party/rust/prost_derive/v0_12/README.chromium b/third_party/rust/prost_derive/v0_12/README.chromium index ec3c0869..16174f7 100644 --- a/third_party/rust/prost_derive/v0_12/README.chromium +++ b/third_party/rust/prost_derive/v0_12/README.chromium
@@ -1,9 +1,9 @@ Name: prost-derive URL: https://crates.io/crates/prost-derive Description: A Protocol Buffers implementation for the Rust Language. -Version: 0.12.3 +Version: 0.12.4 Security Critical: no Shipped: no License: Apache 2.0 -License File: //third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.3/LICENSE -Revision: 907e9f6fbf72262f52333459bbfb27224da1ad72 +License File: //third_party/rust/chromium_crates_io/vendor/prost-derive-0.12.4/LICENSE +Revision: 38a00d89527728b6d50736d2ede49b5963abc2fd
diff --git a/third_party/skia b/third_party/skia index b159229..50ac111 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit b159229f2174800f6655f7b7dbba01d7bd3d5d48 +Subproject commit 50ac1117f1597d57faf9ae5360ad95029c515f97
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 35d6b77..ea0fb51 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 35d6b77d10f523580acf18702b28efc2709bc1d2 +Subproject commit ea0fb515f594700d7fc4cbfff49268f596de4984
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src index 11efd3b..3f94329 160000 --- a/third_party/webgpu-cts/src +++ b/third_party/webgpu-cts/src
@@ -1 +1 @@ -Subproject commit 11efd3b4ad23b66ed7aa88e84193833dbe5a7150 +Subproject commit 3f94329188723ae92fc1bdefbcacd659fed2aa8b
diff --git a/third_party/webrtc b/third_party/webrtc index 181dbeb..d86c0cd 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 181dbebba43f9023754d1f4766e7e4a2516c53a4 +Subproject commit d86c0cdbde7261deefc5771f41a14186bac9fd09
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a4f4b64..4de9a414 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -18868,6 +18868,8 @@ <int value="-1035140982" label="ClientSideDetectionModelOnAndroid:enabled"/> <int value="-1034344165" label="V8NoTurbo:disabled"/> <int value="-1033738911" label="enable-mac-views-dialogs"/> + <int value="-1033128341" + label="CrOSLateBootCrasProcessorDedicatedThread:enabled"/> <int value="-1032884201" label="HeavyAdPrivacyMitigations:enabled"/> <int value="-1032545529" label="FileSystemAccessLockingScheme:disabled"/> <int value="-1032265414" label="AutocompleteExtendedSuggestions:disabled"/> @@ -22439,6 +22441,8 @@ <int value="565406673" label="EnableVirtualKeyboardMdUi:enabled"/> <int value="566031886" label="DIPS:disabled"/> <int value="567368307" label="enable-experimental-canvas-features"/> + <int value="567862349" + label="CrOSLateBootCrasProcessorDedicatedThread:disabled"/> <int value="569192576" label="UpstreamTrustedReportsFirmware:enabled"/> <int value="570445904" label="WGIGamepadTriggerRumble:disabled"/> <int value="570469494" label="LoginDetection:disabled"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml index 7b73808..d81ea7e3 100644 --- a/tools/metrics/histograms/metadata/accessibility/histograms.xml +++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -1237,7 +1237,7 @@ </histogram> <histogram name="Accessibility.ImageLabels.ModalDialogAccepted" - enum="BooleanAccepted" expires_after="2024-08-11"> + enum="BooleanAccepted" expires_after="2024-10-13"> <owner>katie@chromium.org</owner> <owner>dtseng@chromium.org</owner> <summary> @@ -1637,7 +1637,7 @@ </histogram> <histogram name="Accessibility.LiveTranslate.CharactersTranslated" - units="count" expires_after="2024-08-14"> + units="count" expires_after="2024-10-13"> <owner>evliu@google.com</owner> <owner>chrome-a11y-core@google.com</owner> <summary> @@ -1647,7 +1647,7 @@ </histogram> <histogram name="Accessibility.LiveTranslate.EnableFrom{Entrypoint}" - enum="BooleanEnabled" expires_after="2024-08-14"> + enum="BooleanEnabled" expires_after="2024-10-13"> <owner>evliu@google.com</owner> <owner>chrome-a11y-core@google.com</owner> <summary> @@ -1663,7 +1663,7 @@ </histogram> <histogram name="Accessibility.LiveTranslate.SourceLanguage" - enum="LocaleCodeISO639" expires_after="2024-08-14"> + enum="LocaleCodeISO639" expires_after="2024-10-13"> <owner>evliu@google.com</owner> <owner>chrome-a11y-core@google.com</owner> <summary> @@ -1673,7 +1673,7 @@ </histogram> <histogram name="Accessibility.LiveTranslate.TargetLanguage" - enum="LocaleCodeISO639" expires_after="2024-08-14"> + enum="LocaleCodeISO639" expires_after="2024-10-13"> <owner>evliu@google.com</owner> <owner>chrome-a11y-core@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index d4626a5..7f9f056 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1041,7 +1041,7 @@ </histogram> <histogram name="Android.DownloadManager.OpenSource.Audio" - enum="AndroidDownloadOpenSource" expires_after="2024-08-11"> + enum="AndroidDownloadOpenSource" expires_after="2024-10-13"> <owner>shaktisahu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -1110,7 +1110,7 @@ </histogram> <histogram name="Android.DownloadPage.OpenSource" - enum="AndroidDownloadOpenSource" expires_after="2024-08-11"> + enum="AndroidDownloadOpenSource" expires_after="2024-10-13"> <owner>qinmin@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -1884,7 +1884,7 @@ </histogram> <histogram name="Android.InputDevice.Keyboard.Active" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>aishwaryarj@google.com</owner> <owner>clank-large-form-factors@google.com</owner> <summary> @@ -1893,7 +1893,7 @@ </histogram> <histogram name="Android.InputDevice.Mouse.Active" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>aishwaryarj@google.com</owner> <owner>clank-large-form-factors@google.com</owner> <summary>Emitted when a mouse is connected or disconnected.</summary> @@ -2311,7 +2311,7 @@ </histogram> <histogram name="Android.MultiInstance.MaxWindowLimitExceeded" enum="Boolean" - expires_after="2024-06-15"> + expires_after="2024-10-13"> <owner>ranjithkagathi@google.com</owner> <owner>twellington@chromium.org</owner> <summary> @@ -2501,7 +2501,7 @@ </histogram> <histogram name="Android.Omnibox.InvalidMatch" enum="MatchResult" - expires_after="2024-08-14"> + expires_after="2024-10-13"> <owner>ender@chromium.org</owner> <owner>chrome-mobile-search@google.com</owner> <summary> @@ -2887,7 +2887,7 @@ </histogram> <histogram name="Android.Omnibox.UsedSuggestionFromCache" enum="Boolean" - expires_after="2024-08-14"> + expires_after="2024-10-13"> <owner>ender@chromium.org</owner> <owner>chrome-mobile-search@google.com</owner> <summary> @@ -3673,7 +3673,7 @@ </histogram> <histogram name="Android.RestoreTabsOnFRE.ResultActionFirstShow2" - enum="RestoreTabsOnFREResultAction" expires_after="2024-08-11"> + enum="RestoreTabsOnFREResultAction" expires_after="2024-10-13"> <owner>ckitagawa@chromium.org</owner> <owner>bjfong@google.com</owner> <owner>fredmello@chromium.org</owner> @@ -3684,7 +3684,7 @@ </histogram> <histogram name="Android.RestoreTabsOnFRE.ResultActionSecondShow2" - enum="RestoreTabsOnFREResultAction" expires_after="2024-08-11"> + enum="RestoreTabsOnFREResultAction" expires_after="2024-10-13"> <owner>ckitagawa@chromium.org</owner> <owner>bjfong@google.com</owner> <owner>fredmello@chromium.org</owner> @@ -4346,7 +4346,7 @@ </histogram> <histogram name="Android.TabSwitcher.SetupRecyclerView.Time" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>skavuluru@chromium.org</owner> <owner>twellington@chromium.org</owner> <owner>clank-large-form-factors@google.com</owner> @@ -4558,7 +4558,7 @@ </histogram> <histogram name="Android.WebContentsState.SavedStateVersion" units="version" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>ellyjones@chromium.org</owner> <owner>src/chrome/browser/tab/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 7faf9f7..2edc0498 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1684,7 +1684,7 @@ </histogram> <histogram name="Arc.OptInNetworkErrorAction" enum="ArcOptInNetworkErrorAction" - expires_after="2024-08-13"> + expires_after="2024-10-13"> <owner>mhasank@google.com</owner> <owner>arc-core@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 18fac77..ed59586 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -2520,7 +2520,7 @@ </histogram> <histogram name="Ash.Desks.DeskLifetime_{DeskIndex}" units="hr" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>afakhry@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -5710,7 +5710,7 @@ </histogram> <histogram name="Ash.Overview.Enter.PresentationTime" units="ms" - expires_after="2024-08-14"> + expires_after="2024-10-13"> <owner>sammiequon@chromium.org</owner> <owner>zxdan@chromium.org</owner> <owner>chromeos-wm-corexp@google.com</owner> @@ -5984,7 +5984,7 @@ </histogram> <histogram name="Ash.Personalization.App.Duration" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>pzliu@google.com</owner> <owner>assistive-eng@google.com</owner> <summary> @@ -5994,7 +5994,7 @@ </histogram> <histogram name="Ash.Personalization.DynamicColor.ColorScheme.Settled" - enum="PersonalizationDynamicColorColorScheme" expires_after="2024-08-11"> + enum="PersonalizationDynamicColorColorScheme" expires_after="2024-10-13"> <owner>ericamlee@chromium.org</owner> <owner>assistive-eng@google.com</owner> <summary> @@ -6014,7 +6014,7 @@ </histogram> <histogram name="Ash.Personalization.DynamicColor.StaticColor.Settled" - enum="PersonalizationDynamicColorStaticColor" expires_after="2024-08-11"> + enum="PersonalizationDynamicColorStaticColor" expires_after="2024-10-13"> <owner>ericamlee@chromium.org</owner> <owner>assistive-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index 12830c5..adfe215 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -4636,7 +4636,7 @@ <histogram name="Autofill.SharedStorageServerCardDataSetResult" enum="AutofillSharedStorageServerCardDataSetResult" - expires_after="2024-08-01"> + expires_after="2024-10-13"> <owner>nburris@google.com</owner> <owner>payments-autofill-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/background/histograms.xml b/tools/metrics/histograms/metadata/background/histograms.xml index 02a63dc5..2b29758 100644 --- a/tools/metrics/histograms/metadata/background/histograms.xml +++ b/tools/metrics/histograms/metadata/background/histograms.xml
@@ -186,7 +186,7 @@ </histogram> <histogram name="BackgroundSync.Registration.OneShot" - enum="BackgroundSyncStatus" expires_after="2024-06-30"> + enum="BackgroundSyncStatus" expires_after="2024-10-13"> <owner>nator@chromium.org</owner> <owner>rayankans@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index af0edd9..c7bd2ee 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -1350,7 +1350,7 @@ </histogram> <histogram name="Blink.FedCm.ClosedSheetType.Android" enum="FedCmSheetType" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>npm@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -1466,7 +1466,7 @@ </histogram> <histogram name="Blink.FedCm.IdpSigninStatus.ClosePopupWindowReason" - enum="FedCmClosePopupWindowReason" expires_after="2024-08-11"> + enum="FedCmClosePopupWindowReason" expires_after="2024-10-13"> <owner>tanzachary@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -1489,7 +1489,7 @@ </histogram> <histogram name="Blink.FedCm.IdpSigninStatus.MismatchDialogResult" - enum="FedCmMismatchDialogResult" expires_after="2024-08-11"> + enum="FedCmMismatchDialogResult" expires_after="2024-10-13"> <owner>tanzachary@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -1499,7 +1499,7 @@ </histogram> <histogram name="Blink.FedCm.IdpSigninStatus.PopupWindowResult" - enum="FedCmPopupWindowResult" expires_after="2024-08-11"> + enum="FedCmPopupWindowResult" expires_after="2024-10-13"> <owner>tanzachary@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -1509,7 +1509,7 @@ </histogram> <histogram name="Blink.FedCm.IdpSigninStatus.ShowPopupWindowResult" - enum="FedCmShowPopupWindowResult" expires_after="2024-08-11"> + enum="FedCmShowPopupWindowResult" expires_after="2024-10-13"> <owner>tanzachary@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -1826,7 +1826,7 @@ </histogram> <histogram name="Blink.FedCm.Timing.MismatchDialogShownDuration" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>tanzachary@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -2013,7 +2013,7 @@ </histogram> <histogram name="Blink.FencedFrame.CreationOrNavigationOutcome" - enum="FencedFrameCreationOutcome" expires_after="2024-08-08"> + enum="FencedFrameCreationOutcome" expires_after="2024-10-13"> <owner>shivanisha@chromium.org</owner> <owner>dom@chromium.org</owner> <owner>lbrady@google.com</owner> @@ -2025,7 +2025,7 @@ </histogram> <histogram name="Blink.FencedFrame.FailedSandboxLoadInTopLevelFrame" - enum="BooleanYesNo" expires_after="2024-08-08"> + enum="BooleanYesNo" expires_after="2024-10-13"> <owner>shivanisha@chromium.org</owner> <owner>dom@chromium.org</owner> <owner>lbrady@google.com</owner> @@ -2067,7 +2067,7 @@ </histogram> <histogram name="Blink.FencedFrame.MandatoryUnsandboxedFlagsSandboxed" - enum="WebSandboxFlags" expires_after="2024-08-08"> + enum="WebSandboxFlags" expires_after="2024-10-13"> <owner>shivanisha@chromium.org</owner> <owner>dom@chromium.org</owner> <owner>lbrady@google.com</owner> @@ -2103,7 +2103,7 @@ </histogram> <histogram name="Blink.FetchQueuedPreloadsTime.{FrameType}.{IsInitial}" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>cduvall@chromium.org</owner> <owner>jam@chromium.org</owner> <owner>chrome-loading@google.com</owner> @@ -3765,7 +3765,7 @@ </histogram> <histogram name="Blink.ScanAndPreloadTime.{FrameType}.{IsInitial}" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>cduvall@chromium.org</owner> <owner>jam@chromium.org</owner> <owner>chrome-loading@google.com</owner> @@ -4794,7 +4794,7 @@ </histogram> <histogram name="Blink.{CookieOperation}Time" units="ms" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>cduvall@chromium.org</owner> <owner>jam@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/bluetooth/histograms.xml b/tools/metrics/histograms/metadata/bluetooth/histograms.xml index 79bfeb4..f1185d02 100644 --- a/tools/metrics/histograms/metadata/bluetooth/histograms.xml +++ b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
@@ -53,7 +53,7 @@ </variants> <histogram name="Bluetooth.BlueZ.DBus.{MethodName}.Latency" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>jonmann@chromium.org</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary>Tracks the latency of the BlueZ {MethodName} DBus method.</summary> @@ -1417,7 +1417,7 @@ <histogram name="Bluetooth.ChromeOS.FastPair.SavedDevices.GetSavedDevices.Result" - enum="BooleanSuccess" expires_after="2024-08-04"> + enum="BooleanSuccess" expires_after="2024-10-13"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>brandosocarras@google.com</owner> @@ -1431,7 +1431,7 @@ </histogram> <histogram name="Bluetooth.ChromeOS.FastPair.SavedDevices.Remove.Result" - enum="BooleanSuccess" expires_after="2024-06-28"> + enum="BooleanSuccess" expires_after="2024-10-13"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>brandosocarras@google.com</owner> @@ -1445,7 +1445,7 @@ </histogram> <histogram name="Bluetooth.ChromeOS.FastPair.SavedDevices.TotalUxLoadTime" - units="ms" expires_after="2024-06-28"> + units="ms" expires_after="2024-10-13"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>brandosocarras@google.com</owner> @@ -1465,7 +1465,7 @@ </histogram> <histogram name="Bluetooth.ChromeOS.FastPair.SavedDevices.UiEvent" - enum="FastPairSavedDevicesUiEvent" expires_after="2024-06-28"> + enum="FastPairSavedDevicesUiEvent" expires_after="2024-10-13"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>brandosocarras@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/borealis/histograms.xml b/tools/metrics/histograms/metadata/borealis/histograms.xml index 8bbd151d..37b3fad6 100644 --- a/tools/metrics/histograms/metadata/borealis/histograms.xml +++ b/tools/metrics/histograms/metadata/borealis/histograms.xml
@@ -185,7 +185,7 @@ </histogram> <histogram name="Borealis.Install.OverallTime2" units="ms" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <improvement direction="LOWER_IS_BETTER"/> @@ -201,7 +201,7 @@ </histogram> <histogram name="Borealis.Install.Result" enum="BorealisInstallResult" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -253,7 +253,7 @@ </histogram> <histogram name="Borealis.Startup.NumAttempts" enum="BooleanAttempted" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Recording every attempt to start Borealis (via the UI).</summary> @@ -272,7 +272,7 @@ </histogram> <histogram name="Borealis.Startup.OverallTime2" units="ms" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <improvement direction="LOWER_IS_BETTER"/>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml index 67c79b4..4223a94 100644 --- a/tools/metrics/histograms/metadata/browser/histograms.xml +++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -62,7 +62,7 @@ </histogram> <histogram name="Browser.ChromeOS.HatsStatus" enum="HatsStatus" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>aalsum@chromium.org</owner> <owner>chromeos-data-eng@google.com</owner> <summary> @@ -762,7 +762,7 @@ </histogram> <histogram name="Browser.PaintPreview.TabService.DiskUsageAtStartup" units="KB" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>ckitagawa@chromium.org</owner> <owner>fredmello@chromium.org</owner> <summary> @@ -890,7 +890,7 @@ </histogram> <histogram name="Browser.Tabs.TotalIncompleteSwitchDuration3{TabSwitchingType}" - units="ms" expires_after="2024-08-04"> + units="ms" expires_after="2024-10-13"> <owner>fdoray@chromium.org</owner> <owner>jonross@chromium.org</owner> <owner>joenotcharles@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml index 139ad3e4..d79e809 100644 --- a/tools/metrics/histograms/metadata/chrome/histograms.xml +++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -124,7 +124,7 @@ </histogram> <histogram name="Chrome.KAnonymityService.TrustTokenGetter.Action" - enum="KAnonymityTrustTokenGetterAction" expires_after="M127"> + enum="KAnonymityTrustTokenGetterAction" expires_after="2024-10-13"> <owner>behamilton@google.com</owner> <owner>pauljensen@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml index 3d39ce04..d263e869 100644 --- a/tools/metrics/histograms/metadata/chromeos/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -2344,7 +2344,7 @@ </histogram> <histogram name="ChromeOS.Printing.TimeCostOfFailedFoomaticShell" - units="seconds" expires_after="2024-06-30"> + units="seconds" expires_after="2024-10-13"> <owner>pawliczek@chromium.org</owner> <owner>bmgordon@chromium.org</owner> <owner>project-bolton@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml index d2cd1631..c2dc00a 100644 --- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -779,7 +779,7 @@ </histogram> <histogram name="ChromeOS.Settings.SnapWindowSuggestions" enum="BooleanToggled" - expires_after="2024-08-08"> + expires_after="2024-10-13"> <owner>sophiewen@chromium.org</owner> <owner>michelefan@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml index 118b93cf..c634bae 100644 --- a/tools/metrics/histograms/metadata/commerce/histograms.xml +++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -532,7 +532,7 @@ </histogram> <histogram name="Commerce.PriceTracking.PriceInsightsSidePanel.{Action}" - enum="PriceInsightsPriceBucket" expires_after="2024-08-04"> + enum="PriceInsightsPriceBucket" expires_after="2024-10-13"> <owner>yuezhanggg@chromium.org</owner> <owner>zhiyuancai@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/companion/histograms.xml b/tools/metrics/histograms/metadata/companion/histograms.xml index 776503d..aabec2a 100644 --- a/tools/metrics/histograms/metadata/companion/histograms.xml +++ b/tools/metrics/histograms/metadata/companion/histograms.xml
@@ -160,7 +160,7 @@ </histogram> <histogram name="Companion.VisualQuery.Agent.DomImageCount" units="images" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>srna@google.com</owner> <owner>pstjuste@google.com</owner> <owner>src/chrome/browser/companion/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml index ac46ba7..17a8c8fe 100644 --- a/tools/metrics/histograms/metadata/compositing/histograms.xml +++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -969,7 +969,7 @@ </histogram> <histogram name="CompositorLatency.IpcThread.{LatencyType}" - units="microseconds" expires_after="2024-08-11"> + units="microseconds" expires_after="2024-10-13"> <owner>jonross@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml index 3967e55..6694a76 100644 --- a/tools/metrics/histograms/metadata/content/histograms.xml +++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -406,7 +406,7 @@ </histogram> <histogram name="ContentSettings.RegularProfile.DefaultBackgroundSyncSetting" - enum="ContentSetting" expires_after="2024-08-11"> + enum="ContentSetting" expires_after="2024-10-13"> <owner>tungnh@chromium.org</owner> <owner>src/components/permissions/PERMISSIONS_OWNERS</owner> <summary> @@ -650,7 +650,7 @@ <histogram name="ContentSettings.{RegularProfileFiltered}DefaultRequestDesktopSiteSetting" - enum="ContentSetting" expires_after="2024-08-11"> + enum="ContentSetting" expires_after="2024-10-13"> <owner>shuyng@google.com</owner> <owner>twellington@chromium.org</owner> <summary> @@ -824,7 +824,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ActivityLoggingEnabled" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>dewittj@chromium.org</owner> <owner>feed@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index 5bc2cd51..91df4f23 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -364,7 +364,7 @@ </histogram> <histogram name="CustomTabs.Minimized.MinimizeSuccess" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>sinansahin@google.com</owner> <owner>chrome-connective-tissue@google.com</owner> <summary> @@ -385,7 +385,7 @@ </histogram> <histogram name="CustomTabs.MinimizedEvents" enum="CustomTabsMinimizedEvents" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>katzz@google.com</owner> <owner>chrome-connective-tissue@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml index 6a6f0ed..dcee2d8 100644 --- a/tools/metrics/histograms/metadata/dev/histograms.xml +++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -39,7 +39,7 @@ </histogram> <histogram name="DevTools.AnimationPlaybackRateChanged" - enum="DevToolsAnimationPlaybackRateChanged" expires_after="2024-08-08"> + enum="DevToolsAnimationPlaybackRateChanged" expires_after="2024-10-13"> <owner>yangguo@chromium.org</owner> <owner>changhaohan@chromium.org</owner> <owner>ergunsh@chromium.org</owner> @@ -47,7 +47,7 @@ </histogram> <histogram name="DevTools.AnimationPointDragged" - enum="DevToolsAnimationPointDragged" expires_after="2024-08-08"> + enum="DevToolsAnimationPointDragged" expires_after="2024-10-13"> <owner>yangguo@chromium.org</owner> <owner>changhaohan@chromium.org</owner> <owner>ergunsh@chromium.org</owner> @@ -644,7 +644,7 @@ </summary> </histogram> -<histogram name="DevTools.TraceLoad" units="ms" expires_after="2024-08-12"> +<histogram name="DevTools.TraceLoad" units="ms" expires_after="2024-10-13"> <owner>paulirish@chromium.org</owner> <owner>jacktfranklin@chromium.org</owner> <owner>victorporof@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/disk/histograms.xml b/tools/metrics/histograms/metadata/disk/histograms.xml index 57d01f3..bf8b43e 100644 --- a/tools/metrics/histograms/metadata/disk/histograms.xml +++ b/tools/metrics/histograms/metadata/disk/histograms.xml
@@ -34,7 +34,7 @@ </histogram> <histogram name="DiskCache.0.TotalIOTimeRead" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>jam@chromium.org</owner> <owner>swarm-team@google.com</owner> <summary> @@ -45,7 +45,7 @@ </histogram> <histogram name="DiskCache.0.TotalIOTimeWrite" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>jam@chromium.org</owner> <owner>swarm-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml index 72f3828..68f1b9c96 100644 --- a/tools/metrics/histograms/metadata/enterprise/histograms.xml +++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -2401,7 +2401,7 @@ </histogram> <histogram name="Enterprise.ManagedScreensaver.Enabled" enum="BooleanEnabled" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>mpetrisor@chromium.org</owner> <owner>imprivata-eng@google.com</owner> <summary> @@ -3055,7 +3055,7 @@ </histogram> <histogram name="Enterprise.UserPolicy.Count" units="policies" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>vincb@google.com</owner> <owner>ftirelo@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml index 11d2a1f..184443e2 100644 --- a/tools/metrics/histograms/metadata/event/histograms.xml +++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -346,7 +346,7 @@ </histogram> <histogram name="Event.Latency.OS2.{EventType}" units="ms" - expires_after="2024-08-14"> + expires_after="2024-10-13"> <owner>flackr@chromium.org</owner> <owner>joenotcharles@google.com</owner> <owner>input-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index 37809d6..854cf8a 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -1734,7 +1734,7 @@ </histogram> <histogram name="Extensions.ExtensionReenabledRemotely" units="count" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>anunoy@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -3644,7 +3644,7 @@ </histogram> <histogram name="Extensions.ManifestVersion2Count.{ManifestLocation}" - units="number of extensions" expires_after="2024-08-14"> + units="number of extensions" expires_after="2024-10-13"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -3657,7 +3657,7 @@ </histogram> <histogram name="Extensions.ManifestVersion3Count.{ManifestLocation}" - units="number of extensions" expires_after="2024-08-14"> + units="number of extensions" expires_after="2024-10-13"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -3670,7 +3670,7 @@ </histogram> <histogram name="Extensions.ManifestVersionByLocation.{ManifestLocation}" - units="manifest version" expires_after="2024-08-14"> + units="manifest version" expires_after="2024-10-13"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml index 7cb3f1d..00022146 100644 --- a/tools/metrics/histograms/metadata/file/histograms.xml +++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -1526,7 +1526,7 @@ </histogram> <histogram name="FileBrowser.Recent.LoadFileSystemProvider" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml index 506620e..2216094 100644 --- a/tools/metrics/histograms/metadata/gpu/histograms.xml +++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -879,7 +879,7 @@ </histogram> <histogram name="Gpu.FenceHandle.CloneCountsPerSubmit" units="clones" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>petermcneeley@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -1188,7 +1188,7 @@ </histogram> <histogram name="GPU.PaintOpReader.DeserializationError" - enum="PaintOpDeserializationError" expires_after="2024-08-11"> + enum="PaintOpDeserializationError" expires_after="2024-10-13"> <owner>junov@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -1640,7 +1640,7 @@ </histogram> <histogram name="GPU.{GraphiteDawnOrWebGPU}.Support.{FeatureName}" - enum="Boolean" expires_after="2024-08-11"> + enum="Boolean" expires_after="2024-10-13"> <owner>enga@chromium.org</owner> <owner>mdb.webgpu-dev-team@google.com</owner> <summary> @@ -1715,7 +1715,7 @@ </histogram> <histogram name="Viz.BeginFrameSource.Accuracy.AverageDelta2" - units="microseconds" expires_after="2024-08-11"> + units="microseconds" expires_after="2024-10-13"> <owner>magchen@chromium.org</owner> <owner>ccameron@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> @@ -1845,7 +1845,7 @@ </histogram> <histogram name="Viz.FileDescriptorTracking.{FdStat}" units="units" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>petermcneeley@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml index 91a8e74..9a2d243 100644 --- a/tools/metrics/histograms/metadata/history/histograms.xml +++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -1452,7 +1452,7 @@ </histogram> <histogram name="History.DatabaseBasicMetricsTime" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>sophiechang@chromium.org</owner> <owner>tommycli@chromium.org</owner> <owner>treib@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index e7b74650..1a40866c 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -120,7 +120,7 @@ </variants> <histogram name="IOS.Allocator.ShimInstalled" enum="Boolean" - expires_after="2024-08-08"> + expires_after="2024-10-13"> <owner>rohitrao@chromium.org</owner> <owner>justincohen@chromium.org</owner> <summary> @@ -170,7 +170,7 @@ </histogram> <histogram name="IOS.BackgroundTimeBeforeColdStart" units="minutes" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>thegreenfrog@chromium.org</owner> <owner>bling-team@google.com</owner> <summary> @@ -2094,7 +2094,7 @@ <histogram name="IOS.Omnibox.Promo.SelectedPosition.{Context}.{OmniboxDeviceSwitcherResult}" - enum="OmniboxPromoSelectedPositions" expires_after="2024-08-11"> + enum="OmniboxPromoSelectedPositions" expires_after="2024-10-13"> <owner>christianxu@chromium.org</owner> <owner>bling-team@google.com</owner> <summary> @@ -2736,7 +2736,7 @@ </histogram> <histogram name="IOS.PushNotification.ChimeDeviceRegistration" - enum="BooleanSuccess" expires_after="2024-08-11"> + enum="BooleanSuccess" expires_after="2024-10-13"> <owner>ajuma@google.com</owner> <owner>danieltwhite@google.com</owner> <summary> @@ -2849,7 +2849,7 @@ <histogram name="IOS.PushNotification.NotificationSettingsAuthorizationStatus.ByProvider" enum="PushNotificationSettingsAuthorizationStatus" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>guiperez@google.com</owner> <owner>chrome-sherlock@google.com</owner> <summary> @@ -4255,7 +4255,7 @@ </histogram> <histogram name="IOS.WhatsNew.InstructionsShown" enum="WhatsNewType" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>cheickcisse@google.com</owner> <owner>bling-mony-pod@google.com</owner> <summary> @@ -4265,7 +4265,7 @@ </histogram> <histogram name="IOS.WhatsNew.ItemsClickedCount" units="count" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>cheickcisse@google.com</owner> <owner>bling-mony-pod@google.com</owner> <summary>The number of clicked What's New items per impression</summary>
diff --git a/tools/metrics/histograms/metadata/kiosk/histograms.xml b/tools/metrics/histograms/metadata/kiosk/histograms.xml index a689af0e..330e743 100644 --- a/tools/metrics/histograms/metadata/kiosk/histograms.xml +++ b/tools/metrics/histograms/metadata/kiosk/histograms.xml
@@ -162,7 +162,7 @@ </histogram> <histogram name="Kiosk.Extensions.InstallTimedOut" enum="BooleanYesNo" - expires_after="2024-08-01"> + expires_after="2024-10-13"> <owner>yixie@chromium.org</owner> <owner>chromeos-kiosk-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/login/histograms.xml b/tools/metrics/histograms/metadata/login/histograms.xml index 26d30b3..707dd56 100644 --- a/tools/metrics/histograms/metadata/login/histograms.xml +++ b/tools/metrics/histograms/metadata/login/histograms.xml
@@ -86,7 +86,7 @@ </histogram> <histogram name="Login.DevicePolicyState" enum="DevicePoliciesState" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>igorcov@chromium.org</owner> <owner>chromeos-commercial-remote-management@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/magic_stack/histograms.xml b/tools/metrics/histograms/metadata/magic_stack/histograms.xml index 85065b1..f360e1b 100644 --- a/tools/metrics/histograms/metadata/magic_stack/histograms.xml +++ b/tools/metrics/histograms/metadata/magic_stack/histograms.xml
@@ -52,7 +52,7 @@ </variants> <histogram name="MagicStack.Clank.Settings.{ToggleState}" enum="ModuleType" - expires_after="2024-06-20"> + expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary> @@ -131,7 +131,7 @@ <histogram name="MagicStack.Clank.{ModuleDelegateHost}.ContextMenu.RemoveModule." - enum="ModuleType" expires_after="2024-06-20"> + enum="ModuleType" expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary> @@ -277,7 +277,7 @@ <histogram name="MagicStack.Clank.{ModuleDelegateHost}.Module.FetchDataTimeoutType." - enum="ModuleType" expires_after="2024-06-20"> + enum="ModuleType" expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary> @@ -332,7 +332,7 @@ </histogram> <histogram name="MagicStack.Clank.{ModuleDelegateHost}.Module.TopImpression." - enum="ModuleType" expires_after="2024-06-20"> + enum="ModuleType" expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary> @@ -397,7 +397,7 @@ </histogram> <histogram name="MagicStack.Clank.{ModuleDelegateHost}.NotScrollable" - units="count" expires_after="2024-06-20"> + units="count" expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary> @@ -424,7 +424,7 @@ <histogram name="MagicStack.Clank.{ModuleDelegateHost}.Segmentation.FetchRankingResultsDurationMs" - units="ms" expires_after="2024-06-20"> + units="ms" expires_after="2024-10-13"> <owner>hanxi@chromium.org</owner> <owner>xinyiji@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 112e159..62f3df5 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -317,7 +317,7 @@ </histogram> <histogram name="Media.AImageReaderGLOwner.AcquireImageResult" - enum="MediaStatus" expires_after="2024-08-11"> + enum="MediaStatus" expires_after="2024-10-13"> <owner>vikassoni@chromium.org</owner> <owner>media-dev-uma@chromium.org</owner> <summary> @@ -5742,7 +5742,7 @@ </histogram> <histogram name="Media.VideoCapture.Device.SupportedPixelFormat" - enum="VideoPixelFormatUnion" expires_after="2024-08-11"> + enum="VideoPixelFormatUnion" expires_after="2024-10-13"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <owner>atadres@chromium.org</owner> @@ -5996,7 +5996,7 @@ </histogram> <histogram name="Media.VideoCapture.Win.Device.CaptureBeginTime.Interval" - units="ms" expires_after="2024-06-30"> + units="ms" expires_after="2024-10-13"> <owner>ilnik@google.com</owner> <owner>video-cmi-mpp@google.com</owner> <summary> @@ -6007,7 +6007,7 @@ </histogram> <histogram name="Media.VideoCapture.Win.Device.CaptureBeginTime.MFTimeOffset" - units="ms" expires_after="2024-06-30"> + units="ms" expires_after="2024-10-13"> <owner>ilnik@google.com</owner> <owner>video-cmi-mpp@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml index 934627e..d2051a5 100644 --- a/tools/metrics/histograms/metadata/memory/histograms.xml +++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -1633,7 +1633,7 @@ </histogram> <histogram name="Memory.ParkableString.DiskWriteTime.5min" units="ms" - expires_after="2024-06-30"> + expires_after="2024-10-13"> <owner>lizeb@chromium.org</owner> <owner>pasko@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml index 2870e77..9826bb5 100644 --- a/tools/metrics/histograms/metadata/mobile/histograms.xml +++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -91,7 +91,7 @@ </histogram> <histogram name="Mobile.ContextMenu.CopyImage" enum="ContextMenuIOSCopyImage" - expires_after="2024-03-10"> + expires_after="2025-03-10"> <owner>djean@chromium.org</owner> <owner>gambard@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml index 8be9e33..8efccca 100644 --- a/tools/metrics/histograms/metadata/navigation/histograms.xml +++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1040,7 +1040,7 @@ <histogram name="Navigation.MainFrame.NewNavigation.IgnoreRestore.IsHTTPOrHTTPS.{DurationFromTo}.Time2" - units="ms" expires_after="2024-08-04"> + units="ms" expires_after="2024-10-13"> <owner>chikamune@chromium.org</owner> <owner>yyanagisawa@chromium.org</owner> <owner>kouhei@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index b35c9b4..1a8b05c1 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -341,7 +341,7 @@ </histogram> <histogram name="HttpCache.AddTransactionToEntry" units="ms" - expires_after="2024-08-13"> + expires_after="2024-10-13"> <owner>bashi@chromium.org</owner> <owner>net-dev@chromium.org</owner> <summary> @@ -1579,7 +1579,7 @@ </histogram> <histogram name="Net.DNS.UpgradeConfig.DotUpgradeSucceeded" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>horo@chromium.org</owner> <owner>src/net/dns/OWNERS</owner> <summary> @@ -1603,7 +1603,7 @@ </histogram> <histogram name="Net.DNS.UpgradeConfig.Ineligible.DohSpecified" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>horo@chromium.org</owner> <owner>src/net/dns/OWNERS</owner> <summary> @@ -1624,7 +1624,7 @@ </histogram> <histogram name="Net.DNS.UpgradeConfig.InsecureUpgradeSucceeded" enum="Boolean" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>horo@chromium.org</owner> <owner>src/net/dns/OWNERS</owner> <summary> @@ -2234,7 +2234,7 @@ </histogram> <histogram name="Net.NetworkTransaction{HostType}.RetryReason" - enum="HttpNetworkTransactionRetryReason" expires_after="2024-07-07"> + enum="HttpNetworkTransactionRetryReason" expires_after="2024-10-13"> <owner>horo@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary>Log the reason when HttpNetworkTransaction retries.</summary> @@ -2291,7 +2291,7 @@ </histogram> <histogram name="Net.QuicActiveSessionCount.{GoingAwayReason}" units="sesions" - expires_after="2024-07-01"> + expires_after="2024-10-13"> <owner>nidhijaju@chromium.org</owner> <owner>blink-network-stack@google.com</owner> <summary> @@ -3747,7 +3747,7 @@ </histogram> <histogram name="Net.QuicSession.NumPingsSent" units="pings" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>renjietang@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -4682,7 +4682,7 @@ </histogram> <histogram name="Net.Reporting.HeaderType" enum="NetReportingHeaderType" - expires_after="2024-07-01"> + expires_after="2024-10-13"> <owner>rodneyding@google.com</owner> <owner>src/net/reporting/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml index 77744405..50abf91 100644 --- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -2023,7 +2023,7 @@ </histogram> <histogram name="NewTabPage.WallpaperSearch.SetRecentThemeProcessingLatency" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>tiborg@chromium.org</owner> <owner>rtatum@google.com</owner> <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml index eb67d2b..331fa5e9 100644 --- a/tools/metrics/histograms/metadata/omnibox/histograms.xml +++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1507,7 +1507,7 @@ </histogram> <histogram name="Omnibox.SearchEngineType{Population}" - enum="OmniboxSearchEngineType" expires_after="2024-08-08"> + enum="OmniboxSearchEngineType" expires_after="2024-10-13"> <owner>jdonnelly@chromium.org</owner> <owner>mpearson@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml index c02155e4..946ea72b 100644 --- a/tools/metrics/histograms/metadata/optimization/histograms.xml +++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -264,7 +264,7 @@ </variants> <histogram name="OptimizationGuide.AccessTokenHelper.Result" - enum="OptimizationGuideAccessTokenResult" expires_after="2024-08-11"> + enum="OptimizationGuideAccessTokenResult" expires_after="2024-10-13"> <owner>rajendrant@chromium.org</owner> <owner>sophiechang@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 096cfded..03831bc 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -1418,7 +1418,7 @@ </histogram> <histogram name="Ads.InterestGroup.ServerAuction.EndToEndTime" units="ms" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>behamilton@google.com</owner> <owner>pauljensen@chromium.org</owner> <owner>privacy-sandbox-dev@chromium.org</owner> @@ -1972,7 +1972,7 @@ <summary>Records whenever a Blimp tab toggles visibility.</summary> </histogram> -<histogram name="BlueZ.AdapterLost" units="seconds" expires_after="2024-08-11"> +<histogram name="BlueZ.AdapterLost" units="seconds" expires_after="2024-10-13"> <owner>mcchou@chromium.org</owner> <owner>chromeos-bt-platform-sw-core@google.com</owner> <summary> @@ -3518,7 +3518,7 @@ </histogram> <histogram name="Conversions.ExtraReportDelay2" units="ms" - expires_after="2024-07-14"> + expires_after="2024-10-13"> <owner>apaseltiner@chromium.org</owner> <owner>johnidel@chromium.org</owner> <owner>csharrison@chromium.org</owner> @@ -5114,7 +5114,7 @@ <histogram name="Eche.Connection.Result.FailureReason" enum="SecureChannelConnectionAttemptFailureReason" - expires_after="2024-07-10"> + expires_after="2024-10-13"> <owner>jonmann@chromium.org</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -5192,7 +5192,7 @@ </histogram> <histogram name="Eche.StreamEvent.ConnectionFail" enum="ConnectionFailReason" - expires_after="2024-07-10"> + expires_after="2024-10-13"> <owner>crisrael@google.com</owner> <owner>exo-core-eng@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> @@ -6094,7 +6094,7 @@ </histogram> <histogram name="FirstRun.LaunchSource" enum="FirstRunLaunchSource" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>jlebel@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary> @@ -6581,7 +6581,7 @@ </histogram> <histogram name="ImportantFile.FileReplaceRetryCount" units="attempt count" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>etienneb@chromium.org</owner> <owner>grt@chromium.org</owner> <summary> @@ -8944,7 +8944,7 @@ </histogram> <histogram name="PushMessaging.UnregistrationStatus" - enum="PushUnregistrationStatus" expires_after="2024-08-11"> + enum="PushUnregistrationStatus" expires_after="2024-10-13"> <owner>peter@chromium.org</owner> <owner>knollr@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml index 149c943..5c8a0a5c 100644 --- a/tools/metrics/histograms/metadata/page/histograms.xml +++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -381,7 +381,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.HeavyAds.DisallowedByBlocklist" - enum="BooleanBlocked" expires_after="2024-08-11"> + enum="BooleanBlocked" expires_after="2024-10-13"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> @@ -2706,7 +2706,7 @@ <histogram name="PageLoad.Internal.SoftNavigationFromStartInvalidTiming" enum="SoftNavigationFromStartInvalidTimingReasons" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>haoliuk@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml index 3b7cd770..ea9a9fe 100644 --- a/tools/metrics/histograms/metadata/password/histograms.xml +++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -245,7 +245,7 @@ </histogram> <histogram name="KeyboardAccessory.GenerationDialogChoice.{GenerationType}" - enum="GenerationDialogChoice" expires_after="2024-08-11"> + enum="GenerationDialogChoice" expires_after="2024-10-13"> <owner>ioanap@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -574,7 +574,7 @@ </histogram> <histogram name="PasswordManager.AccountStoreCredentialsAfterOptIn" - units="credentials" expires_after="2024-08-11"> + units="credentials" expires_after="2024-10-13"> <owner>treib@chromium.org</owner> <owner>mamir@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/performance_manager/histograms.xml b/tools/metrics/histograms/metadata/performance_manager/histograms.xml index a4111f1..fc5f16f 100644 --- a/tools/metrics/histograms/metadata/performance_manager/histograms.xml +++ b/tools/metrics/histograms/metadata/performance_manager/histograms.xml
@@ -347,7 +347,7 @@ </histogram> <histogram name="PerformanceManager.TabRevisitTracker.TimeToClose2" - units="seconds" expires_after="2024-08-09"> + units="seconds" expires_after="2024-10-13"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-catan@google.com</owner> <summary> @@ -357,7 +357,7 @@ </histogram> <histogram name="PerformanceManager.TabRevisitTracker.TimeToRevisit2" - units="seconds" expires_after="2024-08-09"> + units="seconds" expires_after="2024-10-13"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-catan@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml index 341c846..3857213 100644 --- a/tools/metrics/histograms/metadata/permissions/histograms.xml +++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -1307,7 +1307,7 @@ </histogram> <histogram name="SiteEngagementService.EngagementType" - enum="SiteEngagementServiceEngagementType" expires_after="2024-08-11"> + enum="SiteEngagementServiceEngagementType" expires_after="2024-10-13"> <owner>calamity@chromium.org</owner> <owner>dominickn@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml index 6853d42d..582d70e 100644 --- a/tools/metrics/histograms/metadata/platform/histograms.xml +++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -247,7 +247,7 @@ </histogram> <histogram name="Platform.DetachableBase.ActivePercent" units="%" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>fshao@chromium.org</owner> <owner>phoenixshen@chromium.org</owner> <owner>chromeos-kukui@google.com</owner> @@ -440,7 +440,7 @@ </histogram> <histogram name="Platform.DlcService.InstallResult" - enum="DlcService.InstallResult" expires_after="2024-09-01"> + enum="DlcService.InstallResult" expires_after="2025-02-01"> <owner>kimjae@chromium.org</owner> <owner>chromeos-core-services@google.com</owner> <summary> @@ -450,7 +450,7 @@ </histogram> <histogram name="Platform.DlcService.UninstallResult" - enum="DlcService.UninstallResult" expires_after="2024-04-28"> + enum="DlcService.UninstallResult" expires_after="2025-02-01"> <owner>kimjae@chromium.org</owner> <owner>chromeos-core-services@google.com</owner> <summary> @@ -818,7 +818,7 @@ <histogram name="Platform.Libhwsec.RetryAction.PinWeaverManager.{ReplayOperationType}{ReplayEntryType}" - enum="HwsecRetryActionEnum" expires_after="2024-08-11"> + enum="HwsecRetryActionEnum" expires_after="2024-10-13"> <owner>chensa@google.com</owner> <owner>cros-hwsec-userland-eng+uma@google.com</owner> <summary> @@ -1606,7 +1606,7 @@ </histogram> <histogram name="Platform.Segmentation.FeatureLevel" units="level number" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>gwendal@chromium.org</owner> <owner>iby@chromium.org</owner> <owner>chromeos-data-eng@google.com</owner> @@ -1618,7 +1618,7 @@ </histogram> <histogram name="Platform.Segmentation.ScopeLevel" - enum="FeatureManagementScopeLevel" expires_after="2024-08-09"> + enum="FeatureManagementScopeLevel" expires_after="2024-10-13"> <owner>gwendal@chromium.org</owner> <owner>iby@chromium.org</owner> <owner>chromeos-data-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml index ecbc2168..f28af8c 100644 --- a/tools/metrics/histograms/metadata/power/histograms.xml +++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -1620,7 +1620,7 @@ </histogram> <histogram name="Power.PowerButtonPressInTabletMode" - enum="PowerButtonPressType" expires_after="2024-08-11"> + enum="PowerButtonPressType" expires_after="2024-10-13"> <owner>minch@chromium.org</owner> <owner>xdai@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml index 1536bb2..416cc37 100644 --- a/tools/metrics/histograms/metadata/printing/histograms.xml +++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -145,7 +145,7 @@ </histogram> <histogram name="Printing.CUPS.IppAttributesSuccess" enum="BooleanSuccess" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>bmgordon@chromium.org</owner> <owner>cros-printing-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/privacy/histograms.xml b/tools/metrics/histograms/metadata/privacy/histograms.xml index 38037d3..11e2c53e 100644 --- a/tools/metrics/histograms/metadata/privacy/histograms.xml +++ b/tools/metrics/histograms/metadata/privacy/histograms.xml
@@ -646,7 +646,7 @@ </histogram> <histogram name="PrivacySandbox.AggregationService.Storage.Sql.CreationTime2" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>alexmt@chromium.org</owner> <owner>linnan@chromium.org</owner> <summary> @@ -658,7 +658,7 @@ </histogram> <histogram name="PrivacySandbox.AggregationService.Storage.Sql.Error" - enum="SqliteLoggedResultCode" expires_after="2024-08-11"> + enum="SqliteLoggedResultCode" expires_after="2024-10-13"> <owner>dmcardle@chromium.org</owner> <owner>apaseltiner@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml index 658ea06..dc61c79 100644 --- a/tools/metrics/histograms/metadata/profile/histograms.xml +++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -209,7 +209,7 @@ </histogram> <histogram name="Profile.Incognito.MovedToBackgroundAfterDuration" - units="minutes" expires_after="2024-08-11"> + units="minutes" expires_after="2024-10-13"> <owner>arabm@google.com</owner> <owner>chrome-incognito@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/readaloud/histograms.xml b/tools/metrics/histograms/metadata/readaloud/histograms.xml index fecd2ab..6bf89d2 100644 --- a/tools/metrics/histograms/metadata/readaloud/histograms.xml +++ b/tools/metrics/histograms/metadata/readaloud/histograms.xml
@@ -100,7 +100,7 @@ </histogram> <histogram name="ReadAloud.HighlightingEnabled" enum="BooleanEnabled" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>andreaxg@google.com</owner> <owner>basiaz@google.com</owner> <owner>iwells@chromium.org</owner> @@ -242,7 +242,7 @@ </histogram> <histogram name="ReadAloud.SpeedChange" enum="ReadAloudSpeed" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>andreaxg@google.com</owner> <owner>basiaz@google.com</owner> <owner>iwells@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml index f42fbc47..c7489ef 100644 --- a/tools/metrics/histograms/metadata/renderer/histograms.xml +++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -470,7 +470,7 @@ </histogram> <histogram name="Renderer.PaintPreview.Capture.MainFrameBlinkCaptureDuration" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>ckitagawa@chromium.org</owner> <owner>fredmello@chromium.org</owner> <owner>chrome-fdt@google.com</owner> @@ -526,7 +526,7 @@ </histogram> <histogram name="Renderer.Preload.UnusedResource" enum="BooleanSuccess" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>iclelland@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index b48f96f..62bee6d 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -254,7 +254,7 @@ </histogram> <histogram name="SafeBrowsing.BrowserThrottle.CheckerOnIOLifetime" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>thefrog@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -579,7 +579,7 @@ </histogram> <histogram name="SafeBrowsing.ClientSidePhishingDetection.AllowlistMatchResult" - enum="SafeBrowsingAllowlistAsyncMatch" expires_after="2024-08-11"> + enum="SafeBrowsingAllowlistAsyncMatch" expires_after="2024-10-13"> <owner>thefrog@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -2086,7 +2086,7 @@ </histogram> <histogram name="SafeBrowsing.RT.AllowlistSizeTooSmall" - enum="BooleanUnavailable" expires_after="2024-08-11"> + enum="BooleanUnavailable" expires_after="2024-10-13"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -2451,7 +2451,7 @@ </histogram> <histogram name="SafeBrowsing.RT.Response.VerdictType.{UserPopulation}" - enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2024-08-11"> + enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2024-10-13"> <owner>zackhan@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -3029,7 +3029,7 @@ </histogram> <histogram name="SafeBrowsing.V4ProcessPartialUpdate.RemovalsHashesCount" - units="entries" expires_after="2024-08-11"> + units="entries" expires_after="2024-10-13"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index 63d847f..3139ee3 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -266,7 +266,7 @@ </histogram> <histogram name="SBClientDownload.FileAnalysisDuration{Analysis}" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -418,7 +418,7 @@ <histogram name="SBClientDownload.Warning.DownloadIsHttps.{DangerType}.{Action}" - enum="BooleanHttps" expires_after="2024-08-11"> + enum="BooleanHttps" expires_after="2024-10-13"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -695,7 +695,7 @@ </histogram> <histogram name="SBClientPhishing.ModelDynamicUpdateSuccess" - enum="BooleanSuccess" expires_after="2024-08-11"> + enum="BooleanSuccess" expires_after="2024-10-13"> <owner>andysjlim@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml index 96682bd..4cebc916 100644 --- a/tools/metrics/histograms/metadata/search/histograms.xml +++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -218,7 +218,7 @@ </histogram> <histogram name="Search.ChoiceScreenSelectedEngineIndex" units="index" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>dgn@chromium.org</owner> <owner>chrome-waffle-eng@google.com</owner> <summary> @@ -241,7 +241,7 @@ </histogram> <histogram name="Search.ChoiceScreenShowedEngineAt.Index{Index}" - enum="OmniboxSearchEngineType" expires_after="2024-08-04"> + enum="OmniboxSearchEngineType" expires_after="2024-10-13"> <owner>dgn@chromium.org</owner> <owner>chrome-waffle-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml index 05dee347..6cb41ef1 100644 --- a/tools/metrics/histograms/metadata/settings/histograms.xml +++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -53,7 +53,7 @@ </variants> <histogram name="Settings.AdvancedSpellcheck.OnStartup2" enum="BooleanEnabled" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>harrisonsean@chromium.org</owner> <owner>chrome-privacy-controls@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index eacfd355..04803d8d 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -42,7 +42,7 @@ <histogram name="Signin.AccountCapabilities.GetFromSystemLibraryDuration{Caller}" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>fernandex@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>triploblastic@chromium.org</owner> @@ -118,7 +118,7 @@ </histogram> <histogram name="Signin.AccountCapabilities.{Priority}.FetchDuration.{Result}" - units="ms" expires_after="2024-08-11"> + units="ms" expires_after="2024-10-13"> <owner>alexilin@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> @@ -143,7 +143,7 @@ </histogram> <histogram name="Signin.AccountCapabilities.{Priority}.FetchResult" - enum="AccountCapabilitiesFetchResult" expires_after="2024-08-11"> + enum="AccountCapabilitiesFetchResult" expires_after="2024-10-13"> <owner>alexilin@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> @@ -324,7 +324,7 @@ <histogram name="Signin.AccountTracker.RefreshAccountInfo.IsAlreadyTrackingAccount" - enum="Boolean" expires_after="2024-08-11"> + enum="Boolean" expires_after="2024-10-13"> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary> @@ -532,7 +532,7 @@ <histogram name="Signin.BoundSessionCredentials.Covered{Type}RequestWasDeferred" - enum="BooleanWasDeferred" expires_after="2024-08-11"> + enum="BooleanWasDeferred" expires_after="2024-10-13"> <owner>alexilin@chromium.org</owner> <owner>msalama@chromium.org</owner> <owner>chrome-signin-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml index fd8c2464..cf42a03 100644 --- a/tools/metrics/histograms/metadata/stability/histograms.xml +++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -192,7 +192,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.ShownAfterCrashingReason" - enum="ShownAfterCrashingReason" expires_after="2024-08-09"> + enum="ShownAfterCrashingReason" expires_after="2024-10-13"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <owner>lukasza@chromium.org</owner> @@ -204,7 +204,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload" - enum="BooleanMarkedForReload" expires_after="2024-08-09"> + enum="BooleanMarkedForReload" expires_after="2024-10-13"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary> @@ -214,7 +214,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload.Visibility" - enum="FrameVisibility" expires_after="2024-08-09"> + enum="FrameVisibility" expires_after="2024-10-13"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary> @@ -225,7 +225,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.Visibility" enum="CrashVisibility" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <owner>lukasza@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/storage/histograms.xml b/tools/metrics/histograms/metadata/storage/histograms.xml index e8af214..1b8410b 100644 --- a/tools/metrics/histograms/metadata/storage/histograms.xml +++ b/tools/metrics/histograms/metadata/storage/histograms.xml
@@ -945,7 +945,7 @@ </histogram> <histogram name="Storage.SharedStorage.Document.Timing.Append" units="ms" - expires_after="2024-07-31"> + expires_after="2024-10-13"> <owner>cammie@chromium.org</owner> <owner>yaoxia@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> @@ -1249,7 +1249,7 @@ </histogram> <histogram name="Storage.SharedStorage.Worklet.Timing.Delete" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>cammie@chromium.org</owner> <owner>yaoxia@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index b9e40a4d..47afeba 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -373,7 +373,7 @@ </histogram> <histogram name="Sync.ConfigureTime_{ConfigurationType}.{Result}" units="ms" - expires_after="2024-08-09"> + expires_after="2024-10-13"> <owner>victorvianna@google.com</owner> <component>Services>Sync</component> <summary> @@ -780,7 +780,7 @@ </histogram> <histogram name="Sync.InvalidBookmarkSpecifics" - enum="InvalidBookmarkSpecificsError" expires_after="2024-06-23"> + enum="InvalidBookmarkSpecificsError" expires_after="2024-10-13"> <owner>mastiz@chromium.org</owner> <owner>rushans@google.com</owner> <component>Services>Sync</component> @@ -1429,7 +1429,7 @@ </histogram> <histogram name="Sync.SharingMessage.CommitResult" - enum="SyncSharingMessageCommitErrorCode" expires_after="2024-08-04"> + enum="SyncSharingMessageCommitErrorCode" expires_after="2024-10-13"> <owner>rushans@google.com</owner> <owner>treib@chromium.org</owner> <component>Services>Sync</component> @@ -1955,7 +1955,7 @@ </histogram> <histogram name="Sync.TrustedVaultJavascriptAddRecoveryMethodIsIncognito" - enum="BooleanIncognito" expires_after="2024-06-30"> + enum="BooleanIncognito" expires_after="2024-10-13"> <owner>mmoskvitin@google.com</owner> <owner>mastiz@chromium.org</owner> <component>Services>Sync</component>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index ed9f31b..7d086a5 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -421,7 +421,7 @@ </histogram> <histogram name="Tab.PerceivedRestoreTime" units="ms" - expires_after="2024-08-04"> + expires_after="2024-10-13"> <owner>ckitagawa@chromium.org</owner> <owner>dtrainor@chromium.org</owner> <owner>yfriedman@chromium.org</owner> @@ -547,7 +547,7 @@ </histogram> <histogram name="Tab.SwitchedToForegroundAge" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>dtrainor@chromium.org</owner> <owner>ckitagawa@chroimum.org</owner> <summary> @@ -2270,7 +2270,7 @@ </summary> </histogram> -<histogram name="Tabs.TabState.LoadTime" units="ms" expires_after="2024-06-30"> +<histogram name="Tabs.TabState.LoadTime" units="ms" expires_after="2024-10-13"> <owner>yusufo@chromium.org</owner> <owner>nyquist@chromium.org</owner> <owner>dtrainor@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml index 6ebdc5a..83d08fd 100644 --- a/tools/metrics/histograms/metadata/uma/histograms.xml +++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -954,7 +954,7 @@ </histogram> <histogram name="UMA.TruncatedEvents.UserAction" units="events" - expires_after="2024-10-06"> + expires_after="2024-10-13"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/update_engine/histograms.xml b/tools/metrics/histograms/metadata/update_engine/histograms.xml index b35ab5f..8b142aaa 100644 --- a/tools/metrics/histograms/metadata/update_engine/histograms.xml +++ b/tools/metrics/histograms/metadata/update_engine/histograms.xml
@@ -319,7 +319,7 @@ </histogram> <histogram name="UpdateEngine.Check.TargetVersion" - enum="UpdateEngineChromeOsVersionPrefix" expires_after="2024-08-11"> + enum="UpdateEngineChromeOsVersionPrefix" expires_after="2024-10-13"> <owner>mpolzer@google.com</owner> <owner>chromeos-commercial-remote-management@google.com</owner> <summary> @@ -503,7 +503,7 @@ </histogram> <histogram name="UpdateEngine.InstallDateProvisioningSource" - enum="UpdateEngineInstallDateProvisioningSource" expires_after="2024-08-11"> + enum="UpdateEngineInstallDateProvisioningSource" expires_after="2024-10-13"> <owner>kimjae@chromium.org</owner> <owner>chromeos-core-services@google.com</owner> <summary> @@ -704,7 +704,7 @@ </histogram> <histogram name="UpdateEngine.SuccessfulUpdate.RebootCount" units="count" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>kimjae@chromium.org</owner> <owner>chromeos-core-services@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml index 3b0993d1..782095d 100644 --- a/tools/metrics/histograms/metadata/v8/histograms.xml +++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -1183,16 +1183,6 @@ <summary>Reason a mark-compact garbage collection was started in V8.</summary> </histogram> -<histogram name="V8.GCMarkingSum" units="ms" expires_after="2024-04-28"> - <owner>mlippautz@chromium.org</owner> - <owner>v8-memory-sheriffs@google.com</owner> - <summary> - Sum of all durations of all marking phases (incremental and non-incremental) - within one V8 garbage collection cycle. Reported once per garbage collection - at the end. - </summary> -</histogram> - <histogram name="V8.LiftoffBailoutReasons" enum="LiftoffBailoutReason" expires_after="2024-09-15"> <owner>ecmziegler@chromium.org</owner> @@ -1217,7 +1207,7 @@ </histogram> <histogram name="V8.LocalWindowProxy.InitializeTime" units="ms" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>nidhijaju@chromium.org</owner> <owner>chrome-loading@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/web_core/histograms.xml b/tools/metrics/histograms/metadata/web_core/histograms.xml index 5866c68..7c8f0eee 100644 --- a/tools/metrics/histograms/metadata/web_core/histograms.xml +++ b/tools/metrics/histograms/metadata/web_core/histograms.xml
@@ -113,7 +113,7 @@ </histogram> <histogram name="WebCore.Fullscreen.LockStateAtEntryViaApi" - enum="FullscreenLockState" expires_after="2024-08-11"> + enum="FullscreenLockState" expires_after="2024-10-13"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -126,7 +126,7 @@ </histogram> <histogram name="WebCore.Fullscreen.LockStateAtEntryViaBrowserUi" - enum="FullscreenLockState" expires_after="2024-08-11"> + enum="FullscreenLockState" expires_after="2024-10-13"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml index 9c82aaf..5a78016 100644 --- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml +++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -1460,7 +1460,7 @@ </histogram> <histogram name="WebRTC.PeerConnection.ThermalState" enum="ThermalState" - expires_after="2024-08-11"> + expires_after="2024-10-13"> <owner>eshr@google.com</owner> <owner>hbos@chromium.org</owner> <summary> @@ -1667,7 +1667,7 @@ </histogram> <histogram name="WebRTC.Stun.Integrity.{StunPacketType}" - enum="WebRtcStunIntegrityOutcome" expires_after="2024-08-11"> + enum="WebRtcStunIntegrityOutcome" expires_after="2024-10-13"> <owner>hta@chromium.org</owner> <owner>webrtc-dev@chromium.org</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 d63c801..6e176e29 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/v44.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "6a2bbb73d020b83fc7b916f5645f171328348087", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/3f2b2b6385d24f80239a7c49d464a06292fbd078/trace_processor_shell.exe" + "hash": "b14b8bb20644ed79958bed962481c7ef43430db6", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/6191dd39ee994efe60df79204ebd311f32470a52/trace_processor_shell.exe" }, "linux_arm": { "hash": "d8e27d961be1db97db098c6826017aec0397ecfd", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v44.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "9116d187b986a165ff18eced9c43d1df8b4f22d2", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/3f2b2b6385d24f80239a7c49d464a06292fbd078/trace_processor_shell" + "hash": "250c949ae64d5b57131f7536618ae8f39812840e", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6191dd39ee994efe60df79204ebd311f32470a52/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/web_dev_style/js_checker.py b/tools/web_dev_style/js_checker.py index 86d34a27..1bda403 100644 --- a/tools/web_dev_style/js_checker.py +++ b/tools/web_dev_style/js_checker.py
@@ -38,10 +38,6 @@ ' // <if expr="chromeos">\n' + " // </if>\n") - def DebuggerCheck(self, i, line): - return self.RegexCheck(i, line, r"^\s*(debugger);", - "Debugger statements should be removed") - def EndJsDocCommentCheck(self, i, line): msg = "End JSDoc comments with */ instead of **/" def _check(regex): @@ -139,7 +135,6 @@ self.BindThisCheck(i, line), self.ChromeSendCheck(i, line), self.CommentIfAndIncludeCheck(i, line), - self.DebuggerCheck(i, line), self.EndJsDocCommentCheck(i, line), self.ExtraDotInGenericCheck(i, line), self.InheritDocCheck(i, line),
diff --git a/tools/web_dev_style/js_checker_test.py b/tools/web_dev_style/js_checker_test.py index 8941958d..2692ffe 100755 --- a/tools/web_dev_style/js_checker_test.py +++ b/tools/web_dev_style/js_checker_test.py
@@ -25,36 +25,6 @@ self.checker = js_checker.JSChecker(MockInputApi(), MockOutputApi()) - def ShouldFailDebuggerCheck(self, line): - error = self.checker.DebuggerCheck(1, line) - self.assertNotEqual("", error, "Should be flagged as style error: " + line) - highlight = test_util.GetHighlight(line, error).strip() - self.assertTrue(highlight.startswith("debugger")) - - def ShouldPassDebuggerCheck(self, line): - self.assertEqual("", self.checker.DebuggerCheck(1, line), - "Should not be flagged as style error: " + line) - - def testDebuggerFails(self): - lines = [ - "debugger;", - " debugger;", - ] - for line in lines: - self.ShouldFailDebuggerCheck(line) - - def testDebuggerPasses(self): - lines = [ - "// Test that it works in the debugger", - " // Test that it works in the debugger", - "debugger.debug(func);", - " debugger.debug(func);", - "console.log('debugger enabled');", - " console.log('debugger enabled');", - ] - for line in lines: - self.ShouldPassDebuggerCheck(line) - def ShouldFailBindThisCheck(self, line): error = self.checker.BindThisCheck(1, line) self.assertNotEqual("", error, "Should be flagged as style error: " + line)
diff --git a/ui/aura/test/test_screen.cc b/ui/aura/test/test_screen.cc index bad1abcb..bfb05ec2 100644 --- a/ui/aura/test/test_screen.cc +++ b/ui/aura/test/test_screen.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include "base/check_op.h" +#include "base/containers/adapters.h" #include "build/build_config.h" #include "ui/aura/env.h" #include "ui/aura/window.h" @@ -148,10 +149,37 @@ return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window; } +gfx::NativeWindow TestScreen::GetWindowForPoint(Window* window, + const gfx::Point& local_point) { + DCHECK(window); + if (!window->IsVisible()) { + return nullptr; + } + + if (!window->HitTest(local_point)) { + return nullptr; + } + + for (Window* child : base::Reversed(window->children())) { + gfx::Point point_in_child_coords(local_point); + Window::ConvertPointToTarget(window, child, &point_in_child_coords); + Window* match = GetWindowForPoint(child, point_in_child_coords); + if (match) { + return match; + } + } + return window; +} + gfx::NativeWindow TestScreen::GetWindowAtScreenPoint(const gfx::Point& point) { if (!host_ || !host_->window()) return nullptr; - return host_->window()->GetEventHandlerForPoint(point); + + // GetWindowAtScreenPoint() is designed to return a visible window that + // contains the given point within its bounds. Using GetEventHandlerForPoint() + // can lead to null returns for windows that don't have an event handler, such + // as content_window_ in DesktopNativeWidgetAura. + return GetWindowForPoint(host_->window(), point); } gfx::NativeWindow TestScreen::GetLocalProcessWindowAtPoint(
diff --git a/ui/aura/test/test_screen.h b/ui/aura/test/test_screen.h index 74082eb..9c43d37 100644 --- a/ui/aura/test/test_screen.h +++ b/ui/aura/test/test_screen.h
@@ -45,6 +45,8 @@ void SetWorkAreaInsets(const gfx::Insets& insets); protected: + static gfx::NativeWindow GetWindowForPoint(Window* window, + const gfx::Point& local_point); gfx::Transform GetRotationTransform() const; gfx::Transform GetUIScaleTransform() const;
diff --git a/ui/aura/window.h b/ui/aura/window.h index fd8e7a5..dbcdfd34 100644 --- a/ui/aura/window.h +++ b/ui/aura/window.h
@@ -577,6 +577,7 @@ friend class ScopedWindowEventTargetingBlocker; friend class WindowTargeter; friend class test::WindowTestApi; + friend class TestScreen; // Handles registering FrameSinkId hierarchy for SetEmbedFrameSinkId() and // CreateLayerTreeFrameSink().
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index ab5f160..17ece5e 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc
@@ -144,7 +144,7 @@ void WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) { // Send entered / exited so that visual state can be updated to match // mouse events state. - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window()); // TODO(mazda): Add code to disable mouse events when |enabled| == false. } @@ -233,7 +233,7 @@ if (pending_synthesize_mouse_move) { // Schedule a synthesized mouse move event when there is no held mouse // move and we should generate one. - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window()); } } } @@ -259,7 +259,7 @@ // Synthesize a mouse move in case the cursor's location in root coordinates // changed but its position in WindowTreeHost coordinates did not. - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window()); } void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) { @@ -699,7 +699,7 @@ return; if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window); // Hiding the window releases capture which can implicitly destroy the window // so the window may no longer be valid after this call. @@ -738,7 +738,7 @@ new_bounds_in_root.Contains(last_mouse_location)) || (new_bounds_in_root.Contains(last_mouse_location) && new_bounds_in_root.origin() != old_bounds_in_root.origin())) { - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window); } } } @@ -829,7 +829,7 @@ return dispatch_details; } -void WindowEventDispatcher::PostSynthesizeMouseMove() { +void WindowEventDispatcher::PostSynthesizeMouseMove(Window* window) { // No one should care where the real mouse is when this flag is on. So there // is no need to send a synthetic mouse move here. if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents()) @@ -837,6 +837,26 @@ if (synthesize_mouse_move_ || in_shutdown_) return; + +#if BUILDFLAG(IS_WIN) + // Gets the window at the current cursor point. + gfx::Point cursor_point = + display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::NativeWindow window_under_cursor = + display::Screen::GetScreen()->GetWindowAtScreenPoint(cursor_point); + + ConvertPointFromScreen(&cursor_point); + // If the mouse cursor is within the |window|, but |window_under_cursor| is + // null, it means another program's window is occluding ours. And also, if + // |window_under_cursor| doesn't belong to ours then we do not synthesize a + // mouse move event. + if (window->ContainsPointInRoot(cursor_point) && + (!window_under_cursor || + !host_->window()->Contains(window_under_cursor))) { + return; + } +#endif + synthesize_mouse_move_ = true; base::SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask( FROM_HERE, @@ -851,7 +871,7 @@ return; if (window->IsVisible() && window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { - PostSynthesizeMouseMove(); + PostSynthesizeMouseMove(window); } }
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h index e49ca608..98c88c4 100644 --- a/ui/aura/window_event_dispatcher.h +++ b/ui/aura/window_event_dispatcher.h
@@ -269,7 +269,7 @@ // Posts a task to send synthesized mouse move event if there is no a pending // task. - void PostSynthesizeMouseMove(); + void PostSynthesizeMouseMove(Window* window); // Creates and dispatches synthesized mouse move event using the current mouse // location.
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc index d70f84f1..c7649b7 100644 --- a/ui/aura/window_tree_host_platform.cc +++ b/ui/aura/window_tree_host_platform.cc
@@ -354,6 +354,18 @@ int64_t WindowTreeHostPlatform::OnStateUpdate( const PlatformWindowDelegate::State& old, const PlatformWindowDelegate::State& latest) { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + // Notify the fullscreen type change before the window state change to reflect + // the immersive status at OnWindowStateChanged. + if (old.fullscreen_type != latest.fullscreen_type) { + OnFullscreenTypeChanged(old.fullscreen_type, latest.fullscreen_type); + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + + if (old.window_state != latest.window_state) { + OnWindowStateChanged(old.window_state, latest.window_state); + } + if (old.bounds_dip != latest.bounds_dip || old.size_px != latest.size_px || old.window_scale != latest.window_scale) { bool origin_changed = old.bounds_dip.origin() != latest.bounds_dip.origin(); @@ -364,7 +376,7 @@ compositor()->SetExternalPageScaleFactor(latest.raster_scale); } - bool needs_frame = latest.ProducesFrameOnUpdateFrom(old); + bool needs_frame = latest.WillProduceFrameOnUpdateFrom(old); if (old.occlusion_state != latest.occlusion_state && NativeWindowOcclusionTracker:: IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.ts b/ui/file_manager/integration_tests/file_manager/file_display.ts index a7e8a14e..f6a10b3 100644 --- a/ui/file_manager/integration_tests/file_manager/file_display.ts +++ b/ui/file_manager/integration_tests/file_manager/file_display.ts
@@ -972,3 +972,63 @@ // Check: the toolbar read-only indicator should not be visible. await remoteCall.waitForElement(appId, '#read-only-indicator[hidden]'); } + +/** + * Tests that when local files are disabled, we navigate to default set by the + * policy, e.g. Drive after unmounting a USB. + */ +export async function fileDisplayLocalFilesDisabledUnmountRemovable() { + // Mount Drive and Downloads. + await sendTestMessage({name: 'mountDrive'}); + await sendTestMessage({name: 'mountDownloads'}); + // Ensure two volumes are mounted. + await remoteCall.waitForVolumesCount(2); + + // Enable SkyVault, this should unmount Downloads. + await sendTestMessage({name: 'setupSkyVault'}); + await remoteCall.waitForVolumesCount(1); + + // Open Files app without specifying the initial directory/root. + const appId = await remoteCall.openNewWindow(null, null); + chrome.test.assertTrue(!!appId, 'failed to open new window'); + + // Confirm that the Files App opened in Google Drive, as set by the policy. + await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/My Drive'); + + // Mount USB volume in the Downloads window. + await sendTestMessage({name: 'mountFakeUsb'}); + + // Wait for the USB mount and click to open the USB volume. + const directoryTree = await DirectoryTreePageObject.create(appId); + await directoryTree.selectItemByType('removable'); + await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/fake-usb'); + + // Unmount the USB. + await sendTestMessage({name: 'unmountUsb'}); + + // We should navigate to My Drive. + await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/My Drive'); +} + +/** + * Tests that disabling local storage while in a local folder navigates away to + * the default set by the policy, e.g. Drive. + */ +export async function fileDisplayLocalFilesDisableInMyFiles() { + // Mount Drive and Downloads. + await sendTestMessage({name: 'mountDrive'}); + await sendTestMessage({name: 'mountDownloads'}); + + // Open Files app without specifying the initial directory/root. + const appId = await remoteCall.openNewWindow(null, null); + chrome.test.assertTrue(!!appId, 'failed to open new window'); + + // Confirm that the Files App opened in MyFiles. + await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/My files'); + + // Disable local storage. + await sendTestMessage({name: 'setupSkyVault'}); + + // We should navigate to Drive. + await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/My Drive'); +}
diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc index f9e6427..9098236 100644 --- a/ui/ozone/platform/wayland/host/wayland_popup.cc +++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -80,7 +80,7 @@ auto bounds_dip = wl::TranslateWindowBoundsToParentDIP(this, xdg_parent_window); - bounds_dip.Inset(GetDecorationInsetsInDIP()); + bounds_dip.Inset(delegate()->CalculateInsetsInDIP(GetPlatformWindowState())); ShellPopupParams params; params.bounds = bounds_dip; @@ -196,7 +196,8 @@ if (shell_popup_ && old_bounds_dip != bounds_dip) { auto bounds_dip_in_parent = wl::TranslateWindowBoundsToParentDIP(this, xdg_parent_window); - bounds_dip_in_parent.Inset(GetDecorationInsetsInDIP()); + bounds_dip_in_parent.Inset( + delegate()->CalculateInsetsInDIP(GetPlatformWindowState())); // If Wayland moved the popup (for example, a dnd arrow icon), schedule // redraw as Aura doesn't do that for moved surfaces. If redraw has not been @@ -237,8 +238,12 @@ pending_bounds_dip, xdg_parent_window->GetBoundsInDIP()) + xdg_parent_window->GetWindowGeometryOffsetInDIP(); - // Bounds are in the geometry space. Need to add decoration insets backs. - const auto insets = GetDecorationInsetsInDIP(); + // Bounds are in the geometry space. Need to add decoration insets backs. Note + // that the window state for WaylandPopup is always `kUnknown` now, but we + // check `pending_configure_state_.window_state` to make it consistent. + const auto insets = delegate()->CalculateInsetsInDIP( + pending_configure_state_.window_state.value_or( + PlatformWindowState::kUnknown)); pending_configure_state_.bounds_dip->Inset(-insets); pending_configure_state_.size_px = delegate()->ConvertRectToPixels(pending_bounds_dip).size(); @@ -336,13 +341,13 @@ return shell_popup() ? shell_popup()->IsConfigured() : false; } -void WaylandPopup::SetWindowGeometry(gfx::Size size_dip) { +void WaylandPopup::SetWindowGeometry( + const PlatformWindowDelegate::State& state) { if (!shell_popup_) { return; } - const auto insets = GetDecorationInsetsInDIP(); - gfx::Rect geometry_dip(size_dip); - geometry_dip.Inset(insets); + gfx::Rect geometry_dip(state.bounds_dip.size()); + geometry_dip.Inset(delegate()->CalculateInsetsInDIP(state.window_state)); shell_popup_->SetWindowGeometry(geometry_dip); }
diff --git a/ui/ozone/platform/wayland/host/wayland_popup.h b/ui/ozone/platform/wayland/host/wayland_popup.h index 124b727..a318166 100644 --- a/ui/ozone/platform/wayland/host/wayland_popup.h +++ b/ui/ozone/platform/wayland/host/wayland_popup.h
@@ -48,7 +48,7 @@ bool OnInitialize(PlatformWindowInitProperties properties, PlatformWindowDelegate::State* state) override; WaylandPopup* AsWaylandPopup() override; - void SetWindowGeometry(gfx::Size size_dip) override; + void SetWindowGeometry(const PlatformWindowDelegate::State& state) override; void UpdateWindowMask() override; void PropagateBufferScale(float new_scale) override; void ShowTooltip(const std::u16string& text,
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc index 86f93a3..2ed65ef 100644 --- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc +++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -71,7 +71,6 @@ WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate, WaylandConnection* connection) : WaylandWindow(delegate, connection), - state_(PlatformWindowState::kNormal), screen_coordinates_enabled_(kDefaultScreenCoordinateEnabled) { // Set a class property key, which allows |this| to be used for interactive // events, e.g. move or resize. @@ -109,7 +108,7 @@ #endif shell_toplevel_->SetTitle(window_title_); SetSizeConstraints(); - TriggerStateChanges(); + TriggerStateChanges(GetPlatformWindowState()); SetUpShellIntegration(); OnDecorationModeChanged(); @@ -204,7 +203,8 @@ bool WaylandToplevelWindow::IsVisible() const { // X and Windows return true if the window is minimized. For consistency, do // the same. - return !!shell_toplevel_ || state_ == PlatformWindowState::kMinimized; + return !!shell_toplevel_ || + GetPlatformWindowState() == PlatformWindowState::kMinimized; } void WaylandToplevelWindow::SetTitle(const std::u16string& title) { @@ -236,10 +236,11 @@ if (fullscreen) { new_state = PlatformWindowState::kFullScreen; display_id = target_display_id; - } else if (previous_state_ == PlatformWindowState::kMaximized) - new_state = previous_state_; - else + } else if (previously_maximized_) { + new_state = PlatformWindowState::kMaximized; + } else { new_state = PlatformWindowState::kNormal; + } SetWindowState(new_state, display_id); } @@ -272,9 +273,14 @@ // TODO(crbug.com/1293740): Verify that the claim about a window initialized // as a minimized window cannot ack configure. If not // `IsSurfaceConfigured()` condition can be removed. - previous_state_ = state_; - state_ = PlatformWindowState::kMinimized; - delegate()->OnWindowStateChanged(previous_state_, state_); + // + // TODO(crbug.com/40276379): Use `GetLatestRequestedState().window_state` + // instead once the window state becomes async. + auto previous_state = applied_state().window_state; + previously_maximized_ = previous_state == PlatformWindowState::kMaximized; + ForceApplyWindowStateDoNotUse(PlatformWindowState::kMinimized); + delegate()->OnWindowStateChanged(previous_state, + PlatformWindowState::kMinimized); } } @@ -295,7 +301,7 @@ } PlatformWindowState WaylandToplevelWindow::GetPlatformWindowState() const { - return state_; + return applied_state().window_state; } std::optional<std::string> WaylandToplevelWindow::TakeActivationToken() const { @@ -548,32 +554,32 @@ const WindowStates& window_states) { VLOG(1) << "Wayland XDG/Aura toplevel configure: states=" << window_states.ToString(); - // Store the old state to propagte state changes if Wayland decides to change - // the state to something else. - PlatformWindowState old_state = state_; + + PlatformWindowState window_state = PlatformWindowState::kUnknown; if ((!SupportsConfigureMinimizedState() && - state_ == PlatformWindowState::kMinimized && + GetLatestRequestedState().window_state == + PlatformWindowState::kMinimized && !window_states.is_activated) || window_states.is_minimized) { - state_ = PlatformWindowState::kMinimized; + window_state = PlatformWindowState::kMinimized; } else if (window_states.is_fullscreen) { - state_ = PlatformWindowState::kFullScreen; + window_state = PlatformWindowState::kFullScreen; #if BUILDFLAG(IS_CHROMEOS_LACROS) } else if (window_states.is_pinned_fullscreen) { - state_ = PlatformWindowState::kPinnedFullscreen; + window_state = PlatformWindowState::kPinnedFullscreen; } else if (window_states.is_trusted_pinned_fullscreen) { - state_ = PlatformWindowState::kTrustedPinnedFullscreen; + window_state = PlatformWindowState::kTrustedPinnedFullscreen; #endif // BUILDFLAG(IS_CHROMEOS_LACROS) } else if (window_states.is_maximized) { - state_ = PlatformWindowState::kMaximized; + window_state = PlatformWindowState::kMaximized; } else if (window_states.is_snapped_primary) { - state_ = PlatformWindowState::kSnappedPrimary; + window_state = PlatformWindowState::kSnappedPrimary; } else if (window_states.is_snapped_secondary) { - state_ = PlatformWindowState::kSnappedSecondary; + window_state = PlatformWindowState::kSnappedSecondary; } else if (window_states.is_floated) { - state_ = PlatformWindowState::kFloated; + window_state = PlatformWindowState::kFloated; } else { - state_ = PlatformWindowState::kNormal; + window_state = PlatformWindowState::kNormal; } // No matter what mode we have, the display id doesn't matter at this time @@ -594,23 +600,9 @@ : (IsPinnedOrFullscreen(window_states) ? PlatformFullscreenType::kPlain : PlatformFullscreenType::kNone); - if (fullscreen_type_ != fullscreen_type) { - // The fullscreen state change has finished and we we need to inform the - // browser/app that the transition is done. - delegate()->OnFullscreenTypeChanged(fullscreen_type_, fullscreen_type); - fullscreen_type_ = fullscreen_type; - } + pending_configure_state_.fullscreen_type = fullscreen_type; #endif - // Should skip notifying OnWindowStateChanged() when there are incoming - // responses for the window show state requests to avoid notifying more than - // once. - // TODO(crbug.com/1502744): Implement notification logic correctly. - const bool skip_window_state_changed_notification = - (requested_window_show_state_count_ > 0); - if (requested_window_show_state_count_) - requested_window_show_state_count_--; - // Update state before notifying delegate. const bool did_active_change = is_active_ != window_states.is_activated; is_active_ = window_states.is_activated; @@ -625,6 +617,8 @@ } #endif // IS_LINUX || IS_CHROMEOS_LACROS + pending_configure_state_.window_state = window_state; + // Width or height set to 0 means that we should decide on width and height by // ourselves, but we don't want to set them to anything else. Use restored // bounds size or the current bounds iff the current state is normal (neither @@ -638,12 +632,12 @@ pending_configure_state_.bounds_dip.value_or(gfx::Rect())); if (width_dip > 1 && height_dip > 1) { bounds_dip.SetRect(x, y, width_dip, height_dip); - const auto insets = GetDecorationInsetsInDIP(); - if (ShouldSetBounds(state_) && !insets.IsEmpty()) { + const auto& insets = delegate()->CalculateInsetsInDIP(window_state); + if (ShouldSetBounds(window_state) && !insets.IsEmpty()) { bounds_dip.Inset(-insets); bounds_dip.set_origin({x, y}); } - } else if (ShouldSetBounds(state_)) { + } else if (ShouldSetBounds(window_state)) { bounds_dip = !restored_bounds_dip().IsEmpty() ? restored_bounds_dip() : GetBoundsInDIP(); } @@ -659,17 +653,12 @@ // We reset `restored_bounds_dip_` if the window is normal, snapped or floated // state, or update it to the applied bounds if we don't have any meaningful // value stored. - if (ShouldSetBounds(state_)) { + if (ShouldSetBounds(window_state)) { SetRestoredBoundsInDIP({}); } else if (GetRestoredBoundsInDIP().IsEmpty()) { SetRestoredBoundsInDIP(GetBoundsInDIP()); } - if (old_state != state_ && !skip_window_state_changed_notification) { - previous_state_ = old_state; - delegate()->OnWindowStateChanged(previous_state_, state_); - } - if (did_active_change) { if (active_bubble()) { ActivateBubble(is_active_ ? active_bubble() : nullptr); @@ -713,6 +702,8 @@ bool WaylandToplevelWindow::OnInitialize( PlatformWindowInitProperties properties, PlatformWindowDelegate::State* state) { + state->window_state = PlatformWindowState::kNormal; + #if BUILDFLAG(IS_CHROMEOS_LACROS) auto token = base::UnguessableToken::Create(); window_unique_id_ = @@ -760,17 +751,18 @@ return shell_toplevel() ? shell_toplevel()->IsConfigured() : false; } -void WaylandToplevelWindow::SetWindowGeometry(gfx::Size size_dip) { +void WaylandToplevelWindow::SetWindowGeometry( + const PlatformWindowDelegate::State& state) { DCHECK(connection()->SupportsSetWindowGeometry()); if (!shell_toplevel_) return; - gfx::Rect geometry_dip(size_dip); + gfx::Rect geometry_dip(state.bounds_dip.size()); - const auto insets = GetDecorationInsetsInDIP(); - if (state_ == PlatformWindowState::kNormal && !insets.IsEmpty()) { - geometry_dip.Inset(insets); + auto insets_dip = delegate()->CalculateInsetsInDIP(state.window_state); + if (!insets_dip.IsEmpty()) { + geometry_dip.Inset(insets_dip); // Shrinking the bounds by the decoration insets might result in empty // bounds. For the reasons already explained in WaylandWindow::Initialize(), @@ -1064,9 +1056,8 @@ void WaylandToplevelWindow::Unpin() { if (SupportsConfigurePinnedState()) { - auto new_state = previous_state_ == PlatformWindowState::kMaximized - ? previous_state_ - : PlatformWindowState::kNormal; + auto new_state = previously_maximized_ ? PlatformWindowState::kMaximized + : PlatformWindowState::kNormal; SetWindowState(new_state, display::kInvalidDisplayId); } else { if (auto* zaura_surface = GetZAuraSurface()) { @@ -1083,20 +1074,6 @@ void WaylandToplevelWindow::DumpState(std::ostream& out) const { WaylandWindow::DumpState(out); -#if BUILDFLAG(IS_CHROMEOS_LACROS) - out << ", fullscreen_type="; - switch (fullscreen_type_) { - case PlatformFullscreenType::kNone: - out << "not fullscreen"; - break; - case PlatformFullscreenType::kPlain: - out << "plain fullscreen"; - break; - case PlatformFullscreenType::kImmersive: - out << "immersive fullscreen"; - break; - } -#endif out << ", title=" << window_title_ << ", is_active=" << ToBoolString(is_active_) << ", restore_session_id=" << restore_session_id_; @@ -1131,76 +1108,97 @@ workspace_extension_delegate_ = delegate; } -void WaylandToplevelWindow::TriggerStateChanges() { - if (!shell_toplevel_) - return; - - // Call UnSetMaximized only if current state is normal. Otherwise, if the - // current state is fullscreen and the previous is maximized, calling - // UnSetMaximized may result in wrong restored window position that clients - // are not allowed to know about. - if (state_ == PlatformWindowState::kMinimized) { - LOG(FATAL) << "Should not be called with kMinimized state"; - } else if (state_ == PlatformWindowState::kFullScreen) { - shell_toplevel_->SetFullscreen( - GetWaylandOutputForDisplayId(fullscreen_display_id_)); - } else if (state_ == PlatformWindowState::kPinnedFullscreen || - state_ == PlatformWindowState::kTrustedPinnedFullscreen) { - if (auto* zaura_surface = GetZAuraSurface()) { - zaura_surface->SetPin(state_ == - PlatformWindowState::kTrustedPinnedFullscreen); +void WaylandToplevelWindow::TriggerStateChanges( + PlatformWindowState window_state) { + if (shell_toplevel_) { + // Call UnSetMaximized only if current state is normal. Otherwise, if the + // current state is fullscreen and the previous is maximized, calling + // UnSetMaximized may result in wrong restored window position that clients + // are not allowed to know about. + if (window_state == PlatformWindowState::kMinimized) { + LOG(FATAL) << "Should not be called with kMinimized state"; + } else if (window_state == PlatformWindowState::kFullScreen) { + shell_toplevel_->SetFullscreen( + GetWaylandOutputForDisplayId(fullscreen_display_id_)); + } else if (window_state == PlatformWindowState::kPinnedFullscreen || + window_state == PlatformWindowState::kTrustedPinnedFullscreen) { + if (auto* zaura_surface = GetZAuraSurface()) { + zaura_surface->SetPin(window_state == + PlatformWindowState::kTrustedPinnedFullscreen); + } + } else if (GetLatestRequestedState().window_state == + PlatformWindowState::kFullScreen) { + shell_toplevel_->UnSetFullscreen(); + } else if (GetLatestRequestedState().window_state == + PlatformWindowState::kPinnedFullscreen || + GetLatestRequestedState().window_state == + PlatformWindowState::kTrustedPinnedFullscreen) { + if (auto* zaura_surface = GetZAuraSurface()) { + zaura_surface->UnsetPin(); + } + } else if (window_state == PlatformWindowState::kMaximized) { + shell_toplevel_->SetMaximized(); + } else if (window_state == PlatformWindowState::kNormal) { + shell_toplevel_->UnSetMaximized(); } - } else if (previous_state_ == PlatformWindowState::kFullScreen) { - shell_toplevel_->UnSetFullscreen(); - } else if (previous_state_ == PlatformWindowState::kPinnedFullscreen || - previous_state_ == PlatformWindowState::kTrustedPinnedFullscreen) { - if (auto* zaura_surface = GetZAuraSurface()) { - zaura_surface->UnsetPin(); - } - } else if (state_ == PlatformWindowState::kMaximized) { - shell_toplevel_->SetMaximized(); - } else if (state_ == PlatformWindowState::kNormal) { - shell_toplevel_->UnSetMaximized(); } - delegate()->OnWindowStateChanged(previous_state_, state_); + // Update the window state of the applied state before calling + // OnWindowStateChanged so it can be used to pick up the new window state. We + // cannot request state here because the bounds is not yet synchronized with + // window state. Requesting the state will trigger SetWindowGeometry with the + // current bounds + insets, so it has a risk to set geometry aligning with the + // client side window state while the server side has not yet configured it. + // This behavior is not necessarily a problem, but it causes the failure on + // weston. + // TODO(crbug.com/40276379): Remove this once this is async. + auto previous_state = applied_state().window_state; + ForceApplyWindowStateDoNotUse(window_state); + delegate()->OnWindowStateChanged(previous_state, window_state); connection()->Flush(); } -void WaylandToplevelWindow::SetWindowState(PlatformWindowState state, +void WaylandToplevelWindow::SetWindowState(PlatformWindowState window_state, int64_t target_display_id) { - CHECK_NE(state, PlatformWindowState::kMinimized); + CHECK_NE(window_state, PlatformWindowState::kMinimized); - if (ShouldTriggerStateChange(state, target_display_id)) { - // We don't want to update the previous state, for cases like fullscreening - // to a different output while already in fullscreen, so we can still - // restore back to the previous non-fullscreen state. - if (state_ != state) { - previous_state_ = state_; - state_ = state; + if (ShouldTriggerStateChange(window_state, target_display_id)) { + // TODO(crbug.com/40276379): Use `GetLatestRequestedState().window_state` + // instead once the window state becomes async. + auto previous_state = applied_state().window_state; + + // We want to remember whether it was previously maximized, for cases like + // fullscreening to a different output while already in fullscreen, so we + // can still restore back to the previous non-fullscreen state. + if (previous_state != window_state) { + previously_maximized_ = previous_state == PlatformWindowState::kMaximized; } + // Remember the display id if we are going to fullscreen - otherwise reset. - fullscreen_display_id_ = (state_ == PlatformWindowState::kFullScreen) + fullscreen_display_id_ = (window_state == PlatformWindowState::kFullScreen) ? target_display_id : display::kInvalidDisplayId; - // Tracks this window show state change request, coming from the Browser. - requested_window_show_state_count_++; - TriggerStateChanges(); + TriggerStateChanges(window_state); } } bool WaylandToplevelWindow::ShouldTriggerStateChange( - PlatformWindowState state, + PlatformWindowState window_state, int64_t target_display_id) const { // Allow the state transition if the state is different. - if (state_ != state) { + // + // The latest requested state from the client is stored as + // `applied_state().window_state` so use it as a previous state. + // TODO(crbug.com/40276379): Use `GetLatestRequestedState().window_state` + // instead once the window state becomes async. + if (applied_state().window_state != window_state) { return true; } // Allow the state transition if the state is fullscreen and the screen has // changed to something explicit - or different. - if (state == PlatformWindowState::kFullScreen && + if (window_state == PlatformWindowState::kFullScreen && target_display_id != display::kInvalidDisplayId && target_display_id != fullscreen_display_id_) { return true;
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h index 2561b08d..012fa5fe 100644 --- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h +++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -91,7 +91,7 @@ bool OnInitialize(PlatformWindowInitProperties properties, PlatformWindowDelegate::State* state) override; bool IsActive() const override; - void SetWindowGeometry(gfx::Size size_dip) override; + void SetWindowGeometry(const PlatformWindowDelegate::State& state) override; bool IsScreenCoordinatesEnabled() const override; bool SupportsConfigureMinimizedState() const override; bool SupportsConfigurePinnedState() const override; @@ -211,7 +211,7 @@ void UpdateSystemModal(); - void TriggerStateChanges(); + void TriggerStateChanges(PlatformWindowState window_state); // Sets the new window `state` to the window. `target_display_id` gets ignored // unless the state is `PlatformWindowState::kFullscreen`. @@ -256,10 +256,11 @@ // Wrappers around shell surface. std::unique_ptr<ShellToplevelWrapper> shell_toplevel_; - // Contains the current state of the window. - PlatformWindowState state_ = PlatformWindowState::kUnknown; - // Contains the previous state of the window. - PlatformWindowState previous_state_ = PlatformWindowState::kUnknown; + // True if it's maximized before requesting the window state change from the + // client. + // TODO(b/328109805): Move this logic to server side on Lacros. + bool previously_maximized_ = false; + // The display ID to switch to in case the state is `kFullscreen`. int64_t fullscreen_display_id_ = display::kInvalidDisplayId; @@ -271,10 +272,6 @@ bool is_active_ = false; #if BUILDFLAG(IS_CHROMEOS_LACROS) - // This is used to detect fullscreen type changes from the Aura side - // to inform Lacros clients from the asynchronous task completion. - PlatformFullscreenType fullscreen_type_ = PlatformFullscreenType::kNone; - // The flag that indicates the last requested immersive fullscreen status from // SetImmersiveFullscreenStatue to detect the immersive status changes. Set to // null if it had never been called. @@ -309,16 +306,6 @@ std::optional<std::vector<gfx::Rect>> opaque_region_px_; std::optional<std::vector<gfx::Rect>> input_region_px_; - // Tracks how many the window show state requests by made by the Browser - // are currently being processed by the Wayland Compositor. In practice, - // each individual increment corresponds to an explicit window show state - // change request, and gets a response by the Compositor. - // - // This mechanism allows Ozone/Wayland to filter out notifying the delegate - // (PlatformWindowDelegate) more than once, for the same window show state - // change. - uint32_t requested_window_show_state_count_ = 0; - // Information used by the compositor to restore the window state upon // creation. int32_t restore_session_id_ = 0;
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc index 1925f95..cb640d8 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -363,7 +363,7 @@ void WaylandWindow::Show(bool inactive) { // Initially send the window geometry. After this, we only update window // geometry when the value in latched_state_ updates. - SetWindowGeometry(latched_state_.bounds_dip.size()); + SetWindowGeometry(latched_state_); frame_manager_->MaybeProcessPendingFrame(); } @@ -414,9 +414,6 @@ << ", restore_bounds_dip=" << restored_bounds_dip_.ToString() << ", overlay_delegation=" << (wayland_overlay_delegation_enabled_ ? "enabled" : "disabled"); - if (frame_insets_px_) { - out << ", frame_insets=" << frame_insets_px_->ToString(); - } if (has_touch_focus_) { out << ", has_touch_focus"; } @@ -599,19 +596,6 @@ NOTIMPLEMENTED_LOG_ONCE(); } -void WaylandWindow::SetDecorationInsets(const gfx::Insets* insets_px) { - // TODO(crbug.com/1395267): Add window geometry to WaylandWindow::State. - if ((!frame_insets_px_ && !insets_px) || - (frame_insets_px_ && insets_px && *frame_insets_px_ == *insets_px)) { - return; - } - if (insets_px) { - frame_insets_px_ = *insets_px; - } else { - frame_insets_px_ = std::nullopt; - } -} - void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { NOTIMPLEMENTED_LOG_ONCE(); @@ -886,6 +870,7 @@ } PlatformWindowDelegate::State state; + state.window_state = PlatformWindowState::kUnknown; state.bounds_dip = properties.bounds; // Make sure we don't store empty bounds, or else later on we might send an @@ -922,8 +907,6 @@ connection_->window_manager()->AddWindow(GetWidget(), this); - SetDecorationInsets(&properties.frame_insets_px); - if (!OnInitialize(std::move(properties), &state)) { return false; } @@ -954,23 +937,13 @@ return true; } -void WaylandWindow::SetWindowGeometry(gfx::Size size_dip) {} +void WaylandWindow::SetWindowGeometry( + const PlatformWindowDelegate::State& state) {} gfx::Vector2d WaylandWindow::GetWindowGeometryOffsetInDIP() const { - if (!frame_insets_px_.has_value()) { - return {}; - } - - auto scale = applied_state().window_scale; - return {static_cast<int>(frame_insets_px_->left() / scale), - static_cast<int>(frame_insets_px_->top() / scale)}; -} - -gfx::Insets WaylandWindow::GetDecorationInsetsInDIP() const { - auto scale = latched_state().window_scale; - return frame_insets_px_.has_value() - ? gfx::ScaleToRoundedInsets(*frame_insets_px_, 1.f / scale) - : gfx::Insets{}; + const auto& insets_dip = + delegate()->CalculateInsetsInDIP(GetPlatformWindowState()); + return {insets_dip.left(), insets_dip.top()}; } WaylandWindow* WaylandWindow::GetRootParentWindow() { @@ -1276,6 +1249,15 @@ // For values not specified in pending_configure_state_, use the latest // requested values. auto state = GetLatestRequestedState(); + + if (pending_configure_state_.window_state.has_value()) { + state.window_state = pending_configure_state_.window_state.value(); + } +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (pending_configure_state_.fullscreen_type.has_value()) { + state.fullscreen_type = pending_configure_state_.fullscreen_type.value(); + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) if (pending_configure_state_.bounds_dip.has_value()) { state.bounds_dip = pending_configure_state_.bounds_dip.value(); } @@ -1346,7 +1328,17 @@ // latched state, because in flight configure requests are only removed on // latch. if (in_flight_requests_.empty()) { - DCHECK_EQ(applied_state_, latched_state_); + // Currently, we have a hack that overrides `applied_state_.window_state` + // when the window state change is requested from the client. In such case, + // `applied_state_` may take a different window state value from + // `latched_state_` when the server side sends configure event. + // TODO(crbug.com/40276379): Check window state is equal between + // `applied_state_` and `latched_state_` as well. + auto applied_state_copy = applied_state_; + // Override `applied_state_.window_state` as the same value as + // `latched_state_` to exclude `window_state` from equivalence check. + applied_state_copy.window_state = latched_state_.window_state; + CHECK_EQ(applied_state_copy, latched_state_); } // Adjust state values if necessary. @@ -1361,9 +1353,6 @@ state.size_px = gfx::ScaleToEnclosingRectIgnoringError( gfx::Rect(state.bounds_dip.size()), state.window_scale) .size(); - // This will ensure that if insets at the time of the request changed, a new - // frame is produced when the state is applied. - state.insets = GetDecorationInsetsInDIP(); StateRequest req{.state = state, .serial = serial}; if (in_flight_requests_.empty()) { @@ -1498,8 +1487,6 @@ // Latch the most up to date state we have a frame back for. auto old_state = latched_state_; latched_state_ = req.state; - auto old_latched_insets = latched_insets_; - latched_insets_ = GetDecorationInsetsInDIP(); // Update the geometry if the bounds are different or the window scale has // been changed or if the insets have changed since the last latched request. @@ -1508,14 +1495,13 @@ // the device scale factor known from the display. It can be different from // the one that the |latch_state_.window_scale| has. As a result, the geometry // is set with wrong values as Wayland requires them to be in DIP. + // TODO(crbug.com/328011220): Investigate whether we can remove + // `window_scale` check from here. if (req.state.bounds_dip.size() != old_state.bounds_dip.size() || req.state.window_scale != old_state.window_scale || - // If insets change that is a geometry change even when the bounds or - // scale remain the same. The updated insets may not be known at the time - // of the request, hence the need to check this if there are changes in - // insets since it latched the last time. - old_latched_insets != latched_insets_) { - SetWindowGeometry(req.state.bounds_dip.size()); + delegate()->CalculateInsetsInDIP(req.state.window_state) != + delegate()->CalculateInsetsInDIP(old_state.window_state)) { + SetWindowGeometry(req.state); } UpdateWindowMask(); if (req.serial != -1) { @@ -1580,4 +1566,14 @@ } } +PlatformWindowDelegate::State WaylandWindow::GetLatestRequestedState() const { + return in_flight_requests_.empty() ? applied_state_ + : in_flight_requests_.back().state; +} + +void WaylandWindow::ForceApplyWindowStateDoNotUse( + PlatformWindowState window_state) { + applied_state_.window_state = window_state; +} + } // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h index 915b8f9d..930f364b 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.h +++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -114,6 +114,7 @@ } WaylandWindow* parent_window() const { return parent_window_; } PlatformWindowDelegate* delegate() { return delegate_; } + const PlatformWindowDelegate* delegate() const { return delegate_; } gfx::AcceleratedWidget GetWidget() const; @@ -219,7 +220,6 @@ gfx::Rect GetRestoredBoundsInDIP() const override; bool ShouldWindowContentsBeTransparent() const override; void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; - void SetDecorationInsets(const gfx::Insets* insets_px) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; void SizeConstraintsChanged() override; @@ -330,14 +330,11 @@ virtual void OnDragSessionClose(ui::mojom::DragOperation operation); // Sets the window geometry. - virtual void SetWindowGeometry(gfx::Size size_dip); + virtual void SetWindowGeometry(const PlatformWindowDelegate::State& state); // Returns the offset of the window geometry within the window surface. gfx::Vector2d GetWindowGeometryOffsetInDIP() const; - // Returns the effective decoration insets. - gfx::Insets GetDecorationInsetsInDIP() const; - // Returns a root parent window within the same hierarchy. WaylandWindow* GetRootParentWindow(); @@ -480,10 +477,17 @@ // Returns the next state that will be applied, or the currently applied state // if there are no later unapplied states. This is used when updating a single // property (e.g. window scale) without wanting to modify the others. - PlatformWindowDelegate::State GetLatestRequestedState() const { - return in_flight_requests_.empty() ? applied_state_ - : in_flight_requests_.back().state; - } + PlatformWindowDelegate::State GetLatestRequestedState() const; + + // Sets given `window_state` to `applied_state_` so that it reflects the + // client side window state change immediately, Not that + // `applied_state_.window_state` is the source of truth as a window state. + // This should be called only when the client side requests the new window + // state and it is expected to become the same when the server side + // configures. + // DO NOT USE THIS unless it's really needed and okay to use. + // TODO(crbug.com/40276379): Remove this. + void ForceApplyWindowStateDoNotUse(PlatformWindowState window_state); bool HasInFlightRequestsForStateForTesting() const { return !in_flight_requests_.empty(); @@ -492,6 +496,10 @@ // PendingConfigureState describes the content of a configure sent from the // wayland server. struct PendingConfigureState { + std::optional<PlatformWindowState> window_state; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + std::optional<PlatformFullscreenType> fullscreen_type; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) std::optional<gfx::Rect> bounds_dip; std::optional<gfx::Size> size_px; std::optional<float> raster_scale; @@ -626,12 +634,6 @@ scoped_refptr<BitmapCursor> cursor_; #endif - // Margins between edges of the surface and the window geometry (i.e., the - // area of the window that is visible to the user as the actual window). The - // areas outside the geometry are used to draw client-side window decorations. - // TODO(crbug.com/1306688): Use DIP for frame insets. - std::optional<gfx::Insets> frame_insets_px_; - bool has_touch_focus_ = false; // The UI scale may be forced through the command line, which means that it // replaces the default value that is equal to the natural device scale. @@ -711,9 +713,6 @@ // server. See the comments on applied_state_ for further explanation. PlatformWindowDelegate::State latched_state_; - // Stores the insets in DIP at the time of the last latched state. - gfx::Insets latched_insets_; - // In-flight state requests. Once a frame comes from the GPU // process with the appropriate viz sequence number, ack_configure request // with |serial| will be sent to the Wayland compositor if needed.
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc index 9b6b77e..345f077e 100644 --- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -515,152 +515,6 @@ wl::SyncDisplay(connection_->display_wrapper(), *connection_->display()); } -// Checks that decoration insets do not change final bounds and that -// WaylandToplevelWindow::HandleToplevelConfigure does correct rounding when -// some sides of insets divides by 2 with remainder. -TEST_P(WaylandWindowTest, SetDecorationInsets) { - constexpr gfx::Rect kNormalBounds{956, 556}; - constexpr auto kHiDpiScale = 2; - const BoundsChange kHiDpiBounds{false}; - - window_->SetBoundsInDIP(kNormalBounds); - - auto state = InitializeWlArrayWithActivatedState(); - - PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { - wl::TestOutput* output = server->output(); - // Send the window to |output|. - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl_surface_send_enter(surface->resource(), output->resource()); - }); - - // Set insets for normal DPI. - const auto kDecorationInsets = gfx::Insets::TLBR(24, 28, 32, 28); - auto bounds_with_insets = kNormalBounds; - bounds_with_insets.Inset(kDecorationInsets); - EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - PostToServerAndWait([id = surface_id_, bounds_with_insets]( - wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets)); - }); - window_->SetDecorationInsets(&kDecorationInsets); - AdvanceFrameToCurrent(window_.get(), delegate_); - VerifyAndClearExpectations(); - - EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - // No update to the window geometry. - EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); - }); - - SendConfigureEvent(surface_id_, bounds_with_insets.size(), state); - AdvanceFrameToCurrent(window_.get(), delegate_); - VerifyAndClearExpectations(); - - // Change scale. This is the only time when we expect the pixel position to - // change. - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kHiDpiBounds))).Times(1); - PostToServerAndWait([](wl::TestWaylandServerThread* server) { - auto* output = server->output(); - output->SetScale(kHiDpiScale); - output->SetDeviceScaleFactor(kHiDpiScale); - output->Flush(); - }); - - // Pretend we are already rendering using new scale. - window_->root_surface()->set_surface_buffer_scale(kHiDpiScale); - - // Set new insets so that rounding does not result in integer. - constexpr auto kDecorationInsets_2x = gfx::Insets::TLBR(48, 55, 63, 55); - PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - EXPECT_CALL(*xdg_surface, SetWindowGeometry(gfx::Rect(28, 24, 900, 500))) - .Times(1); - }); - - window_->SetDecorationInsets(&kDecorationInsets_2x); - AdvanceFrameToCurrent(window_.get(), delegate_); - VerifyAndClearExpectations(); - - // Now send configure events many times - bounds mustn't change. - for (size_t i = 0; i < 10; i++) { - EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - PostToServerAndWait( - [id = surface_id_](wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - // No update to the window geometry. - EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); - }); - SendConfigureEvent(surface_id_, bounds_with_insets.size(), state); - AdvanceFrameToCurrent(window_.get(), delegate_); - } - VerifyAndClearExpectations(); -} - -// Checks that geometry is set when decoration insets change even when bounds or -// scale don't. -TEST_P(WaylandWindowTest, OnlyChangeDecorationInsets) { - // The bounds never change throughout this test - constexpr gfx::Rect kBounds{980, 1188}; - - window_->SetBoundsInDIP(kBounds); - - auto state = InitializeWlArrayWithActivatedState(); - - PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { - wl::TestOutput* output = server->output(); - // Send the window to |output|. - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl_surface_send_enter(surface->resource(), output->resource()); - }); - - const auto kInitialInsets = gfx::Insets::TLBR(20, 36, 52, 36); - auto bounds_with_insets = kBounds; - bounds_with_insets.Inset(kInitialInsets); - EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - PostToServerAndWait([id = surface_id_, bounds_with_insets]( - wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets)); - }); - window_->SetDecorationInsets(&kInitialInsets); - AdvanceFrameToCurrent(window_.get(), delegate_); - VerifyAndClearExpectations(); - - const auto kNewInsets = gfx::Insets::TLBR(10, 10, 10, 10); - bounds_with_insets = kBounds; - bounds_with_insets.Inset(kNewInsets); - EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - PostToServerAndWait([id = surface_id_, bounds_with_insets]( - wl::TestWaylandServerThread* server) { - wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id); - ASSERT_TRUE(surface); - wl::MockXdgSurface* xdg_surface = surface->xdg_surface(); - EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets)); - }); - - // Change insets here so that these are detected when a new state is requested - // from the server. - window_->SetDecorationInsets(&kNewInsets); - SendConfigureEvent(surface_id_, bounds_with_insets.size(), state); - AdvanceFrameToCurrent(window_.get(), delegate_); - VerifyAndClearExpectations(); -} - #if BUILDFLAG(IS_LINUX) // Checks that when the window gets some of its edges tiled, it notifies the // delegate appropriately. @@ -844,6 +698,7 @@ window_->HandleToplevelConfigure(kMaximizedBounds.width(), kMaximizedBounds.height(), window_states); + window_->HandleSurfaceConfigure(2); EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); EXPECT_EQ(window_->GetRestoredBoundsInDIP(), kNormalBounds); @@ -882,10 +737,7 @@ // calls) invoke SetWindowGeometry(), but that should not happen during the // change of the window state. // See https://crbug.com/1223005. - EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)) - .Times(1) - .WillOnce( - testing::Invoke([this]() { window_->SetDecorationInsets({}); })); + EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); window_->Maximize(); SendConfigureEvent(surface_id_, kMaximizedBounds.size(), active_maximized); AdvanceFrameToCurrent(window_.get(), delegate_); @@ -928,10 +780,7 @@ // calls) invoke SetWindowGeometry(), but that should not happen during the // change of the window state. // See https://crbug.com/1223005. - EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)) - .Times(1) - .WillOnce( - testing::Invoke([this]() { window_->SetDecorationInsets({}); })); + EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { @@ -948,6 +797,110 @@ VerifyAndClearExpectations(); } +TEST_P(WaylandWindowTest, MaximizeAndRestoreWithInsets) { + constexpr gfx::Rect kNormalBounds{510, 310}; + constexpr gfx::Insets kNormalInsets(5); + + constexpr gfx::Rect kMaximizedBounds{800, 600}; + constexpr gfx::Insets kMaximizedInsets(0); + + // Make sure the window has normal state initially. + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + window_->SetBoundsInDIP(gfx::Rect(kNormalBounds.size())); + EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); + AdvanceFrameToCurrent(window_.get(), delegate_); + VerifyAndClearExpectations(); + + // Deactivate the surface. + auto empty_state = MakeStateArray({}); + SendConfigureEvent(surface_id_, {0, 0}, empty_state); + AdvanceFrameToCurrent(window_.get(), delegate_); + + auto maximized_geometry = kMaximizedBounds; + maximized_geometry.Inset(kMaximizedInsets); + auto active_maximized = MakeStateArray( + {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); + PostToServerAndWait([id = surface_id_, bounds = maximized_geometry]( + wl::TestWaylandServerThread* server) { + wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); + ASSERT_TRUE(mock_surface); + wl::MockXdgSurface* xdg_surface = mock_surface->xdg_surface(); + EXPECT_CALL(*xdg_surface->xdg_toplevel(), SetMaximized()); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(gfx::Rect(bounds.size()))); + }); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + // Emulate a piece of behaviour of BrowserDesktopWindowTreeHostLinux, which is + // the real delegate. Its OnWindowStateChanged() may (through some chain of + // calls) invoke SetWindowGeometry(), but that should not happen during the + // change of the window state. + // See https://crbug.com/1223005. + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kMaximized)) + .WillRepeatedly(Return(kMaximizedInsets)); + EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); + window_->Maximize(); + SendConfigureEvent(surface_id_, maximized_geometry.size(), active_maximized); + AdvanceFrameToCurrent(window_.get(), delegate_); + VerifyAndClearExpectations(); + + auto inactive_maximized = MakeStateArray({XDG_TOPLEVEL_STATE_MAXIMIZED}); + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kMaximized)) + .WillRepeatedly(Return(kMaximizedInsets)); + PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { + wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); + ASSERT_TRUE(mock_surface); + wl::MockXdgSurface* xdg_surface = mock_surface->xdg_surface(); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); + }); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(false))); + EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); + SendConfigureEvent(surface_id_, maximized_geometry.size(), + inactive_maximized); + AdvanceFrameToCurrent(window_.get(), delegate_); + VerifyAndClearExpectations(); + + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kMaximized)) + .WillRepeatedly(Return(kMaximizedInsets)); + PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { + wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); + ASSERT_TRUE(mock_surface); + wl::MockXdgSurface* xdg_surface = mock_surface->xdg_surface(); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); + }); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); + EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); + SendConfigureEvent(surface_id_, maximized_geometry.size(), active_maximized); + AdvanceFrameToCurrent(window_.get(), delegate_); + VerifyAndClearExpectations(); + + auto normal_geometry = kNormalBounds; + normal_geometry.Inset(kNormalInsets); + // Emulate a piece of behaviour of BrowserDesktopWindowTreeHostLinux, which is + // the real delegate. Its OnWindowStateChanged() may (through some chain of + // calls) invoke SetWindowGeometry(), but that should not happen during the + // change of the window state. + // See https://crbug.com/1223005. + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(Return(kNormalInsets)); + EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); + EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + PostToServerAndWait([id = surface_id_, bounds = normal_geometry]( + wl::TestWaylandServerThread* server) { + wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); + ASSERT_TRUE(mock_surface); + wl::MockXdgSurface* xdg_surface = mock_surface->xdg_surface(); + EXPECT_CALL(*xdg_surface->xdg_toplevel(), UnsetMaximized()); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds)); + }); + window_->Restore(); + // Reinitialize wl_array, which removes previous old states. + auto active = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(surface_id_, {0, 0}, active); + AdvanceFrameToCurrent(window_.get(), delegate_); + VerifyAndClearExpectations(); +} + // Tests the event sequence where a minimize request is initiated by the client. TEST_P(WaylandWindowTest, ClientInitiatedMinimize) { if (!window_->SupportsConfigureMinimizedState()) { @@ -1103,11 +1056,14 @@ } TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { + constexpr gfx::Rect kNormalBounds{500, 300}; + constexpr gfx::Rect kFullscreenBounds{800, 600}; + // Make sure the window is initialized to normal state from the beginning. EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); wl::ScopedWlArray states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(surface_id_, {0, 0}, states); + SendConfigureEvent(surface_id_, kNormalBounds.size(), states); states.AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN); @@ -1121,10 +1077,10 @@ window_->SetFullscreen(true, display::kInvalidDisplayId); // Make sure than WaylandWindow manually handles fullscreen states. Check the // comment in the WaylandWindow::SetFullscreen. + VerifyAndClearExpectations(); + SendConfigureEvent(surface_id_, kFullscreenBounds.size(), states); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kFullScreen); - VerifyAndClearExpectations(); - SendConfigureEvent(surface_id_, {0, 0}, states); PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); @@ -1135,11 +1091,10 @@ EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); window_->Restore(); - EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); VerifyAndClearExpectations(); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(surface_id_, {0, 0}, states); + SendConfigureEvent(surface_id_, kNormalBounds.size(), states); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); } @@ -1169,7 +1124,13 @@ server->GetObject<wl::MockSurface>(surface_id); EXPECT_FALSE(mock_surface->xdg_surface()); }); - EXPECT_CALL(delegate, OnWindowStateChanged(_, _)).Times(0); + + // We must receive a state change after SetFullscreen. + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PlatformWindowState::kNormal), + Eq(PlatformWindowState::kFullScreen))) + .Times(1); + window->SetFullscreen(true, display::kInvalidDisplayId); // The state of the window must already be fullscreen one. EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen); @@ -1178,17 +1139,9 @@ Mock::VerifyAndClearExpectations(&delegate); - // We must receive a state change after Show is called. - EXPECT_CALL(delegate, - OnWindowStateChanged(Eq(PlatformWindowState::kNormal), - Eq(PlatformWindowState::kFullScreen))) - .Times(1); - // Show and Activate the surface. window->Show(false); - Mock::VerifyAndClearExpectations(&delegate); - // We mustn't receive any state changes if that does not differ from the last // state. EXPECT_CALL(delegate, OnWindowStateChanged(_, _)).Times(0); @@ -1226,7 +1179,12 @@ server->GetObject<wl::MockSurface>(surface_id); EXPECT_FALSE(mock_surface->xdg_surface()); }); - EXPECT_CALL(delegate, OnWindowStateChanged(_, _)).Times(0); + + // We must receive a state change after Show is called. + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PlatformWindowState::kNormal), + Eq(PlatformWindowState::kMaximized))) + .Times(1); window->Maximize(); // The state of the window must already be fullscreen one. @@ -1236,17 +1194,9 @@ Mock::VerifyAndClearExpectations(&delegate); - // We must receive a state change after Show is called. - EXPECT_CALL(delegate, - OnWindowStateChanged(Eq(PlatformWindowState::kNormal), - Eq(PlatformWindowState::kMaximized))) - .Times(1); - // Show the window now. window->Show(false); - Mock::VerifyAndClearExpectations(&delegate); - // Window show state should be already up to date, so delegate is not // notified. EXPECT_CALL(delegate, OnWindowStateChanged(_, _)).Times(0); @@ -1272,8 +1222,8 @@ // Set nonzero insets and ensure that they are only used when the window has // normal state. // See https://crbug.com/1274629 - window_->SetDecorationInsets(&kInsets); - + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kMaximized)) + .WillRepeatedly(Return(gfx::Insets())); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kMaximized))) .Times(1); @@ -1292,6 +1242,8 @@ VerifyAndClearExpectations(); // Unmaximize + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(Return(kInsets)); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); @@ -1319,6 +1271,8 @@ PlatformFullscreenType::kPlain)) .Times(1); #endif + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kFullScreen)) + .WillRepeatedly(Return(gfx::Insets())); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kFullScreen))) .Times(1); @@ -1339,6 +1293,8 @@ PlatformFullscreenType::kNone)) .Times(1); #endif + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(Return(kInsets)); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); @@ -1360,6 +1316,8 @@ VerifyAndClearExpectations(); // Now, maximize, fullscreen and restore. + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kMaximized)) + .WillRepeatedly(Return(gfx::Insets())); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kMaximized))) .Times(1); @@ -1381,6 +1339,8 @@ PlatformFullscreenType::kPlain)) .Times(1); #endif + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kFullScreen)) + .WillRepeatedly(Return(gfx::Insets())); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kFullScreen))) .Times(1); @@ -1401,6 +1361,8 @@ PlatformFullscreenType::kNone)) .Times(1); #endif + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(Return(kInsets)); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); @@ -2382,6 +2344,8 @@ auto bounds_with_insets = kMainWindowBounds; bounds_with_insets.Inset(kMainWindowInsets); EXPECT_CALL(delegate_, OnBoundsChanged(_)); + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(Return(kMainWindowInsets)); PostToServerAndWait([id = surface_id_, bounds_with_insets]( wl::TestWaylandServerThread* server) { wl::MockSurface* mock_surface = server->GetObject<wl::MockSurface>(id); @@ -2390,7 +2354,8 @@ EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets)); }); window_->SetBoundsInDIP(kMainWindowBounds); - window_->SetDecorationInsets(&kMainWindowInsets); + SendConfigureEvent(surface_id_, bounds_with_insets.size(), + MakeStateArray({XDG_TOPLEVEL_STATE_ACTIVATED})); AdvanceFrameToCurrent(window_.get(), delegate_); VerifyAndClearExpectations(); @@ -4847,6 +4812,7 @@ window_->HandleSurfaceConfigure(3); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); + EXPECT_EQ(gfx::Rect(), window_->GetBoundsInDIP()); VerifyAndClearExpectations(); } else { EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); @@ -4863,19 +4829,20 @@ // It must be still the same minimized state. EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); - } + EXPECT_EQ(gfx::Rect(800, 600), window_->GetBoundsInDIP()); - // The window geometry has to be set to the current bounds of the window for - // minimized state. - EXPECT_EQ(gfx::Rect(800, 600), window_->GetBoundsInDIP()); - PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) { - auto* surface = server->GetObject<wl::MockSurface>(id); - auto* xdg_surface = surface->xdg_surface(); - EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); - }); - // Send one additional empty configuration event for minimized state. - // (which means the surface is not maximized, fullscreen or activated) - SendConfigureEvent(surface_id_, {0, 0}, wl::ScopedWlArray({})); + // The window geometry has to be set to the current bounds of the window for + // minimized state. + PostToServerAndWait( + [id = surface_id_](wl::TestWaylandServerThread* server) { + auto* surface = server->GetObject<wl::MockSurface>(id); + auto* xdg_surface = surface->xdg_surface(); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); + }); + // Send one additional empty configuration event for minimized state. + // (which means the surface is not maximized, fullscreen or activated) + SendConfigureEvent(surface_id_, {0, 0}, wl::ScopedWlArray({})); + } } class BlockableWaylandToplevelWindow : public WaylandToplevelWindow {
diff --git a/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.cc b/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.cc index 93993945..b98fd65 100644 --- a/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.cc +++ b/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.cc
@@ -35,6 +35,16 @@ int64_t MockWaylandPlatformWindowDelegate::OnStateUpdate( const PlatformWindowDelegate::State& old, const PlatformWindowDelegate::State& latest) { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (old.fullscreen_type != latest.fullscreen_type) { + OnFullscreenTypeChanged(old.fullscreen_type, latest.fullscreen_type); + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + + if (old.window_state != latest.window_state) { + OnWindowStateChanged(old.window_state, latest.window_state); + } + if (old.bounds_dip != latest.bounds_dip || old.size_px != latest.size_px || old.window_scale != latest.window_scale) { bool origin_changed = old.bounds_dip.origin() != latest.bounds_dip.origin(); @@ -45,7 +55,7 @@ OnOcclusionStateChanged(latest.occlusion_state); } - if (!latest.ProducesFrameOnUpdateFrom(old)) { + if (!latest.WillProduceFrameOnUpdateFrom(old)) { return -1; }
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc index a9509d4..8c87622 100644 --- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -1577,6 +1577,9 @@ PlatformWindowInitProperties properties; properties.type = PlatformWindowType::kWindow; properties.bounds = kNormalBounds; + gfx::Insets insets; + EXPECT_CALL(delegate_, CalculateInsetsInDIP(PlatformWindowState::kNormal)) + .WillRepeatedly(testing::Return(insets)); auto window = WaylandWindow::Create(&delegate_, connection_.get(), std::move(properties)); ASSERT_TRUE(window); @@ -1590,8 +1593,6 @@ window->SetRestoredBoundsInDIP(kRestoredBounds); wl::SyncDisplay(connection_->display_wrapper(), *connection_->display()); - gfx::Insets insets; - window->SetDecorationInsets(&insets); window->Show(false); const uint32_t surface_id = window->root_surface()->get_surface_id();
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc index 55c1e9f..5765eec9 100644 --- a/ui/ozone/platform/x11/x11_window.cc +++ b/ui/ozone/platform/x11/x11_window.cc
@@ -738,14 +738,6 @@ // save this one for later too. should_maximize_after_map_ = !window_mapped_in_client_; - // Some WMs keep respecting the frame extents even if the window is maximised. - // Remove the insets when maximising. The extents will be set again when the - // window is restored to normal state. - // See https://crbug.com/1260821 - if (CanSetDecorationInsets()) { - SetDecorationInsets(nullptr); - } - SetWMSpecState(true, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); } @@ -1105,26 +1097,6 @@ return connection_->WmSupportsHint(x11::GetAtom("_GTK_FRAME_EXTENTS")); } -void X11Window::SetDecorationInsets(const gfx::Insets* insets_px) { - auto atom = x11::GetAtom("_GTK_FRAME_EXTENTS"); - if (!insets_px) { - connection_->DeleteProperty(xwindow_, atom); - return; - } - - // Insets must be zero when the window state is not normal nor unknown. - CHECK(GetPlatformWindowState() == PlatformWindowState::kNormal || - GetPlatformWindowState() == PlatformWindowState::kUnknown || - *insets_px == gfx::Insets(0)); - - connection_->SetArrayProperty( - xwindow_, atom, x11::Atom::CARDINAL, - std::vector<uint32_t>{static_cast<uint32_t>(insets_px->left()), - static_cast<uint32_t>(insets_px->right()), - static_cast<uint32_t>(insets_px->top()), - static_cast<uint32_t>(insets_px->bottom())}); -} - void X11Window::SetOpaqueRegion( std::optional<std::vector<gfx::Rect>> region_px) { auto atom = x11::GetAtom("_NET_WM_OPAQUE_REGION"); @@ -1427,6 +1399,29 @@ base::Unretained(platform_window_delegate()))); } +void X11Window::UpdateDecorationInsets() { + auto atom = x11::GetAtom("_GTK_FRAME_EXTENTS"); + auto insets_dip = + platform_window_delegate_->CalculateInsetsInDIP(GetPlatformWindowState()); + + if (insets_dip.IsEmpty()) { + connection_->DeleteProperty(xwindow_, atom); + return; + } + + // Insets must be zero when the window state is not normal nor unknown. + CHECK(GetPlatformWindowState() == PlatformWindowState::kNormal || + GetPlatformWindowState() == PlatformWindowState::kUnknown); + + auto insets_px = platform_window_delegate_->ConvertInsetsToPixels(insets_dip); + connection_->SetArrayProperty( + xwindow_, atom, x11::Atom::CARDINAL, + std::vector<uint32_t>{static_cast<uint32_t>(insets_px.left()), + static_cast<uint32_t>(insets_px.right()), + static_cast<uint32_t>(insets_px.top()), + static_cast<uint32_t>(insets_px.bottom())}); +} + void X11Window::OnXWindowStateChanged() { // Determine the new window state information to be propagated to the client. // Note that the order of checks is important here, because window can have @@ -1490,6 +1485,9 @@ auto old_state = state_; state_ = new_state; platform_window_delegate_->OnWindowStateChanged(old_state, state_); + if (CanSetDecorationInsets()) { + UpdateDecorationInsets(); + } } WindowTiledEdges tiled_state = GetTiledState();
diff --git a/ui/ozone/platform/x11/x11_window.h b/ui/ozone/platform/x11/x11_window.h index 970946c..b0dc5aa 100644 --- a/ui/ozone/platform/x11/x11_window.h +++ b/ui/ozone/platform/x11/x11_window.h
@@ -118,7 +118,6 @@ void SizeConstraintsChanged() override; void SetOpacity(float opacity) override; bool CanSetDecorationInsets() const override; - void SetDecorationInsets(const gfx::Insets* insets_px) override; void SetOpaqueRegion( std::optional<std::vector<gfx::Rect>> region_px) override; void SetInputRegion(std::optional<std::vector<gfx::Rect>> region_px) override; @@ -167,6 +166,8 @@ FRIEND_TEST_ALL_PREFIXES(X11WindowTest, ToggleMinimizePropogateToPlatformWindowDelegate); + void UpdateDecorationInsets(); + // PlatformEventDispatcher: bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override;
diff --git a/ui/ozone/test/mock_platform_window_delegate.h b/ui/ozone/test/mock_platform_window_delegate.h index abfde546..8f95d8e 100644 --- a/ui/ozone/test/mock_platform_window_delegate.h +++ b/ui/ozone/test/mock_platform_window_delegate.h
@@ -25,6 +25,8 @@ ~MockPlatformWindowDelegate() override; + MOCK_CONST_METHOD1(CalculateInsetsInDIP, + gfx::Insets(PlatformWindowState window_state)); MOCK_METHOD1(OnBoundsChanged, void(const BoundsChange& change)); MOCK_METHOD1(OnDamageRect, void(const gfx::Rect& damaged_region)); MOCK_METHOD1(DispatchEvent, void(Event* event));
diff --git a/ui/platform_window/platform_window.cc b/ui/platform_window/platform_window.cc index 7220192..1171b27a 100644 --- a/ui/platform_window/platform_window.cc +++ b/ui/platform_window/platform_window.cc
@@ -6,7 +6,6 @@ #include <string> -#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" namespace ui { @@ -59,8 +58,6 @@ return false; } -void PlatformWindow::SetDecorationInsets(const gfx::Insets* insets_px) {} - void PlatformWindow::SetOpaqueRegion( std::optional<std::vector<gfx::Rect>> region_px) {}
diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h index c55f403..8fecce04 100644 --- a/ui/platform_window/platform_window.h +++ b/ui/platform_window/platform_window.h
@@ -20,7 +20,6 @@ namespace gfx { class ImageSkia; -class Insets; class Point; class Rect; class SizeF; @@ -177,12 +176,6 @@ // specifying the decoration insets. virtual bool CanSetDecorationInsets() const; - // Lets the WM know which portion of the window is the frame decoration. The - // WM may use this to eg. snap windows to each other starting where the window - // begins rather than starting where the shadow begins. If |insets_px| is - // nullptr, then any existing insets will be reset. - virtual void SetDecorationInsets(const gfx::Insets* insets_px); - // Sets a hint for the compositor so it can avoid unnecessarily redrawing // occluded portions of windows. If |region_px| is nullopt or empty, then any // existing region will be reset.
diff --git a/ui/platform_window/platform_window_delegate.cc b/ui/platform_window/platform_window_delegate.cc index 9afc628..c37954aa 100644 --- a/ui/platform_window/platform_window_delegate.cc +++ b/ui/platform_window/platform_window_delegate.cc
@@ -20,26 +20,34 @@ state == PlatformWindowState::kTrustedPinnedFullscreen; } -bool PlatformWindowDelegate::State::ProducesFrameOnUpdateFrom( +bool PlatformWindowDelegate::State::WillProduceFrameOnUpdateFrom( const State& old) const { - // Changing the bounds origin won't produce a new frame. Anything else will, - // except for the occlusion state. We do not check that here since there isn't - // enough information to determine if it will produce a frame, as it depends - // on whether native occlusion is enabled and if the ui compositor changes - // visibility. - return old.bounds_dip.size() != bounds_dip.size() || old.size_px != size_px || - old.window_scale != window_scale || old.raster_scale != raster_scale || - old.insets != insets; + // Changing the bounds origin or fullscreen type will not produce a new frame. + // Anything else will produce a frame, except for the occlusion state. We do + // not check that here since there isn't enough information to determine if + // it will produce a frame, as it depends on whether native occlusion is + // enabled and if the ui compositor changes visibility. + // Note: Changing the window state produces a new frame as + // OnWindowStateChanged will schedule relayout even without the bounds change. + // On the other hand, the fullscreen type change will not schedule relayout + // and does not affect producing the frame. + return old.window_state != window_state || + old.bounds_dip.size() != bounds_dip.size() || old.size_px != size_px || + old.window_scale != window_scale || old.raster_scale != raster_scale; } std::string PlatformWindowDelegate::State::ToString() const { std::stringstream result; result << "State {"; - result << "bounds_dip = " << bounds_dip.ToString(); + result << "window_state = " << static_cast<int>(window_state); +#if BUILDFLAG(IS_CHROMEOS_LACROS) + result << ", fullscreen_type = " << static_cast<int>(fullscreen_type); +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + result << ", bounds_dip = " << bounds_dip.ToString(); result << ", size_px = " << size_px.ToString(); result << ", window_scale = " << window_scale; result << ", raster_scale = " << raster_scale; - result << ", insets = " << insets.ToString(); + result << ", occlusion_state = " << static_cast<int>(occlusion_state); result << "}"; return result.str(); } @@ -48,6 +56,11 @@ PlatformWindowDelegate::~PlatformWindowDelegate() = default; +gfx::Insets PlatformWindowDelegate::CalculateInsetsInDIP( + PlatformWindowState window_state) const { + return gfx::Insets(); +} + #if BUILDFLAG(IS_LINUX) void PlatformWindowDelegate::OnWindowTiledStateChanged( WindowTiledEdges new_tiled_edges) {} @@ -125,6 +138,11 @@ return gfx::PointF(screen_in_pixels); } +gfx::Insets PlatformWindowDelegate::ConvertInsetsToPixels( + const gfx::Insets& insets_dip) const { + return insets_dip; +} + void PlatformWindowDelegate::DisableNativeWindowOcclusion() {} } // namespace ui
diff --git a/ui/platform_window/platform_window_delegate.h b/ui/platform_window/platform_window_delegate.h index 469db3e..a83d4d52 100644 --- a/ui/platform_window/platform_window_delegate.h +++ b/ui/platform_window/platform_window_delegate.h
@@ -12,15 +12,11 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "ui/base/ui_base_types.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" -#if BUILDFLAG(IS_FUCHSIA) -#include "ui/gfx/geometry/insets.h" -#endif // BUILDFLAG(IS_FUCHSIA) - namespace gfx { -class Rect; class Size; class PointF; } // namespace gfx @@ -116,35 +112,49 @@ // This is used by OnStateChanged and currently only by ozone/wayland. struct COMPONENT_EXPORT(PLATFORM_WINDOW) State { bool operator==(const State& rhs) const { - return std::tie(bounds_dip, size_px, window_scale, raster_scale, insets, + return std::tie(window_state, +#if BUILDFLAG(IS_CHROMEOS_LACROS) + fullscreen_type, +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + bounds_dip, size_px, window_scale, raster_scale, occlusion_state) == - std::tie(rhs.bounds_dip, rhs.size_px, rhs.window_scale, - rhs.raster_scale, rhs.insets, rhs.occlusion_state); + std::tie(rhs.window_state, +#if BUILDFLAG(IS_CHROMEOS_LACROS) + rhs.fullscreen_type, +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + rhs.bounds_dip, rhs.size_px, rhs.window_scale, + rhs.raster_scale, rhs.occlusion_state); } - // Bounds in DIP. + // Current platform window state. + PlatformWindowState window_state = PlatformWindowState::kUnknown; + +#if BUILDFLAG(IS_CHROMEOS_LACROS) + // Current platform fullscreen type. + PlatformFullscreenType fullscreen_type = PlatformFullscreenType::kNone; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + + // Bounds in DIP. The origin of `bounds_dip` does not affect whether it + // produces a new frame or not. Only the size of `bounds_dip` does. gfx::Rect bounds_dip; + // Size in pixels. Note that it's required to keep information in both DIP // and pixels since it is not always possible to convert between them. gfx::Size size_px; + // Current scale factor of the output where the window is located at. float window_scale = 1.0; - // TODO(crbug.com/1395267): Add window states here. // Scale to raster the window at. float raster_scale = 1.0; - // Insets in DIP. Used in platforms where window decorations are drawn by - // the client. - gfx::Insets insets; - // Occlusion state PlatformWindowOcclusionState occlusion_state = PlatformWindowOcclusionState::kUnknown; - // Returns true if updating from the given State |old| to this state + // Returns true if updating from the given State `old` to this state // should produce a frame. - bool ProducesFrameOnUpdateFrom(const State& old) const; + bool WillProduceFrameOnUpdateFrom(const State& old) const; std::string ToString() const; }; @@ -152,6 +162,10 @@ PlatformWindowDelegate(); virtual ~PlatformWindowDelegate(); + // Calculates the insets in dip based on the window state. + virtual gfx::Insets CalculateInsetsInDIP( + PlatformWindowState window_state) const; + virtual void OnBoundsChanged(const BoundsChange& change) = 0; // Note that |damaged_region| is in the platform-window's coordinates, in @@ -264,15 +278,19 @@ // Called when tooltip is hidden on server. virtual void OnTooltipHiddenOnServer(); - // Convert gfx::Rect in pixels to DIP in screen, and vice versa. + // Converts gfx::Rect in pixels to DIP in screen, and vice versa. virtual gfx::Rect ConvertRectToPixels(const gfx::Rect& rect_in_dp) const; virtual gfx::Rect ConvertRectToDIP(const gfx::Rect& rect_in_pixels) const; - // Convert gfx::Point in screen pixels to dip in the window's local + // Converts gfx::Point in screen pixels to dip in the window's local // coordinate. virtual gfx::PointF ConvertScreenPointToLocalDIP( const gfx::Point& screen_in_pixels) const; + // Converts gfx::Insets in DIP to pixels. + virtual gfx::Insets ConvertInsetsToPixels( + const gfx::Insets& insets_dip) const; + // Disables native window occlusion. virtual void DisableNativeWindowOcclusion(); };
diff --git a/ui/platform_window/platform_window_init_properties.h b/ui/platform_window/platform_window_init_properties.h index 2af60f26..37ffb70a 100644 --- a/ui/platform_window/platform_window_init_properties.h +++ b/ui/platform_window/platform_window_init_properties.h
@@ -76,9 +76,6 @@ PlatformWindowType type = PlatformWindowType::kWindow; // Sets the desired initial bounds. Can be empty. gfx::Rect bounds; - // Sets the frame insets. Can be empty. - // TODO(crbug.com/1306688): Use DIP for frame insets. - gfx::Insets frame_insets_px; // Tells PlatformWindow which native widget its parent holds. It is usually // used to find a parent from internal list of PlatformWindows. gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
diff --git a/ui/views/controls/menu/menu_host.cc b/ui/views/controls/menu/menu_host.cc index 05e2952..b42556c 100644 --- a/ui/views/controls/menu/menu_host.cc +++ b/ui/views/controls/menu/menu_host.cc
@@ -19,6 +19,8 @@ #include "ui/base/ui_base_types.h" #include "ui/compositor/compositor.h" #include "ui/events/gestures/gesture_recognizer.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/views/controls/menu/menu_host_root_view.h" @@ -142,11 +144,6 @@ : gfx::NativeWindow(); params.bounds = init_params.bounds; -#if BUILDFLAG(IS_OZONE) - params.frame_insets = - submenu_->GetScrollViewContainer()->outside_border_insets(); -#endif - #if defined(USE_AURA) params.init_properties_container.SetProperty(aura::client::kOwnedWindowAnchor, init_params.owned_window_anchor); @@ -358,6 +355,15 @@ : Widget::GetPrimaryWindowWidget(); } +gfx::Insets MenuHost::GetCustomInsetsInDIP() const { +#if BUILDFLAG(IS_OZONE) + if (submenu_) { + return submenu_->GetScrollViewContainer()->outside_border_insets(); + } +#endif // BUILDFLAG(IS_OZONE) + return gfx::Insets(); +} + void MenuHost::OnWidgetDestroying(Widget* widget) { DCHECK_EQ(GetOwner(), widget); owner_observation_.Reset();
diff --git a/ui/views/controls/menu/menu_host.h b/ui/views/controls/menu/menu_host.h index 7e92e72..fc1d5fc 100644 --- a/ui/views/controls/menu/menu_host.h +++ b/ui/views/controls/menu/menu_host.h
@@ -12,10 +12,14 @@ #include "base/scoped_observation.h" #include "build/build_config.h" #include "ui/base/owned_window_anchor.h" -#include "ui/gfx/geometry/rect.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" +namespace gfx { +class Insets; +class Rect; +} // namespace gfx + namespace views { class MenuControllerTest; @@ -99,6 +103,7 @@ void OnDragWillStart() override; void OnDragComplete() override; Widget* GetPrimaryWindowWidget() override; + gfx::Insets GetCustomInsetsInDIP() const override; // WidgetObserver: void OnWidgetDestroying(Widget* widget) override;
diff --git a/ui/views/test/widget_test.cc b/ui/views/test/widget_test.cc index 1b9bb494..7caed7ab 100644 --- a/ui/views/test/widget_test.cc +++ b/ui/views/test/widget_test.cc
@@ -21,6 +21,8 @@ BUILDFLAG(IS_CHROMEOS_LACROS) #include "ui/views/test/test_desktop_screen_ozone.h" +#elif BUILDFLAG(IS_WIN) +#include "ui/views/widget/desktop_aura/desktop_screen_win.h" #endif namespace views::test { @@ -154,12 +156,14 @@ #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ BUILDFLAG(IS_CHROMEOS_LACROS) screen_ = views::test::TestDesktopScreenOzone::Create(); +#elif BUILDFLAG(IS_WIN) + screen_ = std::make_unique<views::DesktopScreenWin>(); #endif DesktopWidgetTest::SetUp(); } #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ - BUILDFLAG(IS_CHROMEOS_LACROS) + BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) void DesktopWidgetTestInteractive::TearDown() { DesktopWidgetTest::TearDown(); screen_.reset();
diff --git a/ui/views/test/widget_test.h b/ui/views/test/widget_test.h index ff46bb3..37cc265b 100644 --- a/ui/views/test/widget_test.h +++ b/ui/views/test/widget_test.h
@@ -21,7 +21,7 @@ #include "ui/views/widget/widget_observer.h" #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ - BUILDFLAG(IS_CHROMEOS_LACROS) + BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) #include "ui/display/screen.h" #endif @@ -181,7 +181,7 @@ void SetUp() override; #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ - BUILDFLAG(IS_CHROMEOS_LACROS) + BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) void TearDown() override; std::unique_ptr<display::Screen> screen_; #endif
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index b305f5c2..7727cc1 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -131,8 +131,7 @@ } ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( - const Widget::InitParams& params, - float device_scale_factor) { + const Widget::InitParams& params) { ui::PlatformWindowInitProperties properties; properties.type = GetPlatformWindowType(params.type); properties.accept_events = params.accept_events; @@ -171,9 +170,6 @@ } } properties.inhibit_keyboard_shortcuts = params.inhibit_keyboard_shortcuts; - - properties.frame_insets_px = - gfx::ScaleToCeiledInsets(params.frame_insets, device_scale_factor); #endif #if BUILDFLAG(IS_CHROMEOS) @@ -271,7 +267,7 @@ GetContentWindow()->SetProperty(aura::client::kAnimationsDisabledKey, true); ui::PlatformWindowInitProperties properties = - ConvertWidgetInitParamsToInitProperties(params, device_scale_factor()); + ConvertWidgetInitParamsToInitProperties(params); AddAdditionalInitProperties(params, &properties); #if BUILDFLAG(IS_CHROMEOS) @@ -899,6 +895,11 @@ } } +gfx::Insets DesktopWindowTreeHostPlatform::CalculateInsetsInDIP( + ui::PlatformWindowState window_state) const { + return GetWidget()->GetCustomInsetsInDIP(); +} + void DesktopWindowTreeHostPlatform::OnClosed() { open_windows().remove(GetAcceleratedWidget()); wm::SetWindowMoveClient(window(), nullptr);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index e3686175..d116850 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -152,6 +152,8 @@ bool visible) override; // PlatformWindowDelegate: + gfx::Insets CalculateInsetsInDIP( + ui::PlatformWindowState window_state) const override; void OnClosed() override; void OnWindowStateChanged(ui::PlatformWindowState old_state, ui::PlatformWindowState new_state) override;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index d958581d..5f16bddd 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -34,6 +34,8 @@ #include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/views/drag_controller.h" @@ -697,6 +699,10 @@ return GetRestoredBounds().size(); } +gfx::Insets Widget::GetCustomInsetsInDIP() const { + return gfx::Insets(); +} + void Widget::CenterWindow(const gfx::Size& size) { if (native_widget_) native_widget_->CenterWindow(size);
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 0d373af..7519d49 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -28,7 +28,6 @@ #include "ui/color/color_provider_utils.h" #include "ui/display/types/display_constants.h" #include "ui/events/event_source.h" -#include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_observer.h" @@ -42,6 +41,7 @@ } namespace gfx { +class Insets; class Point; class Rect; } // namespace gfx @@ -460,10 +460,6 @@ // window should request the wayland compositor to send key events, // even if it matches with the compositor's keyboard shortcuts. bool inhibit_keyboard_shortcuts = false; - - // Specifies the insets of the Widget. Default is empty, which means no - // insets are to be set. - gfx::Insets frame_insets; #endif // Directly sets the NativeTheme used by the Widget. Providing the @@ -675,6 +671,10 @@ // Retrieves the restored size for the window. gfx::Size GetSize() const; + // Returns the insets that each widget implementation can customize. It + // returns empty insets by default. + virtual gfx::Insets GetCustomInsetsInDIP() const; + // Sizes the window to the specified size and centers it. void CenterWindow(const gfx::Size& size);
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index 18a0c1e..3402b59 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -1412,6 +1412,83 @@ EXPECT_TRUE(widget_window->CanFocus()); } +class SyntheticMouseMoveCounter : public ui::EventHandler { + public: + explicit SyntheticMouseMoveCounter(Widget* widget) : widget_(widget) { + widget_->GetNativeWindow()->AddPreTargetHandler(this); + } + + SyntheticMouseMoveCounter(const SyntheticMouseMoveCounter&) = delete; + SyntheticMouseMoveCounter& operator=(const SyntheticMouseMoveCounter&) = + delete; + + ~SyntheticMouseMoveCounter() override { + widget_->GetNativeWindow()->RemovePreTargetHandler(this); + } + + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + if (event->type() == ui::ET_MOUSE_MOVED && event->IsSynthesized()) { + ++count_; + } + } + + int num_synthetic_mouse_moves() const { return count_; } + + private: + int count_ = 0; + raw_ptr<Widget> widget_; +}; + +#if BUILDFLAG(ENABLE_DESKTOP_AURA) +TEST_F(DesktopWidgetTestInteractive, + DoNotSynthesizeMouseMoveOnVisibilityChangeIfOccluded) { + // Create a top-level widget. + WidgetAutoclosePtr widget_below(CreateTopLevelPlatformDesktopWidget()); + widget_below->SetBounds(gfx::Rect(300, 300)); + widget_below->Show(); + + // Dispatch a mouse event to place cursor inside window bounds. + base::RunLoop run_loop; + ui_controls::SendMouseMoveNotifyWhenDone(150, 150, run_loop.QuitClosure()); + run_loop.Run(); + + // Create a child widget. + UniqueWidgetPtr child = std::make_unique<Widget>(); + Widget::InitParams child_params = + CreateParams(Widget::InitParams::TYPE_WINDOW); + child_params.parent = widget_below->GetNativeView(); + child_params.context = widget_below->GetNativeWindow(); + child->Init(std::move(child_params)); + child->SetBounds(gfx::Rect(300, 300)); + child->Show(); + base::RunLoop().RunUntilIdle(); + + SyntheticMouseMoveCounter counter_below(widget_below.get()); + EXPECT_EQ(0, counter_below.num_synthetic_mouse_moves()); + + // Update the child window's visibility. This should trigger a synthetic + // mouse move event. + child->Hide(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, counter_below.num_synthetic_mouse_moves()); + + // Occlude the existing widget with a new top-level widget. + WidgetAutoclosePtr widget_above(CreateTopLevelPlatformDesktopWidget()); + widget_above->SetBounds(gfx::Rect(300, 300)); + widget_above->Show(); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(widget_above->AsWidget()->IsStackedAbove( + widget_below->AsWidget()->GetNativeView())); + + // Update the child window's visibility again, but this should not trigger a + // synthetic mouse move event, since there's another widget under the cursor. + child->Show(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, counter_below.num_synthetic_mouse_moves()); +} +#endif // BUILDFLAG(ENABLE_DESKTOP_AURA) #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(ENABLE_DESKTOP_AURA) || BUILDFLAG(IS_MAC)