diff --git a/DEPS b/DEPS index 811a846..67645c0 100644 --- a/DEPS +++ b/DEPS
@@ -253,7 +253,7 @@ # luci-go CIPD package version. # Make sure the revision is uploaded by infra-packagers builder. # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console - 'luci_go': 'git_revision:d8c41eecc02cd7b3377a0452eaf704ef315e87ca', + 'luci_go': 'git_revision:4967d21f2b92546ac3747086cdcbb046b6db52fb', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -277,11 +277,11 @@ # screen-ai CIPD packages # TODO(b/281483558): Use a tag to download the latest version of screen-ai # (e.g. 'version:121.3') and find a way to automate updating //DEPS with it. - 'screen_ai_linux': 'version:124.00', - 'screen_ai_macos_amd64': 'version:124.00', - 'screen_ai_macos_arm64': 'version:124.00', - 'screen_ai_windows_amd64': 'version:124.00', - 'screen_ai_windows_386': 'version:124.00', + 'screen_ai_linux': 'version:124.2', + 'screen_ai_macos_amd64': 'version:124.2', + 'screen_ai_macos_arm64': 'version:124.2', + 'screen_ai_windows_amd64': 'version:124.2', + 'screen_ai_windows_386': 'version:124.2', # siso CIPD package version. 'siso_version': 'git_revision:df7a992166415f66f6958744f149f724df138879', @@ -304,27 +304,27 @@ # 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': 'c414ca3036a61b56b801b7e36e55100d04210410', + 'src_internal_revision': 'af84be9cfd1e15eeb537bf247d1929aedbb5f222', # 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': '93ed643df6d12cfaa553e0734e2828ef916a6b32', + 'skia_revision': '371f52a008fa5a40ba0ae5592560bc3732a53691', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '5ce5de190d00a6d32b6d15f89d169bcf7d70e3be', + 'v8_revision': '1d5b4690a511c9a6c44ee270a11681a4d23c0eb9', # 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': '322608986a23c1d76507d5b66b3f3b915393d95a', + 'angle_revision': '602c0edfc1f23b062bd138f989e43c765594dd27', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'da334852e70510d259bfa8cbaa7c5412966b2f41', + 'swiftshader_revision': 'bf0c5d6b9d00babdc2bef77dc383f9c2efed56ea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '8007d6ed5cd165d13c5655f9a230b58cf10195f0', + 'pdfium_revision': 'd4b014a1b48e326ac526877cd8697da283aaa479', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -335,7 +335,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:20.20240515.2.1', + 'fuchsia_version': 'version:20.20240522.3.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -383,7 +383,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling chromium_variations # and whatever else without interference from each other. - 'chromium_variations_revision': '2ae5d111a8fed78bb687ca076f7a030518aca354', + 'chromium_variations_revision': 'f870ca90e89acf3414674cd9cbf3a78724703953', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -423,7 +423,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': '45d8537d934741a7a9c55b3fe05af3bd5c83cbba', + 'dawn_revision': '7f081d88a6c1faa8753e3305ba0a0822de3fea7e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -443,7 +443,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libavif # and whatever else without interference from each other. - 'libavif_revision': '5d97130f0820dbc97738f5480e2dd00865a35744', + 'libavif_revision': 'd369ffb6a21646395df9c57ae7c0545bf6846101', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling crabbyavif # and whatever else without interference from each other. @@ -459,7 +459,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': 'bf9b5ccb915b301909530db50e6a1b11adbb4d59', + 'nearby_revision': '76a99ec941961c46f685d2a8e777f58427ea77f2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -479,11 +479,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libcxxabi_revision': '5067b87e93fc1ffbe3ba332dda932a605307538e', + 'libcxxabi_revision': 'ba370858669b1e905db5ded82c8887095b61dc14', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libunwind_revision': 'c6e0c0519bc3f2c7854cdef30bdd5699b475464c', + 'libunwind_revision': '0906c4a31502cc7a46b5cf1794e21664ffa23be1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1004,7 +1004,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '4cf2d33f8d37edf5f5e1871ff6f930576f6686bb', + '052219a0c9b8e1c4af50ef4be1a43d92e31d19b4', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1163,7 +1163,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '3DrZE5aR3dp-Q-txsGsnP_F3kcFhSWntvOQBqy9mASkC', + 'version': 'XfjjEUcD39PJCZHKqeWU90_Esp5GFEetk4kpIPZWRZsC', }, ], 'condition': 'checkout_android', @@ -1460,13 +1460,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0c557985c77daa1a809f5a6c2e04e69b792142e9', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '062ecac69f7149d88a467eef91f707f441d62b1d', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '83c9067bf25af9a9d508ca2e7d52b383f27e64c2', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'c036b5ae55b11a90127727a310ffac94515f82e3', 'condition': 'checkout_src_internal', }, @@ -1502,7 +1502,7 @@ Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '689da3a7ed50af7448c3f1961d1791c7c1d9c85c', 'src/third_party/flatbuffers/src': - Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + 'c696275eaffec33796b5ca8755614fd9fec0a6a7', + Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + '150644d7f4d030a0629c564fd90dc3becab77636', # Used for embedded builds. CrOS & Linux use the system version. 'src/third_party/fontconfig/src': { @@ -1930,7 +1930,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '09a4f3ec842a8932341b195c5b01e141c8a16eb7', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + 'f90b21d85c04e51f0477042d0071db520e152593', + Var('chromium_git') + '/openscreen' + '@' + '2fdf9fc760444fa335a6750a85d2fa5b6d5db215', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '95fe35ffb383710a6e0567e958ead9a3b66e930c', @@ -1956,7 +1956,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'fe95ade50a871086b1cfeab9e8374a916bc12b71', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f235f50590e878113c2fc6eec85ebb5ac47b98dd', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '8ef97ff3b7332e38e61b347a2fbed425a4617151', @@ -2120,7 +2120,7 @@ Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', 'src/third_party/tflite/src': - Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '6b9a25f438944132acc54ecf2c59af53c10fd6a1', + Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'd0e577447a11533887249e87e0f9b701d00d527c', 'src/third_party/turbine': { 'packages': [ @@ -2170,10 +2170,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '1b6371436a0a60e6b9a4ae2a40a8eba198e3af02', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '6e29c73079d25269c5d21890f75e08755472b964', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9af84b8d4827c98cd914ebcdacdc6500a846d19a', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '3ffa0e8b6fe73b4a8da9728961d66b17be7b3ec5', + Var('webrtc_git') + '/src.git' + '@' + 'c78f25b7f075d81a2fa17d2b95174be66d51e7cb', # 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. @@ -2198,7 +2198,7 @@ }, 'src/third_party/xnnpack/src': - Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'c9f0470750e7c3c71974cdb997aeb2990d2e2137', + Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'fcb36699c67201ceff7358df42730809e8f2c9cc', 'src/tools/page_cycler/acid3': Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + 'a926d0a32e02c4c03ae95bb798e6c780e0e184ba', @@ -2223,7 +2223,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': '7-DrXBcE9_d-PP6NOnYRSjcuWtwlfgm_C7_8iBP2RFkC', + 'version': 'WMIZj5iCtXaIDiOhz7iiswLMOl8EWWP5gfRyHAEZUSAC', }, ], 'dep_type': 'cipd', @@ -2244,7 +2244,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': '_6-QNIubxnbUvaf2R8w93IgHCXjToAd5-nvN_bPk6DwC', + 'version': '88_YxpnUWyvy_qTnp6FH2cvFsJ3eKeNLLph6CbyXHmoC', }, ], 'dep_type': 'cipd', @@ -2255,7 +2255,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-arm64', - 'version': 'e5gXAjbGt-iz-DoY5wlpOj1ksBMOQR3xGjIdnP1qAj4C', + 'version': 'TtqdFmghiNp8fsnpcuBhyC8e9PjVxKAXDBQhNoTReaUC', }, ], 'dep_type': 'cipd', @@ -2307,7 +2307,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'P4FPxrqADFh0_jZwXT11-DL2tdJIIa1aWQS3kPhqbpoC', + 'version': 'NOUfHK_KLngwCs5ha9DmLaveyfEMtXO0vESSdm5cG9EC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4133,7 +4133,7 @@ # Dependencies from src_internal 'src/chromeos/ash/resources/internal': { 'url': Var('chrome_git') + '/chrome/chromeos/ash/resources/internal.git' + '@' + - '70bca0e40f5fbbfc98120d9c45d3946b172415b0', + '2535bda7eaf460b4c563f8ca62908818463e9d12', 'condition': 'checkout_src_internal and checkout_chromeos', }, @@ -4214,7 +4214,7 @@ 'src/chrome/browser/platform_experience/win': { 'url': Var('chrome_git') + '/chrome/browser/platform_experience/win.git' + '@' + - '8789889d7ba6da10e53a0bcca61418518dd7ad8d', + 'e11c66cf5dcfd34a03fbd475d93b8a068b9479ee', 'condition': 'checkout_src_internal', }, @@ -4350,7 +4350,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '3f6d9031ecaca37232dc4d1dfbf1d901dee9edb4', + 'aead1bc58636071403043aedcb96f127d4c6474d', 'condition': 'checkout_src_internal', }, @@ -4410,7 +4410,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '380efce15f92daa9a34e1c96fcfc10cd0464ff9e', + 'ddc67fe02ca572ab3c10c406506a45b727265d71', 'condition': 'checkout_ios and checkout_src_internal', }, @@ -5747,6 +5747,18 @@ 'gs://aom-test-data', 'src/third_party/libaom/testdata'] }, + { + 'name': 'libvpx_testdata', + 'pattern': '.', + 'condition': 'download_libvpx_testdata', + 'action': ['python3', + 'src/third_party/depot_tools/gsutil.py', + '-q', + '-m', + 'rsync', + 'gs://downloads.webmproject.org/test_data/libvpx', + 'src/third_party/libvpx/testdata'], + }, ] # Add any corresponding DEPS files from this list to chromium.exclusions in
diff --git a/WATCHLISTS b/WATCHLISTS index 4910749..acdede6 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1623,7 +1623,8 @@ 'chrome/browser/resources/ash/settings/nearby_share_page/|'\ 'chrome/browser/ui/webui/nearby_internals/|'\ 'chrome/browser/ui/webui/nearby_share/|'\ - 'chrome/services/sharing/' + 'chrome/services/sharing/|'\ + 'chromeos/ash/components/nearby/common/' }, 'nearby_presence': { 'filepath': 'chrome/browser/ash/nearby/|'\ @@ -3062,7 +3063,6 @@ 'creis+watch@chromium.org', 'navigation-cc+reviews@chromium.org'], 'nearby': ['ajayramamurthy+watch-nearby@google.com', - 'cclem+watch-nearby@google.com', 'crisrael+watch-nearby@google.com', 'dclasson+watch-nearby@google.com', 'hais+watch-nearby@google.com', @@ -3241,7 +3241,6 @@ 'alexmos+watch@chromium.org', 'creis+watch@chromium.org'], 'smartlock': ['bhartmire+watch-smartlock@google.com', - 'cclem+watch-smartlock@google.com', 'ajayramamurthy+watch-smartlock@google.com', 'hansberry+watch-smartlock@chromium.org', 'jackshira+watch-smartlock@google.com', @@ -3295,7 +3294,6 @@ 'test_runner': ['einbinder+watch-test-runner@chromium.org'], 'tests': [], 'tether': ['bhartmire+watch-tether@google.com', - 'cclem+watch-tether@google.com', 'ajayramamurthy+watch-tether@google.com', 'hansberry+watch-tether@chromium.org', 'jackshira+watch-tether@google.com',
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index bf8c14a..9cd0326d 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -1004,6 +1004,8 @@ Flag.baseFeature("WebViewVizUseThreadPool"), Flag.baseFeature("InProcessGpuUseIOThread"), Flag.baseFeature("EnableCustomInputStreamBufferSize"), + Flag.baseFeature("NetworkServiceDedicatedThread"), + Flag.baseFeature("BrowserThreadPoolAdjustment"), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/ash/accessibility/mouse_keys/mouse_keys_controller.cc b/ash/accessibility/mouse_keys/mouse_keys_controller.cc index 8a55df6..83fce19 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_controller.cc +++ b/ash/accessibility/mouse_keys/mouse_keys_controller.cc
@@ -25,6 +25,8 @@ kLeftHandedKeys({ {ui::DomCode::US_W, MouseKeysController::kKeyClick}, {ui::DomCode::US_V, MouseKeysController::kKeyDoubleClick}, + {ui::DomCode::US_Z, MouseKeysController::kKeyDragStart}, + {ui::DomCode::US_C, MouseKeysController::kKeyDragStop}, {ui::DomCode::DIGIT1, MouseKeysController::kKeyUpLeft}, {ui::DomCode::DIGIT2, MouseKeysController::kKeyUp}, {ui::DomCode::DIGIT3, MouseKeysController::kKeyUpRight}, @@ -40,6 +42,8 @@ kRightHandedKeys({ {ui::DomCode::US_I, MouseKeysController::kKeyClick}, {ui::DomCode::SLASH, MouseKeysController::kKeyDoubleClick}, + {ui::DomCode::US_M, MouseKeysController::kKeyDragStart}, + {ui::DomCode::PERIOD, MouseKeysController::kKeyDragStop}, {ui::DomCode::DIGIT7, MouseKeysController::kKeyUpLeft}, {ui::DomCode::DIGIT8, MouseKeysController::kKeyUp}, {ui::DomCode::DIGIT9, MouseKeysController::kKeyUpRight}, @@ -54,6 +58,8 @@ const base::flat_map<ui::DomCode, MouseKeysController::MouseKey> kNumPadKeys({ {ui::DomCode::NUMPAD5, MouseKeysController::kKeyClick}, {ui::DomCode::NUMPAD_ADD, MouseKeysController::kKeyDoubleClick}, + {ui::DomCode::NUMPAD0, MouseKeysController::kKeyDragStart}, + {ui::DomCode::NUMPAD_DECIMAL, MouseKeysController::kKeyDragStop}, {ui::DomCode::NUMPAD7, MouseKeysController::kKeyUpLeft}, {ui::DomCode::NUMPAD8, MouseKeysController::kKeyUp}, {ui::DomCode::NUMPAD9, MouseKeysController::kKeyUpRight}, @@ -103,7 +109,8 @@ paused_ = !paused_; if (paused_) { // Reset everything when pausing. - Reset(); + ResetMovement(); + dragging_ = false; } return true; } @@ -170,11 +177,10 @@ ::wm::ConvertPointFromScreen(root_window, &location_in_pixels); aura::WindowTreeHost* host = root_window->GetHost(); host->ConvertDIPToPixels(&location_in_pixels); - ui::MouseEvent press_event(type, location_in_pixels, location_in_pixels, - ui::EventTimeForNow(), event_flags | button, - button); + ui::MouseEvent event(type, location_in_pixels, location_in_pixels, + ui::EventTimeForNow(), event_flags | button, button); - (void)host->GetEventSink()->OnEventFromSource(&press_event); + (void)host->GetEventSink()->OnEventFromSource(&event); } void MouseKeysController::MoveMouse(const gfx::Vector2d& move_delta_dip) { @@ -196,6 +202,9 @@ } host->MoveCursorToLocationInDIP(location); + if (dragging_) { + SendMouseEventToLocation(ui::ET_MOUSE_DRAGGED, location); + } last_mouse_position_dips_ = location; } @@ -232,6 +241,7 @@ } void MouseKeysController::PressKey(MouseKey key) { + pressed_keys_[key] = true; switch (key) { case kKeyUpLeft: case kKeyUp: @@ -241,11 +251,22 @@ case kKeyDownLeft: case kKeyDown: case kKeyDownRight: - pressed_keys_[key] = true; RefreshVelocity(); break; case kKeyClick: - SendMouseEventToLocation(ui::ET_MOUSE_PRESSED, last_mouse_position_dips_); + case kKeyDragStart: + if (!dragging_) { + SendMouseEventToLocation(ui::ET_MOUSE_PRESSED, + last_mouse_position_dips_); + dragging_ = true; + } + break; + case kKeyDragStop: + if (dragging_) { + SendMouseEventToLocation(ui::ET_MOUSE_RELEASED, + last_mouse_position_dips_); + dragging_ = false; + } break; case kKeyDoubleClick: if (current_mouse_button_ == kLeft) { @@ -280,11 +301,36 @@ } void MouseKeysController::ReleaseKey(MouseKey key) { - if (key == kKeyClick) { - SendMouseEventToLocation(ui::ET_MOUSE_RELEASED, last_mouse_position_dips_); - } else { - pressed_keys_[key] = false; - RefreshVelocity(); + pressed_keys_[key] = false; + switch (key) { + case kKeyUpLeft: + case kKeyUp: + case kKeyUpRight: + case kKeyLeft: + case kKeyRight: + case kKeyDownLeft: + case kKeyDown: + case kKeyDownRight: + RefreshVelocity(); + break; + case kKeyClick: + if (dragging_) { + SendMouseEventToLocation(ui::ET_MOUSE_RELEASED, + last_mouse_position_dips_); + dragging_ = false; + } + break; + case kKeyDragStart: + case kKeyDragStop: + case kKeyDoubleClick: + case kKeySelectLeftButton: + case kKeySelectRightButton: + case kKeySelectBothButtons: + case kKeySelectNextButton: + break; + case kKeyCount: + NOTREACHED_IN_MIGRATION(); + break; } } @@ -329,7 +375,7 @@ if (x_direction == 0 && y_direction == 0) { // Reset everything if there is no movement. - Reset(); + ResetMovement(); return; } @@ -356,7 +402,7 @@ speed_ = std::clamp(speed_ + acceleration, 0.0, max_speed_); } -void MouseKeysController::Reset() { +void MouseKeysController::ResetMovement() { speed_ = 0; if (update_timer_.IsRunning()) { update_timer_.Stop();
diff --git a/ash/accessibility/mouse_keys/mouse_keys_controller.h b/ash/accessibility/mouse_keys/mouse_keys_controller.h index e0dea0a9..b3db8f3 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_controller.h +++ b/ash/accessibility/mouse_keys/mouse_keys_controller.h
@@ -72,6 +72,8 @@ kKeyDownRight, kKeyClick, kKeyDoubleClick, + kKeyDragStart, + kKeyDragStop, kKeySelectLeftButton, kKeySelectRightButton, kKeySelectBothButtons, @@ -104,7 +106,7 @@ void SelectNextButton(); void RefreshVelocity(); void UpdateState(); - void Reset(); + void ResetMovement(); bool enabled_ = false; bool paused_ = false; @@ -117,6 +119,7 @@ MouseButton current_mouse_button_ = kLeft; bool pressed_keys_[kKeyCount]; + bool dragging_ = false; gfx::Point last_mouse_position_dips_ = gfx::Point(-1, -1); int event_flags_ = 0; base::RepeatingTimer update_timer_;
diff --git a/ash/accessibility/mouse_keys/mouse_keys_unittest.cc b/ash/accessibility/mouse_keys/mouse_keys_unittest.cc index e4144394..e5653bb 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_unittest.cc +++ b/ash/accessibility/mouse_keys/mouse_keys_unittest.cc
@@ -677,7 +677,7 @@ auto mouse_events = CheckForMouseEvents(); EXPECT_EQ(0u, CheckForKeyEvents().size()); - EXPECT_EQ(10u, mouse_events.size()); + ASSERT_EQ(10u, mouse_events.size()); gfx::Vector2d move_delta(kMoveDeltaDIP * kMaxSpeed, 0); auto position = kDefaultPosition; for (size_t i = 0; i < mouse_events.size(); ++i) { @@ -935,4 +935,151 @@ EXPECT_EQ(18u, CheckForKeyEvents().size()); } +TEST_F(MouseKeysTest, Dragging) { + // Enough time for the initial event and 9 updates. + constexpr auto kTenEventsInSeconds = + MouseKeysController::kUpdateFrequencyInSeconds * 9.5; + GetEventGenerator()->MoveMouseToWithNative(kDefaultPosition, + kDefaultPosition); + SetEnabled(true); + // No acceleration. + constexpr int kMaxSpeed = 3; + SetMaxSpeed(kMaxSpeed); + SetAcceleration(0); + + // Start Drag. + ClearEvents(); + PressAndReleaseKey(ui::VKEY_M); + auto mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), kDefaultPosition); + + // Move right. + ClearEvents(); + PressKey(ui::VKEY_O); + task_environment()->FastForwardBy(base::Seconds(kTenEventsInSeconds)); + ReleaseKey(ui::VKEY_O); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(10u, mouse_events.size()); + gfx::Vector2d move_delta(kMoveDeltaDIP * kMaxSpeed, 0); + auto position = kDefaultPosition; + for (size_t i = 0; i < mouse_events.size(); ++i) { + position += move_delta; + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, mouse_events[i].type()); + EXPECT_EQ(mouse_events[i].location(), position); + } + + // Stop Drag. + ClearEvents(); + PressAndReleaseKey(ui::VKEY_OEM_PERIOD); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), position); +} + +TEST_F(MouseKeysTest, DragWithClick) { + // Enough time for the initial event and 9 updates. + constexpr auto kTenEventsInSeconds = + MouseKeysController::kUpdateFrequencyInSeconds * 9.5; + GetEventGenerator()->MoveMouseToWithNative(kDefaultPosition, + kDefaultPosition); + SetEnabled(true); + // No acceleration. + constexpr int kMaxSpeed = 3; + SetMaxSpeed(kMaxSpeed); + SetAcceleration(0); + + // Start Drag. + ClearEvents(); + PressKey(ui::VKEY_I); + auto mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), kDefaultPosition); + + // Move right. + ClearEvents(); + PressKey(ui::VKEY_O); + task_environment()->FastForwardBy(base::Seconds(kTenEventsInSeconds)); + ReleaseKey(ui::VKEY_O); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(10u, mouse_events.size()); + gfx::Vector2d move_delta(kMoveDeltaDIP * kMaxSpeed, 0); + auto position = kDefaultPosition; + for (size_t i = 0; i < mouse_events.size(); ++i) { + position += move_delta; + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, mouse_events[i].type()); + EXPECT_EQ(mouse_events[i].location(), position); + } + + // Stop Drag. + ClearEvents(); + ReleaseKey(ui::VKEY_I); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), position); +} + +TEST_F(MouseKeysTest, DragWithMixed) { + // Enough time for the initial event and 9 updates. + constexpr auto kTenEventsInSeconds = + MouseKeysController::kUpdateFrequencyInSeconds * 9.5; + GetEventGenerator()->MoveMouseToWithNative(kDefaultPosition, + kDefaultPosition); + SetEnabled(true); + // No acceleration. + constexpr int kMaxSpeed = 3; + SetMaxSpeed(kMaxSpeed); + SetAcceleration(0); + + // Start Drag. + ClearEvents(); + PressAndReleaseKey(ui::VKEY_M); + auto mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), kDefaultPosition); + + // Move right. + ClearEvents(); + PressKey(ui::VKEY_O); + task_environment()->FastForwardBy(base::Seconds(kTenEventsInSeconds)); + ReleaseKey(ui::VKEY_O); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(10u, mouse_events.size()); + gfx::Vector2d move_delta(kMoveDeltaDIP * kMaxSpeed, 0); + auto position = kDefaultPosition; + for (size_t i = 0; i < mouse_events.size(); ++i) { + position += move_delta; + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, mouse_events[i].type()); + EXPECT_EQ(mouse_events[i].location(), position); + } + + // Stop Drag. + ClearEvents(); + PressAndReleaseKey(ui::VKEY_I); + mouse_events = CheckForMouseEvents(); + EXPECT_EQ(0u, CheckForKeyEvents().size()); + ASSERT_EQ(1u, mouse_events.size()); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, mouse_events[0].type()); + EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & mouse_events[0].flags()); + EXPECT_EQ(mouse_events[0].location(), position); +} + } // namespace ash
diff --git a/ash/app_list/app_list_metrics.cc b/ash/app_list/app_list_metrics.cc index 40cf513..547a09a 100644 --- a/ash/app_list/app_list_metrics.cc +++ b/ash/app_list/app_list_metrics.cc
@@ -428,6 +428,7 @@ case CommandId::REORDER_BY_NAME_REVERSE_ALPHABETICAL: case CommandId::REORDER_BY_COLOR: case CommandId::SHUTDOWN_GUEST_OS: + case CommandId::SHUTDOWN_BRUSCHETTA_OS: case CommandId::EXTENSIONS_CONTEXT_CUSTOM_FIRST: case CommandId::EXTENSIONS_CONTEXT_CUSTOM_LAST: case CommandId::COMMAND_ID_COUNT:
diff --git a/ash/birch/birch_item.cc b/ash/birch/birch_item.cc index 5e46b10..87d8109 100644 --- a/ash/birch/birch_item.cc +++ b/ash/birch/birch_item.cc
@@ -566,12 +566,14 @@ const GURL& url, const base::Time& shared_time, const std::u16string& device_name, - GURL& favicon_url) + GURL& favicon_url, + base::RepeatingClosure callback) : BirchItem(title, GetSubtitle(device_name, shared_time)), guid_(guid), url_(url), shared_time_(shared_time), - favicon_url_(favicon_url) {} + favicon_url_(favicon_url), + activation_callback_(std::move(callback)) {} BirchSelfShareItem::BirchSelfShareItem(BirchSelfShareItem&&) = default; @@ -600,12 +602,14 @@ } void BirchSelfShareItem::PerformAction() { - // TODO(b/333412417): Scope how to mark entry opened. if (!url_.is_valid()) { LOG(ERROR) << "No valid URL for self " "share item"; return; } + if (activation_callback_) { + activation_callback_.Run(); + } RecordActionMetrics(); NewWindowDelegate::GetPrimary()->OpenUrl( url_, NewWindowDelegate::OpenUrlFrom::kUserInteraction,
diff --git a/ash/birch/birch_item.h b/ash/birch/birch_item.h index 1d451c9..32b7658e 100644 --- a/ash/birch/birch_item.h +++ b/ash/birch/birch_item.h
@@ -299,7 +299,8 @@ const GURL& url, const base::Time& shared_time, const std::u16string& device_name, - GURL& favicon_url); + GURL& favicon_url, + base::RepeatingClosure activation_callback); BirchSelfShareItem(BirchSelfShareItem&&); BirchSelfShareItem(const BirchSelfShareItem&); BirchSelfShareItem& operator=(const BirchSelfShareItem&); @@ -326,6 +327,10 @@ GURL url_; base::Time shared_time_; GURL favicon_url_; + // `activation_callback_` is triggered when the item is clicked by the user, + // calling `OnItemPressed()` in `BirchSelfShareProvider` to mark the + // corresponding `SendTabToSelfEntry` as opened. + base::RepeatingClosure activation_callback_; }; class ASH_EXPORT BirchWeatherItem : public BirchItem {
diff --git a/ash/birch/birch_item_remover_unittest.cc b/ash/birch/birch_item_remover_unittest.cc index 0a4f68e..5316e17 100644 --- a/ash/birch/birch_item_remover_unittest.cc +++ b/ash/birch/birch_item_remover_unittest.cc
@@ -65,16 +65,16 @@ GURL favicon_url = GURL("https://favicon.com"); BirchSelfShareItem item0(u"item0_guid", u"item0_title", GURL("https://example.com/0"), base::Time(), - u"device_name", favicon_url); + u"device_name", favicon_url, base::DoNothing()); BirchSelfShareItem item1(u"item1_guid", u"item1_title", GURL("https://example.com/1"), base::Time(), - u"device_name", favicon_url); + u"device_name", favicon_url, base::DoNothing()); BirchSelfShareItem item2(u"item2_guid", u"item2_title", GURL("https://example.com/2"), base::Time(), - u"device_name", favicon_url); + u"device_name", favicon_url, base::DoNothing()); BirchSelfShareItem item3(u"item3_guid", u"item3_title", GURL("https://example.com/3"), base::Time(), - u"device_name", favicon_url); + u"device_name", favicon_url, base::DoNothing()); std::vector<BirchSelfShareItem> self_share_items = {item0, item1, item2, item3};
diff --git a/ash/birch/birch_item_unittest.cc b/ash/birch/birch_item_unittest.cc index 2283c838..d61b078e 100644 --- a/ash/birch/birch_item_unittest.cc +++ b/ash/birch/birch_item_unittest.cc
@@ -16,8 +16,10 @@ #include "ash/system/time/calendar_unittest_utils.h" #include "ash/test/ash_test_base.h" #include "base/files/file_path.h" +#include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_mock_clock_override.h" #include "base/test/test_future.h" @@ -460,6 +462,21 @@ 1); } +TEST_F(BirchItemTest, SelfShare_PerformAction) { + GURL favicon_url("https://www.favicon.com/"); + base::MockCallback<base::RepeatingClosure> activation_callback; + BirchSelfShareItem item( + /*guid=*/u"self share guid", /*title*/ u"self share tab", + /*url=*/GURL("https://www.example.com/"), + /*shared_time=*/base::Time(), /*device_name=*/u"my device", + /*favicon_url=*/favicon_url, + /*activation_callback=*/activation_callback.Get()); + EXPECT_CALL(activation_callback, Run).Times(1); + item.PerformAction(); + EXPECT_EQ(new_window_delegate_->last_opened_url_, + GURL("https://www.example.com/")); +} + //////////////////////////////////////////////////////////////////////////////// // The icon downloader requires ash::Shell, so use AshTestBase.
diff --git a/ash/birch/birch_model.h b/ash/birch/birch_model.h index 6882c679..90357de 100644 --- a/ash/birch/birch_model.h +++ b/ash/birch/birch_model.h
@@ -126,7 +126,7 @@ const std::vector<BirchMostVisitedItem>& GetMostVisitedItemsForTest() const { return most_visited_data_.items; } - const std::vector<BirchSelfShareItem>& GetSelfShareItemsForTest() const { + std::vector<BirchSelfShareItem>& GetSelfShareItemsForTest() { return self_share_data_.items; } const std::vector<BirchReleaseNotesItem>& GetReleaseNotesItemsForTest()
diff --git a/ash/birch/birch_model_unittest.cc b/ash/birch/birch_model_unittest.cc index 874e69b4..1e5f288 100644 --- a/ash/birch/birch_model_unittest.cc +++ b/ash/birch/birch_model_unittest.cc
@@ -503,9 +503,9 @@ model->SetMostVisitedItems(std::move(most_visited_list)); std::vector<BirchSelfShareItem> self_share_item_list; GURL faviconUrl = GURL("https://www.favicon.com/"); - self_share_item_list.emplace_back(u"self share guid", u"self share tab", - GURL("https://www.example.com/"), - base::Time(), u"my device", faviconUrl); + self_share_item_list.emplace_back( + u"self share guid", u"self share tab", GURL("https://www.example.com/"), + base::Time(), u"my device", faviconUrl, base::DoNothing()); model->SetSelfShareItems(std::move(self_share_item_list)); std::vector<BirchWeatherItem> weather_item_list; weather_item_list.emplace_back(u"cloudy", u"16 c", ui::ImageModel()); @@ -835,9 +835,9 @@ std::vector<BirchSelfShareItem> self_share_item_list; GURL faviconUrl = GURL("https://www.favicon.com/"); - self_share_item_list.emplace_back(u"self share guid", u"self share tab", - GURL("foo.bar.two"), base::Time(), - u"my device", faviconUrl); + self_share_item_list.emplace_back( + u"self share guid", u"self share tab", GURL("foo.bar.two"), base::Time(), + u"my device", faviconUrl, base::DoNothing()); model->SetSelfShareItems(std::move(self_share_item_list)); EXPECT_THAT(consumer.items_ready_responses(), testing::IsEmpty()); @@ -980,9 +980,9 @@ model->SetMostVisitedItems(std::move(most_visited_list)); std::vector<BirchSelfShareItem> self_share_item_list; GURL faviconUrl = GURL("favicon"); - self_share_item_list.emplace_back(u"self share guid", u"self share tab", - GURL("foo.bar.two"), base::Time(), - u"my device", faviconUrl); + self_share_item_list.emplace_back( + u"self share guid", u"self share tab", GURL("foo.bar.two"), base::Time(), + u"my device", faviconUrl, base::DoNothing()); model->SetSelfShareItems(std::move(self_share_item_list)); model->SetCalendarItems(MakeCalendarItemList(/*event_count=*/1)); model->SetAttachmentItems(MakeAttachmentItemList(/*item_count=*/1)); @@ -1466,9 +1466,9 @@ std::vector<BirchSelfShareItem> self_share_item_list; GURL faviconUrl = GURL("https://www.favicon.com/"); - self_share_item_list.emplace_back(u"self share guid", u"self share tab", - GURL("https://www.example.com/"), - base::Time(), u"my device", faviconUrl); + self_share_item_list.emplace_back( + u"self share guid", u"self share tab", GURL("https://www.example.com/"), + base::Time(), u"my device", faviconUrl, base::DoNothing()); model->SetSelfShareItems(std::move(self_share_item_list)); std::vector<std::unique_ptr<BirchItem>> all_items = model->GetAllItems(); @@ -1497,7 +1497,8 @@ GURL faviconUrl = GURL("https://www.favicon.com/"); self_share_item_list.emplace_back(u"self share guid", u"self share tab", GURL("https://www.exampletwo.com/"), - base::Time(), u"my device", faviconUrl); + base::Time(), u"my device", faviconUrl, + base::DoNothing()); model->SetSelfShareItems(std::move(self_share_item_list)); std::vector<std::unique_ptr<BirchItem>> all_items = model->GetAllItems();
diff --git a/ash/components/arc/arc_features.cc b/ash/components/arc/arc_features.cc index 1817ba14..93c4445 100644 --- a/ash/components/arc/arc_features.cc +++ b/ash/components/arc/arc_features.cc
@@ -191,29 +191,38 @@ "ArcFilePickerExperiment", base::FEATURE_ENABLED_BY_DEFAULT); -// Controls whether the guest zram is enabled. This is only for ARCVM. -BASE_FEATURE(kGuestZram, "ArcGuestZram", base::FEATURE_DISABLED_BY_DEFAULT); +// Controls whether the guest swap is enabled. This is only for ARCVM. +BASE_FEATURE(kGuestSwap, "ArcGuestZram", base::FEATURE_DISABLED_BY_DEFAULT); -// Controls the size of the guest zram by an absolute value. Ignored if +// Controls the size of the guest swap area by an absolute value. Ignored if // "size_percentage" is set. -const base::FeatureParam<int> kGuestZramSize{&kGuestZram, "size", 0}; +const base::FeatureParam<int> kGuestSwapSize{&kGuestSwap, "size", 0}; -// Controls the size of the guest zram by a percentage of the VM memory size. -const base::FeatureParam<int> kGuestZramSizePercentage{&kGuestZram, +// Controls the size of the guest swap area by a percentage of the VM memory +// size. +const base::FeatureParam<int> kGuestZramSizePercentage{&kGuestSwap, "size_percentage", 0}; // Controls swappiness for the ARCVM guest. -const base::FeatureParam<int> kGuestZramSwappiness{&kGuestZram, "swappiness", +const base::FeatureParam<int> kGuestZramSwappiness{&kGuestSwap, "swappiness", 0}; // Controls whether to do per-process reclaim from the ARCVM guest. const base::FeatureParam<bool> kGuestReclaimEnabled{ - &kGuestZram, "guest_reclaim_enabled", false}; + &kGuestSwap, "guest_reclaim_enabled", false}; // Controls whether only anonymous pages are reclaimed from the ARCVM guest. // Ignored when the "guest_reclaim_enabled" param is false. const base::FeatureParam<bool> kGuestReclaimOnlyAnonymous{ - &kGuestZram, "guest_reclaim_only_anonymous", false}; + &kGuestSwap, "guest_reclaim_only_anonymous", false}; + +// Controls whether to enable virtual swap device for ARCVM. +const base::FeatureParam<bool> kVirtualSwapEnabled{ + &kGuestSwap, "virtual_swap_enabled", false}; + +// Controls how often ARCVM's virtual swap device is swapped out in the host. +const base::FeatureParam<int> kVirtualSwapIntervalMs{ + &kGuestSwap, "virtual_swap_interval_ms", 1000}; // Controls whether enable ignoring hover event ANR in input dispatcher. BASE_FEATURE(kIgnoreHoverEventAnr,
diff --git a/ash/components/arc/arc_features.h b/ash/components/arc/arc_features.h index 1f7ae7fe..d55710c 100644 --- a/ash/components/arc/arc_features.h +++ b/ash/components/arc/arc_features.h
@@ -46,12 +46,14 @@ extern const base::FeatureParam<bool> kVirtioBlkDataConfigUseLvm; BASE_DECLARE_FEATURE(kFilePickerExperimentFeature); BASE_DECLARE_FEATURE(kGmsCoreLowMemoryKillerProtection); -BASE_DECLARE_FEATURE(kGuestZram); -extern const base::FeatureParam<int> kGuestZramSize; +BASE_DECLARE_FEATURE(kGuestSwap); +extern const base::FeatureParam<int> kGuestSwapSize; extern const base::FeatureParam<int> kGuestZramSizePercentage; extern const base::FeatureParam<int> kGuestZramSwappiness; extern const base::FeatureParam<bool> kGuestReclaimEnabled; extern const base::FeatureParam<bool> kGuestReclaimOnlyAnonymous; +extern const base::FeatureParam<bool> kVirtualSwapEnabled; +extern const base::FeatureParam<int> kVirtualSwapIntervalMs; BASE_DECLARE_FEATURE(kIgnoreHoverEventAnr); BASE_DECLARE_FEATURE(kInstantResponseWindowOpen); BASE_DECLARE_FEATURE(kLockGuestMemory);
diff --git a/ash/components/arc/session/arc_vm_client_adapter.cc b/ash/components/arc/session/arc_vm_client_adapter.cc index c7b6b53..4616632 100644 --- a/ash/components/arc/session/arc_vm_client_adapter.cc +++ b/ash/components/arc/session/arc_vm_client_adapter.cc
@@ -457,18 +457,25 @@ base::FeatureList::IsEnabled(kBlockIoScheduler) && kEnableDataBlockIoScheduler.Get()); - if (base::FeatureList::IsEnabled(kGuestZram)) { + if (base::FeatureList::IsEnabled(kGuestSwap)) { request.set_guest_swappiness(kGuestZramSwappiness.Get()); + int guestSwapSizeMiB = kGuestSwapSize.Get() / (1024 * 1024); if (kGuestZramSizePercentage.Get() != 0) { // If there's no custom memory_mib set, try to get the default value to // determine the ZRAM size. if (request.memory_mib() == 0) { request.set_memory_mib(GetDefaultVmMemoryMiB(delegate)); } - request.set_guest_zram_mib(request.memory_mib() * - kGuestZramSizePercentage.Get() / 100); + guestSwapSizeMiB = + request.memory_mib() * kGuestZramSizePercentage.Get() / 100; + } + + if (kVirtualSwapEnabled.Get()) { + auto* virtual_swap_config = request.mutable_virtual_swap_config(); + virtual_swap_config->set_swap_interval_ms(kVirtualSwapIntervalMs.Get()); + virtual_swap_config->set_size_mib(guestSwapSizeMiB); } else { - request.set_guest_zram_mib(kGuestZramSize.Get() / (1024 * 1024)); + request.set_guest_zram_mib(guestSwapSizeMiB); } }
diff --git a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc index 9d5242a..f931e6b 100644 --- a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc +++ b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -2517,7 +2517,7 @@ // disabled. TEST_F(ArcVmClientAdapterTest, ArcGuestZramDisabledSwappiness) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kGuestZram); + feature_list.InitAndDisableFeature(kGuestSwap); StartParams start_params(GetPopulatedStartParams()); StartMiniArcWithParams(true, std::move(start_params)); EXPECT_GE(GetTestConciergeClient()->start_arc_vm_call_count(), 1); @@ -2533,7 +2533,7 @@ params["swappiness"] = "90"; params["size"] = base::NumberToString(256 * 1024 * 1024); params["size_percentage"] = "0"; - feature_list.InitAndEnableFeatureWithParameters(kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(kGuestSwap, params); StartParams start_params(GetPopulatedStartParams()); StartMiniArcWithParams(true, std::move(start_params)); EXPECT_GE(GetTestConciergeClient()->start_arc_vm_call_count(), 1); @@ -2558,7 +2558,7 @@ params["size"] = "2000"; // Should be ignored params["size_percentage"] = "50"; - feature_list.InitAndEnableFeatureWithParameters(kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(kGuestSwap, params); StartParams start_params(GetPopulatedStartParams()); StartMiniArcWithParams(true, std::move(start_params)); @@ -2583,7 +2583,7 @@ params["size"] = "2000"; // Should be ignored params["size_percentage"] = "50"; - feature_list.InitAndEnableFeatureWithParameters(kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(kGuestSwap, params); StartParams start_params(GetPopulatedStartParams()); StartMiniArcWithParams(true, std::move(start_params)); @@ -2607,7 +2607,7 @@ base::FieldTrialParams params; feature_list.InitWithFeaturesAndParameters( - {{kGuestZram, {{"size_percentage", "50"}}}, + {{kGuestSwap, {{"size_percentage", "50"}}}, {kVmMemorySize, {{"shift_mib", "-2048"}}}}, {}); StartParams start_params(GetPopulatedStartParams()); @@ -2974,5 +2974,22 @@ "ro.boot.skip_dexopt_cache")); } +TEST_F(ArcVmClientAdapterTest, VirtualSwapDevice_Enabled) { + base::FieldTrialParams params; + params["size"] = base::NumberToString(256 * 1024 * 1024); + params["virtual_swap_enabled"] = "true"; + params["virtual_swap_interval_ms"] = "1000"; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters(kGuestSwap, params); + + StartParams start_params(GetPopulatedStartParams()); + StartMiniArcWithParams(true, std::move(start_params)); + + const auto& request = GetTestConciergeClient()->start_arc_vm_request(); + EXPECT_EQ(0u, request.guest_zram_mib()); + EXPECT_EQ(1000u, request.virtual_swap_config().swap_interval_ms()); + EXPECT_EQ(256u, request.virtual_swap_config().size_mib()); +} + } // namespace } // namespace arc
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 9d22297..54fc0939 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -2138,7 +2138,7 @@ base::FEATURE_DISABLED_BY_DEFAULT); // Enables OOBE tuna feature. -BASE_FEATURE(kOobeTuna, "OobeTuna", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kOobeTuna, "OobeTuna", base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kFeatureManagementOobeTuna, "FeatureManagementOobeTuna",
diff --git a/ash/glanceables/glanceables_pixeltest.cc b/ash/glanceables/glanceables_pixeltest.cc index 72ccf2e..e3538ac 100644 --- a/ash/glanceables/glanceables_pixeltest.cc +++ b/ash/glanceables/glanceables_pixeltest.cc
@@ -89,7 +89,7 @@ ASSERT_TRUE(GetDateTray()->is_active()); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( - "glanceables_smoke", /*revision_number=*/2, + "glanceables_smoke", /*revision_number=*/3, GetDateTray()->glanceables_bubble_for_test()->GetBubbleView())); }
diff --git a/ash/glanceables/glanceables_unittest.cc b/ash/glanceables/glanceables_unittest.cc index b6c54f9d..87430be 100644 --- a/ash/glanceables/glanceables_unittest.cc +++ b/ash/glanceables/glanceables_unittest.cc
@@ -3,19 +3,31 @@ // found in the LICENSE file. #include "ash/constants/ash_features.h" +#include "ash/constants/ash_switches.h" +#include "ash/glanceables/classroom/fake_glanceables_classroom_client.h" +#include "ash/glanceables/classroom/glanceables_classroom_student_view.h" +#include "ash/glanceables/common/glanceables_util.h" +#include "ash/glanceables/common/glanceables_view_id.h" #include "ash/glanceables/glanceables_controller.h" +#include "ash/glanceables/tasks/glanceables_tasks_view.h" #include "ash/glanceables/tasks/test/glanceables_tasks_test_util.h" #include "ash/public/cpp/test/shell_test_api.h" #include "ash/shell.h" +#include "ash/style/counter_expand_button.h" #include "ash/system/status_area_widget.h" #include "ash/system/status_area_widget_test_helper.h" #include "ash/system/unified/date_tray.h" #include "ash/system/unified/glanceable_tray_bubble.h" +#include "ash/system/unified/glanceable_tray_bubble_view.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" #include "base/time/time.h" +#include "base/types/cxx23_to_underlying.h" #include "components/account_id/account_id.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/view_utils.h" namespace ash { @@ -74,4 +86,308 @@ ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN)); } +class GlanceablesTasksAndClassroomTest : public AshTestBase { + public: + GlanceablesTasksAndClassroomTest() { + feature_list_.InitWithFeatures( + /*enabled_features=*/ + {features::kGlanceablesTimeManagementTasksView, + features::kGlanceablesTimeManagementClassroomStudentView}, + /*disabled_features=*/{}); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kGlanceablesIgnoreEnableMergeRequestBuildFlag); + } + + void SetUp() override { + AshTestBase::SetUp(); + SimulateUserLogin(account_id_); + fake_glanceables_tasks_client_ = + glanceables_tasks_test_util::InitializeFakeTasksClient( + base::Time::Now()); + fake_glanceables_classroom_client_ = + std::make_unique<FakeGlanceablesClassroomClient>(); + Shell::Get()->glanceables_controller()->UpdateClientsRegistration( + account_id_, + GlanceablesController::ClientsRegistration{ + .classroom_client = fake_glanceables_classroom_client_.get(), + .tasks_client = fake_glanceables_tasks_client_.get()}); + ASSERT_TRUE(Shell::Get()->glanceables_controller()->GetTasksClient()); + + date_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->date_tray(); + date_tray_->ShowGlanceableBubble(/*from_keyboard=*/false); + view_ = views::AsViewClass<GlanceableTrayBubbleView>( + date_tray_->glanceables_bubble_for_test()->GetBubbleView()); + + glanceables_util::SetIsNetworkConnectedForTest(true); + } + + void TearDown() override { + date_tray_->HideGlanceableBubble(); + view_ = nullptr; + date_tray_ = nullptr; + AshTestBase::TearDown(); + } + + // Populates `num` of tasks to the default task list. + void PopulateTasks(size_t num) { + for (size_t i = 0; i < num; ++i) { + auto num_string = base::NumberToString(i); + fake_glanceables_tasks_client_->AddTask( + "TaskListID1", base::StrCat({"title_", num_string}), + base::DoNothing()); + } + + // Simulate closing the glanceables bubble to cache the tasks. + fake_glanceables_tasks_client_->OnGlanceablesBubbleClosed( + base::DoNothing()); + + // Recreate the tasks view to update the task views. + date_tray_->ShowGlanceableBubble(/*from_keyboard=*/false); + view_ = views::AsViewClass<GlanceableTrayBubbleView>( + date_tray_->glanceables_bubble_for_test()->GetBubbleView()); + } + + GlanceablesTasksView* GetTasksView() const { + return views::AsViewClass<GlanceablesTasksView>(view_->GetTasksView()); + } + + CounterExpandButton* GetTasksExpandButtonView() const { + return views::AsViewClass<CounterExpandButton>(GetTasksView()->GetViewByID( + base::to_underlying(GlanceablesViewId::kTasksBubbleExpandButton))); + } + + views::ScrollView* GetTasksScrollView() const { + return views::AsViewClass<views::ScrollView>(GetTasksView()->GetViewByID( + base::to_underlying(GlanceablesViewId::kTasksBubbleListScrollView))); + } + + GlanceablesClassroomStudentView* GetClassroomView() const { + return views::AsViewClass<GlanceablesClassroomStudentView>( + view_->GetClassroomStudentView()); + } + + CounterExpandButton* GetClassroomExpandButtonView() const { + return views::AsViewClass<CounterExpandButton>( + GetClassroomView()->GetViewByID(base::to_underlying( + GlanceablesViewId::kClassroomBubbleExpandButton))); + } + + GlanceableTrayBubbleView* view() const { return view_; } + + private: + base::test::ScopedFeatureList feature_list_; + + AccountId account_id_ = + AccountId::FromUserEmailGaiaId("test_user@gmail.com", "123456"); + std::unique_ptr<api::FakeTasksClient> fake_glanceables_tasks_client_; + std::unique_ptr<FakeGlanceablesClassroomClient> + fake_glanceables_classroom_client_; + + raw_ptr<DateTray> date_tray_ = nullptr; + raw_ptr<GlanceableTrayBubbleView> view_ = nullptr; +}; + +TEST_F(GlanceablesTasksAndClassroomTest, Basics) { + auto* const tasks_view = GetTasksView(); + EXPECT_TRUE(tasks_view); + auto* const classroom_view = GetClassroomView(); + EXPECT_TRUE(classroom_view); + + // Check that both views have their own backgrounds. + EXPECT_TRUE(tasks_view->GetBackground()); + EXPECT_TRUE(classroom_view->GetBackground()); + + // Check that both views contain their expand buttons. + EXPECT_TRUE(GetTasksExpandButtonView()); + EXPECT_TRUE(GetClassroomExpandButtonView()); +} + +TEST_F(GlanceablesTasksAndClassroomTest, TimeManagementExpandStates) { + auto* const tasks_view = GetTasksView(); + auto* const classroom_view = GetClassroomView(); + + // Initially both views are expanded. + // TODO(b/338917100): Consider having a half folded state. + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_TRUE(classroom_view->is_expanded()); + + // Expanding/Collapsing `tasks_view` will collapse/expand `classroom_view`. + auto* const tasks_expand_button = GetTasksExpandButtonView(); + ASSERT_TRUE(tasks_expand_button); + LeftClickOn(tasks_expand_button); + EXPECT_FALSE(tasks_view->is_expanded()); + EXPECT_TRUE(classroom_view->is_expanded()); + + LeftClickOn(tasks_expand_button); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + // Same for `classroom_view`. + auto* const classroom_expand_button = GetClassroomExpandButtonView(); + ASSERT_TRUE(classroom_expand_button); + LeftClickOn(classroom_expand_button); + EXPECT_FALSE(tasks_view->is_expanded()); + EXPECT_TRUE(classroom_view->is_expanded()); + + LeftClickOn(classroom_expand_button); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); +} + +TEST_F(GlanceablesTasksAndClassroomTest, + TrackpadScrollingDownFromTheBottomOfTasksExpandsClassroom) { + // Increase the number of tasks to ensure the scroll contents overflow. + PopulateTasks(10); + + auto* const tasks_view = GetTasksView(); + auto* const classroom_view = GetClassroomView(); + + // Expand `tasks_view`. + // TODO(b/338917100): Fix the behavior that clicking on the tasks expand + // button should expand tasks. + auto* const classroom_expand_button = GetClassroomExpandButtonView(); + ASSERT_TRUE(classroom_expand_button); + LeftClickOn(classroom_expand_button); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + view()->GetWidget()->LayoutRootViewIfNecessary(); + + // Make sure the scroll view is scrollable. + auto* const tasks_scroll_bar = GetTasksScrollView()->vertical_scroll_bar(); + EXPECT_TRUE(tasks_scroll_bar->GetVisible()); + const gfx::Point tasks_scroll_view_center = + GetTasksScrollView()->GetBoundsInScreen().CenterPoint(); + + // Set the distance that we want to scroll to the amount that is greater than + // the scrollable length of the scroll view. + const int distance_to_scroll = tasks_scroll_bar->GetMaxPosition() - + tasks_scroll_bar->GetMinPosition() + 10; + + auto generate_trackpad_scroll_event = [&](bool upward) { + GetEventGenerator()->ScrollSequence( + tasks_scroll_view_center, base::TimeDelta(), /*x_offset=*/0, + upward ? distance_to_scroll : -distance_to_scroll, /*steps=*/20, + /*num_fingers=*/2); + }; + + // Scrolling upward at the top of the scroll view doesn't change expand state. + generate_trackpad_scroll_event(/*upward=*/true); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + // Scrolling downward when there is scrollable content doesn't change expand + // state. + generate_trackpad_scroll_event(/*upward=*/false); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + // Scrolling downward at the bottom of the scroll view changes expand state. + generate_trackpad_scroll_event(/*upward=*/false); + EXPECT_FALSE(tasks_view->is_expanded()); + EXPECT_TRUE(classroom_view->is_expanded()); +} + +TEST_F(GlanceablesTasksAndClassroomTest, + GestureScrollingDownFromTheBottomOfTasksExpandsClassroom) { + // Increase the number of tasks to ensure the scroll contents overflow. + PopulateTasks(10); + + auto* const tasks_view = GetTasksView(); + auto* const classroom_view = GetClassroomView(); + + // Expand `tasks_view`. + // TODO(b/338917100): Fix the behavior that clicking on the tasks expand + // button should expand tasks. + auto* const classroom_expand_button = GetClassroomExpandButtonView(); + ASSERT_TRUE(classroom_expand_button); + LeftClickOn(classroom_expand_button); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + view()->GetWidget()->LayoutRootViewIfNecessary(); + + // Make sure the scroll view is scrollable. + auto* const tasks_scroll_bar = GetTasksScrollView()->vertical_scroll_bar(); + EXPECT_TRUE(tasks_scroll_bar->GetVisible()); + const gfx::Point tasks_scroll_view_center = + GetTasksScrollView()->GetBoundsInScreen().CenterPoint(); + + // Set the distance that we want to scroll to the amount that is greater than + // the scrollable length of the scroll view. + const int distance_to_scroll = tasks_scroll_bar->GetMaxPosition() - + tasks_scroll_bar->GetMinPosition() + 10; + + auto generate_gesture_scroll_event = [&](bool upward) { + // Scrolling upward needs to scroll downward using the gesture. + const gfx::Vector2d scroll_distance = + upward ? gfx::Vector2d(0, distance_to_scroll) + : gfx::Vector2d(0, -distance_to_scroll); + GetEventGenerator()->GestureScrollSequence( + tasks_scroll_view_center, tasks_scroll_view_center + scroll_distance, + base::Milliseconds(100), /*steps=*/10); + }; + + // Scrolling upward at the top of the scroll view doesn't change expand state. + generate_gesture_scroll_event(/*upward=*/true); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + // Scrolling downward when there is scrollable content doesn't change expand + // state. + generate_gesture_scroll_event(/*upward=*/false); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + // Scrolling downward at the bottom of the scroll view changes expand state. + generate_gesture_scroll_event(/*upward=*/false); + EXPECT_FALSE(tasks_view->is_expanded()); + EXPECT_TRUE(classroom_view->is_expanded()); +} + +TEST_F(GlanceablesTasksAndClassroomTest, + MouseWheelScrollingDownFromTheBottomOfTasksDoesNotExpandsClassroom) { + // Increase the number of tasks to ensure the scroll contents overflow. + PopulateTasks(10); + + auto* const tasks_view = GetTasksView(); + auto* const classroom_view = GetClassroomView(); + + // Expand `tasks_view`. + // TODO(b/338917100): Fix the behavior that clicking on the tasks expand + // button should expand tasks. + auto* const classroom_expand_button = GetClassroomExpandButtonView(); + ASSERT_TRUE(classroom_expand_button); + LeftClickOn(classroom_expand_button); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + view()->GetWidget()->LayoutRootViewIfNecessary(); + + // Make sure the scroll view is scrollable. + auto* const tasks_scroll_bar = GetTasksScrollView()->vertical_scroll_bar(); + EXPECT_TRUE(tasks_scroll_bar->GetVisible()); + const gfx::Point tasks_scroll_view_center = + GetTasksScrollView()->GetBoundsInScreen().CenterPoint(); + + // Set the distance that we want to scroll to the amount that is greater than + // the scrollable length of the scroll view. + const int distance_to_scroll = tasks_scroll_bar->GetMaxPosition() - + tasks_scroll_bar->GetMinPosition() + 10; + + // Using mouse wheel doesn't change expand state in either direction. + GetEventGenerator()->MoveMouseTo(tasks_scroll_view_center); + GetEventGenerator()->MoveMouseWheel(0, distance_to_scroll); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + GetEventGenerator()->MoveMouseWheel(0, -distance_to_scroll); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); + + GetEventGenerator()->MoveMouseWheel(0, -distance_to_scroll); + EXPECT_TRUE(tasks_view->is_expanded()); + EXPECT_FALSE(classroom_view->is_expanded()); +} + } // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.cc b/ash/glanceables/tasks/glanceables_tasks_view.cc index 886f0a9..6f53781 100644 --- a/ash/glanceables/tasks/glanceables_tasks_view.cc +++ b/ash/glanceables/tasks/glanceables_tasks_view.cc
@@ -10,6 +10,7 @@ #include "ash/api/tasks/tasks_client.h" #include "ash/api/tasks/tasks_types.h" +#include "ash/controls/rounded_scroll_bar.h" #include "ash/glanceables/common/glanceables_list_footer_view.h" #include "ash/glanceables/common/glanceables_progress_bar_view.h" #include "ash/glanceables/common/glanceables_util.h" @@ -43,6 +44,7 @@ #include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/events/types/event_type.h" #include "ui/gfx/animation/linear_animation.h" #include "ui/gfx/geometry/insets.h" #include "ui/strings/grit/ui_strings.h" @@ -54,11 +56,13 @@ #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/flex_layout_types.h" #include "ui/views/layout/flex_layout_view.h" #include "ui/views/view.h" #include "ui/views/view_class_properties.h" +#include "ui/views/view_utils.h" #include "ui/views/widget/widget_delegate.h" #include "url/gurl.h" @@ -168,10 +172,96 @@ BEGIN_METADATA(AddNewTaskButton) END_METADATA +class TaskListScrollBar : public RoundedScrollBar { + METADATA_HEADER(TaskListScrollBar, RoundedScrollBar) + public: + TaskListScrollBar() : RoundedScrollBar(Orientation::kVertical) {} + TaskListScrollBar(const TaskListScrollBar&) = delete; + TaskListScrollBar& operator=(const TaskListScrollBar&) = delete; + ~TaskListScrollBar() override = default; + + // views::ScrollBar: + void OnGestureEvent(ui::GestureEvent* event) override { + if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) { + // `GetMaxPosition()` in ScrollBar has different "position" definitions + // from `GetPosition()`. Calculate the max position of the thumb in the + // scrollbar for comparisons. + const int max_position = + GetTrackBounds().height() - GetThumb()->GetLength(); + + // Check if the position is at the max position at the start of the + // scroll event. + is_at_max_position_ = GetPosition() == max_position; + } else { + // Note that max position is at the bottom of the scrollbar, while the + // event y offset is increasing upward. + const bool start_overscrolling_downward = + is_at_max_position_ && + event->type() == ui::ET_GESTURE_SCROLL_UPDATE && + event->details().scroll_y() < 0; + if (start_overscrolling_downward) { + on_overscroll_callback_.Run(); + } + + // Reset the variables for the next scroll event. + is_at_max_position_ = false; + } + + RoundedScrollBar::OnGestureEvent(event); + } + void ObserveScrollEvent(const ui::ScrollEvent& event) override { + if (event.type() == ui::ET_SCROLL_FLING_CANCEL) { + // `GetMaxPosition()` in ScrollBar has different "position" definitions + // from `GetPosition()`. Calculate the max position for the thumb in the + // scrollbar for comparisons. + const int max_position = + GetTrackBounds().height() - GetThumb()->GetLength(); + + // Check if the position is at the max position at the start of the + // scroll event. + is_at_max_position_ = GetPosition() == max_position; + } else { + // Note that max position is at the bottom of the scrollbar, while the + // event y offset is increasing upward. + const bool start_overscrolling_downward = is_at_max_position_ && + event.type() == ui::ET_SCROLL && + event.y_offset() < 0; + if (start_overscrolling_downward) { + on_overscroll_callback_.Run(); + } + + // Reset the variables for the next scroll event. + is_at_max_position_ = false; + } + + RoundedScrollBar::ObserveScrollEvent(event); + } + + void SetOnOverscrollCallback(const base::RepeatingClosure& callback) { + on_overscroll_callback_ = std::move(callback); + } + + private: + // Whether the scroll bar is at its max position, which is bottom in this + // case. + bool is_at_max_position_ = false; + + // Called when the user attempts to scroll down from the bottom of the + // scroll view. + base::RepeatingClosure on_overscroll_callback_ = base::DoNothing(); +}; + +BEGIN_METADATA(TaskListScrollBar) +END_METADATA + class TaskListScrollView : public views::ScrollView { METADATA_HEADER(TaskListScrollView, views::ScrollView) public: TaskListScrollView() { + auto unique_scroll_bar = std::make_unique<TaskListScrollBar>(); + scroll_bar_ = unique_scroll_bar.get(); + SetVerticalScrollBar(std::move(unique_scroll_bar)); + SetID(base::to_underlying(GlanceablesViewId::kTasksBubbleListScrollView)); ClipHeightTo(0, std::numeric_limits<int>::max()); SetBackgroundColor(std::nullopt); @@ -182,12 +272,17 @@ TaskListScrollView& operator=(const TaskListScrollView&) = delete; ~TaskListScrollView() override = default; + void SetOnOverscrollCallback(const base::RepeatingClosure& callback) { + scroll_bar_->SetOnOverscrollCallback(std::move(callback)); + } + // views::ScrollView: void ChildPreferredSizeChanged(views::View* view) override { PreferredSizeChanged(); } private: + raw_ptr<TaskListScrollBar> scroll_bar_ = nullptr; gfx::Size contents_old_size_; }; @@ -454,6 +549,10 @@ SetBackground(views::CreateThemedRoundedRectBackground( cros_tokens::kCrosSysSystemOnBaseOpaque, 16.f)); expand_button_->SetVisible(true); + views::AsViewClass<TaskListScrollView>(content_scroll_view_) + ->SetOnOverscrollCallback( + base::BindRepeating(&GlanceablesTasksView::SetExpandState, + base::Unretained(this), /*is_expanded=*/false)); } void GlanceablesTasksView::SetExpandState(bool is_expanded) {
diff --git a/ash/picker/mock_picker_asset_fetcher.cc b/ash/picker/mock_picker_asset_fetcher.cc index acefa716..4e90e63 100644 --- a/ash/picker/mock_picker_asset_fetcher.cc +++ b/ash/picker/mock_picker_asset_fetcher.cc
@@ -22,4 +22,9 @@ const GURL& url, PickerImageFetchedCallback callback) {} +void MockPickerAssetFetcher::FetchFileThumbnail( + const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) {} + } // namespace ash
diff --git a/ash/picker/mock_picker_asset_fetcher.h b/ash/picker/mock_picker_asset_fetcher.h index 8cf5d89..3bf1c31c 100644 --- a/ash/picker/mock_picker_asset_fetcher.h +++ b/ash/picker/mock_picker_asset_fetcher.h
@@ -23,6 +23,9 @@ void FetchGifPreviewImageFromUrl( const GURL& url, PickerImageFetchedCallback callback) override; + void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) override; }; } // namespace ash
diff --git a/ash/picker/picker_asset_fetcher.h b/ash/picker/picker_asset_fetcher.h index 377ed53c..b8d3a7e3 100644 --- a/ash/picker/picker_asset_fetcher.h +++ b/ash/picker/picker_asset_fetcher.h
@@ -8,12 +8,15 @@ #include <vector> #include "ash/ash_export.h" +#include "base/files/file.h" #include "base/functional/callback_forward.h" class GURL; +class SkBitmap; namespace gfx { class ImageSkia; +class Size; } namespace ash { @@ -28,9 +31,10 @@ // TODO: b/316936723 - Pass the frames by reference to avoid a copy. using PickerGifFetchedCallback = base::OnceCallback<void(std::vector<image_util::AnimationFrame>)>; - using PickerImageFetchedCallback = base::OnceCallback<void(const gfx::ImageSkia&)>; + using FetchFileThumbnailCallback = + base::OnceCallback<void(const SkBitmap* bitmap, base::File::Error error)>; virtual ~PickerAssetFetcher() = default; @@ -46,6 +50,11 @@ virtual void FetchGifPreviewImageFromUrl( const GURL& url, PickerImageFetchedCallback callback) = 0; + + // Fetches the thumbnail for a file and calls `callback` with the result. + virtual void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) = 0; }; } // namespace ash
diff --git a/ash/picker/picker_asset_fetcher_impl.cc b/ash/picker/picker_asset_fetcher_impl.cc index bbdc56c..1810a1c 100644 --- a/ash/picker/picker_asset_fetcher_impl.cc +++ b/ash/picker/picker_asset_fetcher_impl.cc
@@ -132,4 +132,11 @@ data_decoder::mojom::ImageCodec::kDefault)); } +void PickerAssetFetcherImpl::FetchFileThumbnail( + const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) { + delegate_->FetchFileThumbnail(path, size, std::move(callback)); +} + } // namespace ash
diff --git a/ash/picker/picker_asset_fetcher_impl.h b/ash/picker/picker_asset_fetcher_impl.h index 96605c9..a9365760 100644 --- a/ash/picker/picker_asset_fetcher_impl.h +++ b/ash/picker/picker_asset_fetcher_impl.h
@@ -30,6 +30,9 @@ void FetchGifPreviewImageFromUrl( const GURL& url, PickerImageFetchedCallback callback) override; + void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) override; private: raw_ptr<PickerAssetFetcherImplDelegate> delegate_;
diff --git a/ash/picker/picker_asset_fetcher_impl_delegate.h b/ash/picker/picker_asset_fetcher_impl_delegate.h index baa3dc1..2290ae2 100644 --- a/ash/picker/picker_asset_fetcher_impl_delegate.h +++ b/ash/picker/picker_asset_fetcher_impl_delegate.h
@@ -6,8 +6,15 @@ #define ASH_PICKER_PICKER_ASSET_FETCHER_IMPL_DELEGATE_H_ #include "ash/ash_export.h" +#include "base/files/file.h" #include "base/memory/scoped_refptr.h" +class SkBitmap; + +namespace gfx { +class Size; +} + namespace network { class SharedURLLoaderFactory; } // namespace network @@ -16,10 +23,18 @@ class ASH_EXPORT PickerAssetFetcherImplDelegate { public: + using FetchFileThumbnailCallback = + base::OnceCallback<void(const SkBitmap* bitmap, base::File::Error error)>; + virtual ~PickerAssetFetcherImplDelegate() = default; virtual scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() = 0; + + // Fetches the thumbnail for a file and calls `callback` with the result. + virtual void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) = 0; }; } // namespace ash
diff --git a/ash/picker/picker_asset_fetcher_impl_unittest.cc b/ash/picker/picker_asset_fetcher_impl_unittest.cc index 6c7323f..7e48262 100644 --- a/ash/picker/picker_asset_fetcher_impl_unittest.cc +++ b/ash/picker/picker_asset_fetcher_impl_unittest.cc
@@ -84,6 +84,12 @@ GetSharedURLLoaderFactory, (), (override)); + MOCK_METHOD(void, + FetchFileThumbnail, + (const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback), + (override)); }; class PickerAssetFetcherImplTest : public testing::Test {
diff --git a/ash/picker/picker_controller.cc b/ash/picker/picker_controller.cc index 5e8c284..cbb1638 100644 --- a/ash/picker/picker_controller.cc +++ b/ash/picker/picker_controller.cc
@@ -559,4 +559,10 @@ return client_->GetSharedURLLoaderFactory(); } +void PickerController::FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) { + client_->FetchFileThumbnail(path, size, std::move(callback)); +} + } // namespace ash
diff --git a/ash/picker/picker_controller.h b/ash/picker/picker_controller.h index e71b6f6..b384136c 100644 --- a/ash/picker/picker_controller.h +++ b/ash/picker/picker_controller.h
@@ -101,6 +101,9 @@ // PickerAssetFetcherImplDelegate: scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() override; + void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) override; // Disables the feature key checking. Only works in tests. static void DisableFeatureKeyCheckForTesting();
diff --git a/ash/picker/views/picker_emoji_bar_view.cc b/ash/picker/views/picker_emoji_bar_view.cc index f417af3f..a0c9963 100644 --- a/ash/picker/views/picker_emoji_bar_view.cc +++ b/ash/picker/views/picker_emoji_bar_view.cc
@@ -53,8 +53,9 @@ // `base::Unretained` is safe here because `this` will own the item view // which takes this callback. item_row_->AddResult( - result, base::BindRepeating(&PickerEmojiBarView::SelectSearchResult, - base::Unretained(this), result)); + result, /*preview_controller=*/nullptr, + base::BindRepeating(&PickerEmojiBarView::SelectSearchResult, + base::Unretained(this), result)); } }
diff --git a/ash/picker/views/picker_item_view.cc b/ash/picker/views/picker_item_view.cc index 7ae99e6..6078a34 100644 --- a/ash/picker/views/picker_item_view.cc +++ b/ash/picker/views/picker_item_view.cc
@@ -93,12 +93,14 @@ } void PickerItemView::SetPreview( - PickerPreviewBubbleController* preview_bubble_controller) { + PickerPreviewBubbleController* preview_bubble_controller, + base::FilePath file_path) { if (preview_bubble_controller_ != nullptr) { preview_bubble_controller_->CloseBubble(); } preview_bubble_controller_ = preview_bubble_controller; + preview_file_path_ = file_path; } void PickerItemView::PaintButtonContents(gfx::Canvas* canvas) { @@ -119,7 +121,7 @@ void PickerItemView::OnMouseEntered(const ui::MouseEvent&) { if (preview_bubble_controller_ != nullptr) { - preview_bubble_controller_->ShowBubble(this); + preview_bubble_controller_->ShowBubbleForFile(this, preview_file_path_); } }
diff --git a/ash/picker/views/picker_item_view.h b/ash/picker/views/picker_item_view.h index 8d525dd..095cd8a7 100644 --- a/ash/picker/views/picker_item_view.h +++ b/ash/picker/views/picker_item_view.h
@@ -6,6 +6,7 @@ #define ASH_PICKER_VIEWS_PICKER_ITEM_VIEW_H_ #include "ash/ash_export.h" +#include "base/files/file_path.h" #include "base/functional/callback_forward.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" @@ -53,7 +54,8 @@ PickerItemView& operator=(const PickerItemView&) = delete; ~PickerItemView() override; - void SetPreview(PickerPreviewBubbleController* preview_bubble_controller); + void SetPreview(PickerPreviewBubbleController* preview_bubble_controller, + base::FilePath file_path); // views::Button: void PaintButtonContents(gfx::Canvas* canvas) override; @@ -80,7 +82,9 @@ // Corner radius of the item background and highlight. int corner_radius_ = 0; + // These are only used for file items. raw_ptr<PickerPreviewBubbleController> preview_bubble_controller_; + base::FilePath preview_file_path_; }; } // namespace ash
diff --git a/ash/picker/views/picker_preview_bubble.cc b/ash/picker/views/picker_preview_bubble.cc index 42ce90bb..de795ea 100644 --- a/ash/picker/views/picker_preview_bubble.cc +++ b/ash/picker/views/picker_preview_bubble.cc
@@ -59,6 +59,7 @@ .SetImageSize(kPreviewImageSize) .SetBackground(views::CreateThemedRoundedRectBackground( cros_tokens::kCrosSysSeparator, kPreviewBackgroundBorderRadius)) + .CopyAddressTo(&image_view_) .Build()); auto* label = AddChildView(ash::bubble_utils::CreateLabel( TypographyToken::kCrosAnnotation2, kLinkLabelText.data(), @@ -80,6 +81,18 @@ SetAnchorRect(rect); } +gfx::Size PickerPreviewBubbleView::GetPreferredImageSize() const { + return kPreviewImageSize; +} + +ui::ImageModel PickerPreviewBubbleView::GetPreviewImage() const { + return image_view_->GetImageModel(); +} + +void PickerPreviewBubbleView::SetPreviewImage(ui::ImageModel image) { + image_view_->SetImage(std::move(image)); +} + void PickerPreviewBubbleView::OnThemeChanged() { BubbleDialogDelegateView::OnThemeChanged(); GetBubbleFrameView()->bubble_border()->set_color(
diff --git a/ash/picker/views/picker_preview_bubble.h b/ash/picker/views/picker_preview_bubble.h index 33ff1097..e775f21 100644 --- a/ash/picker/views/picker_preview_bubble.h +++ b/ash/picker/views/picker_preview_bubble.h
@@ -6,9 +6,16 @@ #define ASH_PICKER_VIEWS_PICKER_PREVIEW_BUBBLE_H_ #include "ash/ash_export.h" +#include "base/memory/raw_ptr.h" +#include "ui/base/models/image_model.h" +#include "ui/gfx/geometry/size.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/view.h" +namespace views { +class ImageView; +} + namespace ash { class ASH_EXPORT PickerPreviewBubbleView @@ -20,10 +27,19 @@ PickerPreviewBubbleView(const PickerPreviewBubbleView&) = delete; PickerPreviewBubbleView& operator=(const PickerPreviewBubbleView&) = delete; + // Returns the preferred size of the preview image. + gfx::Size GetPreferredImageSize() const; + + ui::ImageModel GetPreviewImage() const; + void SetPreviewImage(ui::ImageModel image); + // BubbleDialogDelegateView overrides void OnThemeChanged() override; void Close(); + + private: + raw_ptr<views::ImageView> image_view_; }; } // namespace ash
diff --git a/ash/picker/views/picker_preview_bubble_controller.cc b/ash/picker/views/picker_preview_bubble_controller.cc index 37a2979..ce68ca1a 100644 --- a/ash/picker/views/picker_preview_bubble_controller.cc +++ b/ash/picker/views/picker_preview_bubble_controller.cc
@@ -5,19 +5,24 @@ #include "ash/picker/views/picker_preview_bubble_controller.h" #include "ash/picker/views/picker_preview_bubble.h" +#include "ash/public/cpp/holding_space/holding_space_image.h" #include "base/check.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace ash { -PickerPreviewBubbleController::PickerPreviewBubbleController() = default; +PickerPreviewBubbleController::PickerPreviewBubbleController( + AsyncBitmapResolver async_bitmap_resolver) + : async_bitmap_resolver_(std::move(async_bitmap_resolver)) {} PickerPreviewBubbleController::~PickerPreviewBubbleController() { CloseBubble(); } -void PickerPreviewBubbleController::ShowBubble(views::View* anchor_view) { +void PickerPreviewBubbleController::ShowBubbleForFile( + views::View* anchor_view, + const base::FilePath& file_path) { if (bubble_view_ != nullptr) { return; } @@ -26,6 +31,16 @@ // dangling. CHECK(anchor_view); bubble_view_ = new PickerPreviewBubbleView(anchor_view); + preview_image_ = std::make_unique<ash::HoldingSpaceImage>( + bubble_view_->GetPreferredImageSize(), file_path, async_bitmap_resolver_); + bubble_view_->SetPreviewImage( + ui::ImageModel::FromImageSkia(preview_image_->GetImageSkia())); + // base::Unretained is safe here since `image_subscription_` is a member. + // During destruction, `image_subscription_` will be destroyed before the + // other members, so the callback is guaranteed to be safe. + image_subscription_ = preview_image_->AddImageSkiaChangedCallback( + base::BindRepeating(&PickerPreviewBubbleController::UpdateBubbleImage, + base::Unretained(this))); widget_observation_.Observe(bubble_view_->GetWidget()); } @@ -40,10 +55,19 @@ void PickerPreviewBubbleController::OnWidgetDestroying(views::Widget* widget) { widget_observation_.Reset(); bubble_view_ = nullptr; + preview_image_ = nullptr; } -views::View* PickerPreviewBubbleController::bubble_view_for_testing() const { +PickerPreviewBubbleView* +PickerPreviewBubbleController::bubble_view_for_testing() const { return bubble_view_; } +void PickerPreviewBubbleController::UpdateBubbleImage() { + if (bubble_view_ != nullptr) { + bubble_view_->SetPreviewImage( + ui::ImageModel::FromImageSkia(preview_image_->GetImageSkia())); + } +} + } // namespace ash
diff --git a/ash/picker/views/picker_preview_bubble_controller.h b/ash/picker/views/picker_preview_bubble_controller.h index f2e72fd7..3f5e1b471 100644 --- a/ash/picker/views/picker_preview_bubble_controller.h +++ b/ash/picker/views/picker_preview_bubble_controller.h
@@ -6,6 +6,8 @@ #define ASH_PICKER_VIEWS_PICKER_PREVIEW_BUBBLE_CONTROLLER_H_ #include "ash/ash_export.h" +#include "ash/public/cpp/holding_space/holding_space_image.h" +#include "base/callback_list.h" #include "base/scoped_observation.h" #include "ui/views/widget/widget_observer.h" @@ -20,7 +22,10 @@ class ASH_EXPORT PickerPreviewBubbleController : public views::WidgetObserver { public: - PickerPreviewBubbleController(); + using AsyncBitmapResolver = HoldingSpaceImage::AsyncBitmapResolver; + + explicit PickerPreviewBubbleController( + HoldingSpaceImage::AsyncBitmapResolver async_bitmap_resolver); PickerPreviewBubbleController(const PickerPreviewBubbleController&) = delete; PickerPreviewBubbleController& operator=( const PickerPreviewBubbleController&) = delete; @@ -28,7 +33,8 @@ // `anchor_view` must not be `nullptr`. // Destroying `anchor_view` closes the bubble if it's shown. - void ShowBubble(views::View* anchor_view); + void ShowBubbleForFile(views::View* anchor_view, + const base::FilePath& file_path); // TODO: b/322899032 - Take in an `anchor_view` to avoid accidentally closing // the bubble view shown by a different anchor view. @@ -37,12 +43,18 @@ // views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override; - views::View* bubble_view_for_testing() const; + PickerPreviewBubbleView* bubble_view_for_testing() const; private: + void UpdateBubbleImage(); + + AsyncBitmapResolver async_bitmap_resolver_; + std::unique_ptr<HoldingSpaceImage> preview_image_; + // Owned by the bubble widget. raw_ptr<PickerPreviewBubbleView> bubble_view_; + base::CallbackListSubscription image_subscription_; base::ScopedObservation<views::Widget, views::WidgetObserver> widget_observation_{this}; };
diff --git a/ash/picker/views/picker_preview_bubble_controller_unittest.cc b/ash/picker/views/picker_preview_bubble_controller_unittest.cc index 5835ca6ce..c4ec00f 100644 --- a/ash/picker/views/picker_preview_bubble_controller_unittest.cc +++ b/ash/picker/views/picker_preview_bubble_controller_unittest.cc
@@ -7,10 +7,16 @@ #include <memory> #include <utility> +#include "ash/picker/views/picker_preview_bubble.h" #include "ash/test/view_drawn_waiter.h" +#include "base/run_loop.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image_unittest_util.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/widget_test.h" #include "ui/views/view.h" @@ -36,12 +42,17 @@ return widget; } -TEST_F(PickerPreviewBubbleControllerTest, ShowBubbleShowsBubbleWidget) { +PickerPreviewBubbleController::AsyncBitmapResolver CreateUnresolvedBitmap() { + return base::DoNothing(); +} + +TEST_F(PickerPreviewBubbleControllerTest, ShowBubbleForFileShowsBubbleWidget) { std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - PickerPreviewBubbleController controller; + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); - controller.ShowBubble(anchor_widget->GetContentsView()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); views::View* bubble_view = controller.bubble_view_for_testing(); ASSERT_NE(bubble_view, nullptr); @@ -53,8 +64,9 @@ TEST_F(PickerPreviewBubbleControllerTest, CloseBubbleClosesBubbleWidget) { std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - PickerPreviewBubbleController controller; - controller.ShowBubble(anchor_widget->GetContentsView()); + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); ASSERT_NE(controller.bubble_view_for_testing(), nullptr); views::Widget* bubble_widget = controller.bubble_view_for_testing()->GetWidget(); @@ -67,10 +79,11 @@ TEST_F(PickerPreviewBubbleControllerTest, DestroyingAnchorWidgetDestroysBubbleWidget) { - PickerPreviewBubbleController controller; + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - controller.ShowBubble(anchor_widget->GetContentsView()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); ASSERT_NE(controller.bubble_view_for_testing(), nullptr); views::Widget* bubble_widget = controller.bubble_view_for_testing()->GetWidget(); @@ -83,25 +96,29 @@ TEST_F(PickerPreviewBubbleControllerTest, DestroyingAnchorWidgetImmediatelyDoesNotCrash) { - PickerPreviewBubbleController controller; + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - controller.ShowBubble(anchor_widget->GetContentsView()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); anchor_widget->CloseNow(); EXPECT_EQ(controller.bubble_view_for_testing(), nullptr); } -TEST_F(PickerPreviewBubbleControllerTest, ShowBubbleWhileShownKeepsSameBubble) { +TEST_F(PickerPreviewBubbleControllerTest, + ShowBubbleForFileWhileShownKeepsSameBubble) { std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - PickerPreviewBubbleController controller; - controller.ShowBubble(anchor_widget->GetContentsView()); + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); views::View* bubble_view = controller.bubble_view_for_testing(); ViewDrawnWaiter().Wait(bubble_view); - controller.ShowBubble(anchor_widget->GetContentsView()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); ASSERT_EQ(controller.bubble_view_for_testing(), bubble_view); EXPECT_EQ(controller.bubble_view_for_testing()->GetWidget(), @@ -109,7 +126,7 @@ } TEST_F(PickerPreviewBubbleControllerTest, CloseBubbleWithoutShowing) { - PickerPreviewBubbleController controller; + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); controller.CloseBubble(); @@ -119,12 +136,14 @@ TEST_F(PickerPreviewBubbleControllerTest, ShowingBubbleWhileClosingOldBubble) { std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget(GetContext()); - PickerPreviewBubbleController controller; - controller.ShowBubble(anchor_widget->GetContentsView()); + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); // CloseBubble is asynchronous. controller.CloseBubble(); - controller.ShowBubble(anchor_widget->GetContentsView()); + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); views::View* bubble_view = controller.bubble_view_for_testing(); ViewDrawnWaiter().Wait(bubble_view); @@ -133,5 +152,43 @@ bubble_view->GetWidget()); } +TEST_F(PickerPreviewBubbleControllerTest, + ShowBubbleForFileUsesPlaceholderBeforeBitmapResolves) { + std::unique_ptr<views::Widget> anchor_widget = + CreateAnchorWidget(GetContext()); + PickerPreviewBubbleController controller(CreateUnresolvedBitmap()); + + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); + PickerPreviewBubbleView* bubble_view = controller.bubble_view_for_testing(); + ViewDrawnWaiter().Wait(bubble_view); + + EXPECT_EQ(bubble_view->GetPreviewImage().GetImage().AsBitmap().getColor(5, 5), + SK_ColorTRANSPARENT); +} + +TEST_F(PickerPreviewBubbleControllerTest, + ShowBubbleForFileUpdatesPreviewAfterBitmapResolves) { + std::unique_ptr<views::Widget> anchor_widget = + CreateAnchorWidget(GetContext()); + base::RunLoop run_loop; + SkBitmap bitmap = gfx::test::CreateBitmap(100, SK_ColorBLUE); + PickerPreviewBubbleController controller(base::BindLambdaForTesting( + [&](const base::FilePath& file_path, const gfx::Size& size, + HoldingSpaceImage::BitmapCallback callback) { + std::move(callback).Run(&bitmap, base::File::Error::FILE_OK); + run_loop.Quit(); + })); + + controller.ShowBubbleForFile(anchor_widget->GetContentsView(), + base::FilePath()); + PickerPreviewBubbleView* bubble_view = controller.bubble_view_for_testing(); + ViewDrawnWaiter().Wait(bubble_view); + + run_loop.Run(); + EXPECT_EQ(bubble_view->GetPreviewImage().GetImage().AsBitmap().getColor(5, 5), + SK_ColorBLUE); +} + } // namespace } // namespace ash
diff --git a/ash/picker/views/picker_search_results_view.cc b/ash/picker/views/picker_search_results_view.cc index a52f7da..ee5c561 100644 --- a/ash/picker/views/picker_search_results_view.cc +++ b/ash/picker/views/picker_search_results_view.cc
@@ -54,7 +54,10 @@ PickerSearchResultsViewDelegate* delegate, int picker_view_width, PickerAssetFetcher* asset_fetcher) - : delegate_(delegate) { + : delegate_(delegate), + preview_controller_( + base::BindRepeating(&PickerAssetFetcher::FetchFileThumbnail, + base::Unretained(asset_fetcher))) { SetLayoutManager(std::make_unique<views::FlexLayout>()) ->SetOrientation(views::LayoutOrientation::kVertical); SetProperty(views::kElementIdentifierKey, kPickerSearchResultsPageElementId); @@ -237,8 +240,9 @@ // `base::Unretained` is safe here because `this` will own the item view which // takes this callback. section_view->AddResult( - result, base::BindRepeating(&PickerSearchResultsView::SelectSearchResult, - base::Unretained(this), result)); + result, &preview_controller_, + base::BindRepeating(&PickerSearchResultsView::SelectSearchResult, + base::Unretained(this), result)); } void PickerSearchResultsView::SetPseudoFocusedView(views::View* view) {
diff --git a/ash/picker/views/picker_search_results_view.h b/ash/picker/views/picker_search_results_view.h index a9901fc..93c1456 100644 --- a/ash/picker/views/picker_search_results_view.h +++ b/ash/picker/views/picker_search_results_view.h
@@ -104,7 +104,7 @@ // A view for when there are no results. raw_ptr<views::View> no_results_view_ = nullptr; - PickerPreviewBubbleController preview_bubble_controller_; + PickerPreviewBubbleController preview_controller_; }; } // namespace ash
diff --git a/ash/picker/views/picker_section_view.cc b/ash/picker/views/picker_section_view.cc index dc5a89d..39f9e3b 100644 --- a/ash/picker/views/picker_section_view.cc +++ b/ash/picker/views/picker_section_view.cc
@@ -168,8 +168,10 @@ return image_item_ptr; } -void PickerSectionView::AddResult(const PickerSearchResult& result, - SelectResultCallback select_result_callback) { +void PickerSectionView::AddResult( + const PickerSearchResult& result, + PickerPreviewBubbleController* preview_controller, + SelectResultCallback select_result_callback) { std::visit( base::Overloaded{ [&](const PickerSearchResult::TextData& data) { @@ -262,18 +264,18 @@ [&](const PickerSearchResult::LocalFileData& data) { auto item_view = std::make_unique<PickerListItemView>( std::move(select_result_callback)); - // TODO: b/330794217 - Add preview once it's available. item_view->SetPrimaryText(data.title); item_view->SetLeadingIcon(ui::ImageModel::FromVectorIcon( chromeos::kFiletypeImageIcon, cros_tokens::kCrosSysOnSurface)); + item_view->SetPreview(preview_controller, data.file_path); AddListItem(std::move(item_view)); }, [&](const PickerSearchResult::DriveFileData& data) { auto item_view = std::make_unique<PickerListItemView>( std::move(select_result_callback)); - // TODO: b/330794217 - Add preview once it's available. item_view->SetPrimaryText(data.title); item_view->SetLeadingIcon(data.icon); + item_view->SetPreview(preview_controller, data.file_path); AddListItem(std::move(item_view)); }, [&](const PickerSearchResult::CategoryData& data) {
diff --git a/ash/picker/views/picker_section_view.h b/ash/picker/views/picker_section_view.h index f0237a5..59e2473 100644 --- a/ash/picker/views/picker_section_view.h +++ b/ash/picker/views/picker_section_view.h
@@ -30,6 +30,7 @@ class PickerItemView; class PickerListItemContainerView; class PickerListItemView; +class PickerPreviewBubbleController; class PickerSearchResult; class PickerSmallItemGridView; class PickerSymbolItemView; @@ -72,7 +73,10 @@ std::unique_ptr<PickerImageItemView> image_item); // Creates an item based on `result` and adds it to the section view. + // `preview_controller` can be null if previews are not needed. If it's not + // null, it must outlive this class. void AddResult(const PickerSearchResult& result, + PickerPreviewBubbleController* preview_controller, SelectResultCallback select_result_callback); void ClearItems();
diff --git a/ash/picker/views/picker_section_view_unittest.cc b/ash/picker/views/picker_section_view_unittest.cc index 4314d54..869a70d 100644 --- a/ash/picker/views/picker_section_view_unittest.cc +++ b/ash/picker/views/picker_section_view_unittest.cc
@@ -15,6 +15,7 @@ #include "ash/picker/views/picker_image_item_view.h" #include "ash/picker/views/picker_item_view.h" #include "ash/picker/views/picker_list_item_view.h" +#include "ash/picker/views/picker_preview_bubble_controller.h" #include "ash/picker/views/picker_symbol_item_view.h" #include "ash/public/cpp/picker/picker_search_result.h" #include "base/containers/span.h" @@ -157,11 +158,13 @@ TEST_F(PickerSectionViewTest, AddsResults) { MockPickerAssetFetcher asset_fetcher; PickerSectionView section_view(kDefaultSectionWidth, &asset_fetcher); + PickerPreviewBubbleController preview_controller(base::DoNothing()); section_view.AddResult(PickerSearchResult::Text(u"Result"), - base::DoNothing()); + &preview_controller, base::DoNothing()); - section_view.AddResult(PickerSearchResult::Emoji(u"😊"), base::DoNothing()); + section_view.AddResult(PickerSearchResult::Emoji(u"😊"), &preview_controller, + base::DoNothing()); base::span<const raw_ptr<PickerItemView>> items = section_view.item_views_for_testing();
diff --git a/ash/picker/views/picker_zero_state_view.cc b/ash/picker/views/picker_zero_state_view.cc index 95b0cb72..b10906a 100644 --- a/ash/picker/views/picker_zero_state_view.cc +++ b/ash/picker/views/picker_zero_state_view.cc
@@ -55,7 +55,10 @@ base::span<const PickerCategory> recent_results_categories, int picker_view_width, PickerAssetFetcher* asset_fetcher) - : delegate_(delegate) { + : delegate_(delegate), + preview_controller_( + base::BindRepeating(&PickerAssetFetcher::FetchFileThumbnail, + base::Unretained(asset_fetcher))) { SetLayoutManager(std::make_unique<views::FlexLayout>()) ->SetOrientation(views::LayoutOrientation::kVertical); @@ -281,8 +284,9 @@ } for (const auto& result : results) { recent_section_view_->AddResult( - result, base::BindRepeating(&PickerZeroStateView::OnResultSelected, - weak_ptr_factory_.GetWeakPtr(), result)); + result, &preview_controller_, + base::BindRepeating(&PickerZeroStateView::OnResultSelected, + weak_ptr_factory_.GetWeakPtr(), result)); } SetPseudoFocusedView(section_list_view_->GetTopItem()); }
diff --git a/ash/picker/views/picker_zero_state_view.h b/ash/picker/views/picker_zero_state_view.h index a4e0db0..0f1d2b2 100644 --- a/ash/picker/views/picker_zero_state_view.h +++ b/ash/picker/views/picker_zero_state_view.h
@@ -12,6 +12,7 @@ #include "ash/ash_export.h" #include "ash/picker/views/picker_category_type.h" #include "ash/picker/views/picker_page_view.h" +#include "ash/picker/views/picker_preview_bubble_controller.h" #include "ash/public/cpp/picker/picker_category.h" #include "base/containers/span.h" #include "base/functional/callback_forward.h" @@ -80,6 +81,7 @@ std::vector<PickerSearchResult> result); raw_ptr<PickerZeroStateViewDelegate> delegate_; + PickerPreviewBubbleController preview_controller_; // The section list view, contains the section views. raw_ptr<PickerSectionListView> section_list_view_ = nullptr;
diff --git a/ash/public/cpp/app_menu_constants.h b/ash/public/cpp/app_menu_constants.h index c7d6433..0d7098c 100644 --- a/ash/public/cpp/app_menu_constants.h +++ b/ash/public/cpp/app_menu_constants.h
@@ -82,6 +82,7 @@ // Command for shutting down a VM associated with an App. Used by // AppContextMenu and ShelfContextMenu. SHUTDOWN_GUEST_OS = 2000, + SHUTDOWN_BRUSCHETTA_OS = 2001, // Range of command IDs reserved for shelf app menu items when there are // multiple instances of the same app.
diff --git a/ash/public/cpp/picker/mock_picker_client.h b/ash/public/cpp/picker/mock_picker_client.h index 329fa90..85e2bd0 100644 --- a/ash/public/cpp/picker/mock_picker_client.h +++ b/ash/public/cpp/picker/mock_picker_client.h
@@ -56,6 +56,12 @@ (SuggestedLinksCallback), (override)); MOCK_METHOD(bool, IsFeatureAllowedForDogfood, (), (override)); + MOCK_METHOD(void, + FetchFileThumbnail, + (const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback), + (override)); }; } // namespace ash
diff --git a/ash/public/cpp/picker/picker_client.h b/ash/public/cpp/picker/picker_client.h index 8630ea1..7b06cf1 100644 --- a/ash/public/cpp/picker/picker_client.h +++ b/ash/public/cpp/picker/picker_client.h
@@ -14,10 +14,17 @@ #include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/picker/picker_category.h" #include "ash/public/cpp/picker/picker_search_result.h" +#include "base/files/file.h" #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "url/gurl.h" +class SkBitmap; + +namespace gfx { +class Size; +} + namespace network { class SharedURLLoaderFactory; } // namespace network @@ -41,6 +48,8 @@ base::OnceCallback<void(std::vector<PickerSearchResult>)>; using SuggestedLinksCallback = base::RepeatingCallback<void(std::vector<PickerSearchResult>)>; + using FetchFileThumbnailCallback = + base::OnceCallback<void(const SkBitmap* bitmap, base::File::Error error)>; // Gets the SharedURLLoaderFactory to use for Picker network requests, e.g. to // fetch assets. @@ -79,6 +88,10 @@ virtual bool IsFeatureAllowedForDogfood() = 0; + virtual void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) = 0; + protected: PickerClient(); virtual ~PickerClient();
diff --git a/ash/quick_pair/common/logging.cc b/ash/quick_pair/common/logging.cc index d21112a8..653d1fb 100644 --- a/ash/quick_pair/common/logging.cc +++ b/ash/quick_pair/common/logging.cc
@@ -24,7 +24,7 @@ g_logging_enabled = true; } -ScopedLogMessage::ScopedLogMessage(const char* file, +ScopedLogMessage::ScopedLogMessage(const std::string_view file, int line, logging::LogSeverity severity) : file_(file), line_(line), severity_(severity) {} @@ -35,18 +35,18 @@ const std::string string_from_stream = stream_.str(); LogBuffer::GetInstance()->AddLogMessage(LogBuffer::LogMessage( - string_from_stream, base::Time::Now(), file_, line_, severity_)); + string_from_stream, base::Time::Now(), file_.data(), line_, severity_)); // Don't emit VERBOSE-level logging to the standard logging system unless // verbose logging is enabled for the source file. if (severity_ <= logging::LOGGING_VERBOSE && - logging::GetVlogLevelHelper(file_, strlen(file_) + 1) <= 0) { + logging::GetVlogLevelHelper(file_.data(), file_.size()) <= 0) { return; } // The destructor of |log_message| also creates a log for the standard logging // system. - logging::LogMessage log_message(file_, line_, severity_); + logging::LogMessage log_message(file_.data(), line_, severity_); log_message.stream() << string_from_stream; }
diff --git a/ash/quick_pair/common/logging.h b/ash/quick_pair/common/logging.h index cbaf315a..3e7fec1 100644 --- a/ash/quick_pair/common/logging.h +++ b/ash/quick_pair/common/logging.h
@@ -6,6 +6,7 @@ #define ASH_QUICK_PAIR_COMMON_LOGGING_H_ #include <sstream> +#include <string_view> #include "base/component_export.h" #include "base/logging.h" @@ -23,8 +24,9 @@ // QP_LOG(INFO) << "Waiting for " << x << " pending requests."; // QP_LOG(ERROR) << "Request failed: " << error_string; #define QP_LOG(severity) \ - ash::quick_pair::ScopedLogMessage(__FILE__, __LINE__, \ - logging::LOGGING_##severity) \ + ash::quick_pair::ScopedLogMessage( \ + std::string_view(__FILE__, std::size(__FILE__)), __LINE__, \ + logging::LOGGING_##severity) \ .stream() // Disables all logging while in scope. Intended to be called only from test @@ -42,7 +44,9 @@ // directly. class COMPONENT_EXPORT(QUICK_PAIR_COMMON) ScopedLogMessage { public: - ScopedLogMessage(const char* file, int line, logging::LogSeverity severity); + ScopedLogMessage(const std::string_view file, + int line, + logging::LogSeverity severity); ScopedLogMessage(const ScopedLogMessage&) = delete; ScopedLogMessage& operator=(const ScopedLogMessage&) = delete; ~ScopedLogMessage(); @@ -50,7 +54,7 @@ std::ostream& stream() { return stream_; } private: - const char* file_; + const std::string_view file_; int line_; logging::LogSeverity severity_; std::ostringstream stream_;
diff --git a/ash/system/focus_mode/focus_mode_task_view.cc b/ash/system/focus_mode/focus_mode_task_view.cc index 02a1370..d11c8b6 100644 --- a/ash/system/focus_mode/focus_mode_task_view.cc +++ b/ash/system/focus_mode/focus_mode_task_view.cc
@@ -288,14 +288,29 @@ &FocusModeTaskView::OnTaskSelected, base::Unretained(this)))); auto* controller = FocusModeController::Get(); const bool has_selected_task = controller->HasSelectedTask(); + const std::string& selected_task_title = controller->selected_task_title(); if (has_selected_task) { - task_title_ = base::UTF8ToUTF16(controller->selected_task_title()); + // There is a chance that we have a selected task but the title isn't + // updated yet, since we do not save that to user prefs. + if (!selected_task_title.empty()) { + task_title_ = base::UTF8ToUTF16(selected_task_title); + } + + if (is_network_connected) { + // Fetch the selected task to verify if it is still in the uncompleted + // state. + controller->tasks_provider().GetTask( + controller->selected_task_list_id(), controller->selected_task_id(), + base::BindOnce(&FocusModeTaskView::OnTaskFetched, + weak_factory_.GetWeakPtr())); + } } else if (is_network_connected) { controller->tasks_provider().GetSortedTaskList(base::BindOnce( &FocusModeTaskView::OnTasksFetched, weak_factory_.GetWeakPtr())); } - UpdateStyle(/*show_selected_state=*/has_selected_task, + UpdateStyle(/*show_selected_state=*/(has_selected_task && + !selected_task_title.empty()), /*is_network_connected=*/is_network_connected); textfield_controller_ = @@ -414,6 +429,19 @@ chip_carousel_->SetVisible(!tasks.empty()); } +void FocusModeTaskView::OnTaskFetched(const FocusModeTask& task_entry) { + // If the selected task could not be found, then an error has occurred. + if (task_entry.task_id.empty()) { + return; + } + + if (task_entry.completed) { + OnCompleteTask(); + } else { + OnTaskSelected(task_entry); + } +} + void FocusModeTaskView::UpdateStyle(bool show_selected_state, bool is_network_connected) { textfield_->SetText(task_title_);
diff --git a/ash/system/focus_mode/focus_mode_task_view.h b/ash/system/focus_mode/focus_mode_task_view.h index eb7a28f..dc9bd716 100644 --- a/ash/system/focus_mode/focus_mode_task_view.h +++ b/ash/system/focus_mode/focus_mode_task_view.h
@@ -67,6 +67,9 @@ // Called when tasks have been fetched from the tasks provider. void OnTasksFetched(const std::vector<FocusModeTask>& tasks); + // Called when the task has been fetched from the tasks provider. + void OnTaskFetched(const FocusModeTask& task_entry); + // If `show_selected_state` is true, it means that there is a task selected // by the user for a focus session, then we will show `radio_button_` and // `deselect_button_`, update the style of `textfield_`, and hide the
diff --git a/ash/system/focus_mode/focus_mode_tasks_provider.cc b/ash/system/focus_mode/focus_mode_tasks_provider.cc index cecc478..115b4a4 100644 --- a/ash/system/focus_mode/focus_mode_tasks_provider.cc +++ b/ash/system/focus_mode/focus_mode_tasks_provider.cc
@@ -151,7 +151,7 @@ base::RepeatingClosure barrier, bool success, const ui::ListModel<api::Task>* api_tasks) { - // TODO: Skip completed tasks? + // NOTE: Completed tasks will not show up in `api_tasks`. if (success && api_tasks) { for (const auto& api_task : *api_tasks) { FocusModeTask& task = tasks_.emplace_back(); @@ -206,6 +206,16 @@ ScheduleTaskListUpdate(); } +void FocusModeTasksProvider::GetTask(const std::string& task_list_id, + const std::string& task_id, + OnGetTaskCallback callback) { + api::TasksController::Get()->tasks_delegate()->GetTasks( + task_list_id, /*force_fetch=*/true, + base::BindOnce(&FocusModeTasksProvider::OnTasksFetchedForTask, + weak_factory_.GetWeakPtr(), task_list_id, task_id, + std::move(callback))); +} + void FocusModeTasksProvider::AddTask(const std::string& title, OnTaskSavedCallback callback) { if (task_list_for_new_task_.empty()) { @@ -260,6 +270,36 @@ } } +void FocusModeTasksProvider::OnTasksFetchedForTask( + const std::string& task_list_id, + const std::string& task_id, + OnGetTaskCallback callback, + bool success, + const ui::ListModel<api::Task>* api_tasks) { + FocusModeTask task; + + if (success) { + // NOTE: Completed tasks will not show up in `api_tasks`, so we first assume + // it's completed and update the state if the task is found in `api_tasks`. + // TODO: Can we actually verify that the task is complete instead of making + // this assumption? + task.task_list_id = task_list_id; + task.task_id = task_id; + task.completed = true; + + for (const auto& api_task : *api_tasks) { + if (api_task->id == task_id) { + task.title = api_task->title; + task.updated = api_task->updated; + task.completed = api_task->completed; + break; + } + } + } + + std::move(callback).Run(task); +} + void FocusModeTasksProvider::OnTaskSaved(const std::string& task_list_id, const std::string& task_id, bool completed,
diff --git a/ash/system/focus_mode/focus_mode_tasks_provider.h b/ash/system/focus_mode/focus_mode_tasks_provider.h index 2408f78..d28959c 100644 --- a/ash/system/focus_mode/focus_mode_tasks_provider.h +++ b/ash/system/focus_mode/focus_mode_tasks_provider.h
@@ -38,6 +38,8 @@ std::string task_id; std::string title; + bool completed; + // The time when this task was last updated. base::Time updated; @@ -59,6 +61,9 @@ using OnGetTasksCallback = base::OnceCallback<void(const std::vector<FocusModeTask>& tasks)>; + using OnGetTaskCallback = + base::OnceCallback<void(const FocusModeTask& task_entry)>; + FocusModeTasksProvider(); FocusModeTasksProvider(const FocusModeTasksProvider&) = delete; FocusModeTasksProvider& operator=(const FocusModeTasksProvider&) = delete; @@ -69,6 +74,15 @@ // have been fetched. void GetSortedTaskList(OnGetTasksCallback callback); + // Gets an individual task from the `task_list_id` with `task_id`. Since + // completed tasks will not be returned by the delegate, we will update the + // `completed` field to signifiy if the task has been completed or not. + // Returns a `FocusModeTask` in `callback`, or an empty `FocusModeTask` if an + // error has occurred. + void GetTask(const std::string& task_list_id, + const std::string& task_id, + OnGetTaskCallback callback); + // Creates a new task with name `title` and adds it to `task_list_`. Returns // the added `FocusModeTask` in `callback`, or an empty `FocusModeTask` if an // error has occurred. Note that this will clear the internal cache. @@ -88,6 +102,11 @@ private: void OnTasksFetched(); + void OnTasksFetchedForTask(const std::string& task_list_id, + const std::string& task_id, + OnGetTaskCallback callback, + bool success, + const ui::ListModel<api::Task>* api_tasks); void OnTaskSaved(const std::string& task_list_id, const std::string& task_id, bool completed,
diff --git a/ash/system/focus_mode/focus_mode_tray.cc b/ash/system/focus_mode/focus_mode_tray.cc index 9609c32f..7da9d98 100644 --- a/ash/system/focus_mode/focus_mode_tray.cc +++ b/ash/system/focus_mode/focus_mode_tray.cc
@@ -341,13 +341,21 @@ UpdateBubbleViews(session_snapshot_.value()); if (controller->HasSelectedTask()) { - task_item_view_ = - bubble_view_container_->AddChildView(std::make_unique<TaskItemView>( - base::UTF8ToUTF16(controller->selected_task_title()), - base::BindRepeating(&FocusModeTray::OnCompleteTask, - weak_ptr_factory_.GetWeakPtr()))); - task_item_view_->SetProperty(views::kBoxLayoutFlexKey, - views::BoxLayoutFlexSpecification()); + // There is a chance that we have a selected task but the title isn't + // updated yet, since we do not save that to user prefs. + if (const std::string& task_title = controller->selected_task_title(); + !task_title.empty()) { + CreateTaskItemView(task_title); + } + + if (glanceables_util::IsNetworkConnected()) { + // Fetch the selected task to verify if it is still in the uncompleted + // state. + controller->tasks_provider().GetTask( + controller->selected_task_list_id(), controller->selected_task_id(), + base::BindOnce(&FocusModeTray::OnTaskFetched, + weak_ptr_factory_.GetWeakPtr())); + } } bubble_ = std::make_unique<TrayBubbleWrapper>(this); @@ -443,6 +451,47 @@ return task_item_view_->GetTaskTitle(); } +void FocusModeTray::OnTaskFetched(const FocusModeTask& task_entry) { + if (!bubble_) { + return; + } + + // If the selected task could not be found, then an error has occurred. + if (task_entry.task_id.empty()) { + return; + } + + if (task_entry.completed) { + OnCompleteTask(); + return; + } + + // TODO(b/342268177): Move this to the `FocusModeController`. + FocusModeController::Get()->SetSelectedTask(task_entry); + + if (!task_item_view_) { + CreateTaskItemView(task_entry.title); + + // We need to update the bubble after creating the `task_item_view_` so the + // widget bounds are updated and shows the view. + bubble_->bubble_view()->UpdateBubble(); + } +} + +void FocusModeTray::CreateTaskItemView(const std::string& task_title) { + if (task_title.empty()) { + return; + } + + task_item_view_ = + bubble_view_container_->AddChildView(std::make_unique<TaskItemView>( + base::UTF8ToUTF16(task_title), + base::BindRepeating(&FocusModeTray::OnCompleteTask, + weak_ptr_factory_.GetWeakPtr()))); + task_item_view_->SetProperty(views::kBoxLayoutFlexKey, + views::BoxLayoutFlexSpecification()); +} + void FocusModeTray::UpdateTrayIcon() { SkColor color; if (chromeos::features::IsJellyEnabled()) { @@ -500,7 +549,6 @@ task_item_view_->UpdateStyleToCompleted(); - // TODO(b/309857026): Call the task API to mark the task as completed. FocusModeController::Get()->CompleteTask(); // We want to show the check icon and a strikethrough on the label for
diff --git a/ash/system/focus_mode/focus_mode_tray.h b/ash/system/focus_mode/focus_mode_tray.h index abd2a688..2ca4cc0d 100644 --- a/ash/system/focus_mode/focus_mode_tray.h +++ b/ash/system/focus_mode/focus_mode_tray.h
@@ -75,6 +75,13 @@ // TODO(b/314022131): Move `TaskItemView` to its own files. class TaskItemView; + // Called when the selected task has been fetched from the tasks provider. + // Used to determine if it is completed or not. + void OnTaskFetched(const FocusModeTask& task_entry); + + // Helper function for creating and setting up the `TaskItemView`. + void CreateTaskItemView(const std::string& task_title); + // Updates the image and color of the icon. void UpdateTrayIcon(); @@ -92,7 +99,7 @@ const FocusModeSession::Snapshot& session_snapshot); // Called when the user clicks the radio button to mark a selected task as - // completed. + // completed, or if the task is already completed when we show the bubble. void OnCompleteTask(); // Called when the animation in `AnimateBubbleResize` starts.
diff --git a/ash/system/focus_mode/focus_mode_tray_unittest.cc b/ash/system/focus_mode/focus_mode_tray_unittest.cc index d3282a0..6644b69 100644 --- a/ash/system/focus_mode/focus_mode_tray_unittest.cc +++ b/ash/system/focus_mode/focus_mode_tray_unittest.cc
@@ -300,15 +300,15 @@ EXPECT_TRUE(accessibility_controller->spoken_feedback().enabled()); FocusModeController* controller = FocusModeController::Get(); - const std::string task_name = "Podcast interview script"; + const std::string task_name = "Task 1"; const base::TimeDelta session_duration = base::Minutes(40); const std::u16string time_remaining = focus_mode_util::GetDurationString( session_duration, /*digital_format=*/false); controller->SetInactiveSessionDuration(session_duration); FocusModeTask task; - task.task_list_id = "abc"; - task.task_id = "1"; + task.task_list_id = "default"; + task.task_id = "task1"; task.title = task_name; task.updated = base::Time::Now();
diff --git a/ash/system/focus_mode/sounds/soundscape/soundscapes_downloader_unittest.cc b/ash/system/focus_mode/sounds/soundscape/soundscapes_downloader_unittest.cc index d248a57..ded2fb5 100644 --- a/ash/system/focus_mode/sounds/soundscape/soundscapes_downloader_unittest.cc +++ b/ash/system/focus_mode/sounds/soundscape/soundscapes_downloader_unittest.cc
@@ -52,7 +52,6 @@ // network::SharedURLLoaderFactory: std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override { NOTREACHED(); - return nullptr; } network::TestURLLoaderFactory& test_url_loader_factory() {
diff --git a/ash/system/unified/glanceable_tray_bubble_view.h b/ash/system/unified/glanceable_tray_bubble_view.h index 5cb6168..5e413ec 100644 --- a/ash/system/unified/glanceable_tray_bubble_view.h +++ b/ash/system/unified/glanceable_tray_bubble_view.h
@@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "ash/ash_export.h" #include "ash/glanceables/classroom/glanceables_classroom_student_view.h" #include "ash/glanceables/tasks/glanceables_tasks_view.h" #include "ash/system/screen_layout_observer.h" @@ -36,7 +37,7 @@ // The bubble associated with the `GlanceableTrayBubble`. This bubble is the // container for the child `tasks` and `classroom` glanceables. -class GlanceableTrayBubbleView +class ASH_EXPORT GlanceableTrayBubbleView : public TrayBubbleView, public ScreenLayoutObserver, public GlanceablesTimeManagementBubbleView::Observer {
diff --git a/ash/webui/BUILD.gn b/ash/webui/BUILD.gn index f992036..05b7a5d 100644 --- a/ash/webui/BUILD.gn +++ b/ash/webui/BUILD.gn
@@ -30,6 +30,7 @@ "//ash/webui/eche_app_ui/mojom:unit_tests", "//ash/webui/file_manager:unit_tests", "//ash/webui/help_app_ui:unit_tests", + "//ash/webui/metrics:unit_tests", "//ash/webui/os_feedback_ui/backend:unit_tests", "//ash/webui/personalization_app:unit_tests", "//ash/webui/print_management/backend:unit_tests",
diff --git a/ash/webui/common/resources/network/network_password_input.html b/ash/webui/common/resources/network/network_password_input.html index f675b5d..dc56bf6 100644 --- a/ash/webui/common/resources/network/network_password_input.html +++ b/ash/webui/common/resources/network/network_password_input.html
@@ -36,7 +36,8 @@ on-keydown="onKeydown_" invalid="[[invalid]]" readonly="[[readonly]]" - error-message="[[errorMessage]]"> + error-message="[[errorMessage]]" + aria-label="[[ariaLabel]]"> <template is="dom-if" if="[[!showPolicyIndicator_]]" restamp> <div slot="suffix"> <cr-icon-button id="icon"
diff --git a/ash/webui/common/resources/network/network_password_input.js b/ash/webui/common/resources/network/network_password_input.js index 33e63219..f78e453 100644 --- a/ash/webui/common/resources/network/network_password_input.js +++ b/ash/webui/common/resources/network/network_password_input.js
@@ -38,6 +38,10 @@ reflectToAttribute: true, }, + ariaLabel: { + type: String, + }, + showPassword: { type: Boolean, value: false,
diff --git a/ash/webui/common/resources/network/sim_lock_dialogs.html b/ash/webui/common/resources/network/sim_lock_dialogs.html index 41d7fd94..a18f092 100644 --- a/ash/webui/common/resources/network/sim_lock_dialogs.html +++ b/ash/webui/common/resources/network/sim_lock_dialogs.html
@@ -52,7 +52,7 @@ on-enter="sendEnterPin_" disabled="[[inProgress_]]" invalid="[[hasErrorText_]]" - aria-labeledby="pinEntrySubtext"> + aria-label="[[i18n('networkSimEnterPinTitle')]]"> </network-password-input> <div class="pinEntrySubtext" aria-live="assertive"> [[getPinEntrySubtext_(error_, deviceState)]]
diff --git a/ash/webui/mall/BUILD.gn b/ash/webui/mall/BUILD.gn new file mode 100644 index 0000000..699cb72e --- /dev/null +++ b/ash/webui/mall/BUILD.gn
@@ -0,0 +1,28 @@ +# 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("//build/config/chromeos/ui_mode.gni") + +assert(is_chromeos_ash, "Mall is ash-chrome only") + +source_set("mall") { + sources = [ + "mall_ui.cc", + "mall_ui.h", + ] + + deps = [ + ":url_constants", + "//ash/webui/common:chrome_os_webui_config", + "//ash/webui/mall/resources", + "//base", + "//chromeos/constants/", + "//content/public/browser", + "//ui/webui", + ] +} + +source_set("url_constants") { + sources = [ "url_constants.h" ] +}
diff --git a/ash/webui/mall/DIR_METADATA b/ash/webui/mall/DIR_METADATA new file mode 100644 index 0000000..0a01ea9 --- /dev/null +++ b/ash/webui/mall/DIR_METADATA
@@ -0,0 +1,4 @@ +# ChromeOS > Software > Developer > Commerce +buganizer { + component_id: 1210805 +} \ No newline at end of file
diff --git a/ash/webui/mall/OWNERS b/ash/webui/mall/OWNERS new file mode 100644 index 0000000..c0140fc7 --- /dev/null +++ b/ash/webui/mall/OWNERS
@@ -0,0 +1 @@ +file:///chrome/browser/ash/mall/OWNERS \ No newline at end of file
diff --git a/ash/webui/mall/README.md b/ash/webui/mall/README.md new file mode 100644 index 0000000..30d861d --- /dev/null +++ b/ash/webui/mall/README.md
@@ -0,0 +1,3 @@ +# Mall + +WebUI wrapper to integrate the Mall website (go/cros-m-phase1) into Ash. \ No newline at end of file
diff --git a/ash/webui/mall/mall_ui.cc b/ash/webui/mall/mall_ui.cc new file mode 100644 index 0000000..3ccdab6 --- /dev/null +++ b/ash/webui/mall/mall_ui.cc
@@ -0,0 +1,33 @@ +// 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 "ash/webui/mall/mall_ui.h" + +#include "ash/webui/grit/ash_mall_cros_app_resources.h" +#include "ash/webui/mall/url_constants.h" +#include "chromeos/constants/chromeos_features.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/web_ui_data_source.h" +#include "ui/webui/mojo_web_ui_controller.h" + +namespace ash { + +bool MallUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) { + return ChromeOSWebUIConfig::IsWebUIEnabled(browser_context) && + chromeos::features::IsCrosMallSwaEnabled(); +} + +MallUI::MallUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui) { + auto* source = content::WebUIDataSource::CreateAndAdd( + web_ui->GetWebContents()->GetBrowserContext(), ash::kChromeUIMallHost); + + source->SetDefaultResource(IDR_ASH_MALL_CROS_APP_INDEX_HTML); + source->AddResourcePath("mall_icon_192.png", + IDR_ASH_MALL_CROS_APP_IMAGES_MALL_ICON_192_PNG); +} + +WEB_UI_CONTROLLER_TYPE_IMPL(MallUI) + +} // namespace ash
diff --git a/ash/webui/mall/mall_ui.h b/ash/webui/mall/mall_ui.h new file mode 100644 index 0000000..bfc5623e --- /dev/null +++ b/ash/webui/mall/mall_ui.h
@@ -0,0 +1,38 @@ +// 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 ASH_WEBUI_MALL_MALL_UI_H_ +#define ASH_WEBUI_MALL_MALL_UI_H_ + +#include "ash/webui/common/chrome_os_webui_config.h" +#include "ash/webui/mall/url_constants.h" +#include "content/public/browser/web_ui_controller.h" +#include "content/public/common/url_constants.h" +#include "ui/webui/mojo_web_ui_controller.h" +namespace ash { + +class MallUI; + +// WebUI configuration for chrome://mall. +class MallUIConfig : public ChromeOSWebUIConfig<MallUI> { + public: + MallUIConfig() + : ChromeOSWebUIConfig(content::kChromeUIScheme, ash::kChromeUIMallHost) {} + + // ash::ChromeOSWebUIConfig: + bool IsWebUIEnabled(content::BrowserContext* browser_context) override; +}; + +// WebUI controller for chrome://mall. +class MallUI : public ui::MojoWebUIController { + public: + explicit MallUI(content::WebUI* web_ui); + + private: + WEB_UI_CONTROLLER_TYPE_DECL(); +}; + +} // namespace ash + +#endif // ASH_WEBUI_MALL_MALL_UI_H_
diff --git a/ash/webui/mall/resources/BUILD.gn b/ash/webui/mall/resources/BUILD.gn new file mode 100644 index 0000000..117f218 --- /dev/null +++ b/ash/webui/mall/resources/BUILD.gn
@@ -0,0 +1,20 @@ +# 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("//build/config/chromeos/ui_mode.gni") +import("//ui/webui/resources/tools/build_webui.gni") + +assert(is_chromeos_ash, "Mall is ChromeOS only") + +build_webui("build") { + static_files = [ + "images/mall_icon_192.png", + "index.html", + ] + + non_web_component_files = [ "index.ts" ] + + grd_prefix = "ash_mall_cros_app" + grit_output_dir = "$root_gen_dir/ash/webui" +}
diff --git a/ash/webui/mall/resources/images/mall_icon_192.png b/ash/webui/mall/resources/images/mall_icon_192.png new file mode 100644 index 0000000..e0ab199 --- /dev/null +++ b/ash/webui/mall/resources/images/mall_icon_192.png Binary files differ
diff --git a/ash/webui/mall/resources/index.html b/ash/webui/mall/resources/index.html new file mode 100644 index 0000000..0d9c537 --- /dev/null +++ b/ash/webui/mall/resources/index.html
@@ -0,0 +1 @@ +<h1>Get Apps and Games :-)</h1> \ No newline at end of file
diff --git a/ash/webui/mall/resources/index.ts b/ash/webui/mall/resources/index.ts new file mode 100644 index 0000000..1705c7a --- /dev/null +++ b/ash/webui/mall/resources/index.ts
@@ -0,0 +1,3 @@ +// 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.
diff --git a/ash/webui/mall/url_constants.h b/ash/webui/mall/url_constants.h new file mode 100644 index 0000000..af535904 --- /dev/null +++ b/ash/webui/mall/url_constants.h
@@ -0,0 +1,13 @@ +// 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 ASH_WEBUI_MALL_URL_CONSTANTS_H_ +#define ASH_WEBUI_MALL_URL_CONSTANTS_H_ + +namespace ash { +inline constexpr char kChromeUIMallHost[] = "mall"; +inline constexpr char kChromeUIMallUrl[] = "chrome://mall"; +} // namespace ash + +#endif // ASH_WEBUI_MALL_URL_CONSTANTS_H_
diff --git a/ash/webui/media_app_ui/media_app_guest_ui.cc b/ash/webui/media_app_ui/media_app_guest_ui.cc index 862ec5d..4ae53ff 100644 --- a/ash/webui/media_app_ui/media_app_guest_ui.cc +++ b/ash/webui/media_app_ui/media_app_guest_ui.cc
@@ -302,8 +302,9 @@ return; } - delegate_->CreateAndBindMahiHandler(std::move(receiver), std::move(page), - file_name); + delegate_->CreateAndBindMahiHandler( + std::move(receiver), std::move(page), file_name, + web_ui()->GetWebContents()->GetTopLevelNativeWindow()); } MediaAppUserActions GetMediaAppUserActionsForHappinessTracking() {
diff --git a/ash/webui/media_app_ui/media_app_guest_ui.h b/ash/webui/media_app_ui/media_app_guest_ui.h index d01d003..339057c3 100644 --- a/ash/webui/media_app_ui/media_app_guest_ui.h +++ b/ash/webui/media_app_ui/media_app_guest_ui.h
@@ -13,6 +13,7 @@ #include "base/task/sequenced_task_runner.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_ui_data_source.h" +#include "ui/gfx/native_widget_types.h" #include "ui/webui/color_change_listener/color_change_handler.h" #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h" #include "ui/webui/untrusted_web_ui_controller.h" @@ -42,7 +43,8 @@ mojo::PendingReceiver<ash::media_app_ui::mojom::MahiUntrustedPageHandler> receiver, mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name) = 0; + const std::string& file_name, + gfx::NativeWindow window) = 0; }; // The webui for chrome-untrusted://media-app.
diff --git a/ash/webui/metrics/BUILD.gn b/ash/webui/metrics/BUILD.gn new file mode 100644 index 0000000..4ba9e82 --- /dev/null +++ b/ash/webui/metrics/BUILD.gn
@@ -0,0 +1,35 @@ +# 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("//build/config/chromeos/ui_mode.gni") +import("//testing/test.gni") + +assert(is_chromeos_ash) + +source_set("structured_metrics_service_wrapper") { + sources = [ + "structured_metrics_service_wrapper.cc", + "structured_metrics_service_wrapper.h", + ] + + deps = [ + "//base", + "//chromeos/crosapi/mojom", + "//components/metrics/structured:events", + "//components/metrics/structured:structured", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "structured_metrics_service_wrapper_unittest.cc" ] + deps = [ + ":structured_metrics_service_wrapper", + "//ash/constants", + "//base", + "//base/test:test_support", + "//components/metrics/structured:structured_events", + "//components/metrics/structured:test_support", + "//testing/gtest", + ] +}
diff --git a/ash/webui/metrics/DEPS b/ash/webui/metrics/DEPS new file mode 100644 index 0000000..6c5b2f4 --- /dev/null +++ b/ash/webui/metrics/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/metrics/structured", +]
diff --git a/ash/webui/metrics/OWNERS b/ash/webui/metrics/OWNERS new file mode 100644 index 0000000..d6564a7a --- /dev/null +++ b/ash/webui/metrics/OWNERS
@@ -0,0 +1,2 @@ +file://components/metrics/structured/OWNERS +eugenex@google.com \ No newline at end of file
diff --git a/ash/webui/metrics/structured_metrics_service_wrapper.cc b/ash/webui/metrics/structured_metrics_service_wrapper.cc new file mode 100644 index 0000000..2c1ca43e --- /dev/null +++ b/ash/webui/metrics/structured_metrics_service_wrapper.cc
@@ -0,0 +1,50 @@ +// 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 "ash/webui/metrics/structured_metrics_service_wrapper.h" + +#include "base/system/sys_info.h" +#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h" +#include "components/metrics/structured/event.h" +#include "components/metrics/structured/structured_metrics_client.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" + +namespace ash { + +StructuredMetricsServiceWrapper::StructuredMetricsServiceWrapper() = default; +StructuredMetricsServiceWrapper::~StructuredMetricsServiceWrapper() = default; + +void StructuredMetricsServiceWrapper::BindReceiver( + mojo::PendingReceiver<::crosapi::mojom::StructuredMetricsService> + receiver) { + receivers_.Add(this, std::move(receiver)); +} + +// static +base::TimeDelta StructuredMetricsServiceWrapper::ComputeEventUptime( + base::TimeDelta system_uptime, + base::TimeDelta system_timestamp, + base::TimeDelta event_timestamp) { + return system_uptime - + std::max(system_timestamp - event_timestamp, base::Seconds(0)); +} + +void StructuredMetricsServiceWrapper::Record( + std::vector<::metrics::structured::Event> events) { + for (auto& event : events) { + if (event.IsEventSequenceType()) { + event.SetRecordedTimeSinceBoot(ComputeEventUptime( + base::SysInfo::Uptime(), + base::Time::NowFromSystemTime() - base::Time::UnixEpoch(), + // if event does not have system uptime field populated, set it as the + // current system timestamp. + event.recorded_time_since_boot())); + } + ::metrics::structured::StructuredMetricsClient::Get()->Record( + std::move(event)); + } +} + +} // namespace ash
diff --git a/ash/webui/metrics/structured_metrics_service_wrapper.h b/ash/webui/metrics/structured_metrics_service_wrapper.h new file mode 100644 index 0000000..53e1b42 --- /dev/null +++ b/ash/webui/metrics/structured_metrics_service_wrapper.h
@@ -0,0 +1,47 @@ +// 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 ASH_WEBUI_METRICS_STRUCTURED_METRICS_SERVICE_WRAPPER_H_ +#define ASH_WEBUI_METRICS_STRUCTURED_METRICS_SERVICE_WRAPPER_H_ + +#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h" +#include "components/metrics/structured/event.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" + +namespace ash { + +// Implements the StructuredMetricsService mojo interface to record events. +// Wrapper to validate and record structured metrics received from WebUI. Lives +// on the UI thread. +class StructuredMetricsServiceWrapper final + : public ::crosapi::mojom::StructuredMetricsService { + public: + StructuredMetricsServiceWrapper(); + StructuredMetricsServiceWrapper(const StructuredMetricsServiceWrapper&) = + delete; + ~StructuredMetricsServiceWrapper() override; + + void BindReceiver( + mojo::PendingReceiver<::crosapi::mojom::StructuredMetricsService> + receiver); + + // Compute the Structured Event's uptime based on its timestamp and the + // system uptime and timestamp when the event is received by + // StructuredMetricsServiceWrapper. + // Static for unit testing. + static base::TimeDelta ComputeEventUptime(base::TimeDelta system_uptime, + base::TimeDelta system_timestamp, + base::TimeDelta event_timestamp); + + // crosapi::mojom::StructuredMetricsService + void Record(std::vector<::metrics::structured::Event> events) override; + + private: + mojo::ReceiverSet<::crosapi::mojom::StructuredMetricsService> receivers_; +}; + +} // namespace ash + +#endif // ASH_WEBUI_METRICS_STRUCTURED_METRICS_SERVICE_WRAPPER_H_
diff --git a/ash/webui/metrics/structured_metrics_service_wrapper_unittest.cc b/ash/webui/metrics/structured_metrics_service_wrapper_unittest.cc new file mode 100644 index 0000000..1991231 --- /dev/null +++ b/ash/webui/metrics/structured_metrics_service_wrapper_unittest.cc
@@ -0,0 +1,92 @@ +// 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 "ash/webui/metrics/structured_metrics_service_wrapper.h" + +#include "components/metrics/structured/structured_events.h" +#include "components/metrics/structured/test/test_structured_metrics_recorder.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +namespace cros_events = metrics::structured::events::v2::cr_os_events; +} // namespace + +class StructuredMetricsServiceWrapperTest : public testing::Test { + protected: + StructuredMetricsServiceWrapperTest() = default; + StructuredMetricsServiceWrapperTest( + const StructuredMetricsServiceWrapperTest&) = delete; + StructuredMetricsServiceWrapperTest& operator=( + const StructuredMetricsServiceWrapperTest&) = delete; + ~StructuredMetricsServiceWrapperTest() override = default; + + void SetUp() override { + sm_service_ = std::make_unique<StructuredMetricsServiceWrapper>(); + + metrics_recorder_ = + std::make_unique<metrics::structured::TestStructuredMetricsRecorder>(); + metrics_recorder_->Initialize(); + } + + void TearDown() override { + sm_service_.reset(); + metrics_recorder_.reset(); + } + + protected: + std::unique_ptr<StructuredMetricsServiceWrapper> sm_service_; + std::unique_ptr<metrics::structured::TestStructuredMetricsRecorder> + metrics_recorder_; +}; + +TEST_F(StructuredMetricsServiceWrapperTest, + TestRecordCrosEvent_HasEventTimestamp) { + cros_events::CameraApp_StartSession expected_event; + expected_event.SetLaunchType( + static_cast<cros_events::CameraAppLaunchType>(1)); + expected_event.SetLanguage(5); + + cros_events::CameraApp_StartSession input_event; + input_event.SetLaunchType(static_cast<cros_events::CameraAppLaunchType>(1)); + input_event.SetLanguage(5); + input_event.SetRecordedTimeSinceBoot(base::Seconds(1000)); + + std::vector<metrics::structured::Event> events; + events.emplace_back(std::move(input_event)); + sm_service_->Record(std::move(events)); + + const std::vector<metrics::structured::Event>& recorded_events = + metrics_recorder_->GetEvents(); + ASSERT_EQ(recorded_events.size(), 1U); + + auto& received_event = recorded_events[0]; + EXPECT_EQ(received_event.event_name(), expected_event.event_name()); + EXPECT_EQ(received_event.metric_values(), expected_event.metric_values()); + EXPECT_TRUE(received_event.has_system_uptime()); +} + +TEST_F(StructuredMetricsServiceWrapperTest, TestComputeEventUptime_ValidTimes) { + base::TimeDelta system_uptime = base::Seconds(4000); + base::TimeDelta system_timestamp = base::Seconds(10000); + base::TimeDelta event_timestamp = base::Seconds(7000); + base::TimeDelta expected_event_uptime = base::Seconds(1000); + EXPECT_EQ(expected_event_uptime, + sm_service_->ComputeEventUptime(system_uptime, system_timestamp, + event_timestamp)); +} + +TEST_F(StructuredMetricsServiceWrapperTest, + TestComputeEventUptime_EventTimestampLaterThanSystemTimestamp) { + base::TimeDelta system_uptime = base::Seconds(4000); + base::TimeDelta system_timestamp = base::Seconds(10000); + base::TimeDelta event_timestamp = base::Seconds(11000); + base::TimeDelta expected_event_uptime = base::Seconds(4000); + EXPECT_EQ(expected_event_uptime, + sm_service_->ComputeEventUptime(system_uptime, system_timestamp, + event_timestamp)); +} +} // namespace ash
diff --git a/ash/webui/system_apps/public/system_web_app_type.h b/ash/webui/system_apps/public/system_web_app_type.h index 42fe7ae..5677f390 100644 --- a/ash/webui/system_apps/public/system_web_app_type.h +++ b/ash/webui/system_apps/public/system_web_app_type.h
@@ -126,10 +126,15 @@ // Contact: cros-edu-eng@google.com BOCA = 27, + // Mall is an app for finding and installing other apps. + // Source: //ash/webui/mall/ + // Contact: crosdev-commerce-eng@google.com + MALL = 28, + // When adding a new System App, remember to: // // 1. Add a corresponding histogram suffix in WebAppSystemAppInternalName - // (histograms.xml). The suffix name should match the App's + // (histogram_suffixes_list.xml). The suffix name should match the App's // |internal_name|. This is for reporting per-app install results. // // 2. Add a corresponding proto enum entry (with the same numerical value) to @@ -159,13 +164,13 @@ // // 6. Update kMaxValue. // - // 7. (optional) Add your System Web App to |kSystemWebAppsMapping| in + // 7. Add your System Web App to |kSystemWebAppsMapping| in // chrome/browser/apps/app_service/policy_util.cc to make it discoverable // in policies. // // 8. Have one of System Web App Platform owners review the CL. // See: //ash/webui/PLATFORM_OWNERS - kMaxValue = BOCA, + kMaxValue = MALL, }; } // namespace ash
diff --git a/ash/wm/overview/birch/birch_bar_menu_model_adapter.cc b/ash/wm/overview/birch/birch_bar_menu_model_adapter.cc index e8dc3885..7ab04a7 100644 --- a/ash/wm/overview/birch/birch_bar_menu_model_adapter.cc +++ b/ash/wm/overview/birch/birch_bar_menu_model_adapter.cc
@@ -8,6 +8,7 @@ #include "ash/shell.h" #include "ash/style/checkbox.h" #include "ash/style/switch.h" +#include "ash/style/typography.h" #include "ash/wm/overview/birch/birch_bar_context_menu_model.h" #include "ash/wm/overview/birch/birch_bar_controller.h" #include "base/notreached.h" @@ -15,6 +16,7 @@ #include "components/prefs/pref_service.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/views/controls/menu/menu_item_view.h" #include "ui/views/controls/menu/submenu_view.h" @@ -144,6 +146,8 @@ CommandIdToSuggestionType(command_id))); checkbox->set_delegate(this); checkbox->SetAccessibleName(label); + checkbox->SetLabelStyle(TypographyToken::kCrosButton2); + checkbox->SetLabelColorId(cros_tokens::kCrosSysOnSurface); return item_view; } default:
diff --git a/ash/wm/overview/birch/birch_bar_unittest.cc b/ash/wm/overview/birch/birch_bar_unittest.cc index 201ed90..764dde0 100644 --- a/ash/wm/overview/birch/birch_bar_unittest.cc +++ b/ash/wm/overview/birch/birch_bar_unittest.cc
@@ -35,6 +35,7 @@ #include "ash/wm/splitview/split_view_types.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/files/scoped_temp_dir.h" +#include "base/functional/callback_helpers.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_mock_clock_override.h" @@ -366,7 +367,8 @@ /*guid=*/u"self share guid", /*title*/ u"self share tab", /*url=*/GURL("https://www.exampletwo.com/"), /*shared_time=*/base::Time(), /*device_name=*/u"my device", - /*favicon_url=*/faviconUrl); + /*favicon_url=*/faviconUrl, + /*activation_callback=*/base::DoNothing()); item_list.back().set_ranking(1.0f); } birch_client_->SetSelfShareItems(item_list);
diff --git a/base/BUILD.gn b/base/BUILD.gn index d7bec6b..f4543a2e 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1278,6 +1278,7 @@ ":base_shared_preferences_jni", ":callback_jni", ":command_line_jni", + ":jank_tracker_jni", ":library_loader_jni", ":memory_jni", ":metrics_jni", @@ -4346,7 +4347,6 @@ "android/java/src/org/chromium/base/Token.java", "android/java/src/org/chromium/base/TokenBase.java", "android/java/src/org/chromium/base/UnguessableToken.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", ] if (use_clang_profiling) { @@ -4506,19 +4506,6 @@ "android/java/src/org/chromium/base/UserDataHost.java", "android/java/src/org/chromium/base/ValueChangedCallback.java", "android/java/src/org/chromium/base/WrappedClassLoader.java", - "android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "android/java/src/org/chromium/base/jank_tracker/JankEndScenarioTime.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "android/java/src/org/chromium/base/jank_tracker/JankTrackerStateController.java", - "android/java/src/org/chromium/base/jank_tracker/PlaceholderJankTracker.java", ] if (use_clang_profiling) { @@ -4538,6 +4525,7 @@ ":base_switches_java", ":callback_java", ":command_line_java", + ":jank_tracker_java", ":library_loader_java", ":lifetime_java", ":log_java", @@ -4601,6 +4589,39 @@ ] } + generate_jni("jank_tracker_jni") { + sources = [ "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java" ] + } + + android_library("jank_tracker_java") { + srcjar_deps = [ ":jank_tracker_jni" ] + sources = [ + "android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", + "android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", + "android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", + "android/java/src/org/chromium/base/jank_tracker/JankEndScenarioTime.java", + "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", + "android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", + "android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", + "android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", + "android/java/src/org/chromium/base/jank_tracker/JankScenario.java", + "android/java/src/org/chromium/base/jank_tracker/JankTracker.java", + "android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", + "android/java/src/org/chromium/base/jank_tracker/JankTrackerStateController.java", + "android/java/src/org/chromium/base/jank_tracker/PlaceholderJankTracker.java", + ] + deps = [ + ":activity_state_java", + ":lifetime_java", + ":log_java", + ":tasks_java", + ":time_utils_java", + "//build/android:build_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/jni_zero:jni_zero_java", + ] + } + java_cpp_enum("memory_pressure_level_enum_srcjar") { sources = [ "memory/memory_pressure_listener.h" ] } @@ -5095,12 +5116,10 @@ "test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java", "test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java", "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java", - "test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java", "test/android/javatests/src/org/chromium/base/test/LoadNative.java", - "test/android/javatests/src/org/chromium/base/test/MockitoErrorHandler.java", "test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java", + "test/android/javatests/src/org/chromium/base/test/SharedPreferencesTestUtil.java", "test/android/javatests/src/org/chromium/base/test/TestTraceEvent.java", - "test/android/javatests/src/org/chromium/base/test/UnitTestLifetimeAssertRule.java", "test/android/javatests/src/org/chromium/base/test/params/BaseJUnit4RunnerDelegate.java", "test/android/javatests/src/org/chromium/base/test/params/BlockJUnit4RunnerDelegate.java", "test/android/javatests/src/org/chromium/base/test/params/MethodParamAnnotationRule.java", @@ -5135,7 +5154,6 @@ "test/android/javatests/src/org/chromium/base/test/util/DoNotRevive.java", "test/android/javatests/src/org/chromium/base/test/util/DumpThreadsOnFailureRule.java", "test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java", - "test/android/javatests/src/org/chromium/base/test/util/EspressoIdleTimeoutRule.java", "test/android/javatests/src/org/chromium/base/test/util/Feature.java", "test/android/javatests/src/org/chromium/base/test/util/Features.java", "test/android/javatests/src/org/chromium/base/test/util/FieldTrials.java",
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc index 25e6b37..b248bda 100644 --- a/base/allocator/partition_alloc_support.cc +++ b/base/allocator/partition_alloc_support.cc
@@ -454,6 +454,13 @@ internal::PartitionLock g_stack_trace_buffer_lock; +constexpr size_t kDanglingPtrStackTraceSize = + PA_BUILDFLAG(IS_DEBUG) + ? 32 // Symbolizing large stack traces can be expensive in debug + // builds. We prefer displaying a reasonably sized one instead + // of timing out. + : base::debug::StackTrace::kMaxTraces; + struct DanglingPointerFreeInfo { debug::StackTrace stack_trace; debug::TaskTrace task_trace; @@ -476,7 +483,11 @@ for (std::optional<DanglingPointerFreeInfo>& entry : g_stack_trace_buffer) { if (!entry) { - entry = {debug::StackTrace(), debug::TaskTrace(), id}; + entry = { + debug::StackTrace(kDanglingPtrStackTraceSize), + debug::TaskTrace(), + id, + }; return; } } @@ -634,7 +645,8 @@ // This is called from raw_ptr<>'s release operation. Making allocations is // allowed. In particular, symbolizing and printing the StackTraces may // allocate memory. - debug::StackTrace stack_trace_release; + + debug::StackTrace stack_trace_release(kDanglingPtrStackTraceSize); debug::TaskTrace task_trace_release; std::optional<DanglingPointerFreeInfo> free_info = TakeDanglingPointerFreeInfo(id); @@ -1448,6 +1460,9 @@ void PartitionAllocSupport::OnForegrounded(bool has_main_frame) { #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) + // Other changes are renderer-only, not this one. + MemoryReclaimerSupport::Instance().SetForegrounded(true); + { base::AutoLock scoped_lock(lock_); if (established_process_type_ != switches::kRendererProcess) { @@ -1466,12 +1481,13 @@ allocator_shim::AdjustDefaultAllocatorForForeground(); } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - - MemoryReclaimerSupport::Instance().SetForegrounded(true); } void PartitionAllocSupport::OnBackgrounded() { #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) + // Other changes are renderer-only, not this one. + MemoryReclaimerSupport::Instance().SetForegrounded(false); + { base::AutoLock scoped_lock(lock_); if (established_process_type_ != switches::kRendererProcess) { @@ -1505,8 +1521,6 @@ allocator_shim::AdjustDefaultAllocatorForBackground(); } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - - MemoryReclaimerSupport::Instance().SetForegrounded(false); } #if PA_BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
diff --git a/base/allocator/partition_alloc_support.h b/base/allocator/partition_alloc_support.h index 011064a1..1fbf5b9d 100644 --- a/base/allocator/partition_alloc_support.h +++ b/base/allocator/partition_alloc_support.h
@@ -81,7 +81,9 @@ void ReconfigureAfterTaskRunnerInit(const std::string& process_type); // |has_main_frame| tells us if the renderer contains a main frame. - void OnForegrounded(bool has_main_frame); + // The default value is intended for other process types, where the parameter + // does not make sense. + void OnForegrounded(bool has_main_frame = false); void OnBackgrounded(); #if PA_BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni index e4f5445..f9f5ef05 100644 --- a/base/allocator/partition_allocator/partition_alloc.gni +++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -415,3 +415,17 @@ # Embedders may opt-out of using C++ 20 build. assert_cpp20 = assert_cpp20_default } + +declare_args() { + # Enables compilation of the freelist dispatcher, which we'll use to + # carry out runtime evaluation of PartitionAlloc's two freelist + # implementations: the existing encoded-next freelist and the new + # pool offset freelist. When false, the latter is not built. + # + # This is being exposed as a GN arg because of an undiagnosed crashy + # interaction with Mac PGO builders: crbug.com/338094768#comment20 + use_freelist_dispatcher = has_64_bit_pointers && false +} + +assert(has_64_bit_pointers || !use_freelist_dispatcher, + "freelist dispatcher can't be used without 64-bit pointers")
diff --git a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn index 48ff3ed..2d402441 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn +++ b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
@@ -156,12 +156,6 @@ configs += [ ":dependants_extra_warnings" ] } -# Enables compilation of the freelist dispatcher, which we'll use to -# carry out runtime evaluation of PartitionAlloc's two freelist -# implementations: the existing encoded-next freelist and the new -# pool offset freelist. When false, the latter is not built. -use_freelist_dispatcher = has_64_bit_pointers && false - pa_buildflag_header("partition_alloc_buildflags") { header = "partition_alloc_buildflags.h" @@ -232,6 +226,7 @@ "FORWARD_THROUGH_MALLOC=$forward_through_malloc", "ASSERT_CPP_20=$assert_cpp20", + "IS_DEBUG=$is_debug", ] }
diff --git a/base/android/feature_map.cc b/base/android/feature_map.cc index 6768aae..305e76be6 100644 --- a/base/android/feature_map.cc +++ b/base/android/feature_map.cc
@@ -36,8 +36,8 @@ return it->second; } - NOTREACHED_NORETURN() << "Queried feature cannot be found in FeatureMap: " - << feature_name; + NOTREACHED() << "Queried feature cannot be found in FeatureMap: " + << feature_name; } static jboolean JNI_FeatureMap_IsEnabled(JNIEnv* env,
diff --git a/base/android/jank_metric_uma_recorder.cc b/base/android/jank_metric_uma_recorder.cc index 2fe997840..50c3211 100644 --- a/base/android/jank_metric_uma_recorder.cc +++ b/base/android/jank_metric_uma_recorder.cc
@@ -8,7 +8,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_array.h" -#include "base/base_jni/JankMetricUMARecorder_jni.h" +#include "base/jank_tracker_jni/JankMetricUMARecorder_jni.h" #include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/time/time.h"
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineFlagsTest.java b/base/android/javatests/src/org/chromium/base/CommandLineFlagsTest.java index 100bad2..5f46bd3 100644 --- a/base/android/javatests/src/org/chromium/base/CommandLineFlagsTest.java +++ b/base/android/javatests/src/org/chromium/base/CommandLineFlagsTest.java
@@ -13,6 +13,7 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runner.RunWith; +import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; @@ -22,8 +23,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; -import java.util.List; - /** Test class for {@link CommandLineFlags}. */ @RunWith(CommandLineFlagsTest.ClassRunner.class) @Batch(Batch.UNIT_TESTS) @@ -40,29 +39,22 @@ // Verify class-level modifications are reset after class finishes. @Override - protected List<ClassHook> getPostClassHooks() { - return addToList( - ClassRunner.super.getPostClassHooks(), - (targetContext, testClass) -> { - verifyCommandLine(false, false, false, false, false, false, false); - Assert.assertFalse(CommandLine.getInstance().hasSwitch("flagwithvalue")); - String enabledFeatures = - CommandLine.getInstance().getSwitchValue("enable-features"); - if (enabledFeatures != null) { - Assert.assertFalse(enabledFeatures.contains("feature1")); - Assert.assertFalse(enabledFeatures.contains("feature2")); - } - }); + protected void onAfterTestClass() { + super.onAfterTestClass(); + verifyCommandLine(false, false, false, false, false, false, false); + Assert.assertFalse(CommandLine.getInstance().hasSwitch("flagwithvalue")); + String enabledFeatures = CommandLine.getInstance().getSwitchValue("enable-features"); + if (enabledFeatures != null) { + Assert.assertFalse(enabledFeatures.contains("feature1")); + Assert.assertFalse(enabledFeatures.contains("feature2")); + } } // Verify that after each test, flags are reset to class-level state. @Override - protected List<TestHook> getPostTestHooks() { - return addToList( - ClassRunner.super.getPostTestHooks(), - (targetContext, testMethod) -> { - verifyClassLevelStateOnly(); - }); + protected void onAfterTestMethod(FrameworkMethod method) { + super.onAfterTestMethod(method); + verifyClassLevelStateOnly(); } }
diff --git a/base/check.cc b/base/check.cc index 39286d0..b5f12ab 100644 --- a/base/check.cc +++ b/base/check.cc
@@ -396,8 +396,8 @@ log_message_.reset(); // Make sure we die if we haven't. - // TODO(crbug.com/40254046): Replace this with NOTREACHED_NORETURN() once - // LOG(FATAL) is [[noreturn]]. + // TODO(crbug.com/40254046): Replace this with NOTREACHED() once LOG(FATAL) is + // [[noreturn]]. base::ImmediateCrash(); }
diff --git a/base/check_unittest.cc b/base/check_unittest.cc index 9a5db5918..c61dcc6 100644 --- a/base/check_unittest.cc +++ b/base/check_unittest.cc
@@ -505,10 +505,10 @@ CHECK_EQ(g, h)); } -// This non-void function is here to make sure that NOTREACHED_NORETURN() is -// properly annotated as [[noreturn]] and does not require a return statement. -int NotReachedNoreturnInFunction() { - NOTREACHED_NORETURN(); +// This non-void function is here to make sure that NOTREACHED() is properly +// annotated as [[noreturn]] and does not require a return statement. +int NotReachedInFunction() { + NOTREACHED(); // No return statement here. } @@ -549,7 +549,7 @@ "Check failed: false. NOTREACHED log messages " "are omitted in official builds. Sorry!\n"); #endif - EXPECT_DEATH_IF_SUPPORTED(NotReachedNoreturnInFunction(), + EXPECT_DEATH_IF_SUPPORTED(NotReachedInFunction(), CHECK_WILL_STREAM() ? "NOTREACHED hit. " : ""); }
diff --git a/base/features.cc b/base/features.cc index e8e437aa..4f9f7fa 100644 --- a/base/features.cc +++ b/base/features.cc
@@ -40,11 +40,11 @@ FEATURE_ENABLED_BY_DEFAULT); // TODO(crbug.com/40580068): Roll out this to 100% before replacing existing -// NOTREACHED_IN_MIGRATION()s with NOTREACHED_NORETURN() as part of -// NOTREACHED_IN_MIGRATION() migration. Note that a prerequisite for rolling out -// this experiment is that existing NOTREACHED reports are at a very low rate. -// Once this rolls out we should monitor that crash rates for the experiment -// population is within a 1-5% or lower than the control group. +// NOTREACHED_IN_MIGRATION()s with NOTREACHED() as part of [[noreturn]] +// migration. Note that a prerequisite for rolling out this experiment is that +// existing NOTREACHED() reports are at a very low rate. Once this rolls out we +// should monitor that crash rates for the experiment population is within a +// 1-5% or lower than the control group. BASE_FEATURE(kNotReachedIsFatal, "NotReachedIsFatal", FEATURE_DISABLED_BY_DEFAULT);
diff --git a/base/json/json_correctness_fuzzer.cc b/base/json/json_correctness_fuzzer.cc index 0f49de3..68a00d2 100644 --- a/base/json/json_correctness_fuzzer.cc +++ b/base/json/json_correctness_fuzzer.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - // A fuzzer that checks correctness of json parser/writer. // The fuzzer input is passed through parsing twice, // so that presumably valid json is parsed/written again. @@ -17,6 +12,9 @@ #include <string> #include <string_view> +#include "base/compiler_specific.h" +#include "base/containers/heap_array.h" +#include "base/containers/span.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/json/string_escape.h" @@ -30,14 +28,17 @@ if (size < 2) return 0; + // SAFETY: required from fuzzer. + auto all_input = UNSAFE_BUFFERS(base::span<const uint8_t>(data, size)); + // Create a copy of input buffer, as otherwise we don't catch // overflow that touches the last byte (which is used in options). - std::unique_ptr<char[]> input(new char[size - 1]); - memcpy(input.get(), data, size - 1); + auto input = base::HeapArray<char>::CopiedFrom( + base::as_chars(all_input.first(size - 1))); - std::string_view input_string(input.get(), size - 1); + std::string_view input_string = base::as_string_view(input.as_span()); - const int options = data[size - 1]; + const int options = all_input[size - 1]; auto result = base::JSONReader::ReadAndReturnValueWithError(input_string, options); if (!result.has_value())
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc index e9cf67b..64a3b9a7 100644 --- a/base/json/json_parser.cc +++ b/base/json/json_parser.cc
@@ -189,50 +189,6 @@ return error_column_; } -// StringBuilder /////////////////////////////////////////////////////////////// - -JSONParser::StringBuilder::StringBuilder() : StringBuilder(nullptr) {} - -JSONParser::StringBuilder::StringBuilder(const char* pos) - : pos_(pos), length_(0) {} - -JSONParser::StringBuilder::~StringBuilder() = default; - -JSONParser::StringBuilder& JSONParser::StringBuilder::operator=( - StringBuilder&& other) = default; - -void JSONParser::StringBuilder::Append(base_icu::UChar32 point) { - DCHECK(IsValidCodepoint(point)); - - if (point < kExtendedASCIIStart) { - if (!string_) { - DCHECK_EQ(static_cast<char>(point), pos_[length_]); - ++length_; - } else { - string_->push_back(static_cast<char>(point)); - } - } else { - Convert(); - if (UNLIKELY(point == kUnicodeReplacementPoint)) { - string_->append(kUnicodeReplacementString); - } else { - WriteUnicodeCharacter(point, &*string_); - } - } -} - -void JSONParser::StringBuilder::Convert() { - if (string_) - return; - string_.emplace(pos_, length_); -} - -std::string JSONParser::StringBuilder::DestructiveAsString() { - if (string_) - return std::move(*string_); - return std::string(pos_, length_); -} - // JSONParser private ////////////////////////////////////////////////////////// std::optional<std::string_view> JSONParser::PeekChars(size_t count) { @@ -444,8 +400,8 @@ } // First consume the key. - StringBuilder key; - if (!ConsumeStringRaw(&key)) { + std::optional<std::string> key = ConsumeStringRaw(); + if (!key) { return std::nullopt; } @@ -464,7 +420,7 @@ return std::nullopt; } - values.emplace_back(key.DestructiveAsString(), std::move(*value)); + values.emplace_back(std::move(*key), std::move(*value)); token = GetNextToken(); if (token == T_LIST_SEPARATOR) { @@ -532,176 +488,208 @@ } std::optional<Value> JSONParser::ConsumeString() { - StringBuilder string; - if (!ConsumeStringRaw(&string)) + std::optional<std::string> string = ConsumeStringRaw(); + if (!string) { return std::nullopt; - return Value(string.DestructiveAsString()); + } + return Value(std::move(*string)); } -bool JSONParser::ConsumeStringRaw(StringBuilder* out) { +std::optional<std::string> JSONParser::ConsumeStringRaw() { if (ConsumeChar() != '"') { ReportError(JSON_UNEXPECTED_TOKEN, 0); - return false; + return std::nullopt; } - // StringBuilder will internally build a std::string_view unless a UTF-16 - // conversion occurs, at which point it will perform a copy into a - // std::string. - StringBuilder string(pos()); + std::string string; + for (;;) { + auto [result, consumed] = ConsumeStringPart(); + switch (result) { + case StringResult::kError: + return std::nullopt; + case StringResult::kDone: + // This is the last time we're appending, so pre-reserve the desired + // size, to prevent `+=` from overallocating. (In other cases, the + // overallocating is desirable for amortization.) In particular, + // the common case is that `string` is empty and we return in one step. + string.reserve(string.size() + consumed.size()); + string += consumed; + return std::move(string); + + case StringResult::kReplacementCharacter: + string += consumed; + string += kUnicodeReplacementString; + break; // Keep parsing. + + case StringResult::kEscape: + string += consumed; + std::optional<char> escape_char = ConsumeChar(); + if (!escape_char) { + ReportError(JSON_INVALID_ESCAPE, -1); + return std::nullopt; + } + + switch (*escape_char) { + // Allowed esape sequences: + case 'x': { // UTF-8 sequence. + // UTF-8 \x escape sequences are not allowed in the spec, but they + // are supported here for backwards-compatiblity with the old + // parser. + UmaHistogramEnumeration(kExtensionHistogramName, + ChromiumJsonExtension::kXEscape); + if (!(options_ & JSON_ALLOW_X_ESCAPES)) { + ReportError(JSON_INVALID_ESCAPE, -1); + return std::nullopt; + } + + std::optional<std::string_view> escape_sequence = ConsumeChars(2); + if (!escape_sequence) { + ReportError(JSON_INVALID_ESCAPE, -3); + return std::nullopt; + } + + int hex_digit = 0; + if (!UnprefixedHexStringToInt(*escape_sequence, &hex_digit) || + !IsValidCharacter(hex_digit)) { + ReportError(JSON_INVALID_ESCAPE, -3); + return std::nullopt; + } + + WriteUnicodeCharacter(hex_digit, &string); + break; + } + case 'u': { // UTF-16 sequence. + // UTF units are of the form \uXXXX. + base_icu::UChar32 code_point; + if (!DecodeUTF16(&code_point)) { + ReportError(JSON_INVALID_ESCAPE, -1); + return std::nullopt; + } + WriteUnicodeCharacter(code_point, &string); + break; + } + case '"': + string.push_back('"'); + break; + case '\\': + string.push_back('\\'); + break; + case '/': + string.push_back('/'); + break; + case 'b': + string.push_back('\b'); + break; + case 'f': + string.push_back('\f'); + break; + case 'n': + string.push_back('\n'); + break; + case 'r': + string.push_back('\r'); + break; + case 't': + string.push_back('\t'); + break; + case 'v': // Not listed as valid escape sequence in the RFC. + UmaHistogramEnumeration(kExtensionHistogramName, + ChromiumJsonExtension::kVerticalTabEscape); + if (!(options_ & JSON_ALLOW_VERT_TAB)) { + ReportError(JSON_INVALID_ESCAPE, -1); + return std::nullopt; + } + string.push_back('\v'); + break; + // All other escape squences are illegal. + default: + ReportError(JSON_INVALID_ESCAPE, -1); + return std::nullopt; + } + break; // Keep parsing. + } + } +} + +std::pair<JSONParser::StringResult, std::string_view> +JSONParser::ConsumeStringPart() { + const size_t start_index = index_; while (std::optional<char> c = PeekChar()) { - base_icu::UChar32 next_char = 0; - if (static_cast<unsigned char>(*c) < kExtendedASCIIStart) { - // Fast path for ASCII. - next_char = *c; - } else if (!ReadUnicodeCharacter(input_.data(), input_.length(), &index_, - &next_char)) { - if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { - ReportError(JSON_UNSUPPORTED_ENCODING, 0); - return false; + // Handle non-ASCII characters, which never trigger any special handling + // beyond needing to be valid UTF-8. ASCII characters will be handled + // separately below. + if (static_cast<unsigned char>(*c) >= kExtendedASCIIStart) { + base_icu::UChar32 next_char = 0; + size_t last_index = index_; + if (!ReadUnicodeCharacter(input_.data(), input_.length(), &index_, + &next_char)) { + if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { + ReportError(JSON_UNSUPPORTED_ENCODING, 0); + // No need to return consumed data. + return {StringResult::kError, {}}; + } + ConsumeChar(); + return {StringResult::kReplacementCharacter, + input_.substr(start_index, last_index - start_index)}; } + + // Valid UTF-8 will be copied as-is into the output, so keep processing. + DCHECK_GT(next_char, kExtendedASCIIStart); ConsumeChar(); - string.Append(kUnicodeReplacementPoint); continue; } - if (next_char == '"') { + if (*c == '"') { + std::string_view ret = input_.substr(start_index, index_ - start_index); ConsumeChar(); - *out = std::move(string); - return true; + return {StringResult::kDone, ret}; } - if (next_char != '\\') { - // Per Section 7, "All Unicode characters may be placed within the - // quotation marks, except for the characters that MUST be escaped: - // quotation mark, reverse solidus, and the control characters (U+0000 - // through U+001F)". - if (next_char == '\n' || next_char == '\r') { - UmaHistogramEnumeration(kExtensionHistogramName, - ChromiumJsonExtension::kNewlineInString); - if (!(options_ & - (JSON_ALLOW_NEWLINES_IN_STRINGS | JSON_ALLOW_CONTROL_CHARS))) { - ReportError(JSON_UNSUPPORTED_ENCODING, -1); - return false; - } - } else if (next_char <= 0x1F) { - UmaHistogramEnumeration(kExtensionHistogramName, - ChromiumJsonExtension::kControlCharacter); - if (!(options_ & JSON_ALLOW_CONTROL_CHARS)) { - ReportError(JSON_UNSUPPORTED_ENCODING, -1); - return false; - } - } - - // If this character is not an escape sequence, track any line breaks and - // copy next_char to the StringBuilder. The JSON spec forbids unescaped - // ASCII control characters within a string, including '\r' and '\n', but - // this implementation is more lenient. - if ((next_char == '\r') || (next_char == '\n')) { - index_last_line_ = index_; - // Don't increment line_number_ twice for "\r\n". We are guaranteed - // that (index_ > 0) because we are consuming a string, so we must have - // seen an opening '"' quote character. - if ((next_char == '\r') || (input_[index_ - 1] != '\r')) { - ++line_number_; - } - } + if (*c == '\\') { + std::string_view ret = input_.substr(start_index, index_ - start_index); ConsumeChar(); - string.Append(next_char); - } else { - // And if it is an escape sequence, the input string will be adjusted - // (either by combining the two characters of an encoded escape sequence, - // or with a UTF conversion), so using std::string_view isn't possible -- - // force a conversion. - string.Convert(); + return {StringResult::kEscape, ret}; + } - // Read past the escape '\' and ensure there's a character following. - std::optional<std::string_view> escape_sequence = ConsumeChars(2); - if (!escape_sequence) { - ReportError(JSON_INVALID_ESCAPE, -1); - return false; + // Per Section 7, "All Unicode characters may be placed within the + // quotation marks, except for the characters that MUST be escaped: + // quotation mark, reverse solidus, and the control characters (U+0000 + // through U+001F)". + if (*c == '\n' || *c == '\r') { + UmaHistogramEnumeration(kExtensionHistogramName, + ChromiumJsonExtension::kNewlineInString); + if (!(options_ & + (JSON_ALLOW_NEWLINES_IN_STRINGS | JSON_ALLOW_CONTROL_CHARS))) { + ReportError(JSON_UNSUPPORTED_ENCODING, -1); + return {StringResult::kError, {}}; // No need to return consumed data. } - - switch ((*escape_sequence)[1]) { - // Allowed esape sequences: - case 'x': { // UTF-8 sequence. - // UTF-8 \x escape sequences are not allowed in the spec, but they - // are supported here for backwards-compatiblity with the old parser. - UmaHistogramEnumeration(kExtensionHistogramName, - ChromiumJsonExtension::kXEscape); - if (!(options_ & JSON_ALLOW_X_ESCAPES)) { - ReportError(JSON_INVALID_ESCAPE, -1); - return false; - } - - escape_sequence = ConsumeChars(2); - if (!escape_sequence) { - ReportError(JSON_INVALID_ESCAPE, -3); - return false; - } - - int hex_digit = 0; - if (!UnprefixedHexStringToInt(*escape_sequence, &hex_digit) || - !IsValidCharacter(hex_digit)) { - ReportError(JSON_INVALID_ESCAPE, -3); - return false; - } - - string.Append(hex_digit); - break; - } - case 'u': { // UTF-16 sequence. - // UTF units are of the form \uXXXX. - base_icu::UChar32 code_point; - if (!DecodeUTF16(&code_point)) { - ReportError(JSON_INVALID_ESCAPE, -1); - return false; - } - string.Append(code_point); - break; - } - case '"': - string.Append('"'); - break; - case '\\': - string.Append('\\'); - break; - case '/': - string.Append('/'); - break; - case 'b': - string.Append('\b'); - break; - case 'f': - string.Append('\f'); - break; - case 'n': - string.Append('\n'); - break; - case 'r': - string.Append('\r'); - break; - case 't': - string.Append('\t'); - break; - case 'v': // Not listed as valid escape sequence in the RFC. - UmaHistogramEnumeration(kExtensionHistogramName, - ChromiumJsonExtension::kVerticalTabEscape); - if (!(options_ & JSON_ALLOW_VERT_TAB)) { - ReportError(JSON_INVALID_ESCAPE, -1); - return false; - } - string.Append('\v'); - break; - // All other escape squences are illegal. - default: - ReportError(JSON_INVALID_ESCAPE, -1); - return false; + } else if (*c <= 0x1F) { + UmaHistogramEnumeration(kExtensionHistogramName, + ChromiumJsonExtension::kControlCharacter); + if (!(options_ & JSON_ALLOW_CONTROL_CHARS)) { + ReportError(JSON_UNSUPPORTED_ENCODING, -1); + return {StringResult::kError, {}}; // No need to return consumed data. } } + + // If this character is not an escape sequence, track any line breaks and + // keep parsing. The JSON spec forbids unescaped ASCII control characters + // within a string, including '\r' and '\n', but this implementation is more + // lenient. + if (*c == '\r' || *c == '\n') { + index_last_line_ = index_; + // Don't increment line_number_ twice for "\r\n". We are guaranteed that + // (index_ > 0) because we are consuming a string, so we must have seen an + // opening '"' quote character. + if ((*c == '\r') || (input_[index_ - 1] != '\r')) { + ++line_number_; + } + } + ConsumeChar(); } ReportError(JSON_SYNTAX_ERROR, -1); - return false; + return {StringResult::kError, {}}; // No need to return consumed data. } // Entry is at the first X in \uXXXX.
diff --git a/base/json/json_parser.h b/base/json/json_parser.h index d0c5caa..a26b7da0 100644 --- a/base/json/json_parser.h +++ b/base/json/json_parser.h
@@ -12,6 +12,7 @@ #include <optional> #include <string> #include <string_view> +#include <utility> #include "base/base_export.h" #include "base/compiler_specific.h" @@ -114,50 +115,6 @@ T_INVALID_TOKEN, }; - // A helper class used for parsing strings. One optimization performed is to - // create base::Value with a std::string_view to avoid unnecessary std::string - // copies. This is not possible if the input string needs to be decoded from - // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped. - // This class centralizes that logic. - class StringBuilder { - public: - // Empty constructor. Used for creating a builder with which to assign to. - StringBuilder(); - - // |pos| is the beginning of an input string, excluding the |"|. - explicit StringBuilder(const char* pos); - - ~StringBuilder(); - - StringBuilder& operator=(StringBuilder&& other); - - // Appends the Unicode code point |point| to the string, either by - // increasing the |length_| of the string if the string has not been - // converted, or by appending the UTF8 bytes for the code point. - void Append(base_icu::UChar32 point); - - // Converts the builder from its default std::string_view to a full - // std::string, performing a copy. Once a builder is converted, it cannot be - // made a std::string_view again. - void Convert(); - - // Returns the builder as a string, invalidating all state. This allows - // the internal string buffer representation to be destructively moved - // in cases where the builder will not be needed any more. - std::string DestructiveAsString(); - - private: - // The beginning of the input string. - const char* pos_; - - // Number of bytes in |pos_| that make up the string being built. - size_t length_; - - // The copied string representation. Will be unset until Convert() is - // called. - std::optional<std::string> string_; - }; - // Returns the next |count| bytes of the input stream, or nullopt if fewer // than |count| bytes remain. std::optional<std::string_view> PeekChars(size_t count); @@ -205,10 +162,34 @@ std::optional<Value> ConsumeString(); // Assuming that the parser is wound to a double quote, this parses a string, - // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on - // success and places result into |out|. Returns false on failure with - // error information set. - bool ConsumeStringRaw(StringBuilder* out); + // decoding any escape sequences and validating UTF-8. Returns the string on + // success or std::nullopt on error, with error information set. + std::optional<std::string> ConsumeStringRaw(); + + enum class StringResult { + // Parsing stopped because of invalid input. Error information has been set. + // The caller should return failure. + kError, + // Parsing stopped because the string is finished. The parser is wound to + // just paste the closing quote. The caller should stop parsing the string. + kDone, + // Parsing stopped because of invalid Unicode which should be replaced with + // a replacement character. The parser is wound to just past the input that + // should be a replacement character. The caller should add a replacement + // character and continue parsing. + kReplacementCharacter, + // Parsing stopped because of an escape sequence. The parser is wound to + // just past the backslash. The caller should consume the escape sequence + // and continue parsing. + kEscape, + }; + + // Consumes the portion of a JavaScript string which may be copied to the + // input with no conversions, stopping at one of the events above. Returns the + // reason parsing stopped and the data that was consumed. This should be + // called in a loop, handling all the cases above until reaching kDone. + std::pair<StringResult, std::string_view> ConsumeStringPart(); + // Helper function for ConsumeStringRaw() that consumes the next four or 10 // bytes (parser is wound to the first character of a HEX sequence, with the // potential for consuming another \uXXXX for a surrogate). Returns true on
diff --git a/base/json/string_escape_fuzzer.cc b/base/json/string_escape_fuzzer.cc index 360b085..1e4e769c 100644 --- a/base/json/string_escape_fuzzer.cc +++ b/base/json/string_escape_fuzzer.cc
@@ -2,39 +2,41 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif +#include "base/json/string_escape.h" #include <memory> #include <string_view> -#include "base/json/string_escape.h" +#include "base/compiler_specific.h" +#include "base/containers/heap_array.h" +#include "base/containers/span.h" // Entry point for LibFuzzer. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size < 2) return 0; - const bool put_in_quotes = data[size - 1]; + // SAFETY: required from fuzzer. + auto all_input = UNSAFE_BUFFERS(base::span<const uint8_t>(data, size)); + + const bool put_in_quotes = all_input[size - 1]; // Create a copy of input buffer, as otherwise we don't catch // overflow that touches the last byte (which is used in put_in_quotes). - size_t actual_size_char8 = size - 1; - std::unique_ptr<char[]> input(new char[actual_size_char8]); - memcpy(input.get(), data, actual_size_char8); + auto input = base::HeapArray<char>::CopiedFrom( + base::as_chars(all_input.first(size - 1))); - std::string_view input_string(input.get(), actual_size_char8); + std::string_view input_string = base::as_string_view(input.as_span()); std::string escaped_string; base::EscapeJSONString(input_string, put_in_quotes, &escaped_string); // Test for wide-strings if available size is even. - if (actual_size_char8 & 1) + if (input.size() & 1) { return 0; + } - size_t actual_size_char16 = actual_size_char8 / 2; - std::u16string_view input_string16(reinterpret_cast<char16_t*>(input.get()), + size_t actual_size_char16 = input.size() / 2; + std::u16string_view input_string16(reinterpret_cast<char16_t*>(input.data()), actual_size_char16); escaped_string.clear(); base::EscapeJSONString(input_string16, put_in_quotes, &escaped_string);
diff --git a/base/notreached.h b/base/notreached.h index 248fe96..26c4eed 100644 --- a/base/notreached.h +++ b/base/notreached.h
@@ -46,18 +46,10 @@ : EAT_CHECK_STREAM_PARAMS() #endif -// TODO(crbug.com/40580068): Migrate existing NOTREACHED() instances to -// NOTREACHED_IN_MIGRATION() then replace the NOTREACHED_IN_MIGRATION() branch -// here with the NOTREACHED_NORETURN() implementation. -#define NOTREACHED(...) \ - BASE_IF(BASE_IS_EMPTY(__VA_ARGS__), NOTREACHED_IN_MIGRATION(), \ - LOGGING_CHECK_FUNCTION_IMPL( \ - ::logging::NotReachedError::NotReached(__VA_ARGS__), false)) - // NOTREACHED_NORETURN() annotates paths that are supposed to be unreachable. // They crash if they are ever hit. -// TODO(crbug.com/40580068): Rename back to NOTREACHED() once there are no -// callers of the old non-CHECK-fatal macro. +// TODO(crbug.com/40580068): Merge this with NOTREACHED() once +// NOTREACHED_NORETURN() callers are renamed NOTREACHED(). #if CHECK_WILL_STREAM() #define NOTREACHED_NORETURN() ::logging::NotReachedNoreturnError() #else @@ -72,6 +64,11 @@ (true) ? ::logging::NotReachedFailure() : EAT_CHECK_STREAM_PARAMS() #endif +#define NOTREACHED(...) \ + BASE_IF(BASE_IS_EMPTY(__VA_ARGS__), NOTREACHED_NORETURN(), \ + LOGGING_CHECK_FUNCTION_IMPL( \ + ::logging::NotReachedError::NotReached(__VA_ARGS__), false)) + // The DUMP_WILL_BE_NOTREACHED_NORETURN() macro provides a convenient way to // non-fatally dump in official builds if ever hit. See DUMP_WILL_BE_CHECK for // suggested usage.
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java index 87c463a..3911255 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
@@ -16,6 +16,7 @@ import androidx.core.content.ContextCompat; import androidx.test.InstrumentationRegistry; +import androidx.test.espresso.IdlingPolicies; import androidx.test.internal.runner.ClassPathScanner; import androidx.test.internal.runner.RunnerArgs; import androidx.test.internal.runner.TestExecutor; @@ -171,7 +172,7 @@ private void initTestRunner(Bundle arguments) { org.chromium.base.test.ActivityFinisher.finishAll(); - BaseJUnit4TestRule.clearJobSchedulerJobs(); + BaseJUnit4ClassRunner.clearJobSchedulerJobs(); clearDataDirectory(sInMemorySharedPreferencesContext); setInTouchMode(true); // //third_party/mockito is looking for android.support.test.InstrumentationRegistry. @@ -180,6 +181,8 @@ System.setProperty( "org.mockito.android.target", sInMemorySharedPreferencesContext.getCacheDir().getPath()); + // Reduce the time Espresso waits before failing to be less than the Python test timeout. + IdlingPolicies.setMasterPolicyTimeout(20, TimeUnit.SECONDS); setClangCoverageEnvIfEnabled(); if (arguments.getString(IS_UNIT_TEST_FLAG) != null) { LibraryLoader.setBrowserProcessStartupBlockedForTesting();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java index bc6dcb6..29726bce 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
@@ -5,6 +5,7 @@ package org.chromium.base.test; import android.app.Application; +import android.app.job.JobScheduler; import android.content.Context; import android.os.Bundle; import android.os.SystemClock; @@ -24,16 +25,17 @@ import org.chromium.base.FeatureParam; import org.chromium.base.Flag; +import org.chromium.base.LifetimeAssert; import org.chromium.base.Log; import org.chromium.base.ResettersForTesting; import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.metrics.UmaRecorderHolder; import org.chromium.base.test.params.MethodParamAnnotationRule; import org.chromium.base.test.util.AndroidSdkLevelSkipCheck; import org.chromium.base.test.util.BaseRestrictions; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisableIfSkipCheck; -import org.chromium.base.test.util.EspressoIdleTimeoutRule; import org.chromium.base.test.util.RequiresRestart; import org.chromium.base.test.util.RestrictionSkipCheck; import org.chromium.base.test.util.SkipCheck; @@ -42,7 +44,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.TimeUnit; /** * A custom runner for JUnit4 tests that checks requirements to conditionally ignore tests. @@ -69,8 +70,6 @@ * <p>The only reason to use a ClassHook instead of a TestRule is * because @BeforeClass/@AfterClass run during test listing, or multiple times for parameterized * tests. See https://crbug.com/1090043. - * - * <p>TODO(crbug.com/40134682): Migrate all Class/Test Hooks to TestRules. */ public interface ClassHook { /** @@ -97,6 +96,7 @@ } protected final RestrictionSkipCheck mRestrictionSkipCheck = new RestrictionSkipCheck(); + private long mTestStartTimeMs; /** * Create a BaseJUnit4ClassRunner to run {@code klass} and initialize values. @@ -166,7 +166,7 @@ } /** - * See {@link ClassHook}. Prefer to use TestRules over this. + * See {@link ClassHook}. * * <p>Additional hooks can be added to the list by overriding this method and using {@link * #addToList}: {@code return addToList(super.getPreClassHooks(), hook1, hook2);} @@ -177,18 +177,7 @@ } /** - * See {@link ClassHook}. Prefer to use TestRules over this. - * - * <p>Additional hooks can be added to the list by overriding this method and using {@link - * #addToList}: {@code return addToList(super.getPostClassHooks(), hook1, hook2);} - */ - @CallSuper - protected List<ClassHook> getPostClassHooks() { - return Collections.emptyList(); - } - - /** - * See {@link TestHook}. Prefer to use TestRules over this. + * See {@link TestHook}. * * <p>Additional hooks can be added to the list by overriding this method and using {@link * #addToList}: {@code return addToList(super.getPreTestHooks(), hook1, hook2);} @@ -199,7 +188,7 @@ } /** - * See {@link TestHook}. Prefer to use TestRules over this. + * See {@link TestHook}. * * <p>Additional hooks can be added to the list by overriding this method and using {@link * #addToList}: {@code return addToList(super.getPostTestHooks(), hook1, hook2);} @@ -225,16 +214,12 @@ * Override this method to return a list of rules that should be applied to all tests run with * this test runner. * - * Additional rules can be added to the list using {@link #addToList}: - * {@code return addToList(super.getDefaultTestRules(), rule1, rule2);} + * <p>Additional rules can be added to the list using {@link #addToList}: {@code return + * addToList(super.getDefaultTestRules(), rule1, rule2);} */ @CallSuper protected List<TestRule> getDefaultTestRules() { - return Arrays.asList( - new BaseJUnit4TestRule(), - new MockitoErrorHandler(), - new UnitTestLifetimeAssertRule(), - new EspressoIdleTimeoutRule(20, TimeUnit.SECONDS)); + return Collections.emptyList(); } /** Evaluate whether a FrameworkMethod is ignored based on {@code SkipCheck}s. */ @@ -267,23 +252,13 @@ return; } - ResettersForTesting.beforeClassHooksWillExecute(); - - Class<?> testClass = getDescription().getTestClass(); - CommandLineFlags.setUpClass(testClass); - runPreClassHooks(testClass); - + onBeforeTestClass(); super.run(notifier); + onAfterTestClass(); + } - try { - CommandLineFlags.tearDownClass(); - runPostClassHooks(testClass); - } finally { - // Run resetters on UI thread so as to minimize the number of failed thread check - // assertions, and to match the semantics of Robolectric's runners. - BaseChromiumAndroidJUnitRunner.sInstance.runOnMainSync( - ResettersForTesting::afterClassHooksDidExecute); - } + static void clearJobSchedulerJobs() { + BaseJUnit4ClassRunner.getApplication().getSystemService(JobScheduler.class).cancelAll(); } private static void blockUnitTestsFromStartingBrowser(FrameworkMethod testMethod) { @@ -295,72 +270,113 @@ } @Override - protected void runChild(FrameworkMethod method, RunNotifier notifier) { - String testName = method.getName(); - TestTraceEvent.begin(testName); + protected Statement methodBlock(final FrameworkMethod method) { + Statement innerStatement = super.methodBlock(method); + return new Statement() { + @Override + public void evaluate() throws Throwable { + onBeforeTestMethod(method); + Throwable exception = null; + try { + // Runs @Rules, then @Befores, then test method. + innerStatement.evaluate(); + performExtraAssertions(method); + } catch (Throwable t) { + exception = t; + } + try { + onAfterTestMethod(method); + } catch (Throwable t) { + // Ensure original exception is not lost if onAfterTestMethod() throws. + if (exception != null) { + Log.e(TAG, "Unexpected exception in onAfterTestMethod()", t); + } else { + exception = t; + } + } + if (exception != null) { + throw exception; + } + } + }; + } - long start = SystemClock.uptimeMillis(); + private void onBeforeTestMethod(FrameworkMethod method) { + TestTraceEvent.begin(method.getName()); + mTestStartTimeMs = SystemClock.uptimeMillis(); ResettersForTesting.beforeHooksWillExecute(); + // TODO: Might be slow to do this before every test. + SharedPreferencesTestUtil.deleteOnDiskSharedPreferences(getApplication()); + CommandLineFlags.setUpMethod(method.getMethod()); blockUnitTestsFromStartingBrowser(method); // TODO(agrieve): These should not reset flag values set in @BeforeClass Flag.resetAllInMemoryCachedValuesForTesting(); FeatureParam.resetAllInMemoryCachedValuesForTesting(); + UmaRecorderHolder.resetForTesting(); - runPreTestHooks(method); + Context targetContext = InstrumentationRegistry.getTargetContext(); + for (TestHook hook : getPreTestHooks()) { + hook.run(targetContext, method); + } + } - super.runChild(method, notifier); + private void onBeforeTestClass() { + Class<?> testClass = getTestClass().getJavaClass(); + ResettersForTesting.beforeClassHooksWillExecute(); + CommandLineFlags.setUpClass(testClass); - runPostTestHooks(method); + Context targetContext = InstrumentationRegistry.getTargetContext(); + for (ClassHook hook : getPreClassHooks()) { + hook.run(targetContext, testClass); + } + } + + private void performExtraAssertions(FrameworkMethod method) throws Throwable { + SharedPreferencesTestUtil.assertNoOnDiskSharedPreferences(); + + Batch annotation = method.getDeclaringClass().getAnnotation(Batch.class); + if (annotation != null && annotation.value().equals(Batch.UNIT_TESTS)) { + if (method.getAnnotation(RequiresRestart.class) != null) return; + LifetimeAssert.assertAllInstancesDestroyedForTesting(); + } + } + + protected void onAfterTestMethod(FrameworkMethod method) { + Context targetContext = InstrumentationRegistry.getTargetContext(); + for (TestHook hook : getPostTestHooks()) { + hook.run(targetContext, method); + } + + // Do not reset things here for state we may want to persist when set via @BeforeClass. CommandLineFlags.tearDownMethod(); try { // Run resetters on UI thread so as to minimize the number of failed thread check // assertions, and to match the semantics of Robolectric's runners. BaseChromiumAndroidJUnitRunner.sInstance.runOnMainSync( ResettersForTesting::afterHooksDidExecute); + clearJobSchedulerJobs(); } finally { Bundle b = new Bundle(); - b.putLong(DURATION_BUNDLE_ID, SystemClock.uptimeMillis() - start); - BaseChromiumAndroidJUnitRunner.sInstance.sendStatus(STATUS_CODE_TEST_DURATION, b); + b.putLong(DURATION_BUNDLE_ID, SystemClock.uptimeMillis() - mTestStartTimeMs); + InstrumentationRegistry.getInstrumentation().sendStatus(STATUS_CODE_TEST_DURATION, b); - TestTraceEvent.end(testName); + TestTraceEvent.end(method.getName()); - // A new instance of BaseJUnit4ClassRunner is created on the device - // for each new method, so runChild will only be called once. Thus, we - // can disable tracing, and dump the output, once we get here. + // TODO: This dumps trace output after a single test, which means traces do not work for + // @Batched tests. TestTraceEvent.disable(); } } - /** Loop through all the {@code PreTestHook}s to run them */ - private void runPreTestHooks(FrameworkMethod frameworkMethod) { - Context targetContext = InstrumentationRegistry.getTargetContext(); - for (TestHook hook : getPreTestHooks()) { - hook.run(targetContext, frameworkMethod); - } - } - - private void runPreClassHooks(Class<?> klass) { - Context targetContext = InstrumentationRegistry.getTargetContext(); - for (ClassHook hook : getPreClassHooks()) { - hook.run(targetContext, klass); - } - } - - private void runPostTestHooks(FrameworkMethod frameworkMethod) { - Context targetContext = InstrumentationRegistry.getTargetContext(); - for (TestHook hook : getPostTestHooks()) { - hook.run(targetContext, frameworkMethod); - } - } - - private void runPostClassHooks(Class<?> klass) { - Context targetContext = InstrumentationRegistry.getTargetContext(); - for (ClassHook hook : getPostClassHooks()) { - hook.run(targetContext, klass); - } + protected void onAfterTestClass() { + CommandLineFlags.tearDownClass(); + // Run resetters on UI thread so as to minimize the number of failed thread check + // assertions, and to match the semantics of Robolectric's runners. + BaseChromiumAndroidJUnitRunner.sInstance.runOnMainSync( + ResettersForTesting::afterHooksDidExecute); } /** Loop through all the {@code SkipCheck}s to confirm whether a test should be ignored */ @@ -376,6 +392,7 @@ /** Overriding this method to take screenshot of failure before tear down functions are run. */ @Override protected Statement withAfters(FrameworkMethod method, Object test, Statement base) { + // Afters are called before @Rule tearDown, so a good time for a screenshot. return super.withAfters(method, test, new ScreenshotOnFailureStatement(base)); } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/MockitoErrorHandler.java b/base/test/android/javatests/src/org/chromium/base/test/MockitoErrorHandler.java deleted file mode 100644 index 5515b173..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/MockitoErrorHandler.java +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2020 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.base.test; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.Log; -import org.chromium.build.annotations.CheckDiscard; - -/** - * Attempts to provide additional information for Mockito errors that are hard to diagnose, - * b/147584922 in particular. - */ -class MockitoErrorHandler implements TestRule { - private static final String TAG = "MockitoErrorHandler"; - - private static final String MOCKITO_ERROR = - "Note: Proguard optimization is enabled and may cause exceptions when Mocking Derived" - + " classes, or classes that implement interfaces whose methods are not kept. You" - + " may need to add org.chromium.build.annotations.MockedInTests to such classes."; - - @CheckDiscard("") - private void removedMethodUnderRelease() {} - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - base.evaluate(); - } catch (Throwable e) { - if ((e instanceof AbstractMethodError) - // UnfinishedStubbingException isn't on our build path. - || e.getClass().getSimpleName().equals("UnfinishedStubbingException")) { - try { - // Detect if code is being optimized. - getClass().getDeclaredMethod("removedMethodUnderRelease"); - } catch (NoSuchMethodException ignored) { - Log.e(TAG, MOCKITO_ERROR); - } - } - throw e; - } - } - }; - } -}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java b/base/test/android/javatests/src/org/chromium/base/test/SharedPreferencesTestUtil.java similarity index 69% rename from base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java rename to base/test/android/javatests/src/org/chromium/base/test/SharedPreferencesTestUtil.java index 02fe526..a4b9db8 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java +++ b/base/test/android/javatests/src/org/chromium/base/test/SharedPreferencesTestUtil.java
@@ -4,21 +4,15 @@ package org.chromium.base.test; -import android.app.job.JobScheduler; +import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; import androidx.core.content.ContextCompat; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - import org.chromium.base.ContextUtils; -import org.chromium.base.metrics.UmaRecorderHolder; import org.chromium.base.test.util.InMemorySharedPreferences; -import org.chromium.base.test.util.InMemorySharedPreferencesContext; import java.io.File; import java.util.Collection; @@ -26,8 +20,7 @@ import java.util.List; import java.util.Set; -/** Holds setUp / tearDown logic common to all instrumentation tests. */ -class BaseJUnit4TestRule implements TestRule { +class SharedPreferencesTestUtil { // These are SharedPreferences that we do not fail tests for using real (instead of in-memory) // implementations. This is generally because it is impractical to use a test-only Context // for them (e.g. multi-process, or third-party code). @@ -40,42 +33,14 @@ "org.chromium.android_webview.devui.MainActivity", "org.chromium.webengine.test.instrumentation_test_apk_preferences"); - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - InMemorySharedPreferencesContext context = - BaseChromiumAndroidJUnitRunner.sInMemorySharedPreferencesContext; - if (context == null) { - throw new IllegalStateException( - "BaseJUnit4TestRule requires that you use " - + "BaseChromiumAndroidJUnitRunner (or a subclass)"); - } - deleteOnDiskSharedPreferences(); - UmaRecorderHolder.resetForTesting(); - try { - base.evaluate(); - assertNoOnDiskSharedPreferences(); - } finally { - clearJobSchedulerJobs(); - } - } - }; - } - - static void clearJobSchedulerJobs() { - BaseJUnit4ClassRunner.getApplication().getSystemService(JobScheduler.class).cancelAll(); - } - - private static void deleteOnDiskSharedPreferences() { + static void deleteOnDiskSharedPreferences(Application app) { for (String name : findSharedPreferences()) { // Using Application ensure we are not using InMemorySharedPreferencesContext. - BaseJUnit4ClassRunner.getApplication().deleteSharedPreferences(name); + app.deleteSharedPreferences(name); } } - private static void assertNoOnDiskSharedPreferences() { + static void assertNoOnDiskSharedPreferences() { Collection<String> unwantedPrefs = findSharedPreferences(); unwantedPrefs.removeAll(SHARED_PREFS_ALLOWLIST); if (unwantedPrefs.isEmpty()) {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/UnitTestLifetimeAssertRule.java b/base/test/android/javatests/src/org/chromium/base/test/UnitTestLifetimeAssertRule.java deleted file mode 100644 index 8f847265..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/UnitTestLifetimeAssertRule.java +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2023 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.base.test; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.LifetimeAssert; -import org.chromium.base.test.util.Batch; -import org.chromium.base.test.util.RequiresRestart; - -/** TestRule used to ensure we don't leak LifetimeAsserts in unit tests. */ -public final class UnitTestLifetimeAssertRule implements TestRule { - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - base.evaluate(); - Batch annotation = description.getTestClass().getAnnotation(Batch.class); - if (annotation != null && annotation.value().equals(Batch.UNIT_TESTS)) { - if (description.getAnnotation(RequiresRestart.class) != null) return; - LifetimeAssert.assertAllInstancesDestroyedForTesting(); - } - } - }; - } -}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/InstrumentationThreadCondition.java b/base/test/android/javatests/src/org/chromium/base/test/transit/InstrumentationThreadCondition.java index 59aca859..885c41d29 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/InstrumentationThreadCondition.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/InstrumentationThreadCondition.java
@@ -4,9 +4,34 @@ package org.chromium.base.test.transit; +import java.util.concurrent.Callable; + /** A {@link Condition} that is checked in the instrumentation thread. */ public abstract class InstrumentationThreadCondition extends Condition { public InstrumentationThreadCondition() { super(/* isRunOnUiThread= */ false); } + + /** + * Create a simple {@link InstrumentationThreadCondition} that does not need any parameters or + * to wait on suppliers. + */ + public static InstrumentationThreadCondition from( + String description, Callable<ConditionStatus> check) { + return new InstrumentationThreadCondition() { + @Override + public String buildDescription() { + return description; + } + + @Override + public ConditionStatus checkWithSuppliers() { + try { + return check.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/Station.java b/base/test/android/javatests/src/org/chromium/base/test/transit/Station.java index 8052f0c..37e687e 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/Station.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/Station.java
@@ -4,6 +4,8 @@ package org.chromium.base.test.transit; +import static org.junit.Assert.fail; + import org.chromium.base.test.transit.Transition.TransitionOptions; import org.chromium.base.test.transit.Transition.Trigger; @@ -67,6 +69,16 @@ return mId; } + protected void assertSuppliersCanBeUsed() { + int phase = getPhase(); + if (phase != Phase.ACTIVE && phase != Phase.TRANSITIONING_FROM) { + fail( + String.format( + "%s should have been ACTIVE or TRANSITIONING_FROM, but was %s", + this, phaseToString(phase))); + } + } + @Override void setStateTransitioningTo() { super.setStateTransitioningTo();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/UiThreadCondition.java b/base/test/android/javatests/src/org/chromium/base/test/transit/UiThreadCondition.java index 08758ce..c3afb78f 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/UiThreadCondition.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/UiThreadCondition.java
@@ -4,9 +4,33 @@ package org.chromium.base.test.transit; +import java.util.concurrent.Callable; + /** A {@link Condition} that is checked in the UI thread. */ public abstract class UiThreadCondition extends Condition { public UiThreadCondition() { super(/* isRunOnUiThread= */ true); } + + /** + * Create a simple {@link UiThreadCondition} that does not need any parameters or to wait on + * suppliers. + */ + public static UiThreadCondition from(String description, Callable<ConditionStatus> check) { + return new UiThreadCondition() { + @Override + public String buildDescription() { + return description; + } + + @Override + public ConditionStatus checkWithSuppliers() { + try { + return check.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/EspressoIdleTimeoutRule.java b/base/test/android/javatests/src/org/chromium/base/test/util/EspressoIdleTimeoutRule.java deleted file mode 100644 index 8916019..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/EspressoIdleTimeoutRule.java +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2023 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.base.test.util; - -import androidx.test.espresso.IdlingPolicies; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import java.util.concurrent.TimeUnit; - -/** - * Sets Espresso's master timeout policy. This helps reduce the time Espresso waits before failing - * test cases that hang. This results in more useful stacks and errors messages than when the - * process is killed from the outside. - */ -public final class EspressoIdleTimeoutRule implements TestRule { - private final long mTimeout; - private final TimeUnit mUnit; - - public EspressoIdleTimeoutRule(long timeout, TimeUnit unit) { - mTimeout = timeout; - mUnit = unit; - } - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - IdlingPolicies.setMasterPolicyTimeout(mTimeout, mUnit); - base.evaluate(); - } - }; - } -}
diff --git a/base/test/test_trace_processor_impl.cc b/base/test/test_trace_processor_impl.cc index a20e3d1d..e934bfe 100644 --- a/base/test/test_trace_processor_impl.cc +++ b/base/test/test_trace_processor_impl.cc
@@ -73,12 +73,12 @@ return QueryResultOrError(result); } -absl::Status TestTraceProcessorImpl::ParseTrace(std::unique_ptr<uint8_t[]> buf, - size_t size) { +absl::Status TestTraceProcessorImpl::ParseTrace( + const std::vector<char>& raw_trace) { auto status = trace_processor_->Parse(perfetto::trace_processor::TraceBlobView( - perfetto::trace_processor::TraceBlob::TakeOwnership(std::move(buf), - size))); + perfetto::trace_processor::TraceBlob::CopyFrom(raw_trace.data(), + raw_trace.size()))); // TODO(rasikan): Add DCHECK that the trace is well-formed and parsing doesn't // have any errors (e.g. to catch the cases when someone emits overlapping // trace events on the same track). @@ -86,14 +86,6 @@ return status.ok() ? absl::OkStatus() : absl::UnknownError(status.message()); } -absl::Status TestTraceProcessorImpl::ParseTrace( - const std::vector<char>& raw_trace) { - auto size = raw_trace.size(); - std::unique_ptr<uint8_t[]> data_copy(new uint8_t[size]); - std::copy(raw_trace.begin(), raw_trace.end(), data_copy.get()); - return ParseTrace(std::move(data_copy), size); -} - absl::Status TestTraceProcessorImpl::OverrideSqlModule( const std::string& module_name, const TestTraceProcessorImpl::PerfettoSQLModule& module) {
diff --git a/base/test/test_trace_processor_impl.h b/base/test/test_trace_processor_impl.h index 770284d5..3a346da7 100644 --- a/base/test/test_trace_processor_impl.h +++ b/base/test/test_trace_processor_impl.h
@@ -75,8 +75,6 @@ const PerfettoSQLModule& module); private: - absl::Status ParseTrace(std::unique_ptr<uint8_t[]> buf, size_t size); - std::unique_ptr<perfetto::trace_processor::Config> config_; std::unique_ptr<perfetto::trace_processor::TraceProcessor> trace_processor_; };
diff --git a/base/version_info/channel.h b/base/version_info/channel.h index 09cfb09..08c2821 100644 --- a/base/version_info/channel.h +++ b/base/version_info/channel.h
@@ -39,7 +39,7 @@ case Channel::UNKNOWN: return "unknown"; } - NOTREACHED_NORETURN(); + NOTREACHED(); } } // namespace version_info
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index 92cba84..73b80d831 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc
@@ -45,9 +45,6 @@ LayerImpl* base_layer, const CommitState& commit_state, const ThreadUnsafeCommitState& unsafe_state) { - // TODO(enne): http://crbug.com/918126 debugging - CHECK(this); - PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); Layer::PushPropertiesTo(base_layer, commit_state, unsafe_state); @@ -60,21 +57,6 @@ commit_state.device_viewport_rect.size()); layer_impl->SetIsBackdropFilterMask(is_backdrop_filter_mask()); - // TODO(enne): http://crbug.com/918126 debugging - CHECK(this); - if (!recording_source_.Read(*this)) { - bool valid_host = layer_tree_host(); - bool has_parent = parent(); - bool parent_has_host = parent() && parent()->layer_tree_host(); - - auto str = base::StringPrintf("vh: %d, hp: %d, phh: %d", valid_host, - has_parent, parent_has_host); - static auto* crash_key = base::debug::AllocateCrashKeyString( - "issue918126", base::debug::CrashKeySize::Size32); - base::debug::SetCrashKeyString(crash_key, str); - base::debug::DumpWithoutCrashing(); - } - layer_impl->UpdateRasterSource(CreateRasterSource(), &last_updated_invalidation_.Write(*this), nullptr, nullptr); @@ -82,7 +64,7 @@ } scoped_refptr<RasterSource> PictureLayer::CreateRasterSource() const { - return recording_source_.Read(*this)->CreateRasterSource(); + return recording_source_.Read(*this).CreateRasterSource(); } void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) { @@ -91,9 +73,7 @@ if (!host) return; - if (!recording_source_.Read(*this)) - recording_source_.Write(*this) = std::make_unique<RecordingSource>(); - recording_source_.Write(*this)->SetSlowdownRasterScaleFactor( + recording_source_.Write(*this).SetSlowdownRasterScaleFactor( host->GetDebugState().slow_down_raster_scale_factor); // Source frame numbers are relative the LayerTreeHost, so this needs @@ -103,8 +83,7 @@ void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) { DCHECK(IsPropertyChangeAllowed()); - if (recording_source_.Read(*this)) - recording_source_.Write(*this)->SetNeedsDisplayRect(layer_rect); + recording_source_.Write(*this).SetNeedsDisplayRect(layer_rect); Layer::SetNeedsDisplayRect(layer_rect); } @@ -124,10 +103,10 @@ bool updated = Layer::Update(); auto& recording_source = recording_source_.Write(*this); - recording_source->SetBackgroundColor(SafeOpaqueBackgroundColor()); - recording_source->SetRequiresClear(!contents_opaque() && - !client_->FillsBoundsCompletely()); - recording_source->SetCanUseRecordedBounds(CanUseRecordedBoundsForTiling()); + recording_source.SetBackgroundColor(SafeOpaqueBackgroundColor()); + recording_source.SetRequiresClear(!contents_opaque() && + !client_->FillsBoundsCompletely()); + recording_source.SetCanUseRecordedBounds(CanUseRecordedBoundsForTiling()); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "PictureLayer::Update", "source_frame_number", layer_tree_host()->SourceFrameNumber()); @@ -140,7 +119,7 @@ // for them. DCHECK(client_); - updated |= recording_source->Update( + updated |= recording_source.Update( bounds(), layer_tree_host()->recording_scale_factor(), *client_, last_updated_invalidation_.Write(*this)); @@ -239,7 +218,7 @@ void PictureLayer::DropRecordingSourceContentIfInvalid( int source_frame_number) { - gfx::Size recording_source_size = recording_source_.Read(*this)->size(); + gfx::Size recording_source_size = recording_source_.Read(*this).size(); gfx::Size layer_bounds = bounds(); @@ -255,13 +234,12 @@ // Update may not get called for the layer (if it's not in the viewport // for example), even though it has resized making the recording source no // longer valid. In this case just destroy the recording source. - recording_source_.Write(*this)->SetEmptyBounds(); + recording_source_.Write(*this).SetEmptyBounds(); } } const DisplayItemList* PictureLayer::GetDisplayItemList() const { - const RecordingSource* recording_source = recording_source_.Read(*this); - return recording_source ? recording_source->display_list() : nullptr; + return recording_source_.Read(*this).display_list(); } } // namespace cc
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h index a60503d..099a817 100644 --- a/cc/layers/picture_layer.h +++ b/cc/layers/picture_layer.h
@@ -13,13 +13,13 @@ #include "cc/base/invalidation_region.h" #include "cc/benchmarks/micro_benchmark_controller.h" #include "cc/layers/layer.h" +#include "cc/layers/recording_source.h" namespace cc { class ContentLayerClient; class DisplayItemList; class RasterSource; -class RecordingSource; class CC_EXPORT PictureLayer : public Layer { public: @@ -50,11 +50,10 @@ ContentLayerClient* client() { return client_; } - RecordingSource* GetRecordingSourceForTesting() { - return recording_source_.Write(*this).get(); + RecordingSource& GetRecordingSourceForTesting() { + return recording_source_.Write(*this); } - - const RecordingSource* GetRecordingSourceForTesting() const { + const RecordingSource& GetRecordingSourceForTesting() const { return recording_source_.Read(*this); } @@ -81,7 +80,7 @@ raw_ptr<ContentLayerClient, DanglingUntriaged> client_ = nullptr; bool is_backdrop_filter_mask_ = false; - ProtectedSequenceWritable<std::unique_ptr<RecordingSource>> recording_source_; + ProtectedSequenceWritable<RecordingSource> recording_source_; ProtectedSequenceForbidden<devtools_instrumentation::ScopedLayerObjectTracker> instrumentation_object_tracker_;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 232c7b5..3c60ff2 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -4945,12 +4945,12 @@ EXPECT_FALSE(active_layer()->GetPendingOrActiveTwinLayer()); } -void GetClientDataAndUpdateInvalidation(RecordingSource* recording_source, +void GetClientDataAndUpdateInvalidation(RecordingSource& recording_source, FakeContentLayerClient* client, gfx::Size layer_bounds) { Region invalidation; - recording_source->Update(layer_bounds, /*recording_scale_factor=*/1.f, - *client, invalidation); + recording_source.Update(layer_bounds, /*recording_scale_factor=*/1.f, *client, + invalidation); } void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid, @@ -4970,7 +4970,7 @@ std::unique_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create( &host_client, &task_graph_runner, animation_host.get()); host->SetRootLayer(layer); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); + RecordingSource& recording_source = layer->GetRecordingSourceForTesting(); client.set_fill_with_nonsolid_color(!test_for_solid); PaintFlags flags; @@ -4981,7 +4981,7 @@ GetClientDataAndUpdateInvalidation(recording_source, &client, layer_bounds); scoped_refptr<RasterSource> pending_raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); @@ -5056,15 +5056,15 @@ std::unique_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create( &host_client, &task_graph_runner, animation_host.get()); host->SetRootLayer(layer); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); + RecordingSource& recording_source = layer->GetRecordingSourceForTesting(); client.set_fill_with_nonsolid_color(true); - recording_source->SetNeedsDisplayRect(layer_rect); + recording_source.SetNeedsDisplayRect(layer_rect); GetClientDataAndUpdateInvalidation(recording_source, &client, layer_bounds); scoped_refptr<RasterSource> raster_source1 = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); SetupPendingTree(raster_source1); ActivateTree(); @@ -5075,11 +5075,11 @@ client.set_fill_with_nonsolid_color(false); - recording_source->SetNeedsDisplayRect(layer_rect); + recording_source.SetNeedsDisplayRect(layer_rect); GetClientDataAndUpdateInvalidation(recording_source, &client, layer_bounds); scoped_refptr<RasterSource> raster_source2 = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); SetupPendingTree(raster_source2); ActivateTree(); @@ -6185,17 +6185,17 @@ gfx::Size layer_bounds(1000, 1000); // Set up a raster source with 2 animated images. - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); std::vector<FrameMetadata> frames = { FrameMetadata(true, base::Milliseconds(1)), FrameMetadata(true, base::Milliseconds(1))}; PaintImage image1 = CreateAnimatedImage(gfx::Size(200, 200), frames); PaintImage image2 = CreateAnimatedImage(gfx::Size(200, 200), frames); - recording_source->add_draw_image(image1, gfx::Point(100, 100)); - recording_source->add_draw_image(image2, gfx::Point(500, 500)); - recording_source->Rerecord(); + recording_source.add_draw_image(image1, gfx::Point(100, 100)); + recording_source.add_draw_image(image2, gfx::Point(500, 500)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // All images should be registered on the pending layer. SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds))); @@ -6241,14 +6241,14 @@ PaintWorkletInput::NativePropertyType::kClipPath, ElementId()); // Set up a raster source with a PaintWorkletInput. - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); scoped_refptr<TestPaintWorkletInput> input1 = base::MakeRefCounted<TestPaintWorkletInput>(key, gfx::SizeF(100, 100)); PaintImage image1 = CreatePaintWorkletPaintImage(input1); - recording_source->add_draw_image(image1, gfx::Point(100, 100)); - recording_source->Rerecord(); + recording_source.add_draw_image(image1, gfx::Point(100, 100)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Ensure the input is registered SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds))); @@ -6289,18 +6289,18 @@ gfx::Size layer_bounds(1000, 1000); // Set up a raster source with 2 PaintWorkletInputs. - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); scoped_refptr<TestPaintWorkletInput> input1 = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); PaintImage image1 = CreatePaintWorkletPaintImage(input1); scoped_refptr<TestPaintWorkletInput> input2 = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(50, 50)); PaintImage image2 = CreatePaintWorkletPaintImage(input2); - recording_source->add_draw_image(image1, gfx::Point(100, 100)); - recording_source->add_draw_image(image2, gfx::Point(500, 500)); - recording_source->Rerecord(); + recording_source.add_draw_image(image1, gfx::Point(100, 100)); + recording_source.add_draw_image(image2, gfx::Point(500, 500)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // All inputs should be registered on the pending layer. SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds))); @@ -6323,13 +6323,13 @@ // Committing new PaintWorkletInputs (in a new raster source) should replace // the previous ones. - recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source2(layer_bounds); scoped_refptr<TestPaintWorkletInput> input3 = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(12, 12)); PaintImage image3 = CreatePaintWorkletPaintImage(input3); - recording_source->add_draw_image(image3, gfx::Point(10, 10)); - recording_source->Rerecord(); - raster_source = recording_source->CreateRasterSource(); + recording_source2.add_draw_image(image3, gfx::Point(10, 10)); + recording_source2.Rerecord(); + raster_source = recording_source2.CreateRasterSource(); SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds))); EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u); @@ -6339,16 +6339,16 @@ TEST_F(LegacySWPictureLayerImplTest, PaintWorkletInputsIdenticalEntries) { gfx::Size layer_bounds(1000, 1000); - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); scoped_refptr<TestPaintWorkletInput> input = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); PaintImage image = CreatePaintWorkletPaintImage(input); - recording_source->add_draw_image(image, gfx::Point(100, 100)); - recording_source->add_draw_image(image, gfx::Point(100, 100)); - recording_source->Rerecord(); + recording_source.add_draw_image(image, gfx::Point(100, 100)); + recording_source.add_draw_image(image, gfx::Point(100, 100)); + recording_source.Rerecord(); // All inputs should be registered on the pending layer. - SetupPendingTree(recording_source->CreateRasterSource(), gfx::Size(), + SetupPendingTree(recording_source.CreateRasterSource(), gfx::Size(), Region(gfx::Rect(layer_bounds))); EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u); EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input)); @@ -6356,8 +6356,8 @@ PaintRecord record; pending_layer()->SetPaintWorkletRecord(input, record); pending_layer()->picture_layer_tiling_set()->RemoveAllTiles(); - recording_source->Rerecord(); - pending_layer()->SetRasterSource(recording_source->CreateRasterSource(), + recording_source.Rerecord(); + pending_layer()->SetRasterSource(recording_source.CreateRasterSource(), Region()); EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u); auto it = pending_layer()->GetPaintWorkletRecordMap().find(input);
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index 8b90217..c593a7f 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc
@@ -382,7 +382,7 @@ // Make the layer not update. layer->SetHideLayerAndSubtree(true); - EXPECT_EQ(gfx::Size(500, 500), layer->GetRecordingSourceForTesting()->size()); + EXPECT_EQ(gfx::Size(500, 500), layer->GetRecordingSourceForTesting().size()); // Change its bounds while it's in a state that can't update. layer->SetBounds(gfx::Size(600, 600)); @@ -394,7 +394,7 @@ // This layer should also drop its recording source because it was resized // and not recorded. - EXPECT_EQ(gfx::Size(), layer->GetRecordingSourceForTesting()->size()); + EXPECT_EQ(gfx::Size(), layer->GetRecordingSourceForTesting().size()); host_client1.SetLayerTreeHost(nullptr); host_client2.SetLayerTreeHost(nullptr); @@ -440,7 +440,7 @@ // Solid color analysis will return true since the layer tree host has the // recording scale set to its default value of 1. The non solid pixel is // out of bounds for the unscaled layer size in this particular case. - EXPECT_TRUE(layer->GetRecordingSourceForTesting()->is_solid_color()); + EXPECT_TRUE(layer->GetRecordingSourceForTesting().is_solid_color()); host->SetRecordingScaleFactor(recording_scale); layer->SetNeedsDisplayRect(invalidation_bounds); @@ -448,7 +448,7 @@ // Once the recording scale is set and propagated to the recording source, // the solid color analysis should work as expected and return false. - EXPECT_FALSE(layer->GetRecordingSourceForTesting()->is_solid_color()); + EXPECT_FALSE(layer->GetRecordingSourceForTesting().is_solid_color()); } } // namespace
diff --git a/cc/layers/recording_source.cc b/cc/layers/recording_source.cc index cdcec3d..92e906f 100644 --- a/cc/layers/recording_source.cc +++ b/cc/layers/recording_source.cc
@@ -140,7 +140,7 @@ } scoped_refptr<RasterSource> RecordingSource::CreateRasterSource() const { - return scoped_refptr<RasterSource>(new RasterSource(this)); + return base::WrapRefCounted(new RasterSource(*this)); } void RecordingSource::DetermineIfSolidColor() {
diff --git a/cc/layers/recording_source_unittest.cc b/cc/layers/recording_source_unittest.cc index 2bff7d55..271967a 100644 --- a/cc/layers/recording_source_unittest.cc +++ b/cc/layers/recording_source_unittest.cc
@@ -17,7 +17,7 @@ namespace { TEST(RecordingSourceTest, DiscardableImagesWithTransform) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(256, 256)); + FakeRecordingSource recording_source(gfx::Size(256, 256)); PaintImage discardable_image[2][2]; gfx::Transform identity_transform; discardable_image[0][0] = CreateDiscardablePaintImage(gfx::Size(32, 32)); @@ -32,16 +32,16 @@ rotate_transform.Rotate(45); discardable_image[1][1] = CreateDiscardablePaintImage(gfx::Size(32, 32)); - recording_source->add_draw_image_with_transform(discardable_image[0][0], - identity_transform); - recording_source->add_draw_image_with_transform(discardable_image[1][0], - translate_transform); - recording_source->add_draw_image_with_transform(discardable_image[1][1], - rotate_transform); - recording_source->Rerecord(); + recording_source.add_draw_image_with_transform(discardable_image[0][0], + identity_transform); + recording_source.add_draw_image_with_transform(discardable_image[1][0], + translate_transform); + recording_source.add_draw_image_with_transform(discardable_image[1][1], + rotate_transform); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Tile sized iterators. These should find only one pixel ref. { @@ -104,11 +104,11 @@ } TEST(RecordingSourceTest, EmptyImages) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(256, 256)); - recording_source->Rerecord(); + FakeRecordingSource recording_source(gfx::Size(256, 256)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Tile sized iterators. { @@ -134,28 +134,28 @@ } TEST(RecordingSourceTest, NoDiscardableImages) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(256, 256)); + FakeRecordingSource recording_source(gfx::Size(256, 256)); PaintFlags simple_flags; simple_flags.setColor(SkColorSetARGB(255, 12, 23, 34)); auto non_discardable_image = CreateNonDiscardablePaintImage(gfx::Size(128, 128)); - recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 256, 256), - simple_flags); - recording_source->add_draw_rect_with_flags(gfx::Rect(128, 128, 512, 512), - simple_flags); - recording_source->add_draw_rect_with_flags(gfx::Rect(512, 0, 256, 256), - simple_flags); - recording_source->add_draw_rect_with_flags(gfx::Rect(0, 512, 256, 256), - simple_flags); - recording_source->add_draw_image(non_discardable_image, gfx::Point(128, 0)); - recording_source->add_draw_image(non_discardable_image, gfx::Point(0, 128)); - recording_source->add_draw_image(non_discardable_image, gfx::Point(150, 150)); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(0, 0, 256, 256), + simple_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(128, 128, 512, 512), + simple_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(512, 0, 256, 256), + simple_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(0, 512, 256, 256), + simple_flags); + recording_source.add_draw_image(non_discardable_image, gfx::Point(128, 0)); + recording_source.add_draw_image(non_discardable_image, gfx::Point(0, 128)); + recording_source.add_draw_image(non_discardable_image, gfx::Point(150, 150)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Tile sized iterators. { @@ -181,7 +181,7 @@ } TEST(RecordingSourceTest, DiscardableImages) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(256, 256)); + FakeRecordingSource recording_source(gfx::Size(256, 256)); PaintImage discardable_image[2][2]; discardable_image[0][0] = CreateDiscardablePaintImage(gfx::Size(32, 32)); @@ -194,14 +194,14 @@ // |---|---| // | x | x | // |---|---| - recording_source->add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); - recording_source->add_draw_image(discardable_image[1][0], gfx::Point(0, 130)); - recording_source->add_draw_image(discardable_image[1][1], - gfx::Point(140, 140)); - recording_source->Rerecord(); + recording_source.add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); + recording_source.add_draw_image(discardable_image[1][0], gfx::Point(0, 130)); + recording_source.add_draw_image(discardable_image[1][1], + gfx::Point(140, 140)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Tile sized iterators. These should find only one image. { @@ -247,7 +247,7 @@ } TEST(RecordingSourceTest, DiscardableImagesBaseNonDiscardable) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(512, 512)); + FakeRecordingSource recording_source(gfx::Size(512, 512)); PaintImage non_discardable_image = CreateNonDiscardablePaintImage(gfx::Size(512, 512)); @@ -263,15 +263,15 @@ // |---|---| // | | x | // |---|---| - recording_source->add_draw_image(non_discardable_image, gfx::Point(0, 0)); - recording_source->add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); - recording_source->add_draw_image(discardable_image[0][1], gfx::Point(260, 0)); - recording_source->add_draw_image(discardable_image[1][1], - gfx::Point(260, 260)); - recording_source->Rerecord(); + recording_source.add_draw_image(non_discardable_image, gfx::Point(0, 0)); + recording_source.add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); + recording_source.add_draw_image(discardable_image[0][1], gfx::Point(260, 0)); + recording_source.add_draw_image(discardable_image[1][1], + gfx::Point(260, 260)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Tile sized iterators. These should find only one image. { @@ -318,8 +318,8 @@ const std::vector<float> recording_scales = {1.f, 1.25f, 1.33f, 1.5f, 1.6f, 1.66f, 2.f, 2.25f, 2.5f}; for (float recording_scale : recording_scales) { - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetRecordingScaleFactor(recording_scale); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetRecordingScaleFactor(recording_scale); PaintFlags solid_flags; SkColor4f solid_color{0.1f, 0.2f, 0.3f, 1.0f}; @@ -329,12 +329,12 @@ PaintFlags non_solid_flags; non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_flags( + recording_source.add_draw_rect_with_flags( gfx::ScaleToEnclosingRect(gfx::Rect(layer_bounds), recording_scale), solid_flags); - recording_source->Rerecord(); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); EXPECT_TRUE(raster->IsSolidColor()) << " recording scale: " << recording_scale; @@ -342,16 +342,16 @@ for (int y = 0; y < layer_bounds.height(); y += 50) { for (int x = 0; x < layer_bounds.width(); x += 50) { - recording_source->reset_draws(); - recording_source->add_draw_rect_with_flags( + recording_source.reset_draws(); + recording_source.add_draw_rect_with_flags( gfx::ScaleToEnclosingRect(gfx::Rect(layer_bounds), recording_scale), solid_flags); - recording_source->add_draw_rect_with_flags( + recording_source.add_draw_rect_with_flags( gfx::Rect(std::round(x * recording_scale), std::round(y * recording_scale), 1, 1), non_solid_flags); - recording_source->Rerecord(); - raster = recording_source->CreateRasterSource(); + recording_source.Rerecord(); + raster = recording_source.CreateRasterSource(); EXPECT_FALSE(raster->IsSolidColor()) << " recording scale: " << recording_scale << " pixel at: (" << x << ", " << y << ") was not solid."; @@ -361,11 +361,11 @@ } TEST(RecordingSourceTest, RecordedBounds) { - auto recording_source = FakeRecordingSource::Create(gfx::Size(400, 400)); - recording_source->add_draw_rect(gfx::Rect(100, 100, 100, 100)); - recording_source->add_draw_rect(gfx::Rect(50, 200, 200, 50)); - recording_source->Rerecord(); - auto raster = recording_source->CreateRasterSource(); + FakeRecordingSource recording_source(gfx::Size(400, 400)); + recording_source.add_draw_rect(gfx::Rect(100, 100, 100, 100)); + recording_source.add_draw_rect(gfx::Rect(50, 200, 200, 50)); + recording_source.Rerecord(); + auto raster = recording_source.CreateRasterSource(); EXPECT_EQ(gfx::Rect(50, 100, 200, 150), raster->recorded_bounds()); }
diff --git a/cc/raster/raster_source.cc b/cc/raster/raster_source.cc index d172988a..007ccfbf 100644 --- a/cc/raster/raster_source.cc +++ b/cc/raster/raster_source.cc
@@ -23,18 +23,18 @@ namespace cc { -RasterSource::RasterSource(const RecordingSource* other) - : display_list_(other->display_list_), - background_color_(other->background_color_), - requires_clear_(other->requires_clear_), - is_solid_color_(other->is_solid_color_), - solid_color_(other->solid_color_), - recorded_bounds_(other->recorded_bounds_), - size_(other->size_), +RasterSource::RasterSource(const RecordingSource& other) + : display_list_(other.display_list_), + background_color_(other.background_color_), + requires_clear_(other.requires_clear_), + is_solid_color_(other.is_solid_color_), + solid_color_(other.solid_color_), + recorded_bounds_(other.recorded_bounds_), + size_(other.size_), slow_down_raster_scale_factor_for_debug_( - other->slow_down_raster_scale_factor_for_debug_), - recording_scale_factor_(other->recording_scale_factor_), - directly_composited_image_info_(other->directly_composited_image_info_) { + other.slow_down_raster_scale_factor_for_debug_), + recording_scale_factor_(other.recording_scale_factor_), + directly_composited_image_info_(other.directly_composited_image_info_) { DCHECK(recorded_bounds_.IsEmpty() || gfx::Rect(size_).Contains(recorded_bounds_)); }
diff --git a/cc/raster/raster_source.h b/cc/raster/raster_source.h index cff106e..7c474f20 100644 --- a/cc/raster/raster_source.h +++ b/cc/raster/raster_source.h
@@ -160,7 +160,7 @@ friend class RecordingSource; friend class base::RefCountedThreadSafe<RasterSource>; - explicit RasterSource(const RecordingSource* other); + explicit RasterSource(const RecordingSource& other); virtual ~RasterSource(); void ClearForOpaqueRaster(SkCanvas* raster_canvas,
diff --git a/cc/raster/raster_source_unittest.cc b/cc/raster/raster_source_unittest.cc index 45feecf..fab5ebc93 100644 --- a/cc/raster/raster_source_unittest.cc +++ b/cc/raster/raster_source_unittest.cc
@@ -48,7 +48,7 @@ TEST(RasterSourceTest, AnalyzeIsSolidUnscaled) { gfx::Size layer_bounds(400, 400); - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); @@ -60,11 +60,11 @@ bool is_solid_color = false; non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - solid_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + solid_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); // Ensure everything is solid. for (int y = 0; y <= 300; y += 100) { @@ -77,10 +77,10 @@ } // Add one non-solid pixel and recreate the raster source. - recording_source->add_draw_rect_with_flags(gfx::Rect(50, 50, 1, 1), - non_solid_flags); - recording_source->Rerecord(); - raster = recording_source->CreateRasterSource(); + recording_source.add_draw_rect_with_flags(gfx::Rect(50, 50, 1, 1), + non_solid_flags); + recording_source.Rerecord(); + raster = recording_source.CreateRasterSource(); color = SkColors::kTransparent; is_solid_color = @@ -118,8 +118,8 @@ const std::vector<float> recording_scales = {1.25f, 1.33f, 1.5f, 1.6f, 1.66f, 2.f, 2.25f, 2.5f}; for (float recording_scale : recording_scales) { - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetRecordingScaleFactor(recording_scale); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetRecordingScaleFactor(recording_scale); PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); @@ -131,12 +131,12 @@ bool is_solid_color = false; non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_flags( + recording_source.add_draw_rect_with_flags( gfx::ScaleToEnclosingRect(gfx::Rect(layer_bounds), recording_scale), solid_flags); - recording_source->Rerecord(); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); // Ensure everything is solid. for (int y = 0; y <= 300; y += 100) { @@ -151,12 +151,12 @@ } // Add one non-solid pixel and recreate the raster source. - recording_source->add_draw_rect_with_flags( + recording_source.add_draw_rect_with_flags( gfx::Rect(std::round(50 * recording_scale), std::round(50 * recording_scale), 1, 1), non_solid_flags); - recording_source->Rerecord(); - raster = recording_source->CreateRasterSource(); + recording_source.Rerecord(); + raster = recording_source.CreateRasterSource(); color = SkColors::kTransparent; is_solid_color = @@ -202,7 +202,7 @@ TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { gfx::Size layer_bounds(512, 512); - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); PaintImage discardable_image[2][2]; discardable_image[0][0] = CreateDiscardablePaintImage(gfx::Size(32, 32)); @@ -215,13 +215,13 @@ // |---|---| // | | x | // |---|---| - recording_source->add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); - recording_source->add_draw_image(discardable_image[0][1], gfx::Point(260, 0)); - recording_source->add_draw_image(discardable_image[1][1], - gfx::Point(260, 260)); - recording_source->Rerecord(); + recording_source.add_draw_image(discardable_image[0][0], gfx::Point(0, 0)); + recording_source.add_draw_image(discardable_image[0][1], gfx::Point(260, 0)); + recording_source.add_draw_image(discardable_image[1][1], + gfx::Point(260, 260)); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); // Tile sized iterators. These should find only one pixel ref. { @@ -273,18 +273,18 @@ float contents_scale = 1.5f; float raster_divisions = 2.f; - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kBlack); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kBlack); // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. PaintFlags white_flags; white_flags.setColor(SK_ColorWHITE); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds( gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); @@ -337,19 +337,19 @@ gfx::Size layer_bounds(3, 5); float raster_divisions = 2.f; - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kBlack); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kBlack); // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. PaintFlags white_flags; white_flags.setColor(SK_ColorWHITE); white_flags.setAntiAlias(true); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds = layer_bounds; @@ -396,17 +396,17 @@ gfx::Size layer_bounds(3, 5); float contents_scale = 1.5f; - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kGreen); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kGreen); // First record everything as white. PaintFlags white_flags; white_flags.setColor(SK_ColorWHITE); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds( gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); @@ -432,12 +432,12 @@ // Re-record everything as black. PaintFlags black_flags; black_flags.setColor(SK_ColorBLACK); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - black_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + black_flags); + recording_source.Rerecord(); // Make a new RasterSource from the new recording. - raster = recording_source->CreateRasterSource(); + raster = recording_source.CreateRasterSource(); // We're going to playback from "everything is black" into a smaller area, // that touches the edge pixels of the recording. @@ -469,18 +469,18 @@ TEST(RasterSourceTest, RasterPartialContentsWithRasterTranslation) { gfx::Size layer_bounds(3, 5); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kGreen); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kGreen); // First record everything as white. PaintFlags white_flags; white_flags.setAntiAlias(true); white_flags.setColor(SK_ColorWHITE); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds = layer_bounds; @@ -513,12 +513,12 @@ PaintFlags black_flags; black_flags.setColor(SK_ColorBLACK); black_flags.setAntiAlias(true); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - black_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + black_flags); + recording_source.Rerecord(); // Make a new RasterSource from the new recording. - raster = recording_source->CreateRasterSource(); + raster = recording_source.CreateRasterSource(); // We're going to playback from "everything is black" into a smaller area, // that touches the edge pixels of the recording. @@ -559,20 +559,20 @@ gfx::Size partial_bounds(2, 4); float contents_scale = 1.5f; - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kGreen); - recording_source->SetRequiresClear(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kGreen); + recording_source.SetRequiresClear(true); // First record everything as white. const float alpha_dark = 0.04f; PaintFlags white_flags; white_flags.setColor(SK_ColorWHITE); white_flags.setAlphaf(alpha_dark); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds( gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); @@ -596,19 +596,19 @@ EXPECT_COLOR_EQ(pixel_dark, bitmap.getColor(i, j)) << i << "," << j; } - auto recording_source_light = FakeRecordingSource::Create(layer_bounds); - recording_source_light->SetBackgroundColor(SkColors::kGreen); - recording_source_light->SetRequiresClear(true); + FakeRecordingSource recording_source_light(layer_bounds); + recording_source_light.SetBackgroundColor(SkColors::kGreen); + recording_source_light.SetRequiresClear(true); // Record everything as a slightly lighter white. const float alpha_light = 0.1f; white_flags.setAlphaf(alpha_light); - recording_source_light->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - white_flags); - recording_source_light->Rerecord(); + recording_source_light.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); + recording_source_light.Rerecord(); // Make a new RasterSource from the new recording. - raster = recording_source_light->CreateRasterSource(); + raster = recording_source_light.CreateRasterSource(); // We're going to playback from alpha(18) white rectangle into a smaller area // of the recording resulting in a smaller lighter white rectangle over a @@ -632,12 +632,12 @@ gfx::Size layer_bounds(5, 3); float contents_scale = 0.5f; - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->SetBackgroundColor(SkColors::kTransparent); - recording_source->SetRequiresClear(true); - recording_source->Rerecord(); + FakeRecordingSource recording_source(layer_bounds); + recording_source.SetBackgroundColor(SkColors::kTransparent); + recording_source.SetRequiresClear(true); + recording_source.Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); gfx::Size content_bounds( gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); @@ -662,11 +662,11 @@ TEST(RasterSourceTest, RasterTransformWithoutRecordingScale) { gfx::Size size(100, 100); float recording_scale = 2.f; - auto recording_source = FakeRecordingSource::Create(size); - recording_source->Rerecord(); - recording_source->SetRecordingScaleFactor(recording_scale); + FakeRecordingSource recording_source(size); + recording_source.Rerecord(); + recording_source.SetRecordingScaleFactor(recording_scale); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); StrictMock<MockCanvas> mock_canvas; Sequence s;
diff --git a/cc/test/fake_raster_source.cc b/cc/test/fake_raster_source.cc index be577f5..a3c93a0 100644 --- a/cc/test/fake_raster_source.cc +++ b/cc/test/fake_raster_source.cc
@@ -28,11 +28,11 @@ scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilled( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); + FakeRecordingSource recording_source(size); PaintFlags red_flags; red_flags.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(size), red_flags); // Note that we set the blend mode to kMultiply to prevent this raster source // from being detected as a solid color (and we add a check for this below). @@ -42,12 +42,10 @@ salmon_pink_flags.setColor(SK_ColorRED); salmon_pink_flags.setBlendMode(SkBlendMode::kMultiply); salmon_pink_flags.setAlphaf(0.5f); - recording_source->add_draw_rect_with_flags(gfx::Rect(size), - salmon_pink_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(size), salmon_pink_flags); - recording_source->Rerecord(); - auto raster_source = - base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + recording_source.Rerecord(); + auto raster_source = base::MakeRefCounted<FakeRasterSource>(recording_source); if (raster_source->IsSolidColor()) ADD_FAILURE() << "Unexpected solid color!"; return raster_source; @@ -55,49 +53,48 @@ scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilledWithImages( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); + FakeRecordingSource recording_source(size); for (int y = 0; y < size.height(); y += 100) { for (int x = 0; x < size.width(); x += 100) { - recording_source->add_draw_image( + recording_source.add_draw_image( CreateDiscardablePaintImage(gfx::Size(100, 100)), gfx::Point(x, y)); } } - recording_source->Rerecord(); - return base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + recording_source.Rerecord(); + return base::MakeRefCounted<FakeRasterSource>(recording_source); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilledWithText( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); - recording_source->add_draw_rect(gfx::Rect(size)); - recording_source->set_has_draw_text_op(); - recording_source->Rerecord(); - return base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + FakeRecordingSource recording_source(size); + recording_source.add_draw_rect(gfx::Rect(size)); + recording_source.set_has_draw_text_op(); + recording_source.Rerecord(); + return base::MakeRefCounted<FakeRasterSource>(recording_source); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilledWithPaintWorklet( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); + FakeRecordingSource recording_source(size); auto input = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(size)); - recording_source->add_draw_image( + recording_source.add_draw_image( CreatePaintWorkletPaintImage(std::move(input)), gfx::Point(0, 0)); - recording_source->Rerecord(); - return base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + recording_source.Rerecord(); + return base::MakeRefCounted<FakeRasterSource>(recording_source); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilledSolidColor( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); + FakeRecordingSource recording_source(size); PaintFlags red_flags; red_flags.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); - recording_source->Rerecord(); - auto raster_source = - base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + recording_source.add_draw_rect_with_flags(gfx::Rect(size), red_flags); + recording_source.Rerecord(); + auto raster_source = base::MakeRefCounted<FakeRasterSource>(recording_source); if (!raster_source->IsSolidColor()) ADD_FAILURE() << "Not solid color!"; return raster_source; @@ -110,45 +107,44 @@ DCHECK(!size.IsEmpty()); DCHECK(!recorded_bounds.IsEmpty()); DCHECK(gfx::Rect(size).Contains(recorded_bounds)); - auto recording_source = FakeRecordingSource::Create(size); + FakeRecordingSource recording_source(size); PaintFlags red_flags; red_flags.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_flags(recorded_bounds, red_flags); + recording_source.add_draw_rect_with_flags(recorded_bounds, red_flags); gfx::Rect smaller_rect(recorded_bounds.origin(), recorded_bounds.size() - gfx::Size(10, 10)); PaintFlags green_flags; green_flags.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_flags(smaller_rect, green_flags); + recording_source.add_draw_rect_with_flags(smaller_rect, green_flags); - recording_source->Rerecord(); - return base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + recording_source.Rerecord(); + return base::MakeRefCounted<FakeRasterSource>(recording_source); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateEmpty( const gfx::Size& size) { - auto recording_source = FakeRecordingSource::Create(size); - return base::WrapRefCounted(new FakeRasterSource(recording_source.get())); + return base::MakeRefCounted<FakeRasterSource>(FakeRecordingSource(size)); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFromRecordingSource( - const RecordingSource* recording_source) { - return base::WrapRefCounted(new FakeRasterSource(recording_source)); + const RecordingSource& recording_source) { + return base::MakeRefCounted<FakeRasterSource>(recording_source); } scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFromRecordingSourceWithWaitable( - const RecordingSource* recording_source, + const RecordingSource& recording_source, base::WaitableEvent* playback_allowed_event) { - return base::WrapRefCounted( - new FakeRasterSource(recording_source, playback_allowed_event)); + return base::MakeRefCounted<FakeRasterSource>(recording_source, + playback_allowed_event); } -FakeRasterSource::FakeRasterSource(const RecordingSource* recording_source) +FakeRasterSource::FakeRasterSource(const RecordingSource& recording_source) : RasterSource(recording_source), playback_allowed_event_(nullptr) {} -FakeRasterSource::FakeRasterSource(const RecordingSource* recording_source, +FakeRasterSource::FakeRasterSource(const RecordingSource& recording_source, base::WaitableEvent* playback_allowed_event) : RasterSource(recording_source), playback_allowed_event_(playback_allowed_event) {}
diff --git a/cc/test/fake_raster_source.h b/cc/test/fake_raster_source.h index e637bfe5..033b3db 100644 --- a/cc/test/fake_raster_source.h +++ b/cc/test/fake_raster_source.h
@@ -21,6 +21,10 @@ class FakeRasterSource : public RasterSource { public: + explicit FakeRasterSource(const RecordingSource& recording_source); + FakeRasterSource(const RecordingSource& recording_source, + base::WaitableEvent* playback_allowed_event); + static scoped_refptr<FakeRasterSource> CreateInfiniteFilled(); static scoped_refptr<FakeRasterSource> CreateFilled(const gfx::Size& size); static scoped_refptr<FakeRasterSource> CreateFilledWithImages( @@ -36,17 +40,14 @@ const gfx::Rect& recorded_bounds); static scoped_refptr<FakeRasterSource> CreateEmpty(const gfx::Size& size); static scoped_refptr<FakeRasterSource> CreateFromRecordingSource( - const RecordingSource* recording_source); + const RecordingSource& recording_source); static scoped_refptr<FakeRasterSource> CreateFromRecordingSourceWithWaitable( - const RecordingSource* recording_source, + const RecordingSource& recording_source, base::WaitableEvent* playback_allowed_event); void SetDirectlyCompositedImageDefaultRasterScale(gfx::Vector2dF scale); protected: - explicit FakeRasterSource(const RecordingSource* recording_source); - FakeRasterSource(const RecordingSource* recording_source, - base::WaitableEvent* playback_allowed_event); ~FakeRasterSource() override; void PlaybackDisplayListToCanvas(
diff --git a/cc/test/fake_recording_source.h b/cc/test/fake_recording_source.h index d9adf6f..6176acc 100644 --- a/cc/test/fake_recording_source.h +++ b/cc/test/fake_recording_source.h
@@ -25,12 +25,9 @@ // display list. class FakeRecordingSource : public RecordingSource { public: - static std::unique_ptr<FakeRecordingSource> Create( - const gfx::Size& layer_bounds) { - auto recording_source = std::make_unique<FakeRecordingSource>(); - recording_source->SetCanUseRecordedBounds(true); - recording_source->SetLayerBounds(layer_bounds); - return recording_source; + explicit FakeRecordingSource(const gfx::Size& layer_bounds) { + SetCanUseRecordedBounds(true); + SetLayerBounds(layer_bounds); } void SetLayerBounds(const gfx::Size& layer_bounds) { @@ -110,8 +107,6 @@ } private: - using RecordingSource::RecordingSource; - FakeContentLayerClient client_; PaintFlags default_flags_; };
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index c6cf93cf5..1794f19 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -1684,25 +1684,25 @@ gfx::Size size(10, 10); const gfx::Size layer_bounds(1000, 1000); - auto recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource recording_source(layer_bounds); PaintFlags solid_flags; SkColor4f solid_color{0.1f, 0.2f, 0.3f, 1.0f}; solid_flags.setColor(solid_color); - recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), - solid_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + solid_flags); // Create non solid tile as well, otherwise tilings wouldnt be created. SkColor4f non_solid_color{0.2f, 0.3f, 0.4f, 0.5f}; PaintFlags non_solid_flags; non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 10, 10), - non_solid_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(0, 0, 10, 10), + non_solid_flags); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); FakePictureLayerTilingClient tiling_client; tiling_client.SetTileSize(size); @@ -2078,15 +2078,15 @@ surface->getCanvas()->clear(SK_ColorBLUE); sk_sp<SkImage> blue_image = surface->makeImageSnapshot(); - auto recording_source = FakeRecordingSource::Create(size); - recording_source->SetBackgroundColor(SkColors::kTransparent); - recording_source->SetRequiresClear(true); + FakeRecordingSource recording_source(size); + recording_source.SetBackgroundColor(SkColors::kTransparent); + recording_source.SetRequiresClear(true); PaintFlags flags; flags.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_flags(gfx::Rect(size), flags); - recording_source->add_draw_image(std::move(blue_image), gfx::Point()); - recording_source->Rerecord(); - scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource(); + recording_source.add_draw_rect_with_flags(gfx::Rect(size), flags); + recording_source.add_draw_image(std::move(blue_image), gfx::Point()); + recording_source.Rerecord(); + scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource(); FakePictureLayerTilingClient tiling_client; tiling_client.SetTileSize(size); @@ -2173,31 +2173,30 @@ EXPECT_TRUE(host_impl()->use_gpu_rasterization()); // Active tree has no non-solid tiles, so it will generate no tile tasks. - auto active_tree_recording_source = FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource active_tree_recording_source(layer_bounds); PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); solid_flags.setColor(solid_color); - active_tree_recording_source->add_draw_rect_with_flags( - gfx::Rect(layer_bounds), solid_flags); + active_tree_recording_source.add_draw_rect_with_flags(gfx::Rect(layer_bounds), + solid_flags); - active_tree_recording_source->Rerecord(); + active_tree_recording_source.Rerecord(); // Pending tree has non-solid tiles, so it will generate tile tasks. - auto pending_tree_recording_source = - FakeRecordingSource::Create(layer_bounds); + FakeRecordingSource pending_tree_recording_source(layer_bounds); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); PaintFlags non_solid_flags; non_solid_flags.setColor(non_solid_color); - pending_tree_recording_source->add_draw_rect_with_flags( + pending_tree_recording_source.add_draw_rect_with_flags( gfx::Rect(5, 5, 10, 10), non_solid_flags); - pending_tree_recording_source->Rerecord(); + pending_tree_recording_source.Rerecord(); scoped_refptr<RasterSource> active_tree_raster_source = - active_tree_recording_source->CreateRasterSource(); + active_tree_recording_source.CreateRasterSource(); scoped_refptr<RasterSource> pending_tree_raster_source = - pending_tree_recording_source->CreateRasterSource(); + pending_tree_recording_source.CreateRasterSource(); SetupTrees(pending_tree_raster_source, active_tree_raster_source); host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state()); @@ -2403,8 +2402,8 @@ const gfx::Size layer_bounds(500, 500); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); int dimension = 250; PaintImage image1 = @@ -2415,15 +2414,15 @@ CreateDiscardablePaintImage(gfx::Size(dimension, dimension)); PaintImage image4 = CreateDiscardablePaintImage(gfx::Size(dimension, dimension)); - recording_source->add_draw_image(image1, gfx::Point(0, 0)); - recording_source->add_draw_image(image2, gfx::Point(300, 0)); - recording_source->add_draw_image(image3, gfx::Point(0, 300)); - recording_source->add_draw_image(image4, gfx::Point(300, 300)); + recording_source.add_draw_image(image1, gfx::Point(0, 0)); + recording_source.add_draw_image(image2, gfx::Point(300, 0)); + recording_source.add_draw_image(image3, gfx::Point(0, 300)); + recording_source.add_draw_image(image4, gfx::Point(300, 300)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<FakeRasterSource> pending_raster_source = - FakeRasterSource::CreateFromRecordingSource(recording_source.get()); + FakeRasterSource::CreateFromRecordingSource(recording_source); host_impl->CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl->pending_tree(); @@ -2612,46 +2611,41 @@ host_impl()->tile_manager()->SetRasterBufferProviderForTesting( &mock_raster_buffer_provider_); - const gfx::Size layer_bounds(1000, 1000); - - solid_color_recording_source_ = FakeRecordingSource::Create(layer_bounds); - PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); solid_flags.setColor(solid_color); - solid_color_recording_source_->add_draw_rect_with_flags( - gfx::Rect(layer_bounds), solid_flags); + solid_color_recording_source_.add_draw_rect_with_flags( + gfx::Rect(kLayerBounds), solid_flags); - solid_color_recording_source_->Rerecord(); + solid_color_recording_source_.Rerecord(); - recording_source_ = FakeRecordingSource::Create(layer_bounds); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); PaintFlags non_solid_flags; non_solid_flags.setColor(non_solid_color); for (int i = 0; i < 100; ++i) { for (int j = 0; j < 100; ++j) { - recording_source_->add_draw_rect_with_flags( + recording_source_.add_draw_rect_with_flags( gfx::Rect(10 * i, 10 * j, 5, 5), non_solid_flags); } } - recording_source_->Rerecord(); + recording_source_.Rerecord(); } void SetupTreesWithActiveTreeTiles() { scoped_refptr<RasterSource> active_tree_raster_source = - recording_source_->CreateRasterSource(); + recording_source_.CreateRasterSource(); scoped_refptr<RasterSource> pending_tree_raster_source = - solid_color_recording_source_->CreateRasterSource(); + solid_color_recording_source_.CreateRasterSource(); SetupTrees(pending_tree_raster_source, active_tree_raster_source); } void SetupTreesWithPendingTreeTiles() { scoped_refptr<RasterSource> active_tree_raster_source = - solid_color_recording_source_->CreateRasterSource(); + solid_color_recording_source_.CreateRasterSource(); scoped_refptr<RasterSource> pending_tree_raster_source = - recording_source_->CreateRasterSource(); + recording_source_.CreateRasterSource(); SetupTrees(pending_tree_raster_source, active_tree_raster_source); } @@ -2664,8 +2658,9 @@ private: StrictMock<MockReadyToDrawRasterBufferProviderImpl> mock_raster_buffer_provider_; - std::unique_ptr<FakeRecordingSource> recording_source_; - std::unique_ptr<FakeRecordingSource> solid_color_recording_source_; + const gfx::Size kLayerBounds{1000, 1000}; + FakeRecordingSource recording_source_{kLayerBounds}; + FakeRecordingSource solid_color_recording_source_{kLayerBounds}; }; TEST_F(TileManagerReadyToDrawTest, SmoothActivationWaitsOnCallback) { @@ -3246,8 +3241,8 @@ NoImageDecodeDependencyForCheckeredTiles) { const gfx::Size layer_bounds(512, 512); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); auto generator = sk_make_sp<testing::StrictMock<MockImageGenerator>>(gfx::Size(512, 512)); @@ -3256,11 +3251,11 @@ .set_paint_image_generator(generator) .set_decoding_mode(PaintImage::DecodingMode::kAsync) .TakePaintImage(); - recording_source->add_draw_image(image, gfx::Point(0, 0)); + recording_source.add_draw_image(image, gfx::Point(0, 0)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); Region invalidation((gfx::Rect(layer_bounds))); SetupPendingTree(raster_source, layer_bounds, invalidation); @@ -3299,16 +3294,16 @@ TEST_F(EmptyCacheTileManagerTest, AtRasterOnScreenTileRasterTasks) { const gfx::Size layer_bounds(500, 500); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); int dimension = 500; PaintImage image = MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); - recording_source->add_draw_image(image, gfx::Point(0, 0)); + recording_source.add_draw_image(image, gfx::Point(0, 0)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); gfx::Size tile_size(500, 500); Region invalidation((gfx::Rect(layer_bounds))); @@ -3334,16 +3329,16 @@ TEST_F(EmptyCacheTileManagerTest, AtRasterPrepaintTileRasterTasksSkipped) { const gfx::Size layer_bounds(500, 500); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); int dimension = 500; PaintImage image = MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); - recording_source->add_draw_image(image, gfx::Point(0, 0)); + recording_source.add_draw_image(image, gfx::Point(0, 0)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); gfx::Size tile_size(500, 500); Region invalidation((gfx::Rect(layer_bounds))); @@ -3369,8 +3364,8 @@ TEST_F(CheckerImagingTileManagerTest, BuildsImageDecodeQueueAsExpected) { const gfx::Size layer_bounds(900, 900); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); int dimension = 450; PaintImage image1 = @@ -3379,13 +3374,13 @@ MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); PaintImage image3 = MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); - recording_source->add_draw_image(image1, gfx::Point(0, 0)); - recording_source->add_draw_image(image2, gfx::Point(600, 0)); - recording_source->add_draw_image(image3, gfx::Point(0, 600)); + recording_source.add_draw_image(image1, gfx::Point(0, 0)); + recording_source.add_draw_image(image2, gfx::Point(600, 0)); + recording_source.add_draw_image(image3, gfx::Point(0, 600)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); gfx::Size tile_size(500, 500); Region invalidation((gfx::Rect(layer_bounds))); @@ -3532,13 +3527,13 @@ TileManagerCleanupClearsCheckerImagedDecodes) { const gfx::Size layer_bounds(512, 512); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); PaintImage image = MakeCheckerablePaintImage(gfx::Size(512, 512)); - recording_source->add_draw_image(image, gfx::Point(0, 0)); - recording_source->Rerecord(); + recording_source.add_draw_image(image, gfx::Point(0, 0)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); SetupPendingTree(raster_source, gfx::Size(100, 100), Region(gfx::Rect(0, 0, 500, 500))); @@ -3570,13 +3565,13 @@ TileManagerCorrectlyPrioritizesCheckerImagedDecodes) { gfx::Size layer_bounds(500, 500); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); PaintImage image = MakeCheckerablePaintImage(gfx::Size(512, 512)); - recording_source->add_draw_image(image, gfx::Point(0, 0)); - recording_source->Rerecord(); + recording_source.add_draw_image(image, gfx::Point(0, 0)); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); // Required for activation tiles block checker-imaged decodes. SetupPendingTree(raster_source, gfx::Size(100, 100), @@ -3651,20 +3646,20 @@ TEST_F(CheckerImagingTileManagerMemoryTest, AddsAllNowTilesToImageDecodeQueue) { const gfx::Size layer_bounds(900, 1400); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); int dimension = 450; PaintImage image1 = MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); PaintImage image2 = MakeCheckerablePaintImage(gfx::Size(dimension, dimension)); - recording_source->add_draw_image(image1, gfx::Point(0, 515)); - recording_source->add_draw_image(image2, gfx::Point(515, 515)); + recording_source.add_draw_image(image1, gfx::Point(0, 515)); + recording_source.add_draw_image(image2, gfx::Point(515, 515)); - recording_source->Rerecord(); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); gfx::Size tile_size(500, 500); Region invalidation((gfx::Rect(layer_bounds))); @@ -3879,14 +3874,14 @@ // Add images to a fake recording source. const gfx::Size layer_bounds(1000, 500); - auto recording_source = FakeRecordingSource::Create(layer_bounds); - recording_source->set_fill_with_nonsolid_color(true); - recording_source->add_draw_image(image1, gfx::Point(0, 0)); - recording_source->add_draw_image(image2, gfx::Point(700, 0)); - recording_source->Rerecord(); + FakeRecordingSource recording_source(layer_bounds); + recording_source.set_fill_with_nonsolid_color(true); + recording_source.add_draw_image(image1, gfx::Point(0, 0)); + recording_source.add_draw_image(image2, gfx::Point(700, 0)); + recording_source.Rerecord(); scoped_refptr<FakeRasterSource> pending_raster_source = - FakeRasterSource::CreateFromRecordingSource(recording_source.get()); + FakeRasterSource::CreateFromRecordingSource(recording_source); host_impl()->CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl()->pending_tree(); @@ -3953,12 +3948,12 @@ // Add images to a fake recording source. constexpr gfx::Size kLayerBounds(1000, 500); - auto recording_source = FakeRecordingSource::Create(kLayerBounds); - recording_source->set_fill_with_nonsolid_color(true); - recording_source->add_draw_image(hdr_image, gfx::Point(0, 0)); - recording_source->Rerecord(); + FakeRecordingSource recording_source(kLayerBounds); + recording_source.set_fill_with_nonsolid_color(true); + recording_source.add_draw_image(hdr_image, gfx::Point(0, 0)); + recording_source.Rerecord(); - auto raster_source = recording_source->CreateRasterSource(); + auto raster_source = recording_source.CreateRasterSource(); constexpr gfx::Size kTileSize(500, 500); Region invalidation((gfx::Rect(kLayerBounds)));
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index d1d741e..0c815fd8 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -16582,24 +16582,24 @@ CreateHostImpl(settings, CreateLayerTreeFrameSink()); gfx::Size layer_size = gfx::Size(750, 750); - auto recording_source = FakeRecordingSource::Create(layer_size); + FakeRecordingSource recording_source(layer_size); PaintImage checkerable_image = PaintImageBuilder::WithCopy( CreateDiscardablePaintImage(gfx::Size(500, 500))) .set_decoding_mode(PaintImage::DecodingMode::kAsync) .TakePaintImage(); - recording_source->add_draw_image(checkerable_image, gfx::Point(0, 0)); + recording_source.add_draw_image(checkerable_image, gfx::Point(0, 0)); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); PaintFlags non_solid_flags; non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_flags(gfx::Rect(510, 0, 200, 600), - non_solid_flags); - recording_source->add_draw_rect_with_flags(gfx::Rect(0, 510, 200, 400), - non_solid_flags); - recording_source->Rerecord(); + recording_source.add_draw_rect_with_flags(gfx::Rect(510, 0, 200, 600), + non_solid_flags); + recording_source.add_draw_rect_with_flags(gfx::Rect(0, 510, 200, 400), + non_solid_flags); + recording_source.Rerecord(); scoped_refptr<RasterSource> raster_source = - recording_source->CreateRasterSource(); + recording_source.CreateRasterSource(); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index f8c4bf75..b62f770 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -8674,10 +8674,10 @@ break; case 2: { scoped_refptr<RasterSource> child_raster = - child_->GetRecordingSourceForTesting()->CreateRasterSource(); + child_->GetRecordingSourceForTesting().CreateRasterSource(); EXPECT_FALSE(child_raster->IsSolidColor()); scoped_refptr<RasterSource> mask_raster = - mask_->GetRecordingSourceForTesting()->CreateRasterSource(); + mask_->GetRecordingSourceForTesting().CreateRasterSource(); EXPECT_FALSE(mask_raster->IsSolidColor()); }
diff --git a/chrome/VERSION b/chrome/VERSION index 39957466..6d1a8d0 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=127 MINOR=0 -BUILD=6496 +BUILD=6497 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index e470412..47a36b38 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -425,6 +425,7 @@ "//chrome/browser/password_entry_edit:public_java", "//chrome/browser/password_manager/android:java", "//chrome/browser/password_manager/android:settings_interface_java", + "//chrome/browser/password_manager/android/account_storage_toggle:java", "//chrome/browser/password_manager/android/pwd_migration:java", "//chrome/browser/password_manager/android/pwd_migration:java_resources", "//chrome/browser/policy/android:java", @@ -1303,6 +1304,7 @@ "//components/webapps/browser/android:java", "//components/webapps/browser/android:webapps_jni_headers_java", "//content/public/android:content_java", + "//content/public/android:content_main_dex_jni_java", "//content/public/common:common_java", "//content/public/test/android:content_java_test_support", "//mojo/public/java:bindings_java", @@ -1426,11 +1428,13 @@ "//chrome/browser/android/browserservices/intents:java", "//chrome/browser/android/intents:java", "//chrome/browser/autofill/android:java", + "//chrome/browser/feature_engagement:java", "//chrome/browser/flags:java", "//chrome/browser/profiles/android:java", "//chrome/browser/tab:java", "//chrome/browser/ui/android/appmenu:java", "//chrome/test/android:chrome_java_integration_test_support", + "//components/feature_engagement/public:public_java", "//components/payments/content/android:java", "//components/payments/content/android:java_resources", "//components/payments/content/android:payments_java_test_support", @@ -1449,6 +1453,7 @@ "//third_party/hamcrest:hamcrest_java", "//third_party/jni_zero:jni_zero_java", "//third_party/junit:junit", + "//third_party/mockito:mockito_java", "//ui/android:ui_no_recycler_view_java", "//url:gurl_java", ] @@ -1735,6 +1740,7 @@ "//chrome/browser/password_manager/android:java", "//chrome/browser/password_manager/android:settings_interface_java", "//chrome/browser/password_manager/android:test_support_java", + "//chrome/browser/password_manager/android/account_storage_toggle:java", "//chrome/browser/password_manager/android/pwd_check_wrapper:test_support_java", "//chrome/browser/password_manager/android/pwd_migration:java", "//chrome/browser/policy/android:java",
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java index d1087d8..c92a850e 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -532,6 +532,7 @@ /* isScrollableMvtEnabled= */ true, /* mostRecentTab= */ null, /* singleTabCardClickedCallback= */ null, + /* seeMoreLinkClickedCallback= */ null, /* snapshotParentViewRunnable= */ null, mTabContentManager, /* uiConfig= */ null,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediator.java index dcd86ab..70bfecb 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediator.java
@@ -219,27 +219,22 @@ return isFullyClosing ? TabGroupState.IN_CURRENT_CLOSING : TabGroupState.IN_CURRENT; } - private List<Pair<SavedTabGroup, Integer>> getSortedGroupAndStateList() { - List<Pair<SavedTabGroup, Integer>> groupAndStateList = new ArrayList<>(); + private List<SavedTabGroup> getSortedGroupList() { + List<SavedTabGroup> groupList = new ArrayList<>(); for (String syncGroupId : mTabGroupSyncService.getAllGroupIds()) { SavedTabGroup savedTabGroup = mTabGroupSyncService.getGroup(syncGroupId); - @TabGroupState int state = getState(savedTabGroup); // To simplify interactions, do not include any groups currently open in other windows. - if (state != TabGroupState.IN_ANOTHER) { - groupAndStateList.add(new Pair<>(savedTabGroup, state)); + if (getState(savedTabGroup) != TabGroupState.IN_ANOTHER) { + groupList.add(savedTabGroup); } } - groupAndStateList.sort( - (a, b) -> Long.compare(b.first.creationTimeMs, a.first.creationTimeMs)); - return groupAndStateList; + groupList.sort((a, b) -> Long.compare(b.creationTimeMs, a.creationTimeMs)); + return groupList; } private void repopulateModelList() { mModelList.clear(); - for (Pair<SavedTabGroup, Integer> groupAndState : getSortedGroupAndStateList()) { - SavedTabGroup savedTabGroup = groupAndState.first; - @TabGroupState int state = groupAndState.second; - + for (SavedTabGroup savedTabGroup : getSortedGroupList()) { PropertyModel.Builder builder = new PropertyModel.Builder(ALL_KEYS); int numberOfTabs = savedTabGroup.savedTabs.size(); int numberOfCorners = FAVICON_ORDER.length; @@ -270,11 +265,9 @@ builder.with(CREATION_MILLIS, savedTabGroup.creationTimeMs); + builder.with(TabGroupRowProperties.OPEN_RUNNABLE, () -> openGroup(savedTabGroup)); builder.with( - TabGroupRowProperties.OPEN_RUNNABLE, () -> openGroup(savedTabGroup, state)); - builder.with( - TabGroupRowProperties.DELETE_RUNNABLE, - () -> processDeleteGroup(savedTabGroup, state)); + TabGroupRowProperties.DELETE_RUNNABLE, () -> processDeleteGroup(savedTabGroup)); ListItem listItem = new ListItem(0, builder.build()); mModelList.add(listItem); @@ -284,8 +277,12 @@ mPropertyModel.set(TabGroupListProperties.EMPTY_STATE_VISIBLE, empty); } - private void openGroup(SavedTabGroup savedTabGroup, @TabGroupState int state) { - state = updateStateForOpenGroup(savedTabGroup, state); + private void openGroup(SavedTabGroup savedTabGroup) { + @TabGroupState int state = getState(savedTabGroup); + if (state == TabGroupState.IN_ANOTHER) { + return; + } + if (state == TabGroupState.IN_CURRENT_CLOSING) { for (SavedTabGroupTab savedTab : savedTabGroup.savedTabs) { if (savedTab.localId != null) { @@ -308,33 +305,21 @@ assert success; } - private @TabGroupState int updateStateForOpenGroup( - SavedTabGroup savedTabGroup, @TabGroupState int previousState) { - if (previousState != TabGroupState.IN_CURRENT_CLOSING) return previousState; - - // It is possible to "race" with the undo snackbar when IN_CURRENT_CLOSING is happening - // since refreshing this UI is a posted task. Fall back to HIDDEN if there are no tabs - // available to cancel the closure of. - TabList tabList = mFilter.getTabModel().getComprehensiveModel(); - for (int i = 0; i < tabList.getCount(); i++) { - Tab tab = tabList.getTabAt(i); - if (tab.isClosing() && savedTabGroup.localId.tabGroupId.equals(tab.getTabGroupId())) { - return TabGroupState.IN_CURRENT_CLOSING; - } - } - return TabGroupState.HIDDEN; - } - - private void processDeleteGroup(SavedTabGroup savedTabGroup, @TabGroupState int state) { + private void processDeleteGroup(SavedTabGroup savedTabGroup) { mActionConfirmationManager.processDeleteGroupAttempt( (@ConfirmationResult Integer result) -> { if (result != ConfirmationResult.CONFIRMATION_NEGATIVE) { - deleteGroup(savedTabGroup, state); + deleteGroup(savedTabGroup); } }); } - private void deleteGroup(SavedTabGroup savedTabGroup, @TabGroupState int state) { + private void deleteGroup(SavedTabGroup savedTabGroup) { + @TabGroupState int state = getState(savedTabGroup); + if (state == TabGroupState.IN_ANOTHER) { + return; + } + if (state == TabGroupState.IN_CURRENT_CLOSING) { for (SavedTabGroupTab savedTab : savedTabGroup.savedTabs) { if (savedTab.localId != null) { @@ -350,7 +335,6 @@ mFilter.closeMultipleTabs( tabsToClose, /* canUndo= */ false, /* hideTabGroups= */ false); } else { - assert state == TabGroupState.HIDDEN; mTabGroupSyncService.removeGroup(savedTabGroup.syncId); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediatorUnitTest.java index 17f52ff..dcf22fe 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListMediatorUnitTest.java
@@ -110,7 +110,8 @@ @Mock private Callback<Drawable> mFaviconCallback2; @Mock private Callback<Drawable> mFaviconCallback3; @Mock private Callback<Drawable> mFaviconCallback4; - @Mock private Tab mTab; + @Mock private Tab mTab1; + @Mock private Tab mTab2; @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserver; @Captor private ArgumentCaptor<TabGroupSyncService.Observer> mTabGroupSyncObserverCaptor; @@ -247,9 +248,9 @@ assertEquals(1, mModelList.size()); when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {}); - when(mTabGroupModelFilter.isTabInTabGroup(mTab)).thenReturn(true); + when(mTabGroupModelFilter.isTabInTabGroup(mTab1)).thenReturn(true); verify(mTabGroupModelFilter).addObserver(mTabModelObserver.capture()); - mTabModelObserver.getValue().tabClosureUndone(mTab); + mTabModelObserver.getValue().tabClosureUndone(mTab1); ShadowLooper.idleMainLooper(); assertEquals(0, mModelList.size()); @@ -456,10 +457,10 @@ when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID2)) .thenReturn(Tab.INVALID_TAB_ID); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(false); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(false); createMediator(); @@ -496,10 +497,10 @@ when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID2)) .thenReturn(Tab.INVALID_TAB_ID); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(false); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(false); createMediator(); @@ -539,10 +540,10 @@ when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID1}); when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID1)).thenReturn(group1); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(true); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(true); createMediator(); @@ -581,10 +582,10 @@ when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID1}); when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID1)).thenReturn(group1); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(true); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(true); createMediator(); @@ -601,6 +602,52 @@ @Test @SmallTest + public void testOpenRunnable_ClosingAfterShowing() { + SavedTabGroupTab savedTab1 = new SavedTabGroupTab(); + savedTab1.localId = ROOT_ID1; + SavedTabGroupTab savedTab2 = new SavedTabGroupTab(); + savedTab2.localId = ROOT_ID2; + + SavedTabGroup group1 = new SavedTabGroup(); + group1.syncId = SYNC_GROUP_ID1; + group1.savedTabs = Arrays.asList(savedTab1, savedTab2); + group1.localId = new LocalTabGroupId(LOCAL_GROUP_ID1); + + when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID1}); + when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID1)).thenReturn(group1); + when(mComprehensiveModel.getCount()).thenReturn(2); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mComprehensiveModel.getTabAt(1)).thenReturn(mTab2); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab2.getRootId()).thenReturn(ROOT_ID1); + when(mTab2.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID1)).thenReturn(ROOT_ID1); + + createMediator(); + assertEquals(1, mModelList.size()); + + PropertyModel model1 = mModelList.get(0).model; + model1.get(OPEN_RUNNABLE).run(); + verify(mTabModel, never()).cancelTabClosure(ROOT_ID1); + verify(mPaneManager).focusPane(PaneId.TAB_SWITCHER); + verify(mTabSwitcherPaneBase).requestOpenTabGroupDialog(ROOT_ID1); + + when(mTab1.isClosing()).thenReturn(true); + model1.get(OPEN_RUNNABLE).run(); + verify(mTabModel, never()).cancelTabClosure(ROOT_ID1); + verify(mPaneManager, times(2)).focusPane(PaneId.TAB_SWITCHER); + verify(mTabSwitcherPaneBase, times(2)).requestOpenTabGroupDialog(ROOT_ID1); + + when(mTab2.isClosing()).thenReturn(true); + model1.get(OPEN_RUNNABLE).run(); + verify(mTabModel).cancelTabClosure(ROOT_ID1); + verify(mPaneManager, times(3)).focusPane(PaneId.TAB_SWITCHER); + verify(mTabSwitcherPaneBase, times(3)).requestOpenTabGroupDialog(ROOT_ID1); + } + + @Test + @SmallTest public void testDeleteRunnable() { SavedTabGroup group1 = new SavedTabGroup(); group1.syncId = SYNC_GROUP_ID1; @@ -620,12 +667,12 @@ when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID2)) .thenReturn(Tab.INVALID_TAB_ID); when(mTabGroupModelFilter.getRelatedTabListForRootId(ROOT_ID1)) - .thenReturn(Arrays.asList(mTab)); + .thenReturn(Arrays.asList(mTab1)); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(false); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(false); createMediator(); @@ -662,12 +709,12 @@ when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID1)).thenReturn(group1); when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID1)).thenReturn(ROOT_ID1); when(mTabGroupModelFilter.getRelatedTabListForRootId(ROOT_ID1)) - .thenReturn(Arrays.asList(mTab)); + .thenReturn(Arrays.asList(mTab1)); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(false); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(false); createMediator(); @@ -695,12 +742,12 @@ when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID1)).thenReturn(group1); when(mTabGroupModelFilter.getRootIdFromStableId(LOCAL_GROUP_ID1)).thenReturn(ROOT_ID1); when(mTabGroupModelFilter.getRelatedTabListForRootId(ROOT_ID1)) - .thenReturn(Arrays.asList(mTab)); + .thenReturn(Arrays.asList(mTab1)); when(mComprehensiveModel.getCount()).thenReturn(1); - when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab); - when(mTab.getRootId()).thenReturn(ROOT_ID1); - when(mTab.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); - when(mTab.isClosing()).thenReturn(true); + when(mComprehensiveModel.getTabAt(0)).thenReturn(mTab1); + when(mTab1.getRootId()).thenReturn(ROOT_ID1); + when(mTab1.getTabGroupId()).thenReturn(LOCAL_GROUP_ID1); + when(mTab1.isClosing()).thenReturn(true); createMediator();
diff --git a/chrome/android/java/res/layout/improved_bookmark_folder_view_layout.xml b/chrome/android/java/res/layout/improved_bookmark_folder_view_layout.xml index 47f18c8e..dcf3cccb 100644 --- a/chrome/android/java/res/layout/improved_bookmark_folder_view_layout.xml +++ b/chrome/android/java/res/layout/improved_bookmark_folder_view_layout.xml
@@ -122,8 +122,7 @@ android:layout_height="@dimen/improved_bookmark_row_secondary_inner_size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" - android:gravity="center" - android:textAppearance="@style/TextAppearance.FolderChildCount" /> + android:gravity="center" /> </androidx.constraintlayout.widget.ConstraintLayout> </org.chromium.chrome.browser.bookmarks.ImprovedBookmarkFolderView>
diff --git a/chrome/android/java/res/values/styles.xml b/chrome/android/java/res/values/styles.xml index b50878d..81faca63 100644 --- a/chrome/android/java/res/values/styles.xml +++ b/chrome/android/java/res/values/styles.xml
@@ -478,7 +478,11 @@ <style name="TextAppearance.ShoppingPriceDropText" parent="TextAppearance.TextMedium.Secondary"> <item name="android:textColor">@color/price_drop_annotation_text_green</item> </style> - <style name="TextAppearance.FolderChildCount" parent="TextAppearance.TextLarge.Primary.OnAccent1Container" tools:ignore="SpUsage"> + <style name="TextAppearance.SpecialFolderChildCount" parent="TextAppearance.TextLarge.Primary.OnAccent1Container" tools:ignore="SpUsage"> + <!-- The same as the regular style, but using dp instead of sp. --> + <item name="android:textSize">16dp</item> + </style> + <style name="TextAppearance.RegularFolderChildCount" parent="TextAppearance.TextLarge.Primary" tools:ignore="SpUsage"> <!-- The same as the regular style, but using dp instead of sp. --> <item name="android:textSize">16dp</item> </style>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderView.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderView.java index 3187cf6..e0ceb7e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderView.java
@@ -18,6 +18,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; import org.chromium.chrome.R; import org.chromium.components.browser_ui.styles.ChromeColors; @@ -181,6 +182,10 @@ mChildCount.setText(Integer.toString(count)); } + void setChildCountStyle(@StyleRes int styleRes) { + mChildCount.setTextAppearance(styleRes); + } + private void updateChildCountContainer(int numberOfImages) { mChildCountContainer.setVisibility(numberOfImages == 0 ? View.GONE : View.VISIBLE); if (numberOfImages == 1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java index e0b0e86..a50f0d1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java
@@ -180,6 +180,11 @@ ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT, BookmarkUtils.getChildCountForDisplay(bookmarkItem.getId(), mBookmarkModel)); propertyModel.set( + ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE, + BookmarkUtils.isSpecialFolder(mBookmarkModel, bookmarkItem) + ? R.style.TextAppearance_SpecialFolderChildCount + : R.style.TextAppearance_RegularFolderChildCount); + propertyModel.set( ImprovedBookmarkRowProperties.FOLDER_START_AREA_BACKGROUND_COLOR, BookmarkUtils.getIconBackground(mContext, mBookmarkModel, bookmarkItem)); propertyModel.set(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java index 6a1d862f..194196b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java
@@ -105,6 +105,8 @@ public static final WritableObjectPropertyKey<LazyOneshotSupplier<Pair<Drawable, Drawable>>> FOLDER_START_IMAGE_FOLDER_DRAWABLES = new WritableObjectPropertyKey<>(); public static final WritableIntPropertyKey FOLDER_CHILD_COUNT = new WritableIntPropertyKey(); + public static final WritableIntPropertyKey FOLDER_CHILD_COUNT_TEXT_STYLE = + new WritableIntPropertyKey(); private static final PropertyKey[] IMPROVED_BOOKMARK_ROW_PROPERTIES = { ENABLED, @@ -133,7 +135,8 @@ FOLDER_START_ICON_TINT, FOLDER_START_ICON_DRAWABLE, FOLDER_START_IMAGE_FOLDER_DRAWABLES, - FOLDER_CHILD_COUNT + FOLDER_CHILD_COUNT, + FOLDER_CHILD_COUNT_TEXT_STYLE }; public static final PropertyKey[] ALL_KEYS = PropertyModel.concatKeys(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java index f00ea09b..cfce2339 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java
@@ -95,6 +95,9 @@ model.get(ImprovedBookmarkRowProperties.FOLDER_START_IMAGE_FOLDER_DRAWABLES).get(); } else if (key == ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT) { folderView.setChildCount(model.get(ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT)); + } else if (key == ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE) { + folderView.setChildCountStyle( + model.get(ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE)); } else if (key == BookmarkManagerProperties.IS_HIGHLIGHTED) { View highlightedView = view.findViewById(R.id.container); if (model.get(BookmarkManagerProperties.IS_HIGHLIGHTED)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java index a01fabd..6fa2a9a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java
@@ -139,11 +139,7 @@ private NewTabPageStation pauseAndResumeActivity(Station currentStation) { NewTabPageStation destination = - NewTabPageStation.newBuilder() - .withActivityTestRule(sActivityTestRule) - .withIsOpeningTabs(0) - .withIsSelectingTabs(1) - .build(); + NewTabPageStation.newBuilder().withIsOpeningTabs(0).withIsSelectingTabs(1).build(); currentStation.travelToSync( destination, () -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index ad21de74..13e0df10 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -1182,6 +1182,7 @@ isScrollableMvtEnabled(mContext), mostRecentTab, this::onSingleTabCardClicked, + /* seeMoreLinkClickedCallback= */ null, () -> mSnapshotSingleTabCardChanged = true, mTabContentManagerSupplier.get() /* tabContentManager= */ ,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java index 4fd91b4..9d523ba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -148,21 +148,14 @@ runVoiceSearch(); } else if (searchType == SearchType.LENS) { runGoogleLens(); - } else { - focusTextBox(); } + focusTextBox(); mInteractionFromWidget = false; } /** Begins a new Voice query. */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) void runVoiceSearch() { - // Run Voice before focusing the Omnibox. Voice search may trigger omnibox focus as part of - // its own flow in the event where the input is ambiguous. Focusing the Omnibox early may - // affect this flow. - // - // Note that the Voice search will call us back in the event of any failure via - // notifyVoiceRecognitionCanceled() call, giving us the opportunity to focus the Omnibox. View micButton = findViewById(R.id.mic_button); if (!micButton.performClick()) { // Voice recognition is not available. Fall back to regular text search. @@ -171,20 +164,11 @@ R.string.quick_action_search_widget_message_no_voice_search, Toast.LENGTH_LONG) .show(); - focusTextBox(); } } /** Begins a new Lens query. */ private void runGoogleLens() { - // Preemptively focus the Search box to handle fallback to text search for every case where - // Lens search could not be performed, including events where Lens is started and canceled - // by the User. - // Unlike Voice, Lens gives us no feedback about completion and does not interact with the - // Omnibox at any point. Focus is relevant here, because otherwise canceled Lens intent - // lands the User on a white, unfocused activity with no keyboard and single, empty text - // field on top. - focusTextBox(); View lensButton = findViewById(R.id.lens_camera_button); if (!lensButton.performClick()) { Toast.makeText(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java index 6464951..7aad126c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java
@@ -22,6 +22,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.metrics.ChangeMetricsReportingStateCalledFrom; import org.chromium.chrome.browser.metrics.UmaSessionStats; +import org.chromium.chrome.browser.password_manager.account_storage_toggle.AccountStorageToggleFragmentArgs; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures; import org.chromium.chrome.browser.price_tracking.PriceTrackingUtilities; @@ -124,6 +125,10 @@ mPasswordsAccountStorage = (ChromeSwitchPreference) findPreference(PREF_PASSWORDS_ACCOUNT_STORAGE); mPasswordsAccountStorage.setOnPreferenceChangeListener(this); + if (getArguments() != null + && getArguments().getBoolean(AccountStorageToggleFragmentArgs.HIGHLIGHT)) { + mPasswordsAccountStorage.setBackgroundColor(R.color.iph_highlight_blue); + } SyncServiceFactory.getForProfile(getProfile()).addSyncStateChangedListener(this); mSearchSuggestions = (ChromeSwitchPreference) findPreference(PREF_SEARCH_SUGGESTIONS);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java index 5344c65..76349ef 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java
@@ -85,7 +85,6 @@ // Exit settings for the initial state rule to be able to reset state. settings.pressBack( WebPageStation.newWebPageStationBuilder() - .withActivityTestRule(sActivityTestRule) .withIncognito(false) .withIsOpeningTabs(0) .withTabAlreadySelected(tab)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java index f396bbe..5e9ff17d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java
@@ -91,7 +91,7 @@ @Rule public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(8) + .setRevision(9) .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java index fdc3a36..fa71eb3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java
@@ -83,7 +83,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) - .setRevision(2) + .setRevision(3) .build(); @Rule public TestRule mProcessor = new Features.JUnitProcessor(); @@ -142,6 +142,9 @@ PropertyModelChangeProcessor.create( mModel, row, ImprovedBookmarkRowViewBinder::bind); mModel.set(ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT, 5); + mModel.set( + ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE, + R.style.TextAppearance_RegularFolderChildCount); }); } @@ -205,6 +208,9 @@ ColorStateList.valueOf( SemanticColorUtils.getDefaultIconColorAccent1( mActivityTestRule.getActivity()))); + mModel.set( + ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE, + R.style.TextAppearance_SpecialFolderChildCount); }); mRenderTestRule.render(mFolderView, "no_image_bookmarks_bar"); } @@ -234,6 +240,9 @@ ColorStateList.valueOf( SemanticColorUtils.getDefaultIconColorAccent1( mActivityTestRule.getActivity()))); + mModel.set( + ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT_TEXT_STYLE, + R.style.TextAppearance_SpecialFolderChildCount); }); mRenderTestRule.render(mFolderView, "no_image_reading_list"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java index 0d030ec..718d6e5e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java
@@ -4,16 +4,25 @@ package org.chromium.chrome.browser.customtabs; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + import android.content.Intent; import androidx.annotation.NonNull; import org.junit.Assert; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.mockito.Mockito; +import org.chromium.base.Log; import org.chromium.base.test.util.ScalableTimeout; +import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabTestUtils; import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.components.feature_engagement.Tracker; /** * Custom ActivityTestRule for all instrumentation tests that require a {@link CustomTabActivity}. @@ -21,12 +30,34 @@ public class CustomTabActivityTestRule extends ChromeActivityTestRule<CustomTabActivity> { protected static final long STARTUP_TIMEOUT_MS = ScalableTimeout.scaleTimeout(5L * 1000); protected static final long LONG_TIMEOUT_MS = 10L * 1000; + private static final String TAG = "CustomTabTestRule"; private static int sCustomTabId; public CustomTabActivityTestRule() { super(CustomTabActivity.class); } + @Override + public Statement apply(Statement base, Description description) { + Statement statement = + new Statement() { + @Override + public void evaluate() throws Throwable { + // TODO(crbug.com/342240475): Find a better way to deal with IPH in tests. + Log.w( + TAG, + "A mock Tracker is set in CustomTabActivityTestRule. This will" + + " prevent any IPH from showing. See crbug.com/342240475."); + Tracker tracker = Mockito.mock(Tracker.class); + // Disable IPH to prevent it from interfering with the tests. + when(tracker.shouldTriggerHelpUI(anyString())).thenReturn(false); + TrackerFactory.setTrackerForTests(tracker); + base.evaluate(); + } + }; + return super.apply(statement, description); + } + public static void putCustomTabIdInIntent(Intent intent) { boolean hasCustomTabId = intent.hasExtra(CustomTabsTestUtils.EXTRA_CUSTOM_TAB_ID); // Intent already has a custom tab id assigned to it and we should reuse the same activity.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java index ded4e4f8..625199f7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -45,6 +45,7 @@ import org.chromium.ui.test.util.DisableAnimationsTestRule; import org.chromium.ui.test.util.UiRestriction; +import java.util.Optional; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -89,14 +90,17 @@ public final boolean hasAutocomplete; public final String textWithoutAutocomplete; public final String textWithAutocomplete; + public final String additionalText; public AutocompleteState( boolean hasAutocomplete, String textWithoutAutocomplete, - String textWithAutocomplete) { + String textWithAutocomplete, + String additionalText) { this.hasAutocomplete = hasAutocomplete; this.textWithoutAutocomplete = textWithoutAutocomplete; this.textWithAutocomplete = textWithAutocomplete; + this.additionalText = additionalText; } } @@ -104,17 +108,22 @@ final AtomicBoolean hasAutocomplete = new AtomicBoolean(); final AtomicReference<String> textWithoutAutocomplete = new AtomicReference<String>(); final AtomicReference<String> textWithAutocomplete = new AtomicReference<String>(); + final AtomicReference<String> additionalText = new AtomicReference<String>(); TestThreadUtils.runOnUiThreadBlocking( () -> { if (action != null) action.run(); + hasAutocomplete.set(mUrlBar.hasAutocomplete()); textWithoutAutocomplete.set(mUrlBar.getTextWithoutAutocomplete()); textWithAutocomplete.set(mUrlBar.getTextWithAutocomplete()); - hasAutocomplete.set(mUrlBar.hasAutocomplete()); + additionalText.set(mUrlBar.getAdditionalText().orElse("")); }); return new AutocompleteState( - hasAutocomplete.get(), textWithoutAutocomplete.get(), textWithAutocomplete.get()); + hasAutocomplete.get(), + textWithoutAutocomplete.get(), + textWithAutocomplete.get(), + additionalText.get()); } private AutocompleteState setSelection(final int selectionStart, final int selectionEnd) { @@ -165,11 +174,11 @@ public void testAutocompleteUpdatedOnSetText() { // Verify that setting a new string will clear the autocomplete. mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); // Replace part of the non-autocomplete text mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); TestThreadUtils.runOnUiThreadBlocking( () -> { mUrlBar.setText(mUrlBar.getText().replace(1, 2, "a")); @@ -178,7 +187,7 @@ // Replace part of the autocomplete text. mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); TestThreadUtils.runOnUiThreadBlocking( () -> { mUrlBar.setText(mUrlBar.getText().replace(8, 10, "no")); @@ -189,6 +198,7 @@ private void verifySelectionState( String text, String inlineAutocomplete, + String additionalText, int selectionStart, int selectionEnd, boolean expectedHasAutocomplete, @@ -198,7 +208,7 @@ String expectedRequestedAutocompleteText) throws TimeoutException { mOmnibox.setText(text); - mOmnibox.setAutocompleteText(inlineAutocomplete); + mOmnibox.setAutocompleteText(inlineAutocomplete, Optional.of(additionalText)); final CallbackHelper autocompleteHelper = new CallbackHelper(); final AtomicReference<String> requestedAutocompleteText = new AtomicReference<String>(); @@ -219,6 +229,7 @@ state.textWithoutAutocomplete); Assert.assertEquals( "Text w/ Autocomplete", expectedTextWithAutocomplete, state.textWithAutocomplete); + Assert.assertEquals("Addition Text", additionalText, state.additionalText); autocompleteHelper.waitForCallback(0); Assert.assertEquals( @@ -235,16 +246,19 @@ @SmallTest public void testAutocompleteUpdatedOnSelection() throws TimeoutException { // Verify that setting a selection before the autocomplete clears it. - verifySelectionState("test", "ing is fun", 1, 1, false, "test", "test", true, "test"); + verifySelectionState( + "test", "ing is fun", "foo.com", 1, 1, false, "test", "test", true, "test"); // Verify that setting a selection range before the autocomplete clears it. - verifySelectionState("test", "ing is fun", 0, 4, false, "test", "test", true, "test"); + verifySelectionState( + "test", "ing is fun", "foo.com", 0, 4, false, "test", "test", true, "test"); // Verify that setting a selection range that covers a portion of the non-autocomplete // and autocomplete text does not delete the autocomplete text. verifySelectionState( "test", "ing is fun", + "foo.com", 2, 5, false, @@ -258,6 +272,7 @@ verifySelectionState( "test", "ing is fun", + "foo.com", 0, 14, false, @@ -272,6 +287,7 @@ verifySelectionState( "test", "ing is fun", + "foo.com", 14, 14, false, @@ -285,6 +301,7 @@ verifySelectionState( "test", "ing is fun", + "foo.com", 9, 9, false, @@ -298,6 +315,7 @@ verifySelectionState( "test", "ing is fun", + "foo.com", 8, 11, false, @@ -309,9 +327,9 @@ // Select autocomplete text. As we do not expect the suggestions to be refreshed, we test // this slightly differently than the other cases. mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.of("www.bar.com")); TestThreadUtils.runOnUiThreadBlocking(() -> mUrlBar.setSelection(4, 14)); - mOmnibox.checkText(equalTo("testing is fun"), null); + mOmnibox.checkText(equalTo("testing is fun"), null, equalTo("www.bar.com")); } /** @@ -417,7 +435,7 @@ @SmallTest public void testSuggestionsUpdatedWhenDeletingInlineAutocomplete() throws TimeoutException { mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing"); + mOmnibox.setAutocompleteText("ing", Optional.empty()); final CallbackHelper autocompleteHelper = new CallbackHelper(); final AtomicBoolean didPreventInlineAutocomplete = new AtomicBoolean(); @@ -442,9 +460,8 @@ @Test @SmallTest public void testAutocorrectionChangesTriggerCorrectSuggestions() { - final AtomicReference<String> requestedAutocompleteText = new AtomicReference<String>(); mOmnibox.setComposingText("test", 0, 4); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); mOmnibox.checkText(equalTo("test"), equalTo("testing is fun")); mOmnibox.commitText("rest", false); mOmnibox.checkText(equalTo("rest"), null); @@ -453,10 +470,9 @@ @Test @SmallTest public void testAutocompletionChangesTriggerCorrectSuggestions() { - final AtomicReference<String> requestedAutocompleteText = new AtomicReference<String>(); // Type text. Make sure it appears as composing text for the IME. mOmnibox.setComposingText("test", 0, 4); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); mOmnibox.checkText(equalTo("test"), equalTo("testing is fun")); mOmnibox.commitText("y", true); mOmnibox.checkText(equalTo("testy"), null); @@ -467,13 +483,13 @@ public void testAutocompleteCorrectlyPerservedOnBatchMode() { // Valid case (cursor at the end of text, single character, matches previous autocomplete). mOmnibox.setText("g"); - mOmnibox.setAutocompleteText("oogle.com"); + mOmnibox.setAutocompleteText("oogle.com", Optional.empty()); mOmnibox.typeText("o", false); mOmnibox.checkText(equalTo("go"), equalTo("google.com")); // Invalid case (cursor not at the end of the text). mOmnibox.setText("g"); - mOmnibox.setAutocompleteText("oogle.com"); + mOmnibox.setAutocompleteText("oogle.com", Optional.empty()); TestThreadUtils.runOnUiThreadBlocking( () -> { InputConnection conn = mUrlBar.getInputConnection(); @@ -487,13 +503,13 @@ // Invalid case (next character did not match previous autocomplete) mOmnibox.setText("g"); - mOmnibox.setAutocompleteText("oogle.com"); + mOmnibox.setAutocompleteText("oogle.com", Optional.empty()); mOmnibox.typeText("a", false); mOmnibox.checkText(equalTo("ga"), null); // Multiple characters entered instead of 1. mOmnibox.setText("g"); - mOmnibox.setAutocompleteText("oogle.com"); + mOmnibox.setAutocompleteText("oogle.com", Optional.empty()); mOmnibox.commitText("oogl", true); mOmnibox.checkText(equalTo("googl"), equalTo("google.com")); } @@ -502,7 +518,7 @@ @SmallTest public void testAutocompleteSpanClearedOnNonMatchingCommitText() { mOmnibox.setText("a"); - mOmnibox.setAutocompleteText("mazon.com"); + mOmnibox.setAutocompleteText("mazon.com", Optional.empty()); mOmnibox.checkText(equalTo("a"), equalTo("amazon.com")); mOmnibox.typeText("l", false); @@ -513,7 +529,7 @@ @SmallTest public void testAutocompleteClearedOnComposition() { mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is fun"); + mOmnibox.setAutocompleteText("ing is fun", Optional.empty()); mOmnibox.setComposingText("ing compose", 4, 4); mOmnibox.checkText(equalTo("testing compose"), null); @@ -524,27 +540,27 @@ public void testDelayedCompositionCorrectedWithAutocomplete() { // Test with a single IME autocomplete mOmnibox.typeText("chrome://f", false); - mOmnibox.setAutocompleteText("lags"); + mOmnibox.setAutocompleteText("lags", Optional.empty()); mOmnibox.setComposingText("l", 13, 14); mOmnibox.checkText(equalTo("chrome://fl"), equalTo("chrome://flags")); // Test with > 1 characters in composition. mOmnibox.setText("chrome://fl"); - mOmnibox.setAutocompleteText("ags"); + mOmnibox.setAutocompleteText("ags", Optional.empty()); mOmnibox.checkText(equalTo("chrome://fl"), equalTo("chrome://flags")); mOmnibox.setComposingText("fl", 12, 14); mOmnibox.checkText(equalTo("chrome://flfl"), null); // Test with non-matching composition. Should just append to the URL text. mOmnibox.setText("chrome://f"); - mOmnibox.setAutocompleteText("lags"); + mOmnibox.setAutocompleteText("lags", Optional.empty()); mOmnibox.checkText(equalTo("chrome://f"), equalTo("chrome://flags")); mOmnibox.setComposingText("g", 13, 14); mOmnibox.checkText(equalTo("chrome://fg"), null); // Test with composition text that matches the entire text w/o autocomplete. mOmnibox.setText("chrome://f"); - mOmnibox.setAutocompleteText("lags"); + mOmnibox.setAutocompleteText("lags", Optional.empty()); mOmnibox.checkText(equalTo("chrome://f"), equalTo("chrome://flags")); mOmnibox.setComposingText("chrome://f", 13, 14); mOmnibox.checkText(equalTo("chrome://fchrome://f"), null); @@ -552,7 +568,7 @@ // Test with composition text longer than the URL text. // Shouldn't crash and should just append text. mOmnibox.setText("chrome://f"); - mOmnibox.setAutocompleteText("lags"); + mOmnibox.setAutocompleteText("lags", Optional.empty()); mOmnibox.checkText(equalTo("chrome://f"), equalTo("chrome://flags")); mOmnibox.setComposingText("blahblahblah", 13, 14); mOmnibox.checkText(equalTo("chrome://fblahblahblah"), null); @@ -569,7 +585,7 @@ Mockito.verify(listener).onTextChanged("onomatop"); // Setting autocomplete does not send a change update. - mOmnibox.setAutocompleteText("oeia"); + mOmnibox.setAutocompleteText("oeia", Optional.empty()); mOmnibox.setText(""); Mockito.verify(listener).onTextChanged(""); @@ -579,30 +595,61 @@ @SmallTest public void testSetAutocompleteText_ShrinkingText() { mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ing is awesome"); - mOmnibox.setAutocompleteText("ing is hard"); - mOmnibox.setAutocompleteText("ingz"); - mOmnibox.checkText(equalTo("test"), equalTo("testingz"), 4, 8); + mOmnibox.setAutocompleteText("ing is awesome", Optional.empty()); + mOmnibox.setAutocompleteText("ing is hard", Optional.empty()); + mOmnibox.setAutocompleteText("ingz", Optional.empty()); + mOmnibox.checkText(equalTo("test"), equalTo("testingz"), null, 4, 8); + } + + @Test + @SmallTest + public void testSetAutocompleteTextWithAdditionalText_ShrinkingText() { + mOmnibox.setText("test"); + mOmnibox.setAutocompleteText("ing is awesome", Optional.of("www.foobar.com")); + mOmnibox.setAutocompleteText("ing is hard", Optional.of("www.bar.com")); + mOmnibox.setAutocompleteText("ingz", Optional.of("www.foo.com")); + mOmnibox.checkText(equalTo("test"), equalTo("testingz"), equalTo("www.foo.com"), 4, 8); } @Test @SmallTest public void testSetAutocompleteText_GrowingText() { mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ingz"); - mOmnibox.setAutocompleteText("ing is hard"); - mOmnibox.setAutocompleteText("ing is awesome"); - mOmnibox.checkText(equalTo("test"), equalTo("testing is awesome"), 4, 18); + mOmnibox.setAutocompleteText("ingz", Optional.empty()); + mOmnibox.setAutocompleteText("ing is hard", Optional.empty()); + mOmnibox.setAutocompleteText("ing is awesome", Optional.empty()); + mOmnibox.checkText(equalTo("test"), equalTo("testing is awesome"), null, 4, 18); + } + + @Test + @SmallTest + public void testSetAutocompleteTextWithAdditionalText_GrowingText() { + mOmnibox.setText("test"); + mOmnibox.setAutocompleteText("ingz", Optional.of("www.foo.com")); + mOmnibox.setAutocompleteText("ing is hard", Optional.of("www.bar.com")); + mOmnibox.setAutocompleteText("ing is awesome", Optional.of("www.foobar.com")); + mOmnibox.checkText( + equalTo("test"), equalTo("testing is awesome"), equalTo("www.foobar.com"), 4, 18); } @Test @SmallTest public void testSetAutocompleteText_DuplicateText() { mOmnibox.setText("test"); - mOmnibox.setAutocompleteText("ingz"); - mOmnibox.setAutocompleteText("ingz"); - mOmnibox.setAutocompleteText("ingz"); - mOmnibox.checkText(equalTo("test"), equalTo("testingz"), 4, 8); + mOmnibox.setAutocompleteText("ingz", Optional.empty()); + mOmnibox.setAutocompleteText("ingz", Optional.empty()); + mOmnibox.setAutocompleteText("ingz", Optional.empty()); + mOmnibox.checkText(equalTo("test"), equalTo("testingz"), null, 4, 8); + } + + @Test + @SmallTest + public void testSetAutocompleteTextWithAdditionalText_DuplicateText() { + mOmnibox.setText("test"); + mOmnibox.setAutocompleteText("ingz", Optional.of("www.foo.com")); + mOmnibox.setAutocompleteText("ingz", Optional.of("www.foo.com")); + mOmnibox.setAutocompleteText("ingz", Optional.of("www.foo.com")); + mOmnibox.checkText(equalTo("test"), equalTo("testingz"), equalTo("www.foo.com"), 4, 8); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java index b89aa372..ba83fe3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
@@ -13,7 +13,9 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import android.os.Build; +import android.os.Bundle; +import androidx.annotation.Nullable; import androidx.test.filters.LargeTest; import org.junit.After; @@ -33,6 +35,7 @@ import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.password_manager.account_storage_toggle.AccountStorageToggleFragmentArgs; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures; import org.chromium.chrome.browser.price_tracking.PriceTrackingUtilities; @@ -338,7 +341,22 @@ @Test @LargeTest + @EnableFeatures({ + ChromeFeatureList.ENABLE_PASSWORDS_ACCOUNT_STORAGE_FOR_NON_SYNCING_USERS, + ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS + }) + public void hidePasswordsAccountStorageToggleIfSignedInAndSyncToSigninEnabled() { + mSigninTestRule.addTestAccountThenSignin(); + + startGoogleServicesSettings(); + + onView(withText(R.string.passwords_account_storage_toggle_title)).check(doesNotExist()); + } + + @Test + @LargeTest @EnableFeatures({ChromeFeatureList.ENABLE_PASSWORDS_ACCOUNT_STORAGE_FOR_NON_SYNCING_USERS}) + @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS}) public void showPasswordsAccountStorageToggleIfSignedInAndFlagEnabled() { CoreAccountInfo account = mSigninTestRule.addTestAccountThenSignin(); @@ -360,6 +378,7 @@ settings.findPreference( GoogleServicesSettings.PREF_PASSWORDS_ACCOUNT_STORAGE); Assert.assertTrue(toggle.isChecked()); + Assert.assertNull(toggle.getBackgroundColor()); Assert.assertTrue(isPasswordSyncEnabled()); onView(withText(R.string.passwords_account_storage_toggle_title)).perform(click()); @@ -380,6 +399,7 @@ @Test @LargeTest @EnableFeatures({ChromeFeatureList.ENABLE_PASSWORDS_ACCOUNT_STORAGE_FOR_NON_SYNCING_USERS}) + @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS}) public void showPasswordsAccountStorageToggleForNonDisplayableEmail() { String email = "auto-generated-email@gmail.com"; String gaiaId = FakeAccountManagerFacade.toGaiaId(email); @@ -399,6 +419,28 @@ .check(matches(isDisplayed())); } + @Test + @LargeTest + @EnableFeatures({ChromeFeatureList.ENABLE_PASSWORDS_ACCOUNT_STORAGE_FOR_NON_SYNCING_USERS}) + @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS}) + public void showPasswordsAccountStorageToggleWithHighlight() { + mSigninTestRule.addTestAccountThenSignin(); + + Bundle args = new Bundle(); + args.putBoolean(AccountStorageToggleFragmentArgs.HIGHLIGHT, true); + mSettingsActivityTestRule.startSettingsActivity(args); + + ChromeSwitchPreference toggle = + (ChromeSwitchPreference) + mSettingsActivityTestRule + .getFragment() + .findPreference( + GoogleServicesSettings.PREF_PASSWORDS_ACCOUNT_STORAGE); + @Nullable Integer backgroundColor = toggle.getBackgroundColor(); + Assert.assertNotNull(backgroundColor); + Assert.assertTrue(backgroundColor.equals(R.color.iph_highlight_blue)); + } + private boolean isPasswordSyncEnabled() { return TestThreadUtils.runOnUiThreadBlockingNoException( () ->
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index a72f0636..620517a 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1476,11 +1476,12 @@ Navigate to extra content <ph name="CURRENT_ELEMENT">$1<ex>1</ex></ph> out of <ph name="TOTAL_ELEMENTS">$2<ex>2</ex></ph> </message> <!-- Strings for tuna screen --> - <message name="IDS_TUNA_TITLE" desc="The title of the tuna dialog" translateable="false"> - Your <ph name="DEVICE_TYPE">$1<ex>Chromebook Plus</ex></ph> comes with Google AI + <message name="IDS_TUNA_TITLE" desc="The title of the tuna dialog"> + Your <ph name="DEVICE_TYPE">$1<ex>Chromebook Plus</ex></ph> comes with Gemini </message> - <message name="IDS_TUNA_SUBTITLE" desc="The subtitle of the tuna dialog" translateable="false"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>Get help on writing, planning, learning and more.<ph name="END_PARAGRAPH1"></p></ph> + <message name="IDS_TUNA_SUBTITLE" desc="The subtitle of the tuna dialog"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>Chat with Gemini to start writing, planning, learning and more with Google AI.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>After setup, start using Gemini by selecting the Gemini app on your shelf, at the bottom of your screen.<ph name="END_PARAGRAPH2"></p></ph> </message> <!-- Strings for marketing optin screen --> <message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_TITLE" desc="The title of the last dialog in the set of screens that are always displayed to the user on the first login to the ChromeOS device."> @@ -5436,6 +5437,9 @@ <message name="IDS_BRUSCHETTA_INSTALLER_RETRY_BUTTON" desc="Button for Bruschetta (Codename) installer to retry after failing."> Retry </message> + <message name="IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM" desc="Text shown in the context menu for the Bruschetta terminal app, allowing users to shut down the Linux virtual machine."> + Shut down <ph name="VM_NAME">$1<ex>Bruschetta</ex></ph> + </message> <!-- Time limit notification --> <message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device."> @@ -7572,4 +7576,8 @@ Learn more </message> + <!-- Mall app --> + <message name="IDS_MALL_APP_NAME" desc="Name of a system app which can be used to find and install apps and games"> + Get Apps and Games + </message> </grit-part>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM.png.sha1 new file mode 100644 index 0000000..6ba7dae --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM.png.sha1
@@ -0,0 +1 @@ +17da0e88a0f9cf28d1cdffaea288e21a047dee68 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_MALL_APP_NAME.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_MALL_APP_NAME.png.sha1 new file mode 100644 index 0000000..6ad727d --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_MALL_APP_NAME.png.sha1
@@ -0,0 +1 @@ +4d8447b09fbae99a8c61247eae13def556261379 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_TUNA_SUBTITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_TUNA_SUBTITLE.png.sha1 new file mode 100644 index 0000000..e241fc3 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_TUNA_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +01e36704c40d81f9d671303d5925a89236fa57f7 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_TUNA_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_TUNA_TITLE.png.sha1 new file mode 100644 index 0000000..e241fc3 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_TUNA_TITLE.png.sha1
@@ -0,0 +1 @@ +01e36704c40d81f9d671303d5925a89236fa57f7 \ No newline at end of file
diff --git a/chrome/app/extensions_strings.grdp b/chrome/app/extensions_strings.grdp index 0df095e..c0e1b74 100644 --- a/chrome/app/extensions_strings.grdp +++ b/chrome/app/extensions_strings.grdp
@@ -599,6 +599,9 @@ More actions for <ph name="EXTENSION_NAME">$1<ex>Voice Over</ex></ph> extension </message> <!-- Extensions Manifest V2 Deprecation Panel strings --> + <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_TITLE" desc="Title text displayed before the manifest v2 deprecation panel"> + Updates + </message> <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_HEADER" desc="Header text displayed in the manifest v2 deprecation panel for the warning stage."> {NUM_EXTENSIONS, plural, =1 {This extension may soon no longer be suported} @@ -611,6 +614,12 @@ other {Remove or replace them with similar extensions from the <ph name="BEGIN_LINK"><a href='https://chromewebstore.google.com/category/extensions'></ph>Chrome Web Store<ph name="END_LINK"></a></ph>} } </message> + <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_HEADER" desc="Header text displayed in the manifest v2 deprecation message for a specific extension during the warning stage."> + This extension may soon no longer be suported + </message> + <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation message for a specific extension during the warning stage."> + Remove or replace it with similar extensions from the <ph name="BEGIN_LINK"><a href='https://chromewebstore.google.com/category/extensions'></ph>Chrome Web Store<ph name="END_LINK"></a></ph> + </message> <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISMISS_BUTTON" desc="The label for a button to dismiss the manifest v2 deprecation panel"> Got it </message>
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_HEADER.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_HEADER.png.sha1 new file mode 100644 index 0000000..fd5acbc2 --- /dev/null +++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_HEADER.png.sha1
@@ -0,0 +1 @@ +77163f4eab8bbf8f8f5c14487bc8ab96f45e07a4 \ No newline at end of file
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1 new file mode 100644 index 0000000..fd5acbc2 --- /dev/null +++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +77163f4eab8bbf8f8f5c14487bc8ab96f45e07a4 \ No newline at end of file
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_TITLE.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_TITLE.png.sha1 new file mode 100644 index 0000000..6d4cdfa --- /dev/null +++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_TITLE.png.sha1
@@ -0,0 +1 @@ +367ce23c2729b980eb4c57153943d42210349012 \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 513420e6..85bcc14 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8883,20 +8883,20 @@ To easily get back to the side panel, click Pin at the top right </message> <message name="IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH" desc="The body text of the IPH describing that the Lens Overlay panel is pinnable."> - You can pin this feature for easy access + You can pin Google Lens for easy access </message> <message name="IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH_SCREENREADER" desc="The screen reader text of the IPH describing that the Lens Overlay panel is pinnable." is_accessibility_with_no_ui="true"> - You can pin this feature for easy access; click the Pin button at the top of the side panel + You can pin Google Lens for easy access; click the Pin button at the top of the side panel </message> <message name="IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH" desc="The body text of the IPH describing that the Lens Overlay panel has been pinned."> - Pinned! Use this feature again from the toolbar + Pinned! Use Google Lens again from the toolbar </message> <message name="IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH_SCREENREADER" desc="The screen reader text of the IPH describing that the Lens Overlay panel has been pinned." is_accessibility_with_no_ui="true"> - Pinned! You can access this feature again from the new button on the toolbar + Pinned! You can access Google Lens again from the new button on the toolbar </message> <!-- Bookmarks strings --> @@ -16337,6 +16337,19 @@ This passkey will be saved to your password manager. Anyone with access to it will be able to use this passkey. </message> + <!-- Web-modal dialog shown during Digital Credential request --> + <message name="IDS_WEB_DIGITAL_CREDENTIALS_QR_TITLE" translateable="false"> + Retrieve credentials from phone or tablet. + </message> + + <message name="IDS_WEB_DIGITAL_CREDENTIALS_QR_BODY" translateable="false"> + Scan this QR code with a camera on the device from which you want to retrieve credentials for <ph name="APP_NAME">$1<ex>example.com</ex></ph> + </message> + + <message name="IDS_WEB_DIGITAL_CREDENTIALS_QR_CODE_ALT_TEXT" translateable="false"> + QR code + </message> + <!-- Side Search --> <message name="IDS_ACCNAME_SIDE_SEARCH_TOOL" desc="The accessible name for the side search tool."> Side Search @@ -16897,6 +16910,9 @@ <message name="IDS_LENS_OVERLAY_INFO_BUTTON_LABEL" desc="Text that is shown in the tooltip of the info button in the Lens Overlay."> Learn more </message> + <message name="IDS_LENS_OVERLAY_INITIAL_TOAST_LABEL" desc="Accessibility label for the initial user eduction bubble that appears at the top of the screen after the user invokes the Lens Overlay feature. Informs the user to select an object to search with Google Lens, or use the escape key to exit the feature."> + Select anything to search with Google Lens or press escape to exit Google Lens + </message> <message name="IDS_LENS_OVERLAY_INITIAL_TOAST_MESSAGE" desc="Text that is shown in the Lens Overlay education bubble when starting the feature. Informs the user to tap an object or drag over the screen to select a region to search with Google Lens."> Select anything to search with Google Lens </message>
diff --git a/chrome/app/generated_resources_grd/IDS_LENS_OVERLAY_INITIAL_TOAST_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_LENS_OVERLAY_INITIAL_TOAST_LABEL.png.sha1 new file mode 100644 index 0000000..951d102 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_LENS_OVERLAY_INITIAL_TOAST_LABEL.png.sha1
@@ -0,0 +1 @@ +ddcec8f3317b8c91513f7405bcfd15d4d6434389 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH.png.sha1 b/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH.png.sha1 index 454e698..131c9f4 100644 --- a/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_FOLLOWUP_IPH.png.sha1
@@ -1 +1 @@ -5ac7c6a94ea056845522369fbaad24ff9031fab9 \ No newline at end of file +4c9036773cb69f07eb61d28a09e8cfe9d9790053 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH.png.sha1 b/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH.png.sha1 index 0a15415..0fc84242 100644 --- a/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_SIDE_PANEL_LENS_OVERLAY_PINNABLE_IPH.png.sha1
@@ -1 +1 @@ -86320dabd94c0e2972756acf1768da7f06a67e63 \ No newline at end of file +5ebf1145c9e72197b1c7378679ac04d3c74736b1 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d7696cd..49edd91f 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -512,6 +512,10 @@ "enterprise/connectors/interstitials/enterprise_warn_controller_client.h", "enterprise/connectors/interstitials/enterprise_warn_page.cc", "enterprise/connectors/interstitials/enterprise_warn_page.h", + "enterprise/identifiers/profile_id_delegate_impl.cc", + "enterprise/identifiers/profile_id_delegate_impl.h", + "enterprise/identifiers/profile_id_service_factory.cc", + "enterprise/identifiers/profile_id_service_factory.h", "enterprise/profile_management/saml_response_parser.cc", "enterprise/profile_management/saml_response_parser.h", "enterprise/reporting/legacy_tech/legacy_tech_report_generator.cc", @@ -1981,6 +1985,8 @@ "visited_url_ranking/desktop_tab_model_url_visit_data_fetcher.h", "webapps/webapps_client_desktop.cc", "webapps/webapps_client_desktop.h", + "webid/digital_identity_provider_desktop.cc", + "webid/digital_identity_provider_desktop.h", ] } @@ -2107,7 +2113,6 @@ "//chrome/browser/companion/text_finder", "//chrome/browser/crash_upload_list", "//chrome/browser/devtools", - "//chrome/browser/enterprise/identifiers", "//chrome/browser/enterprise/platform_auth:features", "//chrome/browser/favicon", "//chrome/browser/first_party_sets", @@ -2406,6 +2411,7 @@ "//components/privacy_sandbox/privacy_sandbox_attestations", "//components/profile_metrics", "//components/proxy_config", + "//components/qr_code_generator:bitmap_generator", "//components/query_parser", "//components/query_tiles", "//components/reading_list/core", @@ -2672,7 +2678,9 @@ if (!is_android) { deps += [ + "//chrome/browser/new_tab_page/chrome_colors", "//chrome/browser/ui/lens", + "//chrome/browser/ui/webui/cr_components/theme_color_picker", "//chrome/browser/ui/webui/search_engine_choice:mojo_bindings", "//components/manta", "//components/manta/proto",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 984b5b07..57a2e76f 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1210,6 +1210,17 @@ heap_profiling::kMemlogSamplingRate, heap_profiling::kMemlogSamplingRate5MB}, }; + +const FeatureEntry::FeatureParam + kOptimizationGuideOnDeviceModelBypassPerfParams[] = { + {"compatible_on_device_performance_classes", "*"}, +}; +const FeatureEntry::FeatureVariation + kOptimizationGuideOnDeviceModelVariations[] = { + {"BypassPerfRequirement", + kOptimizationGuideOnDeviceModelBypassPerfParams, + std::size(kOptimizationGuideOnDeviceModelBypassPerfParams), nullptr}}; + const FeatureEntry::FeatureParam kPageContentAnnotationsContentParams[] = { {"annotate_title_instead_of_page_content", "false"}, {"extract_related_searches", "true"}, @@ -5955,11 +5966,6 @@ kOsAndroid, FEATURE_VALUE_TYPE(omnibox::kOmniboxMatchToolbarAndStatusBarColor)}, - {"omnibox-modernize-visual-update", - flag_descriptions::kOmniboxModernizeVisualUpdateName, - flag_descriptions::kOmniboxModernizeVisualUpdateDescription, kOsAndroid, - FEATURE_VALUE_TYPE(omnibox::kOmniboxModernizeVisualUpdate)}, - {"omnibox-most-visited-tiles-horizontal-render-group", flag_descriptions::kOmniboxMostVisitedTilesHorizontalRenderGroupName, flag_descriptions:: @@ -6335,8 +6341,10 @@ {"optimization-guide-on-device-model", flag_descriptions::kOptimizationGuideOnDeviceModelName, flag_descriptions::kOptimizationGuideOnDeviceModelDescription, kOsDesktop, - FEATURE_VALUE_TYPE( - optimization_guide::features::kOptimizationGuideOnDeviceModel)}, + FEATURE_WITH_PARAMS_VALUE_TYPE( + optimization_guide::features::kOptimizationGuideOnDeviceModel, + kOptimizationGuideOnDeviceModelVariations, + "OptimizationGuideOnDeviceModel")}, {"organic-repeatable-queries", flag_descriptions::kOrganicRepeatableQueriesName, @@ -7029,12 +7037,12 @@ FEATURE_VALUE_TYPE(printing::features::kAddPrinterViaPrintscanmgr)}, #endif // BUILDFLAG(IS_CHROMEOS) -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) {"cups-ipp-printing-backend", flag_descriptions::kCupsIppPrintingBackendName, - flag_descriptions::kCupsIppPrintingBackendDescription, kOsMac, + flag_descriptions::kCupsIppPrintingBackendDescription, kOsDesktop, FEATURE_VALUE_TYPE(printing::features::kCupsIppPrintingBackend)}, -#endif // BUILDFLAG(IS_MAC) +#endif // BUILDFLAG(IS_LINUX) ||BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_WIN) {"print-with-postscript-type42-fonts", @@ -7326,6 +7334,13 @@ FEATURE_VALUE_TYPE(features::kImageDescriptionsAlternateRouting)}, #if BUILDFLAG(IS_ANDROID) + {"app-info-tab-resumption-module", + flag_descriptions::kAppInfoTabResumptionModuleName, + flag_descriptions::kAppInfoTabResumptionModuleNameDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kAppInfoTabResumptionModule)}, +#endif + +#if BUILDFLAG(IS_ANDROID) {"app-specific-history", flag_descriptions::kAppSpecificHistoryName, flag_descriptions::kAppSpecificHistoryDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAppSpecificHistory)}, @@ -11410,6 +11425,10 @@ password_manager::features::kScreenlockReauthPromoCard)}, #endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + {"ruby-short-heuristics", flag_descriptions::kRubyShortHeuristicsName, + flag_descriptions::kRubyShortHeuristicsDescription, kOsAll, + FEATURE_VALUE_TYPE(blink::features::kRubyShortHeuristics)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/accessibility/embedded_a11y_extension_loader.cc b/chrome/browser/accessibility/embedded_a11y_extension_loader.cc index 1066aa93..03f35cd8 100644 --- a/chrome/browser/accessibility/embedded_a11y_extension_loader.cc +++ b/chrome/browser/accessibility/embedded_a11y_extension_loader.cc
@@ -226,7 +226,7 @@ base::FilePath resources_path; #if BUILDFLAG(IS_MAC) base::FilePath root_path; - CHECK(base::PathService::Get(base::DIR_ASSETS, &root_path)); + CHECK(base::PathService::Get(base::DIR_MODULE, &root_path)); resources_path = root_path.Append("resources"); #else if (!base::PathService::Get(chrome::DIR_RESOURCES, &resources_path)) {
diff --git a/chrome/browser/apps/app_service/policy_util.cc b/chrome/browser/apps/app_service/policy_util.cc index e4de3c9..ae1f391b 100644 --- a/chrome/browser/apps/app_service/policy_util.cc +++ b/chrome/browser/apps/app_service/policy_util.cc
@@ -21,6 +21,7 @@ #include "components/services/app_service/public/cpp/types_util.h" #if BUILDFLAG(IS_CHROMEOS_ASH) +#include "ash/webui/system_apps/public/system_web_app_type.h" #include "base/containers/map_util.h" #include "base/types/optional_util.h" #include "chrome/browser/ash/file_manager/office_file_tasks.h" @@ -65,7 +66,8 @@ {"os_flags", ash::SystemWebAppType::OS_FLAGS}, {"vc_background", ash::SystemWebAppType::VC_BACKGROUND}, {"print_preview_cros", ash::SystemWebAppType::PRINT_PREVIEW_CROS}, - {"boca", ash::SystemWebAppType::BOCA}}); + {"boca", ash::SystemWebAppType::BOCA}, + {"app_mall", ash::SystemWebAppType::MALL}}); constexpr ash::SystemWebAppType GetMaxSystemWebAppType() { return base::ranges::max(kSystemWebAppsMapping, base::ranges::less{},
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 03ddc01..2074260 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -2928,8 +2928,8 @@ "policy/skyvault/file_location_utils.h", "policy/skyvault/local_files_cleanup.cc", "policy/skyvault/local_files_cleanup.h", - "policy/skyvault/observer.cc", - "policy/skyvault/observer.h", + "policy/skyvault/local_user_files_policy_observer.cc", + "policy/skyvault/local_user_files_policy_observer.h", "policy/skyvault/odfs_skyvault_uploader.cc", "policy/skyvault/odfs_skyvault_uploader.h", "policy/skyvault/policy_utils.cc", @@ -3501,6 +3501,8 @@ "system_web_apps/apps/help_app/help_app_untrusted_ui_config.h", "system_web_apps/apps/help_app/help_app_web_app_info.cc", "system_web_apps/apps/help_app/help_app_web_app_info.h", + "system_web_apps/apps/mall_system_web_app_info.cc", + "system_web_apps/apps/mall_system_web_app_info.h", "system_web_apps/apps/media_app/chrome_media_app_ui_delegate.cc", "system_web_apps/apps/media_app/chrome_media_app_ui_delegate.h", "system_web_apps/apps/media_app/media_app_guest_ui_config.cc", @@ -4180,6 +4182,8 @@ "//ash/webui/file_manager/resources:file_manager_swa_resources", "//ash/webui/firmware_update_ui", "//ash/webui/firmware_update_ui/resources:resources", + "//ash/webui/mall:url_constants", + "//ash/webui/mall/resources", "//ash/webui/media_app_ui:buildflags", "//ash/webui/os_feedback_ui", "//ash/webui/os_feedback_ui/mojom", @@ -4255,7 +4259,6 @@ "//chrome/browser/screen_ai:screen_ai_dlc_installer", "//chrome/browser/screen_ai/public:optical_character_recognizer", "//chrome/browser/ui/ash/system_web_apps", - "//chrome/browser/ui/chromeos/magic_boost:magic_boost", "//chrome/browser/ui/webui/ash/cloud_upload:mojo_bindings_shared", "//chrome/browser/ui/webui/ash/crostini_upgrader:mojo_bindings", "//chrome/browser/webshare:storage", @@ -4366,6 +4369,7 @@ "//chromeos/components/kcer", "//chromeos/components/kcer:chaps_proto", "//chromeos/components/kiosk", + "//chromeos/components/magic_boost/public/cpp:cpp", "//chromeos/components/mahi/public/cpp:cpp", "//chromeos/components/mgs", "//chromeos/components/mojo_bootstrap",
diff --git a/chrome/browser/ash/app_list/search/personalization_provider.cc b/chrome/browser/ash/app_list/search/personalization_provider.cc index db26e81..daeeace8 100644 --- a/chrome/browser/ash/app_list/search/personalization_provider.cc +++ b/chrome/browser/ash/app_list/search/personalization_provider.cc
@@ -20,12 +20,16 @@ #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/app_list/search/common/icon_constants.h" #include "chrome/browser/ash/app_list/search/search_provider.h" +#include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_manager.h" +#include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_manager_factory.h" #include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_metrics.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" #include "chrome/browser/web_applications/web_app_id_constants.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/app_types.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/core/session_manager_observer.h" #include "url/gurl.h" namespace app_list { @@ -69,28 +73,52 @@ launch_params); } -PersonalizationProvider::PersonalizationProvider( - Profile* profile, - ash::personalization_app::SearchHandler* search_handler) - : SearchProvider(SearchCategory::kSettings), - profile_(profile), - search_handler_(search_handler) { - app_registry_cache_observer_.Observe( - &apps::AppServiceProxyFactory::GetForProfile(profile_) - ->AppRegistryCache()); - StartLoadIcon(); - - if (search_handler_) { - search_handler_->AddObserver( - search_results_observer_.BindNewPipeAndPassRemote()); +PersonalizationProvider::PersonalizationProvider(Profile* profile) + : SearchProvider(SearchCategory::kSettings), profile_(profile) { + auto* session_manager = session_manager::SessionManager::Get(); + if (session_manager->IsUserSessionStartUpTaskCompleted()) { + // If user session start up task has completed, the initialization can + // start. + Initialize(); + } else { + // Wait for the user session start up task completion to prioritize + // resources for them. + session_manager_observation_.Observe(session_manager); } } PersonalizationProvider::~PersonalizationProvider() = default; +void PersonalizationProvider::Initialize( + ::ash::personalization_app::SearchHandler* fake_search_handler) { + // Initialization is happening, so we no longer need to wait for user session + // start up task completion. + session_manager_observation_.Reset(); + + app_registry_cache_observer_.Observe( + &apps::AppServiceProxyFactory::GetForProfile(profile_) + ->AppRegistryCache()); + StartLoadIcon(); + + // Use fake search handler if provided in tests, or get it from + // `personalization_app_manager`. + if (fake_search_handler) { + search_handler_ = fake_search_handler; + } else { + auto* personalization_app_manager = ash::personalization_app:: + PersonalizationAppManagerFactory::GetForBrowserContext(profile_); + CHECK(personalization_app_manager); + search_handler_ = personalization_app_manager->search_handler(); + } + CHECK(search_handler_); + search_handler_->AddObserver( + search_results_observer_.BindNewPipeAndPassRemote()); +} + void PersonalizationProvider::Start(const std::u16string& query) { - if (!search_handler_) + if (!search_handler_) { return; + } if (query.size() < kMinQueryLength) { return; @@ -159,6 +187,10 @@ SwapResults(&search_results); } +void PersonalizationProvider::OnUserSessionStartUpTaskCompleted() { + Initialize(); +} + void PersonalizationProvider::StartLoadIcon() { auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); proxy->LoadIcon(
diff --git a/chrome/browser/ash/app_list/search/personalization_provider.h b/chrome/browser/ash/app_list/search/personalization_provider.h index 2f0b97d..eb301ca 100644 --- a/chrome/browser/ash/app_list/search/personalization_provider.h +++ b/chrome/browser/ash/app_list/search/personalization_provider.h
@@ -18,6 +18,8 @@ #include "chrome/browser/ash/app_list/search/search_provider.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/icon_types.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/core/session_manager_observer.h" #include "mojo/public/cpp/bindings/receiver.h" #include "ui/base/models/image_model.h" @@ -56,16 +58,21 @@ class PersonalizationProvider : public SearchProvider, public ::ash::personalization_app::mojom::SearchResultsObserver, - public ::apps::AppRegistryCache::Observer { + public ::apps::AppRegistryCache::Observer, + public session_manager::SessionManagerObserver { public: - PersonalizationProvider( - Profile* profile, - ::ash::personalization_app::SearchHandler* search_handler); + explicit PersonalizationProvider(Profile* profile); ~PersonalizationProvider() override; PersonalizationProvider(const PersonalizationProvider&) = delete; PersonalizationProvider& operator=(const PersonalizationProvider&) = delete; + // Initialize the provider. It should be called when: + // 1. User session start up tasks has completed. + // 2. In tests with fake search handler provided. + void Initialize( + ::ash::personalization_app::SearchHandler* fake_search_handler = nullptr); + // SearchProvider: void Start(const std::u16string& query) override; void StopQuery() override; @@ -79,6 +86,9 @@ void OnAppRegistryCacheWillBeDestroyed( apps::AppRegistryCache* cache) override; + // session_manager::SessionManagerObserver: + void OnUserSessionStartUpTaskCompleted() override; + private: void OnSearchDone( base::TimeTicks start_time, @@ -91,7 +101,8 @@ const raw_ptr<Profile> profile_; std::u16string current_query_; gfx::ImageSkia icon_; - raw_ptr<::ash::personalization_app::SearchHandler> search_handler_; + + raw_ptr<::ash::personalization_app::SearchHandler> search_handler_ = nullptr; mojo::Receiver<::ash::personalization_app::mojom::SearchResultsObserver> search_results_observer_{this}; @@ -99,6 +110,10 @@ apps::AppRegistryCache::Observer> app_registry_cache_observer_{this}; + base::ScopedObservation<session_manager::SessionManager, + session_manager::SessionManagerObserver> + session_manager_observation_{this}; + base::WeakPtrFactory<PersonalizationProvider> weak_ptr_factory_{this}; base::WeakPtrFactory<PersonalizationProvider> app_service_weak_ptr_factory_{ this};
diff --git a/chrome/browser/ash/app_list/search/personalization_provider_unittest.cc b/chrome/browser/ash/app_list/search/personalization_provider_unittest.cc index 58e7766..f6b8f9c 100644 --- a/chrome/browser/ash/app_list/search/personalization_provider_unittest.cc +++ b/chrome/browser/ash/app_list/search/personalization_provider_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/services/app_service/public/cpp/stub_icon_loader.h" +#include "components/session_manager/core/session_manager.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -90,8 +91,8 @@ 1; mock_handler_ = std::make_unique<MockSearchHandler>(); - auto provider = std::make_unique<PersonalizationProvider>( - profile_, mock_handler_.get()); + auto provider = std::make_unique<PersonalizationProvider>(profile_); + provider->Initialize(mock_handler_.get()); provider_ = provider.get(); search_controller_->AddProvider(std::move(provider)); task_environment_.RunUntilIdle(); @@ -120,6 +121,7 @@ content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestSearchController> search_controller_; std::unique_ptr<MockSearchHandler> mock_handler_; + session_manager::SessionManager session_manager_; private: std::unique_ptr<TestingProfileManager> profile_manager_;
diff --git a/chrome/browser/ash/app_list/search/search_controller_factory.cc b/chrome/browser/ash/app_list/search/search_controller_factory.cc index 2eac5c66..5f6e658d 100644 --- a/chrome/browser/ash/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ash/app_list/search/search_controller_factory.cc
@@ -41,8 +41,6 @@ #include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/ash/crosapi/crosapi_manager.h" #include "chrome/browser/ash/drive/drive_integration_service.h" -#include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_manager.h" -#include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_manager_factory.h" #include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_utils.h" #include "chrome/browser/chromeos/launcher_search/search_util.h" #include "chrome/browser/profiles/profile.h" @@ -163,14 +161,7 @@ } if (ash::personalization_app::CanSeeWallpaperOrPersonalizationApp(profile)) { - auto* personalization_app_manager = ash::personalization_app:: - PersonalizationAppManagerFactory::GetForBrowserContext(profile); - DCHECK(personalization_app_manager); - - if (personalization_app_manager) { - controller->AddProvider(std::make_unique<PersonalizationProvider>( - profile, personalization_app_manager->search_handler())); - } + controller->AddProvider(std::make_unique<PersonalizationProvider>(profile)); } return controller;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu_unittest.cc b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu_unittest.cc index 1a589d7..60db8c648 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu_unittest.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu_unittest.cc
@@ -11,6 +11,7 @@ #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" #include "ash/style/icon_button.h" +#include "ash/style/option_button_group.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/browser/ash/arc/input_overlay/actions/action.h" #include "chrome/browser/ash/arc/input_overlay/arc_input_overlay_metrics.h" @@ -65,17 +66,20 @@ return menu->action()->GetType(); } - void PressActionMoveButton(ButtonOptionsMenu* menu) { + ActionTypeButtonGroup* GetActionTypeButtonGroup(ButtonOptionsMenu* menu) { DCHECK(menu); - ActionTypeButtonGroup* button_group = menu->button_group_; + auto button_group = menu->button_group_; DCHECK(button_group); + return button_group; + } + + void PressActionMoveButton(ButtonOptionsMenu* menu) { + auto* button_group = GetActionTypeButtonGroup(menu); button_group->OnActionMoveButtonPressed(); } void PressTapButton(ButtonOptionsMenu* menu) { - DCHECK(menu); - ActionTypeButtonGroup* button_group = menu->button_group_; - DCHECK(button_group); + auto* button_group = GetActionTypeButtonGroup(menu); button_group->OnActionTapButtonPressed(); } @@ -126,6 +130,13 @@ DCHECK(edit_labels); return edit_labels->labels_[index]->HasFocus(); } + + bool IsSelectedActionTypeFocused(ButtonOptionsMenu* menu) { + auto selected_buttons = + GetActionTypeButtonGroup(menu)->GetSelectedButtons(); + EXPECT_GT(selected_buttons.size(), 0u); + return selected_buttons[0]->HasFocus(); + } }; TEST_F(ButtonOptionsMenuTest, TestRemoveAction) { @@ -213,6 +224,36 @@ EXPECT_EQ(list_index, GetIndexInEditingList(menu->action())); } +TEST_F(ButtonOptionsMenuTest, TestActionTypeChangeByArrowKey) { + // Open up the button options menu and focus the selected action type. + auto* menu = ShowButtonOptionsMenu(tap_action_); + int list_index = GetIndexInEditingList(tap_action_); + EXPECT_EQ(GetActionType(menu), ActionType::TAP); + + auto selected_buttons = GetActionTypeButtonGroup(menu)->GetSelectedButtons(); + EXPECT_GT(selected_buttons.size(), 0u); + selected_buttons[0]->RequestFocus(); + auto* event_generator = GetEventGenerator(); + + // Press the right arrow key and verify action type is changed and focus on + // the new type. + event_generator->PressKey(ui::VKEY_RIGHT, ui::EF_NONE); + EXPECT_EQ(GetActionType(menu), ActionType::MOVE); + EXPECT_TRUE(IsSelectedActionTypeFocused(menu)); + EXPECT_TRUE(IsActionInTouchInjector(menu->action())); + EXPECT_TRUE(IsActionInEditingList(menu->action())); + EXPECT_EQ(list_index, GetIndexInEditingList(menu->action())); + + // Press the left arrow key and verify action type is changed and focus on + // the new type. + event_generator->PressKey(ui::VKEY_LEFT, ui::EF_NONE); + EXPECT_EQ(GetActionType(menu), ActionType::TAP); + EXPECT_TRUE(IsSelectedActionTypeFocused(menu)); + EXPECT_TRUE(IsActionInTouchInjector(menu->action())); + EXPECT_TRUE(IsActionInEditingList(menu->action())); + EXPECT_EQ(list_index, GetIndexInEditingList(menu->action())); +} + TEST_F(ButtonOptionsMenuTest, TestActionMoveDefaultInputBinding) { // Originally there is an `ActionMove` with WASD as default bindings. Add // another new `ActionMove` and the new `ActionMove` will not assign default
diff --git a/chrome/browser/ash/arc/vmm/arcvm_working_set_trim_executor.cc b/chrome/browser/ash/arc/vmm/arcvm_working_set_trim_executor.cc index b572f87..14e0de6 100644 --- a/chrome/browser/ash/arc/vmm/arcvm_working_set_trim_executor.cc +++ b/chrome/browser/ash/arc/vmm/arcvm_working_set_trim_executor.cc
@@ -103,7 +103,7 @@ // guest through ArcMemoryBridge's reclaim API (if "guest_reclaim_enabled" // param is enabled). Otherwise the memory should be reclaimed from host // through ArcSessionManager's TrimVmMemory if requested. - if (base::FeatureList::IsEnabled(arc::kGuestZram) && + if (base::FeatureList::IsEnabled(arc::kGuestSwap) && arc::kGuestReclaimEnabled.Get()) { if (!context) { LogErrorAndInvokeCallback(BROWSER_CONTEXT_ERROR_MSG, std::move(callback));
diff --git a/chrome/browser/ash/bruschetta/bruschetta_service.cc b/chrome/browser/ash/bruschetta/bruschetta_service.cc index ee0d17de..824c0d0 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_service.cc +++ b/chrome/browser/ash/bruschetta/bruschetta_service.cc
@@ -7,6 +7,7 @@ #include <memory> #include <string_view> #include <utility> +#include <vector> #include "ash/constants/ash_features.h" #include "base/feature_list.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ash/guest_os/guest_id.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" #include "chrome/browser/ash/guest_os/guest_os_remover.h" +#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h" #include "chrome/browser/ash/guest_os/guest_os_share_path.h" #include "chrome/browser/ash/guest_os/public/guest_os_service.h" #include "chrome/browser/ash/guest_os/public/types.h" @@ -191,6 +193,13 @@ runnable_vms_.erase(it); } +void BruschettaService::StopRunningVms() { + for (const auto& [name, _] : running_vms_) { + VLOG(1) << "Stopping vm " << name; + StopVm(std::move(name)); + } +} + void BruschettaService::StopVm(std::string vm_name) { auto* client = ash::ConciergeClient::Get(); DCHECK(client); @@ -350,4 +359,9 @@ std::move(callback).Run(true); } + +bool BruschettaService::IsVmRunning(std::string_view vm_name) { + return running_vms_.contains(vm_name); +} + } // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_service.h b/chrome/browser/ash/bruschetta/bruschetta_service.h index 971c7055..aece7ba0 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_service.h +++ b/chrome/browser/ash/bruschetta/bruschetta_service.h
@@ -72,6 +72,12 @@ void RemoveVm(const guest_os::GuestId& guest_id, base::OnceCallback<void(bool)> callback); + // Checks if the vm identified by `vm_name` is in the running list. + bool IsVmRunning(std::string_view vm_name); + + // Stops all running VMs. + void StopRunningVms(); + private: struct VmRegistration { std::unique_ptr<BruschettaLauncher> launcher;
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.cc b/chrome/browser/ash/bruschetta/bruschetta_util.cc index 83a2396..e77595b0 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_util.cc +++ b/chrome/browser/ash/bruschetta/bruschetta_util.cc
@@ -6,6 +6,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h" +#include "chrome/browser/ash/bruschetta/bruschetta_service.h" #include "chrome/browser/ash/guest_os/guest_id.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" #include "chrome/browser/ash/guest_os/virtual_machines/virtual_machines_util.h" @@ -226,4 +227,13 @@ return guest.vm_name; } +bool IsBruschettaRunning(Profile* profile) { + auto* service = bruschetta::BruschettaService::GetForProfile(profile); + return service && service->IsVmRunning(kBruschettaVmName); +} + +std::string GetBruschettaDisplayName(Profile* profile) { + return GetDisplayName(profile, GetBruschettaAlphaId()); +} + } // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.h b/chrome/browser/ash/bruschetta/bruschetta_util.h index 982ef8b..714071d 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_util.h +++ b/chrome/browser/ash/bruschetta/bruschetta_util.h
@@ -93,6 +93,12 @@ // Gets the display name of the specified `guest` running under `profile`. std::string GetDisplayName(Profile* profile, guest_os::GuestId guest); +// Returns whether the default Bruschetta VM is running for the user. +bool IsBruschettaRunning(Profile* profile); + +// Gets the display name for the default Bruschetta VM. +std::string GetBruschettaDisplayName(Profile* profile); + } // namespace bruschetta #endif // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_UTIL_H_
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn index bfe7704..c20ef57 100644 --- a/chrome/browser/ash/crosapi/BUILD.gn +++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -21,6 +21,7 @@ "//base", "//chrome/browser:browser_process", "//chrome/common", + "//chromeos/ash/components/channel", "//chromeos/ash/components/standalone_browser", "//chromeos/crosapi/cpp", "//chromeos/crosapi/cpp:crosapi_constants", @@ -346,10 +347,10 @@ "//chrome/browser/ui/webui/ash/parent_access:mojo_bindings", "//chrome/browser/web_applications", "//chrome/common", - "//chrome/common:channel_info", "//chrome/common:constants", "//chromeos/ash/components/account_manager", "//chromeos/ash/components/browser_context_helper:browser_context_helper", + "//chromeos/ash/components/channel", "//chromeos/ash/components/cryptohome", "//chromeos/ash/components/dbus", "//chromeos/ash/components/dbus/attestation:attestation_proto",
diff --git a/chrome/browser/ash/crosapi/DEPS b/chrome/browser/ash/crosapi/DEPS index 6185e680..9cb8088 100644 --- a/chrome/browser/ash/crosapi/DEPS +++ b/chrome/browser/ash/crosapi/DEPS
@@ -132,24 +132,12 @@ ] specific_include_rules = { - "browser_launcher\.cc": [ - # TODO(crbug.com/339770461): Remove. - "+chrome/common/channel_info.h", - ], - "browser_util\.cc": [ - # TODO(crbug.com/339770461): Remove. - "+chrome/common/channel_info.h", - ], "crosapi_ash\.cc": [ "+services/video_capture/ash", ], "crosapi_ash\.h": [ "+media/gpu/buildflags.h", ], - "crosapi_util\.cc": [ - # TODO(crbug.com/339770461): Remove. - "+chrome/common/channel_info.h", - ], "eye_dropper_ash\.cc": [ "+components/eye_dropper", ], @@ -174,10 +162,6 @@ # For Chrome OS-specific file manager parameters. "+chrome/browser/ui/views/select_file_dialog_extension.h", ], - "stateful_lacros_loader\.cc": [ - # TODO(crbug.com/339770461): Remove. - "+chrome/common/channel_info.h", - ], "test_controller_ash\.cc": [ # For Chrome OS-specific tab scrubbing tests. "+chrome/browser/ui/views/tabs/tab_scrubber_chromeos.h",
diff --git a/chrome/browser/ash/crosapi/browser_launcher.cc b/chrome/browser/ash/crosapi/browser_launcher.cc index 3779991..e37510a 100644 --- a/chrome/browser/ash/crosapi/browser_launcher.cc +++ b/chrome/browser/ash/crosapi/browser_launcher.cc
@@ -45,10 +45,10 @@ #include "chrome/browser/ash/crosapi/crosapi_util.h" #include "chrome/browser/ash/crosapi/primary_profile_creation_waiter.h" #include "chrome/browser/browser_process.h" -#include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/logging_chrome.h" +#include "chromeos/ash/components/channel/channel_info.h" #include "chromeos/ash/components/standalone_browser/lacros_selection.h" #include "chromeos/crosapi/cpp/crosapi_constants.h" #include "chromeos/crosapi/mojom/crosapi.mojom-shared.h" @@ -381,7 +381,7 @@ // should be using an unknown channel for Lacros as well. This prevents Lacros // from picking up Finch experiments. version_info::Channel update_channel = version_info::Channel::UNKNOWN; - if (chrome::GetChannel() != version_info::Channel::UNKNOWN) { + if (ash::GetChannel() != version_info::Channel::UNKNOWN) { update_channel = browser_util::GetLacrosSelectionUpdateChannel(lacros_selection); // If we don't have channel information, we default to the "dev" channel.
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc index b44d6fe..963f2174 100644 --- a/chrome/browser/ash/crosapi/browser_util.cc +++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -27,9 +27,9 @@ #include "base/values.h" #include "base/version.h" #include "chrome/browser/browser_process.h" -#include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" +#include "chromeos/ash/components/channel/channel_info.h" #include "chromeos/ash/components/standalone_browser/browser_support.h" #include "chromeos/ash/components/standalone_browser/lacros_availability.h" #include "chromeos/ash/components/standalone_browser/migrator_util.h" @@ -204,7 +204,7 @@ return it->second; } } - return chrome::GetChannel(); + return ash::GetChannel(); } } // namespace @@ -485,7 +485,7 @@ case ash::standalone_browser::LacrosSelection::kRootfs: // For 'rootfs' Lacros use the same channel as ash/OS. Obtained from // the LSB's release track property. - return chrome::GetChannel(); + return ash::GetChannel(); case ash::standalone_browser::LacrosSelection::kStateful: // For 'stateful' Lacros directly check the channel of stateful-lacros // that the user is on.
diff --git a/chrome/browser/ash/crosapi/clipboard_history_ash_unittest.cc b/chrome/browser/ash/crosapi/clipboard_history_ash_unittest.cc index 62ce377..403077a 100644 --- a/chrome/browser/ash/crosapi/clipboard_history_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/clipboard_history_ash_unittest.cc
@@ -10,10 +10,10 @@ #include "ash/clipboard/test_support/mock_clipboard_history_controller.h" #include "ash/test/ash_test_base.h" -#include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/unguessable_token.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/crosapi/mojom/clipboard_history.mojom-shared.h" @@ -102,17 +102,15 @@ // descriptors. std::vector<mojom::ClipboardHistoryItemDescriptorPtr> WaitForReceivedDescriptors() { - base::RunLoop run_loop; - std::vector<mojom::ClipboardHistoryItemDescriptorPtr> received_descriptors; + base::test::TestFuture< + std::vector<mojom::ClipboardHistoryItemDescriptorPtr>> + future; EXPECT_CALL(mock_client_, SetClipboardHistoryItemDescriptors) - .WillOnce( - [&received_descriptors, &run_loop]( - std::vector<mojom::ClipboardHistoryItemDescriptorPtr> ptrs) { - received_descriptors = std::move(ptrs); - run_loop.Quit(); - }); - run_loop.Run(); - return received_descriptors; + .WillOnce([&future](auto descriptors) { + future.SetValue(std::move(descriptors)); + }); + + return future.Take(); } void RegisterClient() {
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc index c98477f..2dc830b7 100644 --- a/chrome/browser/ash/crosapi/crosapi_util.cc +++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -42,9 +42,9 @@ #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" #include "chrome/browser/web_applications/preinstalled_web_app_utils.h" #include "chrome/browser/web_applications/web_app_utils.h" -#include "chrome/common/channel_info.h" #include "chromeos/ash/components/browser_context_helper/browser_context_helper.h" #include "chromeos/ash/components/browser_context_helper/browser_context_types.h" +#include "chromeos/ash/components/channel/channel_info.h" #include "chromeos/ash/components/install_attributes/install_attributes.h" #include "chromeos/ash/components/settings/cros_settings.h" #include "chromeos/ash/components/settings/cros_settings_names.h" @@ -790,7 +790,7 @@ } std::string_view limited_entropy_randomization_source; - if (variations::IsLimitedEntropyModeEnabled(chrome::GetChannel()) && + if (variations::IsLimitedEntropyModeEnabled(ash::GetChannel()) && limited_entropy_synthetic_trial.IsEnabled()) { limited_entropy_randomization_source = metrics_service->GetLimitedEntropyRandomizationSource();
diff --git a/chrome/browser/ash/crosapi/document_scan_ash_unittest.cc b/chrome/browser/ash/crosapi/document_scan_ash_unittest.cc index d4ddab5..c8543ae 100644 --- a/chrome/browser/ash/crosapi/document_scan_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/document_scan_ash_unittest.cc
@@ -7,16 +7,19 @@ #include <memory> #include <optional> #include <string> +#include <tuple> #include <vector> #include "ash/constants/ash_features.h" #include "base/containers/contains.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.h" #include "chrome/browser/ash/scanning/lorgnette_scanner_manager_factory.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/crosapi/mojom/document_scan.mojom-forward.h" #include "components/user_manager/scoped_user_manager.h" #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" @@ -73,6 +76,83 @@ DocumentScanAsh& document_scan_ash() { return document_scan_ash_; } + std::vector<std::string> GetScannerNames() { + base::test::TestFuture<const std::vector<std::string>&> future; + document_scan_ash().GetScannerNames(future.GetCallback()); + return future.Take(); + } + + std::tuple<mojom::ScanFailureMode, const std::optional<std::string>> + ScanFirstPage(const std::string& scanner_name) { + base::test::TestFuture<mojom::ScanFailureMode, + const std::optional<std::string>&> + future; + document_scan_ash().ScanFirstPage(scanner_name, future.GetCallback()); + + return future.Take(); + } + + mojom::GetScannerListResponsePtr GetScannerList( + const std::string& client_id, + mojom::ScannerEnumFilterPtr filter) { + base::test::TestFuture<mojom::GetScannerListResponsePtr> future; + document_scan_ash().GetScannerList(client_id, std::move(filter), + future.GetCallback()); + return future.Take(); + } + + mojom::OpenScannerResponsePtr OpenScanner(const std::string& client_id, + const std::string& scanner_id) { + base::test::TestFuture<mojom::OpenScannerResponsePtr> future; + document_scan_ash().OpenScanner(client_id, scanner_id, + future.GetCallback()); + return future.Take(); + } + + mojom::CloseScannerResponsePtr CloseScanner( + const std::string& scanner_handle) { + base::test::TestFuture<mojom::CloseScannerResponsePtr> future; + document_scan_ash().CloseScanner(scanner_handle, future.GetCallback()); + return future.Take(); + } + + mojom::StartPreparedScanResponsePtr StartPreparedScan( + const std::string& scanner_handle, + mojom::StartScanOptionsPtr options) { + base::test::TestFuture<mojom::StartPreparedScanResponsePtr> future; + document_scan_ash().StartPreparedScan("scanner-handle", std::move(options), + future.GetCallback()); + return future.Take(); + } + + mojom::ReadScanDataResponsePtr ReadScanData(const std::string& job_handle) { + base::test::TestFuture<mojom::ReadScanDataResponsePtr> future; + document_scan_ash().ReadScanData(job_handle, future.GetCallback()); + return future.Take(); + } + + mojom::SetOptionsResponsePtr SetOptions( + const std::string& scanner_handle, + std::vector<mojom::OptionSettingPtr> options) { + base::test::TestFuture<mojom::SetOptionsResponsePtr> future; + document_scan_ash().SetOptions(scanner_handle, std::move(options), + future.GetCallback()); + return future.Take(); + } + + mojom::GetOptionGroupsResponsePtr GetOptionGroups( + const std::string& scanner_handle) { + base::test::TestFuture<mojom::GetOptionGroupsResponsePtr> future; + document_scan_ash().GetOptionGroups(scanner_handle, future.GetCallback()); + return future.Take(); + } + + mojom::CancelScanResponsePtr CancelScan(const std::string& job_handle) { + base::test::TestFuture<mojom::CancelScanResponsePtr> future; + document_scan_ash().CancelScan(job_handle, future.GetCallback()); + return future.Take(); + } + private: // Must outlive `profile_`. content::BrowserTaskEnvironment task_environment_; @@ -89,85 +169,53 @@ }; TEST_F(DocumentScanAshTest, ScanFirstPage_NoScanners) { - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetGetScannerNamesResponse({}); - document_scan_ash().GetScannerNames(base::BindLambdaForTesting( - [&](const std::vector<std::string>& scanner_names) { - EXPECT_TRUE(scanner_names.empty()); - run_loop.Quit(); - })); - run_loop.Run(); + const std::vector<std::string> scanner_names = GetScannerNames(); + + EXPECT_TRUE(scanner_names.empty()); } TEST_F(DocumentScanAshTest, ScanFirstPage_SingleScanner) { GetLorgnetteScannerManager()->SetGetScannerNamesResponse({kTestScannerName}); - base::RunLoop run_loop; - document_scan_ash().GetScannerNames(base::BindLambdaForTesting( - [&](const std::vector<std::string>& scanner_names) { - EXPECT_THAT(scanner_names, ElementsAre(kTestScannerName)); - run_loop.Quit(); - })); - run_loop.Run(); + const std::vector<std::string> scanner_names = GetScannerNames(); + + EXPECT_THAT(scanner_names, ElementsAre(kTestScannerName)); } TEST_F(DocumentScanAshTest, ScanFirstPage_MultipleScanner) { GetLorgnetteScannerManager()->SetGetScannerNamesResponse( {kTestScannerName, kVirtualUSBPrinterName}); - base::RunLoop run_loop; - document_scan_ash().GetScannerNames(base::BindLambdaForTesting( - [&](const std::vector<std::string>& scanner_names) { - EXPECT_THAT(scanner_names, - ElementsAre(kTestScannerName, kVirtualUSBPrinterName)); - run_loop.Quit(); - })); - run_loop.Run(); + const std::vector<std::string> scanner_names = GetScannerNames(); + + EXPECT_THAT(scanner_names, + ElementsAre(kTestScannerName, kVirtualUSBPrinterName)); } TEST_F(DocumentScanAshTest, ScanFirstPage_InvalidScannerName) { - base::RunLoop run_loop; - document_scan_ash().ScanFirstPage( - "bad_scanner", base::BindLambdaForTesting( - [&](mojom::ScanFailureMode failure_mode, - const std::optional<std::string>& scan_data) { - EXPECT_EQ(failure_mode, - mojom::ScanFailureMode::kDeviceBusy); - EXPECT_FALSE(scan_data.has_value()); - run_loop.Quit(); - })); - run_loop.Run(); + const auto [failure_mode, scan_data] = ScanFirstPage("bad_scanner"); + + EXPECT_EQ(failure_mode, mojom::ScanFailureMode::kDeviceBusy); + EXPECT_FALSE(scan_data.has_value()); } TEST_F(DocumentScanAshTest, ScanFirstPage_ScannerNoData) { GetLorgnetteScannerManager()->SetGetScannerNamesResponse({kTestScannerName}); - base::RunLoop run_loop; - document_scan_ash().ScanFirstPage( - kTestScannerName, base::BindLambdaForTesting( - [&](mojom::ScanFailureMode failure_mode, - const std::optional<std::string>& scan_data) { - EXPECT_EQ(failure_mode, - mojom::ScanFailureMode::kDeviceBusy); - EXPECT_FALSE(scan_data.has_value()); - run_loop.Quit(); - })); - run_loop.Run(); + const auto [failure_mode, scan_data] = ScanFirstPage(kTestScannerName); + + EXPECT_EQ(failure_mode, mojom::ScanFailureMode::kDeviceBusy); + EXPECT_FALSE(scan_data.has_value()); } TEST_F(DocumentScanAshTest, ScanFirstPage_ScannerData) { GetLorgnetteScannerManager()->SetGetScannerNamesResponse({kTestScannerName}); const std::vector<std::string> scan_data = {"PrettyPicture"}; GetLorgnetteScannerManager()->SetScanResponse(scan_data); - base::RunLoop run_loop; - document_scan_ash().ScanFirstPage( - kTestScannerName, base::BindLambdaForTesting( - [&](mojom::ScanFailureMode failure_mode, - const std::optional<std::string>& scan_data) { - EXPECT_EQ(failure_mode, - mojom::ScanFailureMode::kNoFailure); - ASSERT_TRUE(scan_data.has_value()); - EXPECT_EQ(scan_data.value(), "PrettyPicture"); - run_loop.Quit(); - })); - run_loop.Run(); + const auto [failure_mode, scan_data_response] = + ScanFirstPage(kTestScannerName); + + EXPECT_EQ(failure_mode, mojom::ScanFailureMode::kNoFailure); + ASSERT_TRUE(scan_data_response.has_value()); + EXPECT_EQ(scan_data_response.value(), "PrettyPicture"); } TEST_F(DocumentScanAshTest, GetScannerList_FeatureDisabled) { @@ -175,38 +223,26 @@ feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); GetLorgnetteScannerManager()->SetGetScannerInfoListResponse(std::nullopt); - base::RunLoop run_loop; auto request = mojom::ScannerEnumFilter::New(); request->local = true; request->secure = true; - document_scan_ash().GetScannerList( - "client-id", std::move(request), - base::BindLambdaForTesting( - [&](mojom::GetScannerListResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_EQ(response->scanners.size(), 0U); - })); - run_loop.Run(); + const mojom::GetScannerListResponsePtr response = + GetScannerList("client-id", std::move(request)); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_EQ(response->scanners.size(), 0U); } TEST_F(DocumentScanAshTest, GetScannerList_BadResponse) { GetLorgnetteScannerManager()->SetGetScannerInfoListResponse(std::nullopt); - base::RunLoop run_loop; auto request = mojom::ScannerEnumFilter::New(); request->local = true; request->secure = true; - document_scan_ash().GetScannerList( - "client-id", std::move(request), - base::BindLambdaForTesting( - [&](mojom::GetScannerListResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_EQ(response->scanners.size(), 0U); - })); - run_loop.Run(); + const mojom::GetScannerListResponsePtr response = + GetScannerList("client-id", std::move(request)); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_EQ(response->scanners.size(), 0U); } TEST_F(DocumentScanAshTest, GetScannerList_GoodResponse) { @@ -216,56 +252,40 @@ scanner->set_name("test:scanner"); GetLorgnetteScannerManager()->SetGetScannerInfoListResponse( std::move(fake_response)); - base::RunLoop run_loop; auto request = mojom::ScannerEnumFilter::New(); request->local = true; request->secure = true; - document_scan_ash().GetScannerList( - "client-id", std::move(request), - base::BindLambdaForTesting( - [&](mojom::GetScannerListResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kSuccess); - ASSERT_EQ(response->scanners.size(), 1U); - EXPECT_EQ(response->scanners[0]->id, "test:scanner"); - })); - run_loop.Run(); + const mojom::GetScannerListResponsePtr response = + GetScannerList("client-id", std::move(request)); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); + ASSERT_EQ(response->scanners.size(), 1U); + EXPECT_EQ(response->scanners[0]->id, "test:scanner"); } TEST_F(DocumentScanAshTest, OpenScanner_FeatureDisabled) { base::test::ScopedFeatureList feature; feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetOpenScannerResponse(std::nullopt); - document_scan_ash().OpenScanner( - "client-id", "scanner-id", - base::BindLambdaForTesting([&](mojom::OpenScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_id, "scanner-id"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_FALSE(response->scanner_handle.has_value()); - EXPECT_FALSE(response->options.has_value()); - })); - run_loop.Run(); + const mojom::OpenScannerResponsePtr response = + OpenScanner("client-id", "scanner-id"); + + EXPECT_EQ(response->scanner_id, "scanner-id"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_FALSE(response->scanner_handle.has_value()); + EXPECT_FALSE(response->options.has_value()); } TEST_F(DocumentScanAshTest, OpenScanner_BadResponse) { - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetOpenScannerResponse(std::nullopt); - document_scan_ash().OpenScanner( - "client-id", "scanner-id", - base::BindLambdaForTesting([&](mojom::OpenScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_id, "scanner-id"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_FALSE(response->scanner_handle.has_value()); - EXPECT_FALSE(response->options.has_value()); - })); - run_loop.Run(); + const mojom::OpenScannerResponsePtr response = + OpenScanner("client-id", "scanner-id"); + + EXPECT_EQ(response->scanner_id, "scanner-id"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_FALSE(response->scanner_handle.has_value()); + EXPECT_FALSE(response->options.has_value()); } TEST_F(DocumentScanAshTest, OpenScanner_GoodResponse) { @@ -276,71 +296,52 @@ fake_config->mutable_scanner()->set_token("12345"); (*fake_config->mutable_options())["option1-name"] = {}; (*fake_config->mutable_options())["option2-name"] = {}; - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetOpenScannerResponse( std::move(fake_response)); - document_scan_ash().OpenScanner( - "client-id", "scanner-id", - base::BindLambdaForTesting([&](mojom::OpenScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_id, "scanner-id"); - EXPECT_EQ(response->result, mojom::ScannerOperationResult::kDeviceBusy); - ASSERT_TRUE(response->scanner_handle.has_value()); - EXPECT_EQ(response->scanner_handle.value(), "12345"); - ASSERT_TRUE(response->options.has_value()); - EXPECT_TRUE(base::Contains(response->options.value(), "option1-name")); - EXPECT_TRUE(base::Contains(response->options.value(), "option2-name")); - })); - run_loop.Run(); + const mojom::OpenScannerResponsePtr response = + OpenScanner("client-id", "scanner-id"); + + EXPECT_EQ(response->scanner_id, "scanner-id"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kDeviceBusy); + ASSERT_TRUE(response->scanner_handle.has_value()); + EXPECT_EQ(response->scanner_handle.value(), "12345"); + ASSERT_TRUE(response->options.has_value()); + EXPECT_TRUE(base::Contains(response->options.value(), "option1-name")); + EXPECT_TRUE(base::Contains(response->options.value(), "option2-name")); } TEST_F(DocumentScanAshTest, CloseScanner_FeatureDisabled) { base::test::ScopedFeatureList feature; feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetCloseScannerResponse(std::nullopt); - document_scan_ash().CloseScanner( - "scanner-handle", - base::BindLambdaForTesting([&](mojom::CloseScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - })); - run_loop.Run(); + const mojom::CloseScannerResponsePtr response = + CloseScanner("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); } TEST_F(DocumentScanAshTest, CloseScanner_BadResponse) { - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetCloseScannerResponse(std::nullopt); - document_scan_ash().CloseScanner( - "scanner-handle", - base::BindLambdaForTesting([&](mojom::CloseScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - })); - run_loop.Run(); + const mojom::CloseScannerResponsePtr response = + CloseScanner("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); } TEST_F(DocumentScanAshTest, CloseScanner_GoodResponse) { lorgnette::CloseScannerResponse fake_response; fake_response.mutable_scanner()->set_token("scanner-handle"); fake_response.set_result(lorgnette::OPERATION_RESULT_MISSING); - base::RunLoop run_loop; GetLorgnetteScannerManager()->SetCloseScannerResponse( std::move(fake_response)); - document_scan_ash().CloseScanner( - "scanner-handle", - base::BindLambdaForTesting([&](mojom::CloseScannerResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kDeviceMissing); - })); - run_loop.Run(); + const mojom::CloseScannerResponsePtr response = + CloseScanner("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kDeviceMissing); } TEST_F(DocumentScanAshTest, StartPreparedScan_FeatureDisabled) { @@ -348,34 +349,22 @@ feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); GetLorgnetteScannerManager()->SetStartPreparedScanResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().StartPreparedScan( - "scanner-handle", mojom::StartScanOptions::New(), - base::BindLambdaForTesting( - [&](mojom::StartPreparedScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_FALSE(response->job_handle.has_value()); - })); - run_loop.Run(); + const mojom::StartPreparedScanResponsePtr response = + StartPreparedScan("scanner-handle", mojom::StartScanOptions::New()); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_FALSE(response->job_handle.has_value()); } TEST_F(DocumentScanAshTest, StartPreparedScan_BadResponse) { GetLorgnetteScannerManager()->SetStartPreparedScanResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().StartPreparedScan( - "scanner-handle", mojom::StartScanOptions::New(), - base::BindLambdaForTesting( - [&](mojom::StartPreparedScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_FALSE(response->job_handle.has_value()); - })); - run_loop.Run(); + const mojom::StartPreparedScanResponsePtr response = + StartPreparedScan("scanner-handle", mojom::StartScanOptions::New()); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_FALSE(response->job_handle.has_value()); } TEST_F(DocumentScanAshTest, StartPreparedScan_GoodResponse) { @@ -385,22 +374,16 @@ fake_response.mutable_job_handle()->set_token("job-handle"); GetLorgnetteScannerManager()->SetStartPreparedScanResponse( std::move(fake_response)); - base::RunLoop run_loop; auto options = mojom::StartScanOptions::New(); options->format = "image/png"; options->max_read_size = 32768; - document_scan_ash().StartPreparedScan( - "scanner-handle", std::move(options), - base::BindLambdaForTesting( - [&](mojom::StartPreparedScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kSuccess); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - ASSERT_TRUE(response->job_handle.has_value()); - EXPECT_EQ(response->job_handle.value(), "job-handle"); - })); - run_loop.Run(); + const mojom::StartPreparedScanResponsePtr response = + StartPreparedScan("scanner-handle", std::move(options)); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + ASSERT_TRUE(response->job_handle.has_value()); + EXPECT_EQ(response->job_handle.value(), "job-handle"); } TEST_F(DocumentScanAshTest, ReadScanData_FeatureDisabled) { @@ -408,32 +391,20 @@ feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); GetLorgnetteScannerManager()->SetReadScanDataResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().ReadScanData( - "job-handle", - base::BindLambdaForTesting([&](mojom::ReadScanDataResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_EQ(response->job_handle, "job-handle"); - EXPECT_FALSE(response->data.has_value()); - })); - run_loop.Run(); + const mojom::ReadScanDataResponsePtr response = ReadScanData("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_EQ(response->job_handle, "job-handle"); + EXPECT_FALSE(response->data.has_value()); } TEST_F(DocumentScanAshTest, ReadScanData_BadResponse) { GetLorgnetteScannerManager()->SetReadScanDataResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().ReadScanData( - "job-handle", - base::BindLambdaForTesting([&](mojom::ReadScanDataResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_EQ(response->job_handle, "job-handle"); - EXPECT_FALSE(response->data.has_value()); - })); - run_loop.Run(); + const mojom::ReadScanDataResponsePtr response = ReadScanData("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_EQ(response->job_handle, "job-handle"); + EXPECT_FALSE(response->data.has_value()); } TEST_F(DocumentScanAshTest, ReadScanData_GoodResponse) { @@ -444,19 +415,14 @@ fake_response.set_estimated_completion(24); GetLorgnetteScannerManager()->SetReadScanDataResponse( std::move(fake_response)); - base::RunLoop run_loop; - document_scan_ash().ReadScanData( - "job-handle", - base::BindLambdaForTesting([&](mojom::ReadScanDataResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); - EXPECT_EQ(response->job_handle, "job-handle"); - ASSERT_TRUE(response->data.has_value()); - EXPECT_THAT(response->data.value(), ElementsAre('d', 'a', 't', 'a')); - ASSERT_TRUE(response->estimated_completion.has_value()); - EXPECT_EQ(response->estimated_completion.value(), 24U); - })); - run_loop.Run(); + const mojom::ReadScanDataResponsePtr response = ReadScanData("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); + EXPECT_EQ(response->job_handle, "job-handle"); + ASSERT_TRUE(response->data.has_value()); + EXPECT_THAT(response->data.value(), ElementsAre('d', 'a', 't', 'a')); + ASSERT_TRUE(response->estimated_completion.has_value()); + EXPECT_EQ(response->estimated_completion.value(), 24U); } TEST_F(DocumentScanAshTest, SetOptions_FeatureDisabled) { @@ -469,19 +435,15 @@ options.emplace_back(std::move(option)); GetLorgnetteScannerManager()->SetSetOptionsResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().SetOptions( - "scanner-handle", std::move(options), - base::BindLambdaForTesting([&](mojom::SetOptionsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_FALSE(response->options.has_value()); - ASSERT_EQ(response->results.size(), 1U); - EXPECT_EQ(response->results[0]->name, "option-name"); - EXPECT_EQ(response->results[0]->result, - mojom::ScannerOperationResult::kUnsupported); - })); - run_loop.Run(); + const mojom::SetOptionsResponsePtr response = + SetOptions("scanner-handle", std::move(options)); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_FALSE(response->options.has_value()); + ASSERT_EQ(response->results.size(), 1U); + EXPECT_EQ(response->results[0]->name, "option-name"); + EXPECT_EQ(response->results[0]->result, + mojom::ScannerOperationResult::kUnsupported); } TEST_F(DocumentScanAshTest, SetOptions_BadResponse) { @@ -491,19 +453,15 @@ options.emplace_back(std::move(option)); GetLorgnetteScannerManager()->SetSetOptionsResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().SetOptions( - "scanner-handle", std::move(options), - base::BindLambdaForTesting([&](mojom::SetOptionsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_FALSE(response->options.has_value()); - ASSERT_EQ(response->results.size(), 1U); - EXPECT_EQ(response->results[0]->name, "option-name"); - EXPECT_EQ(response->results[0]->result, - mojom::ScannerOperationResult::kInternalError); - })); - run_loop.Run(); + const mojom::SetOptionsResponsePtr response = + SetOptions("scanner-handle", std::move(options)); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_FALSE(response->options.has_value()); + ASSERT_EQ(response->results.size(), 1U); + EXPECT_EQ(response->results[0]->name, "option-name"); + EXPECT_EQ(response->results[0]->result, + mojom::ScannerOperationResult::kInternalError); } TEST_F(DocumentScanAshTest, SetOptions_GoodResponse) { @@ -524,22 +482,18 @@ *fake_response.mutable_config() = std::move(config); GetLorgnetteScannerManager()->SetSetOptionsResponse(std::move(fake_response)); - base::RunLoop run_loop; - document_scan_ash().SetOptions( - "scanner-handle", std::move(options), - base::BindLambdaForTesting([&](mojom::SetOptionsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - ASSERT_EQ(response->results.size(), 1U); - EXPECT_EQ(response->results[0]->name, "option-name"); - EXPECT_EQ(response->results[0]->result, - mojom::ScannerOperationResult::kSuccess); - ASSERT_TRUE(response->options.has_value()); - const auto& it = response->options.value().find("config-option"); - ASSERT_TRUE(it != response->options.value().end()); - EXPECT_EQ(it->second->name, "scanner-option"); - })); - run_loop.Run(); + const mojom::SetOptionsResponsePtr response = + SetOptions("scanner-handle", std::move(options)); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + ASSERT_EQ(response->results.size(), 1U); + EXPECT_EQ(response->results[0]->name, "option-name"); + EXPECT_EQ(response->results[0]->result, + mojom::ScannerOperationResult::kSuccess); + ASSERT_TRUE(response->options.has_value()); + const auto& it = response->options.value().find("config-option"); + ASSERT_TRUE(it != response->options.value().end()); + EXPECT_EQ(it->second->name, "scanner-option"); } TEST_F(DocumentScanAshTest, GetOptionGroups_FeatureDisabled) { @@ -547,34 +501,22 @@ feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); GetLorgnetteScannerManager()->SetGetCurrentConfigResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().GetOptionGroups( - "scanner-handle", - base::BindLambdaForTesting( - [&](mojom::GetOptionGroupsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_FALSE(response->groups.has_value()); - })); - run_loop.Run(); + const mojom::GetOptionGroupsResponsePtr response = + GetOptionGroups("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_FALSE(response->groups.has_value()); } TEST_F(DocumentScanAshTest, GetOptionGroups_BadResponse) { GetLorgnetteScannerManager()->SetGetCurrentConfigResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().GetOptionGroups( - "scanner-handle", - base::BindLambdaForTesting( - [&](mojom::GetOptionGroupsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_FALSE(response->groups.has_value()); - })); - run_loop.Run(); + const mojom::GetOptionGroupsResponsePtr response = + GetOptionGroups("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_FALSE(response->groups.has_value()); } TEST_F(DocumentScanAshTest, GetOptionGroups_GoodResponse) { @@ -592,22 +534,16 @@ GetLorgnetteScannerManager()->SetGetCurrentConfigResponse( std::move(fake_response)); - base::RunLoop run_loop; - document_scan_ash().GetOptionGroups( - "scanner-handle", - base::BindLambdaForTesting( - [&](mojom::GetOptionGroupsResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->scanner_handle, "scanner-handle"); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kSuccess); - EXPECT_TRUE(response->groups.has_value()); - ASSERT_EQ(response->groups.value().size(), 1U); - EXPECT_EQ(response->groups.value()[0]->title, "group-title"); - EXPECT_THAT(response->groups.value()[0]->members, - ElementsAre("group-member")); - })); - run_loop.Run(); + const mojom::GetOptionGroupsResponsePtr response = + GetOptionGroups("scanner-handle"); + + EXPECT_EQ(response->scanner_handle, "scanner-handle"); + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); + EXPECT_TRUE(response->groups.has_value()); + ASSERT_EQ(response->groups.value().size(), 1U); + EXPECT_EQ(response->groups.value()[0]->title, "group-title"); + EXPECT_THAT(response->groups.value()[0]->members, + ElementsAre("group-member")); } TEST_F(DocumentScanAshTest, CancelScan_FeatureDisabled) { @@ -615,30 +551,18 @@ feature.InitAndDisableFeature(ash::features::kAdvancedDocumentScanAPI); GetLorgnetteScannerManager()->SetCancelScanResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().CancelScan( - "job-handle", - base::BindLambdaForTesting([&](mojom::CancelScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kUnsupported); - EXPECT_EQ(response->job_handle, "job-handle"); - })); - run_loop.Run(); + const mojom::CancelScanResponsePtr response = CancelScan("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kUnsupported); + EXPECT_EQ(response->job_handle, "job-handle"); } TEST_F(DocumentScanAshTest, CancelScan_BadResponse) { GetLorgnetteScannerManager()->SetCancelScanResponse(std::nullopt); - base::RunLoop run_loop; - document_scan_ash().CancelScan( - "job-handle", - base::BindLambdaForTesting([&](mojom::CancelScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, - mojom::ScannerOperationResult::kInternalError); - EXPECT_EQ(response->job_handle, "job-handle"); - })); - run_loop.Run(); + const mojom::CancelScanResponsePtr response = CancelScan("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kInternalError); + EXPECT_EQ(response->job_handle, "job-handle"); } TEST_F(DocumentScanAshTest, CancelScan_GoodResponse) { @@ -646,15 +570,10 @@ fake_response.set_result(lorgnette::OPERATION_RESULT_SUCCESS); fake_response.mutable_job_handle()->set_token("job-handle"); GetLorgnetteScannerManager()->SetCancelScanResponse(std::move(fake_response)); - base::RunLoop run_loop; - document_scan_ash().CancelScan( - "job-handle", - base::BindLambdaForTesting([&](mojom::CancelScanResponsePtr response) { - run_loop.Quit(); - EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); - EXPECT_EQ(response->job_handle, "job-handle"); - })); - run_loop.Run(); + const mojom::CancelScanResponsePtr response = CancelScan("job-handle"); + + EXPECT_EQ(response->result, mojom::ScannerOperationResult::kSuccess); + EXPECT_EQ(response->job_handle, "job-handle"); } } // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc index 2954bab7..4f63f14 100644 --- a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
@@ -37,6 +37,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/printing/printer_capabilities.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/crosapi/mojom/local_printer.mojom-forward.h" #include "chromeos/crosapi/mojom/local_printer.mojom.h" #include "chromeos/printing/cups_printer_status.h" #include "chromeos/printing/ppd_provider.h" @@ -81,6 +82,8 @@ using LocalPrintersCallback = base::OnceCallback<void( std::vector<crosapi::mojom::LocalDestinationInfoPtr>)>; +using crosapi::mojom::GetOAuthAccessTokenResultPtr; +using printing::mojom::IppClientInfoPtr; constexpr char kPrinterUri[] = "http://localhost:80"; const AccountId kAffiliatedUserAccountId = @@ -106,21 +109,6 @@ fetched_eula_url = eula_url; } -void RecordOAuthAccessToken( - crosapi::mojom::GetOAuthAccessTokenResultPtr& out, - base::OnceClosure closure, - crosapi::mojom::GetOAuthAccessTokenResultPtr param) { - out = std::move(param); - std::move(closure).Run(); -} - -void RecordIppClientInfo(std::vector<printing::mojom::IppClientInfoPtr>& out, - base::OnceClosure closure, - std::vector<printing::mojom::IppClientInfoPtr> param) { - out = std::move(param); - std::move(closure).Run(); -} - Printer CreateTestPrinter(const std::string& id, const std::string& name, const std::string& description) { @@ -1200,6 +1188,14 @@ std::make_unique<TestLocalPrinterAsh>(&profile_, ppd_provider_); } + GetOAuthAccessTokenResultPtr GetOAuthAccessToken( + const std::string& printer_id) { + base::test::TestFuture<GetOAuthAccessTokenResultPtr> future; + local_printer_ash()->GetOAuthAccessToken("printer_id", + future.GetCallback()); + return future.Take(); + } + protected: ash::FakeCupsPrintersManager& printers_manager() { DCHECK(printers_manager_); @@ -1233,12 +1229,7 @@ }; TEST_F(LocalPrinterAshWithOAuth2Test, GetOAuthAccessTokenUnknownPrinter) { - crosapi::mojom::GetOAuthAccessTokenResultPtr result; - base::RunLoop loop; - local_printer_ash()->GetOAuthAccessToken( - "printer_id", base::BindOnce(&RecordOAuthAccessToken, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const GetOAuthAccessTokenResultPtr result = GetOAuthAccessToken("printer_id"); ASSERT_TRUE(result); EXPECT_TRUE(result->is_error()); @@ -1252,12 +1243,7 @@ chromeos::CupsPrinterStatus printer_status("printer_id"); printers_manager().SetPrinterStatus(printer_status); - crosapi::mojom::GetOAuthAccessTokenResultPtr result; - base::RunLoop loop; - local_printer_ash()->GetOAuthAccessToken( - "printer_id", base::BindOnce(&RecordOAuthAccessToken, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const GetOAuthAccessTokenResultPtr result = GetOAuthAccessToken("printer_id"); ASSERT_TRUE(result); EXPECT_TRUE(result->is_none()); @@ -1283,12 +1269,7 @@ "error_message"); }); - crosapi::mojom::GetOAuthAccessTokenResultPtr result; - base::RunLoop loop; - local_printer_ash()->GetOAuthAccessToken( - "printer_id", base::BindOnce(&RecordOAuthAccessToken, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const GetOAuthAccessTokenResultPtr result = GetOAuthAccessToken("printer_id"); ASSERT_TRUE(result); EXPECT_TRUE(result->is_error()); @@ -1313,12 +1294,7 @@ "access_token"); }); - crosapi::mojom::GetOAuthAccessTokenResultPtr result; - base::RunLoop loop; - local_printer_ash()->GetOAuthAccessToken( - "printer_id", base::BindOnce(&RecordOAuthAccessToken, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const GetOAuthAccessTokenResultPtr result = GetOAuthAccessToken("printer_id"); ASSERT_TRUE(result); ASSERT_TRUE(result->is_token()); @@ -1390,6 +1366,13 @@ fake_user_manager()->SwitchActiveUser(account_id); } + std::vector<IppClientInfoPtr> GetIppClientInfo( + const std::string& printer_id) { + base::test::TestFuture<std::vector<IppClientInfoPtr>> future; + local_printer_ash()->GetIppClientInfo(printer_id, future.GetCallback()); + return future.Take(); + } + protected: ash::FakeCupsPrintersManager& printers_manager() { DCHECK(printers_manager_); @@ -1415,12 +1398,7 @@ // Checks that `GetIppClientInfo()` returns an empty result if called with a // `printer_id` that has no associated printer. TEST_F(LocalPrinterAshWithIppClientInfoTest, GetIppClientInfoMissingPrinter) { - std::vector<printing::mojom::IppClientInfoPtr> result; - base::RunLoop loop; - local_printer_ash()->GetIppClientInfo( - "id", base::BindOnce(&RecordIppClientInfo, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const std::vector<IppClientInfoPtr> result = GetIppClientInfo("id"); ASSERT_TRUE(result.empty()); } @@ -1434,17 +1412,12 @@ printer.set_source(Printer::Source::SRC_POLICY); printers_manager().AddPrinter(printer, PrinterClass::kSaved); - std::vector<printing::mojom::IppClientInfoPtr> result; - base::RunLoop loop; const mojom::IppClientInfoPtr expected = mojom::IppClientInfo::New( mojom::IppClientInfo::ClientType::kOperatingSystem, "ChromeOS", std::nullopt, "1.2.3", std::nullopt); EXPECT_CALL(client_info_calculator(), GetOsInfo) .WillOnce(Return(ByMove(expected.Clone()))); - local_printer_ash()->GetIppClientInfo( - "id", base::BindOnce(&RecordIppClientInfo, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const std::vector<IppClientInfoPtr> result = GetIppClientInfo("id"); ASSERT_EQ(result.size(), 1u); EXPECT_EQ(result[0], expected); @@ -1459,17 +1432,12 @@ printer.set_source(Printer::Source::SRC_POLICY); printers_manager().AddPrinter(printer, PrinterClass::kSaved); - std::vector<printing::mojom::IppClientInfoPtr> result; - base::RunLoop loop; const mojom::IppClientInfoPtr expected = mojom::IppClientInfo::New( mojom::IppClientInfo::ClientType::kOperatingSystem, "ChromeOS", std::nullopt, "1.2.3", std::nullopt); EXPECT_CALL(client_info_calculator(), GetOsInfo) .WillOnce(Return(ByMove(expected.Clone()))); - local_printer_ash()->GetIppClientInfo( - "id", base::BindOnce(&RecordIppClientInfo, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const std::vector<IppClientInfoPtr> result = GetIppClientInfo("id"); ASSERT_EQ(result.size(), 1u); EXPECT_EQ(result[0], expected); @@ -1484,17 +1452,12 @@ printer.set_source(Printer::Source::SRC_USER_PREFS); printers_manager().AddPrinter(printer, PrinterClass::kSaved); - std::vector<printing::mojom::IppClientInfoPtr> result; - base::RunLoop loop; const mojom::IppClientInfoPtr expected = mojom::IppClientInfo::New( mojom::IppClientInfo::ClientType::kOperatingSystem, "ChromeOS", std::nullopt, "1.2.3", std::nullopt); EXPECT_CALL(client_info_calculator(), GetOsInfo) .WillOnce(Return(ByMove(expected.Clone()))); - local_printer_ash()->GetIppClientInfo( - "id", base::BindOnce(&RecordIppClientInfo, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const std::vector<IppClientInfoPtr> result = GetIppClientInfo("id"); ASSERT_EQ(result.size(), 1u); EXPECT_EQ(result[0], expected); @@ -1511,8 +1474,6 @@ printer.set_source(Printer::Source::SRC_POLICY); printers_manager().AddPrinter(printer, PrinterClass::kSaved); - std::vector<printing::mojom::IppClientInfoPtr> result; - base::RunLoop loop; const mojom::IppClientInfo expected_os_info = mojom::IppClientInfo(mojom::IppClientInfo::ClientType::kOperatingSystem, "ChromeOS", std::nullopt, "1.2.3", std::nullopt); @@ -1523,10 +1484,7 @@ .WillOnce(Return(ByMove(expected_os_info.Clone()))); EXPECT_CALL(client_info_calculator(), GetDeviceInfo) .WillOnce(Return(ByMove(expected_device_info.Clone()))); - local_printer_ash()->GetIppClientInfo( - "id", base::BindOnce(&RecordIppClientInfo, std::ref(result), - loop.QuitClosure())); - loop.Run(); + const std::vector<IppClientInfoPtr> result = GetIppClientInfo("id"); EXPECT_THAT(result, testing::UnorderedElementsAre( testing::Pointee(expected_os_info),
diff --git a/chrome/browser/ash/crosapi/login_state_ash_unittest.cc b/chrome/browser/ash/crosapi/login_state_ash_unittest.cc index 38844fc2..28efb963 100644 --- a/chrome/browser/ash/crosapi/login_state_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/login_state_ash_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/crosapi/login_state_ash.h" +#include "base/test/test_future.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/crosapi/mojom/login_state.mojom.h" @@ -92,11 +93,11 @@ mojom::GetSessionStateResultPtr expected_result_ptr = mojom::GetSessionStateResult::NewSessionState(test.expected); - base::RunLoop run_loop; + base::test::TestFuture<void> future; login_state_remote_->GetSessionState( - base::BindOnce(&EvaluateGetSessionStateResult, run_loop.QuitClosure(), + base::BindOnce(&EvaluateGetSessionStateResult, future.GetCallback(), std::move(expected_result_ptr))); - run_loop.Run(); + EXPECT_TRUE(future.Wait()); } }
diff --git a/chrome/browser/ash/crosapi/metrics_reporting_ash_unittest.cc b/chrome/browser/ash/crosapi/metrics_reporting_ash_unittest.cc index 5c4b40c8..0b0228c 100644 --- a/chrome/browser/ash/crosapi/metrics_reporting_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/metrics_reporting_ash_unittest.cc
@@ -9,6 +9,7 @@ #include "base/callback_list.h" #include "base/run_loop.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "chromeos/crosapi/mojom/message_center.mojom.h" #include "components/metrics/metrics_service.h" #include "components/prefs/pref_service.h" @@ -118,10 +119,10 @@ // Calling SetMetricsReportingEnabled() over mojo calls through to the metrics // reporting subsystem. - base::RunLoop run_loop; + base::test::TestFuture<void> waiter; metrics_reporting_remote->SetMetricsReportingEnabled(true, - run_loop.QuitClosure()); - run_loop.Run(); + waiter.GetCallback()); + EXPECT_TRUE(waiter.Wait()); EXPECT_TRUE(test_delegate->metrics_enabled_); }
diff --git a/chrome/browser/ash/crosapi/parent_access_ash_unittest.cc b/chrome/browser/ash/crosapi/parent_access_ash_unittest.cc index 92b8e10..17c4c6f 100644 --- a/chrome/browser/ash/crosapi/parent_access_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/parent_access_ash_unittest.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ash/crosapi/parent_access_ash.h" + #include <memory> #include <string> #include <vector> -#include "chrome/browser/ash/crosapi/parent_access_ash.h" - #include "base/memory/raw_ptr.h" -#include "base/run_loop.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/time/time.h" #include "chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.h" #include "extensions/browser/extension_util.h" @@ -26,6 +26,8 @@ #include "ui/gfx/image/image_unittest_util.h" #include "url/gurl.h" +using crosapi::mojom::ParentAccessResultPtr; + class FakeParentAccessDialogProvider : public ash::ParentAccessDialogProvider { public: ParentAccessDialogProvider::ShowError Show( @@ -164,21 +166,10 @@ // Makes sure the correct result is returned by the crosapi when the request is // approved. TEST_F(ParentAccessAshTest, GetWebsiteParentApproval_Approved) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // The request was approved. - EXPECT_TRUE(result->is_approved()); - EXPECT_EQ(result->get_approved()->parent_access_token, "ABC123"); - EXPECT_EQ( - result->get_approved()->parent_access_token_expire_timestamp, - base::Time::FromSecondsSinceUnixEpoch(123456UL)); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kApproved; @@ -186,117 +177,93 @@ dialog_result->parent_access_token_expire_timestamp = base::Time::FromSecondsSinceUnixEpoch(123456UL); dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + ASSERT_TRUE(result->is_approved()); + EXPECT_EQ(result->get_approved()->parent_access_token, "ABC123"); + EXPECT_EQ(result->get_approved()->parent_access_token_expire_timestamp, + base::Time::FromSecondsSinceUnixEpoch(123456UL)); } // Makes sure the correct result is returned by the crosapi when the request // is declined. TEST_F(ParentAccessAshTest, GetWebsiteParentApproval_Declined) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // The request was declined. - EXPECT_TRUE(result->is_declined()); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kDeclined; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + EXPECT_TRUE(result->is_declined()); } // Makes sure an cancel result is returned by the crosapi when the request // is canceled. TEST_F(ParentAccessAshTest, GetWebsiteParentApproval_Canceled) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // The request had an was canceled. - EXPECT_TRUE(result->is_canceled()); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kCanceled; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + EXPECT_TRUE(result->is_canceled()); } // Makes sure an error result is returned by the crosapi when the request // had an error. TEST_F(ParentAccessAshTest, GetWebsiteParentApproval_Error) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // The request had an unknown error. - EXPECT_TRUE(result->is_error()); - EXPECT_EQ(result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kUnknown); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kError; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + ASSERT_TRUE(result->is_error()); + EXPECT_EQ(result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kUnknown); } // Makes sure only one ParentAccess request can exist at a time.. TEST_F(ParentAccessAshTest, GetWebsiteParentApproval_AlreadyVisible) { - base::RunLoop successful_show_run_loop; + base::test::TestFuture<ParentAccessResultPtr> successful_show_future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // The request was approved. - EXPECT_TRUE(result->is_approved()); - std::move(quit_closure).Run(); - }, - successful_show_run_loop.QuitClosure())); + successful_show_future.GetCallback()); dialog_provider_->SetNextShowError( ash::ParentAccessDialogProvider::ShowError::kDialogAlreadyVisible); // Show dialog again, should be blocked because it is already visible. - base::RunLoop already_visible_run_loop; + base::test::TestFuture<ParentAccessResultPtr> already_visible_future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - // There was an error showing the ParentAccessUI - EXPECT_TRUE(result->is_error()); - // The error was that it is already visible. - EXPECT_EQ( - result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kAlreadyVisible); - std::move(quit_closure).Run(); - }, - already_visible_run_loop.QuitClosure())); + already_visible_future.GetCallback()); - // The second run loop completes. - already_visible_run_loop.Run(); + const ParentAccessResultPtr already_visible_result = + already_visible_future.Take(); + ASSERT_TRUE(already_visible_result->is_error()); + // The error was that it is already visible. + EXPECT_EQ(already_visible_result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kAlreadyVisible); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kApproved; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - // The original run loop completes. - successful_show_run_loop.Run(); + const ParentAccessResultPtr show_result = successful_show_future.Take(); + EXPECT_TRUE(show_result->is_approved()); } // Makes sure regular users can't request parent access. @@ -304,120 +271,92 @@ dialog_provider_->SetNextShowError( ash::ParentAccessDialogProvider::ShowError::kNotAChildUser); - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetWebsiteParentApproval( GURL(test_url), test_child_display_name, test_favicon, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_error()); - EXPECT_EQ( - result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kNotAChildUser); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - run_loop.Run(); + future.GetCallback()); + + const ParentAccessResultPtr result = future.Take(); + ASSERT_TRUE(result->is_error()); + EXPECT_EQ(result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kNotAChildUser); } TEST_F(ParentAccessAshTest, GetExtensionParentApproval_Canceled) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetExtensionParentApproval( test_extension_name, test_child_display_name, extensions::util::GetDefaultExtensionIcon(), {}, true, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_canceled()); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kCanceled; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + EXPECT_TRUE(result->is_canceled()); } TEST_F(ParentAccessAshTest, GetExtensionParentApproval_Error) { - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetExtensionParentApproval( test_extension_name, test_child_display_name, extensions::util::GetDefaultExtensionIcon(), {}, true, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_error()); - EXPECT_EQ(result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kUnknown); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); + future.GetCallback()); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kError; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - run_loop.Run(); + + const ParentAccessResultPtr result = future.Take(); + ASSERT_TRUE(result->is_error()); + EXPECT_EQ(result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kUnknown); } TEST_F(ParentAccessAshTest, GetExtensionParentApproval_AlreadyVisible) { - base::RunLoop successful_show_run_loop; + base::test::TestFuture<ParentAccessResultPtr> successful_show_future; parent_access_ash_->GetExtensionParentApproval( test_extension_name, test_child_display_name, extensions::util::GetDefaultExtensionIcon(), {}, true, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_approved()); - std::move(quit_closure).Run(); - }, - successful_show_run_loop.QuitClosure())); + successful_show_future.GetCallback()); dialog_provider_->SetNextShowError( ash::ParentAccessDialogProvider::ShowError::kDialogAlreadyVisible); // Show dialog again, should be blocked because it is already visible. - base::RunLoop already_visible_run_loop; + base::test::TestFuture<ParentAccessResultPtr> already_visible_future; parent_access_ash_->GetExtensionParentApproval( test_extension_name, test_child_display_name, extensions::util::GetDefaultExtensionIcon(), {}, true, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_error()); - EXPECT_EQ( - result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kAlreadyVisible); - std::move(quit_closure).Run(); - }, - already_visible_run_loop.QuitClosure())); + already_visible_future.GetCallback()); - already_visible_run_loop.Run(); + const ParentAccessResultPtr already_visible_result = + already_visible_future.Take(); + ASSERT_TRUE(already_visible_result->is_error()); + EXPECT_EQ(already_visible_result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kAlreadyVisible); auto dialog_result = std::make_unique<ash::ParentAccessDialog::Result>(); dialog_result->status = ash::ParentAccessDialog::Result::Status::kApproved; dialog_provider_->TriggerCallbackWithResult(std::move(dialog_result)); - successful_show_run_loop.Run(); + const ParentAccessResultPtr show_result = successful_show_future.Take(); + EXPECT_TRUE(show_result->is_approved()); } TEST_F(ParentAccessAshTest, GetExtensionParentApproval_NotAChildUser) { dialog_provider_->SetNextShowError( ash::ParentAccessDialogProvider::ShowError::kNotAChildUser); - base::RunLoop run_loop; + base::test::TestFuture<ParentAccessResultPtr> future; parent_access_ash_->GetExtensionParentApproval( test_extension_name, test_child_display_name, extensions::util::GetDefaultExtensionIcon(), {}, true, - base::BindOnce( - [](base::OnceClosure quit_closure, - crosapi::mojom::ParentAccessResultPtr result) { - EXPECT_TRUE(result->is_error()); - EXPECT_EQ( - result->get_error()->type, - crosapi::mojom::ParentAccessErrorResult::Type::kNotAChildUser); - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - run_loop.Run(); + future.GetCallback()); + + const ParentAccessResultPtr result = future.Take(); + ASSERT_TRUE(result->is_error()); + EXPECT_EQ(result->get_error()->type, + crosapi::mojom::ParentAccessErrorResult::Type::kNotAChildUser); }
diff --git a/chrome/browser/ash/crosapi/screen_ai_downloader_ash_unittest.cc b/chrome/browser/ash/crosapi/screen_ai_downloader_ash_unittest.cc index dfc75a0..a1b6d61 100644 --- a/chrome/browser/ash/crosapi/screen_ai_downloader_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/screen_ai_downloader_ash_unittest.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ash/crosapi/screen_ai_downloader_ash.h" -#include "base/run_loop.h" #include "base/task/sequenced_task_runner.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "chrome/browser/screen_ai/screen_ai_downloader_chromeos.h" #include "testing/gtest/include/gtest/gtest.h" @@ -82,17 +82,11 @@ ScreenAIDownloaderAshReplyTest() { downloader_ash_.Bind(downloader_remote_.BindNewPipeAndPassReceiver()); if (start_observing_before_call_) { - base::RunLoop run_loop; + base::test::TestFuture<const std::optional<::base::FilePath>&> future; // Calling `GetComponentFolder` for the first time sets the observer. GetComponentFolder( - /*download_if_needed=*/true, - base::BindOnce( - [](base::RunLoop* run_loop, - const std::optional<::base::FilePath>& file_path) { - run_loop->Quit(); - }, - &run_loop)); - run_loop.Run(); + /*download_if_needed=*/true, future.GetCallback()); + EXPECT_TRUE(future.Wait()); // Remove downloaded component path and reset state. install_state_.ResetForTesting(); @@ -133,15 +127,9 @@ // - Call parameter `download_if_needed`. // - If fake download should result successful. TEST_P(ScreenAIDownloaderAshReplyTest, EnsureReplyInAllStates) { - base::RunLoop run_loop; + base::test::TestFuture<const std::optional<::base::FilePath>&> future; GetComponentFolder( - /*download_if_needed=*/request_download_if_needed_, - base::BindOnce( - [](base::RunLoop* run_loop, - const std::optional<::base::FilePath>& file_path) { - run_loop->Quit(); - }, - &run_loop)); + /*download_if_needed=*/request_download_if_needed_, future.GetCallback()); // A `downloading` state will eventually result in a state change to // `downloaded` or `failed`. @@ -149,7 +137,7 @@ MockDownloadCompletion(); } - run_loop.Run(); + EXPECT_TRUE(future.Wait()); } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ash/crosapi/search_controller_factory_ash_unittest.cc b/chrome/browser/ash/crosapi/search_controller_factory_ash_unittest.cc index fad5222..a20828a 100644 --- a/chrome/browser/ash/crosapi/search_controller_factory_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/search_controller_factory_ash_unittest.cc
@@ -53,10 +53,10 @@ } void RunUntilSearch() { - base::RunLoop loop; - base::AutoReset<base::RepeatingClosure> quit_loop(&search_callback_, - loop.QuitClosure()); - loop.Run(); + base::test::TestFuture<void> waiter; + base::AutoReset<base::RepeatingClosure> quit_loop( + &search_callback_, waiter.GetRepeatingCallback()); + EXPECT_TRUE(waiter.Wait()); } void ProduceResults( @@ -101,10 +101,10 @@ } void RunUntilCreateSearchController() { - base::RunLoop loop; + base::test::TestFuture<void> waiter; base::AutoReset<base::RepeatingClosure> quit_loop( - &create_search_controller_callback_, loop.QuitClosure()); - loop.Run(); + &create_search_controller_callback_, waiter.GetRepeatingCallback()); + EXPECT_TRUE(waiter.Wait()); } std::unique_ptr<TestMojomSearchController> TakeLastTestController() {
diff --git a/chrome/browser/ash/crosapi/stateful_lacros_loader.cc b/chrome/browser/ash/crosapi/stateful_lacros_loader.cc index 7637baa..72600e1 100644 --- a/chrome/browser/ash/crosapi/stateful_lacros_loader.cc +++ b/chrome/browser/ash/crosapi/stateful_lacros_loader.cc
@@ -20,7 +20,7 @@ #include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/component_updater/cros_component_installer_chromeos.h" -#include "chrome/common/channel_info.h" +#include "chromeos/ash/components/channel/channel_info.h" #include "chromeos/ash/components/cryptohome/system_salt_getter.h" #include "chromeos/ash/components/standalone_browser/migrator_util.h" #include "components/component_updater/component_updater_paths.h" @@ -88,7 +88,7 @@ // Returns the name of the component on success, empty string on failure. std::string CheckForComponentToPreloadMayBlock() { browser_util::ComponentInfo info = - browser_util::GetLacrosComponentInfoForChannel(chrome::GetChannel()); + browser_util::GetLacrosComponentInfoForChannel(ash::GetChannel()); bool registered = IsInstalledMayBlock(info.name); if (registered) { return info.name;
diff --git a/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc b/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc index 2bd7465..731889e1 100644 --- a/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc +++ b/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/run_loop.h" +#include "base/test/test_future.h" #include "chrome/browser/ash/crosapi/test/crosapi_test_base.h" #include "chromeos/crosapi/mojom/crosapi.mojom.h" #include "chromeos/crosapi/mojom/network_change.mojom.h" @@ -51,7 +51,7 @@ }; TEST_F(NetworkChangeCrosapiTest, OnNetworkChanged) { - base::RunLoop run_loop; + base::test::TestFuture<void> waiter; // When NetworkChange::AddObserver() is called, // NetworkChangeObserver::OnNetworkChange() should also be called to // initialize network setup. @@ -64,16 +64,16 @@ /*connection_subtype_changed=*/true, mojom::ConnectionSubtype( net::NetworkChangeNotifier::SUBTYPE_UNKNOWN))) - .WillOnce([&] { run_loop.Quit(); }); + .WillOnce([&] { waiter.SetValue(); }); network_change_->AddObserver(receiver_.BindNewPipeAndPassRemote()); - run_loop.Run(); + EXPECT_TRUE(waiter.Wait()); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_)); { testing::InSequence sequence; - base::RunLoop run_loop2; + base::test::TestFuture<void> waiter2; // Ignore OnNetworkChange() calls and only check the last result which // overrides all results passed before. The first called // DisconnectFromNetwork() causes a few network chaneges for some reason. @@ -88,14 +88,14 @@ mojom::ConnectionType::CONNECTION_WIFI, /*connection_subtype_changed=*/true, mojom::ConnectionSubtype::SUBTYPE_UNKNOWN)) - .WillOnce([&] { run_loop2.Quit(); }); + .WillOnce([&] { waiter2.SetValue(); }); test_controller_->DisconnectFromNetwork(kEthServicePath); - run_loop2.Run(); + EXPECT_TRUE(waiter2.Wait()); } EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_)); - base::RunLoop run_loop3; + base::test::TestFuture<void> waiter3; // Check if disconnected from Wifi and not connected to anything. EXPECT_CALL(observer_, OnNetworkChanged( /*dns_changed=*/true, @@ -104,14 +104,14 @@ mojom::ConnectionType::CONNECTION_NONE, /*connection_subtype_changed=*/true, mojom::ConnectionSubtype::SUBTYPE_NONE)) - .WillOnce([&] { run_loop3.Quit(); }); + .WillOnce([&] { waiter3.SetValue(); }); test_controller_->DisconnectFromNetwork(kWifiServicePath); - run_loop3.Run(); + EXPECT_TRUE(waiter3.Wait()); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_)); - base::RunLoop run_loop4; + base::test::TestFuture<void> waiter4; // Check if connected to Ethernet. EXPECT_CALL(observer_, OnNetworkChanged( /*dns_changed=*/true, @@ -120,10 +120,10 @@ mojom::ConnectionType::CONNECTION_ETHERNET, /*connection_subtype_changed=*/true, mojom::ConnectionSubtype::SUBTYPE_UNKNOWN)) - .WillOnce([&] { run_loop4.Quit(); }); + .WillOnce([&] { waiter4.SetValue(); }); test_controller_->ConnectToNetwork(kEthServicePath); - run_loop4.Run(); + EXPECT_TRUE(waiter4.Wait()); } } // namespace
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc index 07276ff2..8eb48ef 100644 --- a/chrome/browser/ash/crostini/crostini_manager.cc +++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -1568,7 +1568,7 @@ }, std::move(callback))); for (const auto& name : names) { - LOG(WARNING) << "Stopping vm " << name; + VLOG(1) << "Stopping vm " << name; StopVm(name, barrier); } }
diff --git a/chrome/browser/ash/extensions/file_manager/event_router.h b/chrome/browser/ash/extensions/file_manager/event_router.h index 0e24a96..a1a53aa 100644 --- a/chrome/browser/ash/extensions/file_manager/event_router.h +++ b/chrome/browser/ash/extensions/file_manager/event_router.h
@@ -31,7 +31,7 @@ #include "chrome/browser/ash/guest_os/guest_os_share_path.h" #include "chrome/browser/ash/guest_os/public/guest_os_mount_provider.h" #include "chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h" -#include "chrome/browser/ash/policy/skyvault/observer.h" +#include "chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h" #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_util.h" #include "chrome/common/extensions/api/file_manager_private.h" #include "chromeos/ash/components/settings/timezone_settings.h" @@ -75,7 +75,7 @@ chromeos::DlpClient::Observer, apps::AppRegistryCache::Observer, network::NetworkConnectionTracker::NetworkConnectionObserver, - policy::local_user_files::Observer { + policy::local_user_files::LocalUserFilesPolicyObserver { public: using DispatchDirectoryChangeEventImplCallback = base::RepeatingCallback<void(const base::FilePath& virtual_path,
diff --git a/chrome/browser/ash/file_manager/volume_manager.h b/chrome/browser/ash/file_manager/volume_manager.h index d95f4d1c..4b60c08 100644 --- a/chrome/browser/ash/file_manager/volume_manager.h +++ b/chrome/browser/ash/file_manager/volume_manager.h
@@ -26,7 +26,7 @@ #include "chrome/browser/ash/file_system_provider/observer.h" #include "chrome/browser/ash/file_system_provider/service.h" #include "chrome/browser/ash/guest_os/public/types.h" -#include "chrome/browser/ash/policy/skyvault/observer.h" +#include "chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h" #include "components/prefs/pref_change_registrar.h" #include "components/storage_monitor/removable_storage_observer.h" #include "services/device/public/mojom/mtp_manager.mojom.h" @@ -65,7 +65,7 @@ storage_monitor::RemovableStorageObserver, ui::ClipboardObserver, DocumentsProviderRootManager::Observer, - policy::local_user_files::Observer { + policy::local_user_files::LocalUserFilesPolicyObserver { public: // An alternate to device::mojom::MtpManager::GetStorageInfo. // Used for injecting fake MTP manager for testing in VolumeManagerTest.
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system.cc b/chrome/browser/ash/file_system_provider/cloud_file_system.cc index ab592207..f42c2f3 100644 --- a/chrome/browser/ash/file_system_provider/cloud_file_system.cc +++ b/chrome/browser/ash/file_system_provider/cloud_file_system.cc
@@ -254,6 +254,9 @@ int bytes_read, bool has_more, base::File::Error result) { + VLOG(2) << "OnReadFileFromCacheCompleted {fsid = " << GetFileSystemId() + << ", file_handle = '" << file_handle << "', result = '" << result + << "}"; if (result == base::File::FILE_OK) { // If the cached read file was successful, ensure that is passed to the // caller. @@ -262,8 +265,9 @@ } if (result == base::File::FILE_ERROR_NOT_FOUND) { - // The file doesn't exist in the cache, we need to make a cloud request - // first and write the result into the cache upon successful return. + // The file doesn't exist in the cache or is not available, we need to make + // a cloud request first and attempt to write the result into the cache upon + // successful return. file_system_->ReadFile( file_handle, buffer.get(), offset, length, base::BindRepeating(&CloudFileSystem::OnReadFileCompleted, @@ -285,6 +289,10 @@ int bytes_read, bool has_more, base::File::Error result) { + VLOG(2) << "OnReadFileCompleted {fsid = " << GetFileSystemId() + << ", file_handle = '" << file_handle << "', result = '" << result + << ", bytes_read = " << bytes_read << "}"; + const OpenedCloudFileMap::const_iterator it = opened_files_.find(file_handle); if (it == opened_files_.end() || result != base::File::FILE_OK || !content_cache_) {
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc b/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc index 77d19d19..e9fb96f 100644 --- a/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc +++ b/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc
@@ -30,6 +30,7 @@ namespace { using base::test::IsNotNullCallback; +using base::test::RunClosure; using base::test::RunOnceCallback; using base::test::TestFuture; using testing::_; @@ -115,6 +116,10 @@ OnItemEvicted, (const base::FilePath& fsp_path), (override)); + MOCK_METHOD(void, + OnItemRemovedFromDisk, + (const base::FilePath& fsp_path, int64_t bytes_removed), + (override)); }; // Holder for the constructed mock content cache and the cloud file system. @@ -643,5 +648,70 @@ DeleteFileSuccessfully(*cloud_file_system, fake_file_path); } +TEST_F(FileSystemProviderCloudFileSystemTest, CurrentReaderCanReadEvictedFile) { + // Underlying FakeProvidedFileSystem is (always) initialised with fake file + // with kFakeFilePath. + const base::FilePath fake_file_path(kFakeFilePath); + auto [mock_content_cache_observer, cloud_file_system] = + CreateContentCacheAndObserverAndCloudFileSystem(); + + // Read 2 bytes of the `kFakeFilePath` file and insert them into the cache. + int file_handle = GetFileHandleFromSuccessfulOpenFile( + *cloud_file_system, base::FilePath(kFakeFilePath)); + scoped_refptr<net::IOBuffer> buffer = + base::MakeRefCounted<net::IOBufferWithSize>(1); + + ReadFileSuccessfully(*cloud_file_system, file_handle, buffer, /*offset=*/0, + /*length=*/1); + ReadFileSuccessfully(*cloud_file_system, file_handle, buffer, /*offset=*/1, + /*length=*/1); + CloseFileSuccessfully(*cloud_file_system, file_handle); + + // Open the file again. + file_handle = GetFileHandleFromSuccessfulOpenFile( + *cloud_file_system, base::FilePath(kFakeFilePath)); + + // Read the first byte from the cache. + ReadFileSuccessfully(*cloud_file_system, file_handle, buffer, /*offset=*/0, + /*length=*/1); + + // Remove the entry from the underlying FSP to ensure that the ReadFile is + // indeed reading from the cache. + DeleteEntryOnFakeFileSystem(fake_file_path); + + // Send a delete notification. Expect that the item gets evicted. + auto changes = std::make_unique<ProvidedFileSystemObserver::Changes>(); + changes->emplace_back( + fake_file_path, storage::WatcherManager::ChangeType::DELETED, + std::make_unique<ash::file_system_provider::CloudFileInfo>("versionA")); + EXPECT_CALL(*mock_content_cache_observer, OnItemEvicted(fake_file_path)); + cloud_file_system->Notify(fake_file_path, /*recursive=*/true, + storage::WatcherManager::ChangeType::DELETED, + std::move(changes), /*tag=*/"", base::DoNothing()); + + // Read the second byte from the cache. + ReadFileSuccessfully(*cloud_file_system, file_handle, buffer, /*offset=*/1, + /*length=*/1); + + // Fail to read the third byte. Expect that the request is forwarded to the + // FSP which responds with a `base::File::FILE_ERROR_INVALID_OPERATION` due to + // the file not existing. + ReadFileFuture read_file_future; + cloud_file_system->ReadFile(file_handle, buffer.get(), /*offset=*/2, + /*length=*/1, + read_file_future.GetRepeatingCallback()); + EXPECT_EQ(read_file_future.Get<int>(), 0); + EXPECT_EQ(read_file_future.Get<base::File::Error>(), + base::File::FILE_ERROR_INVALID_OPERATION); + + // Close the file, expect that it now gets removed. + base::RunLoop run_loop; + EXPECT_CALL(*mock_content_cache_observer, + OnItemRemovedFromDisk(fake_file_path, /*bytes_removed=*/2)) + .WillOnce(RunClosure(run_loop.QuitClosure())); + CloseFileSuccessfully(*cloud_file_system, file_handle); + run_loop.Run(); +} + } // namespace } // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc index de3acde3..0d3cf7ec 100644 --- a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc +++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc
@@ -354,6 +354,10 @@ VLOG(1) << "Cache miss: not possible to read the file on disk"; callback.Run(/*bytes_read=*/-1, /*has_more=*/false, base::File::FILE_ERROR_NOT_FOUND); + if (file.version_tag != ctx.version_tag()) { + // The cached file is out of date. + Evict(file.file_path); + } return; } @@ -425,6 +429,7 @@ } // Add a new CacheFileContext to the lru_cache. + VLOG(1) << "Adding '" << file.file_path << "' to the cache"; it = lru_cache_.Put( PathContextPair(file.file_path, CacheFileContext(file.version_tag))); EvictExcessItems();
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc index 210b559..d6c4b3a 100644 --- a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc +++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc
@@ -426,18 +426,24 @@ } TEST_F(FileSystemProviderContentCacheImplTest, - ReadBytesShouldReturnNotFoundIfVersionTagMismatch) { + ReadBytesShouldReturnNotFoundAndEvictIfVersionTagMismatch) { // Write to cache a file with `versionA`. const base::FilePath fsp_path("random-path"); - WriteFileToCache(fsp_path, "versionA", kDefaultChunkSize); + OpenedCloudFile file = + WriteFileToCache(fsp_path, "versionA", kDefaultChunkSize); + content_cache_->CloseFile(file); - // Attempt to read from the cache the same file with `versionB`. - OpenedCloudFile file(fsp_path, OpenFileMode::OPEN_FILE_MODE_READ, - ++request_id_, - /*version_tag=*/"versionB", kDefaultChunkSize); - EXPECT_THAT(ReadBytesFromContentCache(file, /*buffer=*/nullptr, + // Attempt to read from the cache the same file with `versionB`. Expect this + // leads to a NOT_FOUND and the eviction and removal of the cached file. + std::unique_ptr<base::RunLoop> run_loop = + CreateItemRemovedRunLoop(fsp_path, /*bytes_removed*/ kDefaultChunkSize); + OpenedCloudFile file2(fsp_path, OpenFileMode::OPEN_FILE_MODE_READ, + ++request_id_, + /*version_tag=*/"versionB", kDefaultChunkSize); + EXPECT_THAT(ReadBytesFromContentCache(file2, /*buffer=*/nullptr, /*offset=*/0, kDefaultChunkSize), Pair(-1, base::File::FILE_ERROR_NOT_FOUND)); + run_loop->Run(); } TEST_F(FileSystemProviderContentCacheImplTest,
diff --git a/chrome/browser/ash/file_system_provider/fake_provided_file_system.cc b/chrome/browser/ash/file_system_provider/fake_provided_file_system.cc index b9146d6..a6fb304 100644 --- a/chrome/browser/ash/file_system_provider/fake_provided_file_system.cc +++ b/chrome/browser/ash/file_system_provider/fake_provided_file_system.cc
@@ -620,8 +620,32 @@ std::unique_ptr<ProvidedFileSystemObserver::Changes> changes, const std::string& tag, storage::AsyncFileUtil::StatusCallback callback) { - NOTREACHED_IN_MIGRATION(); - std::move(callback).Run(base::File::FILE_ERROR_SECURITY); + // Very simple implementation that unconditionally calls notification + // callbacks and notifies observers of the change. + + const WatcherKey key(entry_path, recursive); + const auto& watcher_it = watchers_.find(key); + if (watcher_it == watchers_.end()) { + std::move(callback).Run(base::File::FILE_ERROR_NOT_FOUND); + return; + } + + const ProvidedFileSystemObserver::Changes& changes_ref = *changes.get(); + + // Call all notification callbacks (if any). + for (const auto& subscriber_it : watcher_it->second.subscribers) { + const storage::WatcherManager::NotificationCallback& notification_callback = + subscriber_it.second.notification_callback; + if (!notification_callback.is_null()) { + notification_callback.Run(change_type); + } + } + + // Notify all observers. + for (auto& observer : observers_) { + observer.OnWatcherChanged(file_system_info_, watcher_it->second, + change_type, changes_ref, base::DoNothing()); + } } void FakeProvidedFileSystem::Configure(
diff --git a/chrome/browser/ash/growth/campaigns_manager_session.cc b/chrome/browser/ash/growth/campaigns_manager_session.cc index 7c16245..d40876d0 100644 --- a/chrome/browser/ash/growth/campaigns_manager_session.cc +++ b/chrome/browser/ash/growth/campaigns_manager_session.cc
@@ -104,34 +104,52 @@ MaybeTriggerSlot(growth::Slot::kNotification); } -const GURL FindActiveWebAppBrowser(Profile* profile, - const webapps::AppId& app_id) { +// The app_id is optional and only required if the browser type is app. +const GURL FindActiveBrowserUrl(const Profile* profile, + Browser::Type browser_type, + const webapps::AppId& app_id = std::string()) { for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) { + if (browser->IsAttemptingToCloseBrowser() || browser->IsBrowserClosing()) { + continue; + } + if (browser->type() != browser_type) { + continue; + } if (browser->profile() != profile) { continue; } - - if (web_app::AppBrowserController::IsForWebApp(browser, app_id)) { - const auto* tab_strip_model = browser->tab_strip_model(); - if (!tab_strip_model) { - LOG(ERROR) << "No tab_strip_model."; - continue; - } - - auto* active_web_contents = tab_strip_model->GetActiveWebContents(); - if (!active_web_contents) { - LOG(ERROR) << "No active web contents."; - continue; - } - - return active_web_contents->GetURL(); + // For web app type, it must match the app_id. + if (browser_type == Browser::TYPE_APP && + !web_app::AppBrowserController::IsForWebApp(browser, app_id)) { + continue; } - } + const auto* tab_strip_model = browser->tab_strip_model(); + if (!tab_strip_model) { + LOG(ERROR) << "No tab_strip_model."; + continue; + } + + auto* active_web_contents = tab_strip_model->GetActiveWebContents(); + if (!active_web_contents) { + LOG(ERROR) << "No active web contents."; + continue; + } + + return active_web_contents->GetURL(); + } return GURL::EmptyGURL(); } -bool IsBrowserApp(const std::string& app_id) { +const GURL FindActiveWebAppUrl(Profile* profile, const webapps::AppId& app_id) { + return FindActiveBrowserUrl(profile, Browser::TYPE_APP, app_id); +} + +const GURL FindActiveTabUrl(Profile* profile) { + return FindActiveBrowserUrl(profile, Browser::TYPE_NORMAL); +} + +bool IsBrowserAppId(const std::string& app_id) { return app_id == app_constants::kChromeAppId || app_id == app_constants::kAshDebugBrowserAppId || app_id == app_constants::kLacrosAppId; @@ -213,13 +231,14 @@ auto app_id = update.AppId(); // For browser app, the user can open a new tab or switch to an existing tab. // The campaigns will be triggered when navigating to the target url. - if (IsBrowserApp(app_id)) { + if (IsBrowserAppId(app_id)) { if (ash::features::IsGrowthCampaignsTriggerByBrowserEnabled() && IsAppActiveAndVisible(update)) { auto* campaigns_manager = growth::CampaignsManager::Get(); CHECK(campaigns_manager); - // TODO: b/339706247 - Set the app id and window on PrimaryPageChanged. + // The app id set here will be used to check if active app is browser when + // primary page changed. campaigns_manager->SetOpenedApp(app_id); opened_window_ = update.Window(); } @@ -240,16 +259,23 @@ } void CampaignsManagerSession::PrimaryPageChanged(const GURL& url) { - if (!ash::features::IsGrowthCampaignsTriggerByBrowserEnabled()) { - return; - } - auto* campaigns_manager = growth::CampaignsManager::Get(); CHECK(campaigns_manager); - if (!IsBrowserApp(campaigns_manager->GetOpenedAppId())) { + auto app_id = campaigns_manager->GetOpenedAppId(); + if (!IsBrowserAppId(app_id)) { return; } + + // If the source of page change is different from active tab url, skip showing + // the campaign. This could happen when the user navigates to url_1, and while + // it is loading switches to another tab with url_2. The url_1 nudge will not + // be shown in this case. + auto active_tab_url = FindActiveTabUrl(GetProfile()); + if (!active_tab_url.EqualsIgnoringRef(url)) { + return; + } + campaigns_manager->SetActiveUrl(url); MaybeTriggerCampaignsWhenAppOpened(); } @@ -328,8 +354,7 @@ auto app_id = update.AppId(); campaigns_manager->SetOpenedApp(app_id); - campaigns_manager->SetActiveUrl( - FindActiveWebAppBrowser(GetProfile(), app_id)); + campaigns_manager->SetActiveUrl(FindActiveWebAppUrl(GetProfile(), app_id)); opened_window_ = update.Window(); MaybeTriggerCampaignsWhenAppOpened();
diff --git a/chrome/browser/ash/guest_os/guest_os_terminal.cc b/chrome/browser/ash/guest_os/guest_os_terminal.cc index ca105d9..f0dd7850 100644 --- a/chrome/browser/ash/guest_os/guest_os_terminal.cc +++ b/chrome/browser/ash/guest_os/guest_os_terminal.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/menu_item_constants.h" #include "chrome/browser/apps/app_service/menu_util.h" +#include "chrome/browser/ash/bruschetta/bruschetta_util.h" #include "chrome/browser/ash/crostini/crostini_features.h" #include "chrome/browser/ash/crostini/crostini_installer.h" #include "chrome/browser/ash/crostini/crostini_util.h" @@ -545,6 +546,10 @@ apps::AddCommandItem(ash::SHUTDOWN_GUEST_OS, IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM, menu_items); } + if (bruschetta::IsBruschettaRunning(profile)) { + apps::AddCommandItem(ash::SHUTDOWN_BRUSCHETTA_OS, + IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM, menu_items); + } } void AddTerminalMenuShortcuts(
diff --git a/chrome/browser/ash/login/app_mode/test/chome_app_kiosk_lacros_browsertest.cc b/chrome/browser/ash/login/app_mode/test/chome_app_kiosk_lacros_browsertest.cc index 8899ef0..c1d8d1ef 100644 --- a/chrome/browser/ash/login/app_mode/test/chome_app_kiosk_lacros_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/test/chome_app_kiosk_lacros_browsertest.cc
@@ -74,7 +74,14 @@ EXPECT_TRUE(crosapi::BrowserManager::Get()->IsRunning()); } -IN_PROC_BROWSER_TEST_F(ChromeAppKioskLacrosTest, NonKioskAppLaunchError) { +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it fails. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_NonKioskAppLaunchError DISABLED_NonKioskAppLaunchError +#else +#define MAYBE_NonKioskAppLaunchError NonKioskAppLaunchError +#endif +IN_PROC_BROWSER_TEST_F(ChromeAppKioskLacrosTest, MAYBE_NonKioskAppLaunchError) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; }
diff --git a/chrome/browser/ash/login/app_mode/test/kiosk_accelerator_lacros_browsertest.cc b/chrome/browser/ash/login/app_mode/test/kiosk_accelerator_lacros_browsertest.cc index d0f3be73..fbe9564 100644 --- a/chrome/browser/ash/login/app_mode/test/kiosk_accelerator_lacros_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/test/kiosk_accelerator_lacros_browsertest.cc
@@ -60,7 +60,15 @@ // Tests system accelerators (ash-side) do not work with Lacros in kiosk. using WebKioskAcceleratorLacrosTest = WebKioskLacrosBaseTest; -IN_PROC_BROWSER_TEST_F(WebKioskAcceleratorLacrosTest, SignOutDoesNotWork) { +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it fails. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_SignOutDoesNotWork DISABLED_SignOutDoesNotWork +#else +#define MAYBE_SignOutDoesNotWork SignOutDoesNotWork +#endif +IN_PROC_BROWSER_TEST_F(WebKioskAcceleratorLacrosTest, + MAYBE_SignOutDoesNotWork) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; }
diff --git a/chrome/browser/ash/login/app_mode/test/web_kiosk_lacros_browsertest.cc b/chrome/browser/ash/login/app_mode/test/web_kiosk_lacros_browsertest.cc index 2a5a6a6c..cf42aec 100644 --- a/chrome/browser/ash/login/app_mode/test/web_kiosk_lacros_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/test/web_kiosk_lacros_browsertest.cc
@@ -62,7 +62,14 @@ using WebKioskLacrosTest = WebKioskLacrosBaseTest; -IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, RegularOnlineKiosk) { +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it is flaky. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_RegularOnlineKiosk DISABLED_RegularOnlineKiosk +#else +#define MAYBE_RegularOnlineKiosk RegularOnlineKiosk +#endif +IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, MAYBE_RegularOnlineKiosk) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; } @@ -74,7 +81,16 @@ EXPECT_TRUE(crosapi::BrowserManager::Get()->IsRunning()); } -IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, ShouldCloseNewAshBrowserWindow) { +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it fails. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_ShouldCloseNewAshBrowserWindow \ + DISABLED_ShouldCloseNewAshBrowserWindow +#else +#define MAYBE_ShouldCloseNewAshBrowserWindow ShouldCloseNewAshBrowserWindow +#endif +IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, + MAYBE_ShouldCloseNewAshBrowserWindow) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; } @@ -97,8 +113,17 @@ EXPECT_FALSE(DidSessionCloseNewWindow()); } +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it fails. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_ShouldNotEndSessionWhenSettingsWindowIsClosed \ + DISABLED_ShouldNotEndSessionWhenSettingsWindowIsClosed +#else +#define MAYBE_ShouldNotEndSessionWhenSettingsWindowIsClosed \ + ShouldNotEndSessionWhenSettingsWindowIsClosed +#endif IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, - ShouldNotEndSessionWhenSettingsWindowIsClosed) { + MAYBE_ShouldNotEndSessionWhenSettingsWindowIsClosed) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; } @@ -111,7 +136,14 @@ EXPECT_FALSE(session().is_shutting_down()); } -IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, RecoverFromLacrosCrash) { +// TODO(b/342108781): Disable the test on ci/linux-chromeos-chrome-with-lacros +// since it fails. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#define MAYBE_RecoverFromLacrosCrash DISABLED_RecoverFromLacrosCrash +#else +#define MAYBE_RecoverFromLacrosCrash RecoverFromLacrosCrash +#endif +IN_PROC_BROWSER_TEST_F(WebKioskLacrosTest, MAYBE_RecoverFromLacrosCrash) { if (!kiosk_ash_starter_.HasLacrosArgument()) { return; }
diff --git a/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.cc b/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.cc index 8148fbc..d0def71 100644 --- a/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.cc +++ b/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.cc
@@ -5,12 +5,14 @@ #include "chrome/browser/ash/login/screens/personalized_recommend_apps_screen.h" #include <algorithm> +#include <memory> #include <optional> #include <unordered_map> #include <unordered_set> #include "ash/components/arc/arc_prefs.h" #include "ash/constants/ash_switches.h" +#include "base/timer/timer.h" #include "chrome/browser/apps/app_service/app_install/app_install_service.h" #include "chrome/browser/apps/app_service/app_install/app_install_types.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" @@ -132,16 +134,19 @@ LOG(ERROR) << "Got an error when fetched cached data from the OOBE Apps Service"; exit_callback_.Run(Result::kNotApplicable); + return; } if (app_infos.empty()) { LOG(ERROR) << "Empty set of apps received from the server"; exit_callback_.Run(Result::kNotApplicable); + return; } if (use_cases.empty()) { LOG(ERROR) << "Empty set of use-cases received from the server"; exit_callback_.Run(Result::kNotApplicable); + return; } // This code performs the following steps to prepare recommended app data for @@ -266,9 +271,17 @@ } } + if (apps_dict.empty()) { + LOG(ERROR) << "No apps found after filtering, skipping the screen"; + exit_callback_.Run(Result::kNotApplicable); + return; + } + apps_category_map_ = std::move(apps_dict); - delay_set_apps_timer_.Start( + delay_set_apps_timer_ = std::make_unique<base::OneShotTimer>(); + + delay_set_apps_timer_->Start( FROM_HERE, kDelaySetCategoriesAppsMapTime, this, &PersonalizedRecommendAppsScreen::SetCategoriesAppsMapData); } @@ -349,7 +362,8 @@ const std::string& action_id = args[0].GetString(); if (action_id == kUserActionLoaded) { - delay_overview_timer_.Start( + delay_overview_timer_ = std::make_unique<base::OneShotTimer>(); + delay_overview_timer_->Start( FROM_HERE, kDelayOverviewStepTime, this, &PersonalizedRecommendAppsScreen::ShowOverviewStep); return;
diff --git a/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.h b/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.h index 61c09ed..d441fca6 100644 --- a/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.h +++ b/chrome/browser/ash/login/screens/personalized_recommend_apps_screen.h
@@ -58,9 +58,9 @@ base::Value::Dict apps_category_map_; - base::OneShotTimer delay_set_apps_timer_; + std::unique_ptr<base::OneShotTimer> delay_set_apps_timer_; - base::OneShotTimer delay_overview_timer_; + std::unique_ptr<base::OneShotTimer> delay_overview_timer_; base::WeakPtr<PersonalizedRecommendAppsScreenView> view_; ScreenExitCallback exit_callback_;
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_client.cc b/chrome/browser/ash/mahi/media_app/mahi_media_app_client.cc index b01035d..e3effaf 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_client.cc +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_client.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/mahi/media_app/mahi_media_app_client.h" +#include "ash/shell.h" #include "base/check_deref.h" #include "base/i18n/break_iterator.h" #include "base/strings/utf_string_conversions.h" @@ -14,6 +15,7 @@ #include "chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h" #include "chromeos/components/mahi/public/cpp/mahi_media_app_events_proxy.h" #include "chromeos/crosapi/mojom/mahi.mojom.h" +#include "ui/aura/client/focus_client.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/image/image_skia.h" @@ -51,17 +53,46 @@ MahiMediaAppClient::MahiMediaAppClient( mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name) + const std::string& file_name, + aura::Window* media_app_window) : client_id_(base::UnguessableToken::Create()), media_app_pdf_file_(std::move(page)), - file_name_(file_name) { + file_name_(file_name), + media_app_window_(media_app_window) { + if (!ash::Shell::HasInstance()) { + return; + } + CHECK(media_app_window_); + // Registers self to `MahiMediaAppContentManager` as a client. chromeos::MahiMediaAppContentManager::Get()->AddClient(client_id_, this); + + // Registers self as the window observer. + media_app_window_->AddObserver(this); + + // Registers self as a focus event observer. + aura::client::FocusClient* focus_client = + aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); + focus_client->AddObserver(this); + + // Checks the current focused window. + OnWindowFocused(focus_client->GetFocusedWindow(), nullptr); } MahiMediaAppClient::~MahiMediaAppClient() { - // Manually calling `RemoveClient()` when disconnecting. + // Manually calls `RemoveClient()` when disconnecting. chromeos::MahiMediaAppContentManager::Get()->RemoveClient(client_id_); + + // Unregisters window observer. + if (media_app_window_) { + media_app_window_->RemoveObserver(this); + } + + // Unregisters focus observer. + if (ash::Shell::HasInstance()) { + aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()) + ->RemoveObserver(this); + } } void MahiMediaAppClient::OnPdfContextMenuShow(const ::gfx::RectF& anchor) { @@ -109,4 +140,23 @@ media_app_pdf_file_->HidePdfContextMenu(); } +void MahiMediaAppClient::OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) { + if (gained_focus == nullptr || gained_focus == lost_focus) { + return; + } + + if (gained_focus == media_app_window_ || + gained_focus->GetToplevelWindow() == media_app_window_) { + // Observed media app window get focus. + chromeos::MahiMediaAppEventsProxy::Get()->OnPdfGetFocus(client_id_); + } +} + +void MahiMediaAppClient::OnWindowDestroying(aura::Window* window) { + if (window == media_app_window_) { + media_app_window_ = nullptr; + } +} + } // namespace ash
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_client.h b/chrome/browser/ash/mahi/media_app/mahi_media_app_client.h index 12fa539..77e926b 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_client.h +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_client.h
@@ -6,22 +6,33 @@ #define CHROME_BROWSER_ASH_MAHI_MEDIA_APP_MAHI_MEDIA_APP_CLIENT_H_ #include "ash/webui/media_app_ui/media_app_ui_untrusted.mojom.h" +#include "base/memory/raw_ptr.h" +#include "base/scoped_observation.h" #include "base/unguessable_token.h" #include "chromeos/crosapi/mojom/mahi.mojom.h" #include "mojo/public/cpp/bindings/remote.h" +#include "ui/aura/client/focus_change_observer.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/window_observer.h" #include "ui/gfx/geometry/rect_f.h" namespace ash { -class MahiMediaAppClient - : public media_app_ui::mojom::MahiUntrustedPageHandler { +// A full-duplex Mojo connection between Mahi and media app. +// Its lifetime is bound to the Mojo connection and inherently the PDF file +// opened in the media app, i.e. it gets destructed when the media app window +// opens a new file, or the media app window closes. +class MahiMediaAppClient : public media_app_ui::mojom::MahiUntrustedPageHandler, + public aura::client::FocusChangeObserver, + public aura::WindowObserver { public: using GetContentCallback = base::OnceCallback<void(crosapi::mojom::MahiPageContentPtr)>; MahiMediaAppClient( mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name); + const std::string& file_name, + aura::Window* media_app_window); MahiMediaAppClient(const MahiMediaAppClient&) = delete; MahiMediaAppClient& operator=(const MahiMediaAppClient&) = delete; ~MahiMediaAppClient() override; @@ -38,7 +49,19 @@ void GetPdfContent(GetContentCallback callback); void HideMediaAppContextMenu(); + // aura::client::FocusChangeObserver: + // Compares `media_app_window_` against `gained_focus` to deduce whether it's + // the focused window. + void OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) override; + + // aura::WindowObserver: + // When the associated media app closes, resets `media_app_window_` to avoid + // dangling raw_ptr. + void OnWindowDestroying(aura::Window* window) override; + const std::string& file_name() const { return file_name_; } + const aura::Window* media_app_window() const { return media_app_window_; } private: // Unique id associated with this client. It is used by the @@ -47,6 +70,9 @@ mojo::Remote<media_app_ui::mojom::MahiUntrustedPage> media_app_pdf_file_; std::string file_name_; + // Not owned. The window this client is associated with, whose address is used + // in checking focus status. + raw_ptr<aura::Window> media_app_window_; }; } // namespace ash
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.cc b/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.cc index 976d601..065622a2 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.cc +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.h" +#include "base/containers/contains.h" #include "base/strings/utf_string_conversions.h" #include "base/unguessable_token.h" #include "chromeos/components/mahi/public/cpp/mahi_manager.h" @@ -92,10 +93,10 @@ } } -void MahiMediaAppContentManagerImpl::AddClient( - base::UnguessableToken client_id, - raw_ptr<MahiMediaAppClient> client) { +void MahiMediaAppContentManagerImpl::AddClient(base::UnguessableToken client_id, + MahiMediaAppClient* client) { client_id_to_client_[client_id] = client; + observed_windows_.insert(client->media_app_window()); } void MahiMediaAppContentManagerImpl::RemoveClient( @@ -105,7 +106,14 @@ LOG(ERROR) << "Tried to remove a non-existing client id, do nothing"; return; } + + observed_windows_.erase(it->second->media_app_window()); client_id_to_client_.erase(it); } +bool MahiMediaAppContentManagerImpl::ObservingWindow( + const aura::Window* window) const { + return observed_windows_.contains(window); +} + } // namespace ash
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.h b/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.h index 98c4ac1..4a3f854e 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.h +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_content_manager_impl.h
@@ -45,12 +45,14 @@ chromeos::mahi::ButtonType button_type, const std::u16string& question) override; void AddClient(base::UnguessableToken client_id, - raw_ptr<MahiMediaAppClient> client) override; + MahiMediaAppClient* client) override; void RemoveClient(base::UnguessableToken client_id) override; + bool ObservingWindow(const aura::Window* window) const override; private: std::map<base::UnguessableToken, raw_ptr<MahiMediaAppClient>> client_id_to_client_; + std::set<raw_ptr<const aura::Window, SetExperimental>> observed_windows_; }; } // namespace ash
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_events_proxy_impl.cc b/chrome/browser/ash/mahi/media_app/mahi_media_app_events_proxy_impl.cc index c56f6f19..7b7cd69 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_events_proxy_impl.cc +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_events_proxy_impl.cc
@@ -22,9 +22,6 @@ base::UnguessableToken client_id, const gfx::Rect& anchor) { for (auto& observer : observers_) { - // TODO(b/335741382): notify focus for test purpose. Remove after we have a - // proper focus event. - observer.OnPdfGetFocus(client_id); observer.OnPdfContextMenuShown(anchor); } }
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.cc b/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.cc index bf732f99e..8a2b94c 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.cc +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.cc
@@ -23,9 +23,10 @@ mojo::PendingReceiver<ash::media_app_ui::mojom::MahiUntrustedPageHandler> receiver, mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name) { + const std::string& file_name, + aura::Window* window) { auto mahi_pdf_handler = - std::make_unique<MahiMediaAppClient>(std::move(page), file_name); + std::make_unique<MahiMediaAppClient>(std::move(page), file_name, window); media_app_receivers_.Add(std::move(mahi_pdf_handler), std::move(receiver)); }
diff --git a/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.h b/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.h index 347c1e8..f1d873c6 100644 --- a/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.h +++ b/chrome/browser/ash/mahi/media_app/mahi_media_app_handler_factory.h
@@ -8,6 +8,7 @@ #include "ash/webui/media_app_ui/media_app_ui_untrusted.mojom.h" #include "base/no_destructor.h" #include "mojo/public/cpp/bindings/unique_receiver_set.h" +#include "ui/aura/window.h" namespace ash { @@ -26,7 +27,8 @@ mojo::PendingReceiver<ash::media_app_ui::mojom::MahiUntrustedPageHandler> receiver, mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name); + const std::string& file_name, + aura::Window* window); mojo::UniqueReceiverSet<ash::media_app_ui::mojom::MahiUntrustedPageHandler>& media_app_receivers() {
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_provider.cc b/chrome/browser/ash/policy/core/device_local_account_policy_provider.cc index ade8f92b..029d8f8 100644 --- a/chrome/browser/ash/policy/core/device_local_account_policy_provider.cc +++ b/chrome/browser/ash/policy/core/device_local_account_policy_provider.cc
@@ -24,7 +24,7 @@ DeviceLocalAccountPolicyProvider::DeviceLocalAccountPolicyProvider( const std::string& user_id, DeviceLocalAccountPolicyService* service, - DeviceLocalAccount::Type type) + DeviceLocalAccountType type) : user_id_(user_id), service_(service), type_(type), @@ -44,15 +44,13 @@ const std::string& user_id, DeviceLocalAccountPolicyService* device_local_account_policy_service, bool force_immediate_load) { - DeviceLocalAccount::Type type; - if (!device_local_account_policy_service || - !IsDeviceLocalAccountUser(user_id, &type)) { + auto type = GetDeviceLocalAccountType(user_id); + if (!device_local_account_policy_service || !type.has_value()) { return nullptr; } - std::unique_ptr<DeviceLocalAccountPolicyProvider> provider( - new DeviceLocalAccountPolicyProvider( - user_id, device_local_account_policy_service, type)); + auto provider = std::make_unique<DeviceLocalAccountPolicyProvider>( + user_id, device_local_account_policy_service, type.value()); // In case of restore-after-restart broker should already be initialized. if (force_immediate_load && provider->GetBroker()) provider->GetBroker()->LoadImmediately(); @@ -139,31 +137,42 @@ // administrator given that this is an enterprise user. SetEnterpriseUsersDefaults(&chrome_policy); - // Apply managed guest session specific default values if no value is fetched - // from the cloud. - if (type_ == DeviceLocalAccount::TYPE_PUBLIC_SESSION) { - if (!chrome_policy.IsPolicySet(key::kShelfAutoHideBehavior)) { - // Force the |ShelfAutoHideBehavior| policy to |Never|, ensuring that the - // ash shelf does not auto-hide. - chrome_policy.Set(key::kShelfAutoHideBehavior, POLICY_LEVEL_MANDATORY, - POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, - base::Value("Never"), nullptr); + switch (type_) { + case DeviceLocalAccountType::kPublicSession: { + // Apply managed guest session specific default values if no value is + // fetched from the cloud. + + if (!chrome_policy.IsPolicySet(key::kShelfAutoHideBehavior)) { + // Force the |ShelfAutoHideBehavior| policy to |Never|, ensuring that + // the ash shelf does not auto-hide. + chrome_policy.Set(key::kShelfAutoHideBehavior, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, + base::Value("Never"), nullptr); + } + + if (!chrome_policy.IsPolicySet(key::kShowLogoutButtonInTray)) { + // Force the |ShowLogoutButtonInTray| policy to |true|, ensuring that a + // big, red logout button is shown in the ash system tray. + chrome_policy.Set(key::kShowLogoutButtonInTray, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(true), + nullptr); + } + break; } - if (!chrome_policy.IsPolicySet(key::kShowLogoutButtonInTray)) { - // Force the |ShowLogoutButtonInTray| policy to |true|, ensuring that a - // big, red logout button is shown in the ash system tray. - chrome_policy.Set(key::kShowLogoutButtonInTray, POLICY_LEVEL_MANDATORY, - POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, - base::Value(true), nullptr); - } - } - - // Disable translation functionality in Web Kiosk Mode. - if (type_ == DeviceLocalAccount::TYPE_WEB_KIOSK_APP) { - chrome_policy.Set(key::kTranslateEnabled, POLICY_LEVEL_MANDATORY, - POLICY_SCOPE_USER, POLICY_SOURCE_ENTERPRISE_DEFAULT, - base::Value(false), nullptr); + case DeviceLocalAccountType::kWebKioskApp: + // Disable translation functionality in Web Kiosk Mode. + chrome_policy.Set(key::kTranslateEnabled, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_ENTERPRISE_DEFAULT, + base::Value(false), nullptr); + break; + case DeviceLocalAccountType::kSamlPublicSession: + case DeviceLocalAccountType::kKioskApp: + case DeviceLocalAccountType::kArcKioskApp: + // Do nothing. + break; } UpdatePolicy(std::move(bundle));
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_provider.h b/chrome/browser/ash/policy/core/device_local_account_policy_provider.h index b503ec43..08d31ef 100644 --- a/chrome/browser/ash/policy/core/device_local_account_policy_provider.h +++ b/chrome/browser/ash/policy/core/device_local_account_policy_provider.h
@@ -15,6 +15,7 @@ #include "chrome/browser/ash/policy/core/device_local_account_policy_service.h" #include "chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h" #include "components/policy/core/common/configuration_policy_provider.h" +#include "components/policy/core/common/device_local_account_type.h" #include "components/policy/core/common/policy_types.h" namespace policy { @@ -31,7 +32,7 @@ public: DeviceLocalAccountPolicyProvider(const std::string& user_id, DeviceLocalAccountPolicyService* service, - DeviceLocalAccount::Type type); + DeviceLocalAccountType type); DeviceLocalAccountPolicyProvider(const DeviceLocalAccountPolicyProvider&) = delete; @@ -75,7 +76,7 @@ scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager_; raw_ptr<DeviceLocalAccountPolicyService> service_; - DeviceLocalAccount::Type type_; + DeviceLocalAccountType type_; bool store_initialized_; bool waiting_for_policy_refresh_;
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_service_unittest.cc b/chrome/browser/ash/policy/core/device_local_account_policy_service_unittest.cc index 64d515a9..5419b74 100644 --- a/chrome/browser/ash/policy/core/device_local_account_policy_service_unittest.cc +++ b/chrome/browser/ash/policy/core/device_local_account_policy_service_unittest.cc
@@ -39,6 +39,7 @@ #include "components/policy/core/common/cloud/cloud_policy_service.h" #include "components/policy/core/common/cloud/mock_device_management_service.h" #include "components/policy/core/common/cloud/test/policy_builder.h" +#include "components/policy/core/common/device_local_account_type.h" #include "components/policy/core/common/external_data_fetcher.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_bundle.h" @@ -135,7 +136,7 @@ void AddDeviceLocalAccountToPolicy(const std::string& account_id); void AddWebKioskToPolicy(const std::string& account_id); virtual void InstallDevicePolicy(); - virtual DeviceLocalAccount::Type type() const; + virtual DeviceLocalAccountType type() const; const std::string account_1_user_id_; const std::string account_2_user_id_; @@ -202,7 +203,7 @@ TestingBrowserProcess::GetGlobal()->local_state()); extension_cache_task_runner_ = new base::TestSimpleTaskRunner; - if (type() == DeviceLocalAccount::TYPE_PUBLIC_SESSION) { + if (type() == DeviceLocalAccountType::kPublicSession) { expected_policy_map_.Set(key::kSearchSuggestEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(true), nullptr); @@ -295,8 +296,8 @@ Mock::VerifyAndClearExpectations(&service_observer_); } -DeviceLocalAccount::Type DeviceLocalAccountPolicyServiceTestBase::type() const { - return DeviceLocalAccount::TYPE_PUBLIC_SESSION; +DeviceLocalAccountType DeviceLocalAccountPolicyServiceTestBase::type() const { + return DeviceLocalAccountType::kPublicSession; } TEST_F(DeviceLocalAccountPolicyServiceTest, NoAccounts) { @@ -945,7 +946,7 @@ provider_->AddObserver(&provider_observer_); // Values implicitly enforced for public accounts. - if (type() == DeviceLocalAccount::TYPE_PUBLIC_SESSION) { + if (type() == DeviceLocalAccountType::kPublicSession) { expected_policy_map_.Set(key::kShelfAutoHideBehavior, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT, @@ -970,8 +971,8 @@ class DeviceLocalAccountPolicyProviderKioskTest : public DeviceLocalAccountPolicyProviderTest { protected: - DeviceLocalAccount::Type type() const override { - return DeviceLocalAccount::TYPE_WEB_KIOSK_APP; + DeviceLocalAccountType type() const override { + return DeviceLocalAccountType::kWebKioskApp; } };
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc index ee6e59fe..5254695 100644 --- a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc +++ b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
@@ -38,6 +38,7 @@ #include "components/policy/core/common/cloud/cloud_policy_store.h" #include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h" #include "components/policy/core/common/cloud/test/policy_builder.h" +#include "components/policy/core/common/device_local_account_type.h" #include "components/policy/core/common/external_data_fetcher.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" @@ -342,7 +343,7 @@ device_local_account_policy_provider_ = std::make_unique<DeviceLocalAccountPolicyProvider>( account_id.GetUserEmail(), device_local_account_policy_service_.get(), - DeviceLocalAccount::TYPE_PUBLIC_SESSION); + DeviceLocalAccountType::kPublicSession); PolicyServiceImpl::Providers providers; providers.push_back(device_local_account_policy_provider_.get());
diff --git a/chrome/browser/ash/policy/reporting/user_event_reporter_helper.cc b/chrome/browser/ash/policy/reporting/user_event_reporter_helper.cc index f929ae0..4385b36 100644 --- a/chrome/browser/ash/policy/reporting/user_event_reporter_helper.cc +++ b/chrome/browser/ash/policy/reporting/user_event_reporter_helper.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/task/sequenced_task_runner.h" #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h" #include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h" @@ -16,6 +17,7 @@ #include "chromeos/ash/components/settings/cros_settings.h" #include "components/reporting/client/report_queue_factory.h" #include "components/reporting/proto/synced/record.pb.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/browser_task_traits.h" @@ -74,6 +76,9 @@ if (!report_queue_) { std::move(enqueue_cb) .Run(Status(error::UNAVAILABLE, "Reporting queue is null.")); + base::UmaHistogramEnumeration(reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::REPORT_QUEUE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } report_queue_->Enqueue(std::move(record), priority, std::move(enqueue_cb));
diff --git a/chrome/browser/ash/policy/skyvault/local_files_cleanup.h b/chrome/browser/ash/policy/skyvault/local_files_cleanup.h index b0352ed4..1d43555b4 100644 --- a/chrome/browser/ash/policy/skyvault/local_files_cleanup.h +++ b/chrome/browser/ash/policy/skyvault/local_files_cleanup.h
@@ -6,13 +6,13 @@ #define CHROME_BROWSER_ASH_POLICY_SKYVAULT_LOCAL_FILES_CLEANUP_H_ #include "base/memory/weak_ptr.h" -#include "chrome/browser/ash/policy/skyvault/observer.h" +#include "chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h" #include "chrome/browser/chromeos/extensions/login_screen/login/cleanup/files_cleanup_handler.h" namespace policy::local_user_files { // Kicks-off user files removal when LocalUserFilesEnabled is set to 'false'. -class LocalFilesCleanup : public Observer { +class LocalFilesCleanup : public LocalUserFilesPolicyObserver { public: LocalFilesCleanup(); ~LocalFilesCleanup() override;
diff --git a/chrome/browser/ash/policy/skyvault/observer.cc b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.cc similarity index 67% rename from chrome/browser/ash/policy/skyvault/observer.cc rename to chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.cc index a76f42d..37f3394 100644 --- a/chrome/browser/ash/policy/skyvault/observer.cc +++ b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/policy/skyvault/observer.h" +#include "chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h" #include "base/check_is_test.h" #include "chrome/browser/browser_process.h" @@ -10,7 +10,7 @@ namespace policy::local_user_files { -Observer::Observer() +LocalUserFilesPolicyObserver::LocalUserFilesPolicyObserver() : pref_change_registrar_(std::make_unique<PrefChangeRegistrar>()) { if (!g_browser_process->local_state()) { // Can be NULL in tests. @@ -20,11 +20,12 @@ pref_change_registrar_->Init(g_browser_process->local_state()); pref_change_registrar_->Add( prefs::kLocalUserFilesAllowed, - base::BindRepeating(&Observer::OnLocalUserFilesPolicyChanged, - base::Unretained(this))); + base::BindRepeating( + &LocalUserFilesPolicyObserver::OnLocalUserFilesPolicyChanged, + base::Unretained(this))); } -Observer::~Observer() { +LocalUserFilesPolicyObserver::~LocalUserFilesPolicyObserver() { pref_change_registrar_->RemoveAll(); }
diff --git a/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h new file mode 100644 index 0000000..778341f --- /dev/null +++ b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h
@@ -0,0 +1,27 @@ +// 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_ASH_POLICY_SKYVAULT_LOCAL_USER_FILES_POLICY_OBSERVER_H_ +#define CHROME_BROWSER_ASH_POLICY_SKYVAULT_LOCAL_USER_FILES_POLICY_OBSERVER_H_ + +#include "components/prefs/pref_change_registrar.h" + +namespace policy::local_user_files { + +// LocalUserFilesAllowed policy observer interface. +class LocalUserFilesPolicyObserver { + public: + LocalUserFilesPolicyObserver(); + virtual ~LocalUserFilesPolicyObserver(); + + // Called when the value of the LocalUserFilesEnabled policy changes. + virtual void OnLocalUserFilesPolicyChanged() {} + + private: + std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; +}; + +} // namespace policy::local_user_files + +#endif // CHROME_BROWSER_ASH_POLICY_SKYVAULT_LOCAL_USER_FILES_POLICY_OBSERVER_H_
diff --git a/chrome/browser/ash/policy/skyvault/observer_browsertest.cc b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer_browsertest.cc similarity index 81% rename from chrome/browser/ash/policy/skyvault/observer_browsertest.cc rename to chrome/browser/ash/policy/skyvault/local_user_files_policy_observer_browsertest.cc index 16eadd3..dc4fd82 100644 --- a/chrome/browser/ash/policy/skyvault/observer_browsertest.cc +++ b/chrome/browser/ash/policy/skyvault/local_user_files_policy_observer_browsertest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/policy/skyvault/observer.h" +#include "chrome/browser/ash/policy/skyvault/local_user_files_policy_observer.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/browser_process.h" @@ -18,7 +18,9 @@ namespace policy::local_user_files { -class TestObserver : Observer { +namespace { + +class TestObserver : LocalUserFilesPolicyObserver { public: void OnLocalUserFilesPolicyChanged() override { local_user_files_allowed_ = g_browser_process->local_state()->GetBoolean( @@ -31,12 +33,14 @@ bool local_user_files_allowed_; }; -class LocalUserFilesObserverBrowserTest : public policy::PolicyTest { +} // namespace + +class LocalUserFilesPolicyObserverTest : public policy::PolicyTest { public: - LocalUserFilesObserverBrowserTest() { + LocalUserFilesPolicyObserverTest() { scoped_feature_list_.InitAndEnableFeature(features::kSkyVault); } - ~LocalUserFilesObserverBrowserTest() override = default; + ~LocalUserFilesPolicyObserverTest() override = default; protected: void SetPolicyValue(bool local_user_files_allowed) { @@ -50,7 +54,7 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -IN_PROC_BROWSER_TEST_F(LocalUserFilesObserverBrowserTest, CheckPolicyValue) { +IN_PROC_BROWSER_TEST_F(LocalUserFilesPolicyObserverTest, CheckPolicyValue) { TestObserver observer; SetPolicyValue(/*local_user_files_allowed=*/true);
diff --git a/chrome/browser/ash/policy/skyvault/observer.h b/chrome/browser/ash/policy/skyvault/observer.h deleted file mode 100644 index 35af3bc..0000000 --- a/chrome/browser/ash/policy/skyvault/observer.h +++ /dev/null
@@ -1,27 +0,0 @@ -// 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_ASH_POLICY_SKYVAULT_OBSERVER_H_ -#define CHROME_BROWSER_ASH_POLICY_SKYVAULT_OBSERVER_H_ - -#include "components/prefs/pref_change_registrar.h" - -namespace policy::local_user_files { - -// Observer interface for LocalUserFilesEnabled policy changes. -class Observer { - public: - Observer(); - virtual ~Observer(); - - // Called when the value of the LocalUserFilesEnabled policy changes. - virtual void OnLocalUserFilesPolicyChanged() {} - - private: - std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; -}; - -} // namespace policy::local_user_files - -#endif // CHROME_BROWSER_ASH_POLICY_SKYVAULT_OBSERVER_H_
diff --git a/chrome/browser/ash/preferences.cc b/chrome/browser/ash/preferences.cc index 12870d9..e23d431 100644 --- a/chrome/browser/ash/preferences.cc +++ b/chrome/browser/ash/preferences.cc
@@ -50,7 +50,6 @@ #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/prefs/pref_service_syncable_util.h" #include "chrome/browser/ui/ash/system_tray_client_impl.h" -#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/ash/components/dbus/pciguard/pciguard_client.h" @@ -65,6 +64,7 @@ #include "chromeos/ash/components/system/statistics_provider.h" #include "chromeos/ash/components/timezone/timezone_resolver.h" #include "chromeos/components/disks/disks_prefs.h" +#include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h" #include "chromeos/constants/pref_names.h" #include "components/feedback/content/content_tracing_manager.h" #include "components/language/core/browser/pref_names.h"
diff --git a/chrome/browser/ash/printing/printer_configurer.cc b/chrome/browser/ash/printing/printer_configurer.cc index 801ced5..42b3057 100644 --- a/chrome/browser/ash/printing/printer_configurer.cc +++ b/chrome/browser/ash/printing/printer_configurer.cc
@@ -518,9 +518,9 @@ case PrinterSetupResult::kDbusError: return "D-Bus error occurred. Reboot required."; case PrinterSetupResult::kDbusNoReply: - return "Couldn't talk to debugd over D-Bus."; + return "Couldn't talk to printscanmgr over D-Bus."; case PrinterSetupResult::kDbusTimeout: - return "Timed out trying to reach debugd over D-Bus."; + return "Timed out trying to reach printscanmgr over D-Bus."; // Problem reported by OS. case PrinterSetupResult::kIoError: return "I/O error occurred.";
diff --git a/chrome/browser/ash/system_web_apps/apps/BUILD.gn b/chrome/browser/ash/system_web_apps/apps/BUILD.gn index 9e88153..d86091f 100644 --- a/chrome/browser/ash/system_web_apps/apps/BUILD.gn +++ b/chrome/browser/ash/system_web_apps/apps/BUILD.gn
@@ -18,6 +18,7 @@ "eche_app_integration_browsertest.cc", "firmware_update_app_integration_browsertest.cc", "help_app/help_app_integration_browsertest.cc", + "mall_app_integration_browsertest.cc", "media_app/media_app_integration_browsertest.cc", "media_app/media_app_ocr_integration_browsertest.cc", "os_feedback_app_integration_browsertest.cc", @@ -45,6 +46,7 @@ "//ash/webui/firmware_update_ui", "//ash/webui/help_app_ui:buildflags", "//ash/webui/help_app_ui/search:mojo_bindings", + "//ash/webui/mall:url_constants", "//ash/webui/media_app_ui:browser_test_support", "//ash/webui/media_app_ui:buildflags", "//ash/webui/os_feedback_ui",
diff --git a/chrome/browser/ash/system_web_apps/apps/mall_app_integration_browsertest.cc b/chrome/browser/ash/system_web_apps/apps/mall_app_integration_browsertest.cc new file mode 100644 index 0000000..074d108 --- /dev/null +++ b/chrome/browser/ash/system_web_apps/apps/mall_app_integration_browsertest.cc
@@ -0,0 +1,41 @@ +// 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 "ash/constants/ash_features.h" +#include "ash/webui/mall/url_constants.h" +#include "ash/webui/print_preview_cros/url_constants.h" +#include "ash/webui/system_apps/public/system_web_app_type.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_integration_test.h" +#include "chromeos/constants/chromeos_features.h" +#include "content/public/test/browser_test.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace { + +class MallAppIntegrationTest : public ash::SystemWebAppIntegrationTest { + public: + MallAppIntegrationTest() { + features_.InitWithFeatures( + {chromeos::features::kCrosMall, chromeos::features::kCrosMallSwa}, + /*disabled_features=*/{}); + } + + private: + base::test::ScopedFeatureList features_; +}; + +// Test that the Mall app installs and launches correctly. +IN_PROC_BROWSER_TEST_P(MallAppIntegrationTest, MallApp) { + const GURL url{ash::kChromeUIMallUrl}; + EXPECT_NO_FATAL_FAILURE( + ExpectSystemWebAppValid(ash::SystemWebAppType::MALL, url, + /*title=*/"Get Apps and Games")); +} + +INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P( + MallAppIntegrationTest); + +} // namespace
diff --git a/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.cc b/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.cc new file mode 100644 index 0000000..e05adb8 --- /dev/null +++ b/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.cc
@@ -0,0 +1,50 @@ +// 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/ash/system_web_apps/apps/mall_system_web_app_info.h" + +#include "ash/webui/grit/ash_mall_cros_app_resources.h" +#include "ash/webui/mall/url_constants.h" +#include "ash/webui/system_apps/public/system_web_app_type.h" +#include "base/feature_list.h" +#include "chrome/browser/ash/system_web_apps/apps/system_web_app_install_utils.h" +#include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/constants/chromeos_features.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +constexpr char kMallInternalName[] = "Mall"; +} + +MallSystemAppDelegate::MallSystemAppDelegate(Profile* profile) + : ash::SystemWebAppDelegate(ash::SystemWebAppType::MALL, + kMallInternalName, + GURL(ash::kChromeUIMallUrl), + profile) {} + +std::unique_ptr<web_app::WebAppInstallInfo> +MallSystemAppDelegate::GetWebAppInfo() const { + std::unique_ptr<web_app::WebAppInstallInfo> info = + std::make_unique<web_app::WebAppInstallInfo>(); + const GURL url = GURL(ash::kChromeUIMallUrl); + info->start_url = url; + info->scope = url; + info->display_mode = blink::mojom::DisplayMode::kStandalone; + info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; + info->title = l10n_util::GetStringUTF16(IDS_MALL_APP_NAME); + + web_app::CreateIconInfoForSystemWebApp( + info->start_url, + {{"mall_icon_192.png", 192, + IDR_ASH_MALL_CROS_APP_IMAGES_MALL_ICON_192_PNG}}, + *info); + + return info; +} + +bool MallSystemAppDelegate::IsAppEnabled() const { + return chromeos::features::IsCrosMallSwaEnabled(); +}
diff --git a/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.h b/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.h new file mode 100644 index 0000000..3c6b3082 --- /dev/null +++ b/chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.h
@@ -0,0 +1,19 @@ +// 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_ASH_SYSTEM_WEB_APPS_APPS_MALL_SYSTEM_WEB_APP_INFO_H_ +#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_MALL_SYSTEM_WEB_APP_INFO_H_ + +#include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" + +class MallSystemAppDelegate : public ash::SystemWebAppDelegate { + public: + explicit MallSystemAppDelegate(Profile* profile); + + // ash::SystemWebAppDelegate: + std::unique_ptr<web_app::WebAppInstallInfo> GetWebAppInfo() const override; + bool IsAppEnabled() const override; +}; + +#endif // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_MALL_SYSTEM_WEB_APP_INFO_H_
diff --git a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc index f589420e..dafeb99 100644 --- a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc +++ b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc
@@ -119,10 +119,11 @@ mojo::PendingReceiver<ash::media_app_ui::mojom::MahiUntrustedPageHandler> receiver, mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name) { + const std::string& file_name, + aura::Window* window) { ash::MahiMediaAppHandlerFactory::GetInstance() ->CreateMahiMediaAppUntrustedHandler(std::move(receiver), std::move(page), - file_name); + file_name, window); } MediaAppGuestUIConfig::MediaAppGuestUIConfig()
diff --git a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h index 6c64890..e8690a8f 100644 --- a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h +++ b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h
@@ -38,7 +38,8 @@ mojo::PendingReceiver<ash::media_app_ui::mojom::MahiUntrustedPageHandler> receiver, mojo::PendingRemote<ash::media_app_ui::mojom::MahiUntrustedPage> page, - const std::string& file_name) override; + const std::string& file_name, + aura::Window* window) override; }; // A webui config for the chrome-untrusted:// part of media-app.
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc index bb852c4..7d813f2 100644 --- a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
@@ -49,6 +49,7 @@ #include "chrome/browser/ash/system_web_apps/apps/file_manager_web_app_info.h" #include "chrome/browser/ash/system_web_apps/apps/firmware_update_system_web_app_info.h" #include "chrome/browser/ash/system_web_apps/apps/help_app/help_app_web_app_info.h" +#include "chrome/browser/ash/system_web_apps/apps/mall_system_web_app_info.h" #include "chrome/browser/ash/system_web_apps/apps/media_app/media_web_app_info.h" #include "chrome/browser/ash/system_web_apps/apps/os_feedback_system_web_app_info.h" #include "chrome/browser/ash/system_web_apps/apps/os_flags_system_web_app_info.h" @@ -145,6 +146,7 @@ if (features::IsBocaEnabled()) { info_vec.push_back(std::make_unique<BocaSystemAppDelegate>(profile)); } + info_vec.push_back(std::make_unique<MallSystemAppDelegate>(profile)); #if !defined(OFFICIAL_BUILD) info_vec.push_back(std::make_unique<SampleSystemAppDelegate>(profile)); @@ -257,8 +259,9 @@ // SystemWebAppManager lifetime matches WebAppProvider lifetime (see // BrowserContextDependencyManager) but we reset pointers to // system_app_delegates_ for integrity with DCHECKs. - if (provider_->is_registry_ready()) + if (provider_->is_registry_ready()) { ConnectProviderToSystemWebAppDelegateMap(nullptr); + } } // static @@ -281,14 +284,16 @@ web_app::WebAppProvider* provider = SystemWebAppManager::GetWebAppProvider(profile); - if (!provider) + if (!provider) { return nullptr; + } SystemWebAppManager* swa_manager = Get(profile); DCHECK(swa_manager); - if (provider->on_registry_ready().is_signaled()) + if (provider->on_registry_ready().is_signaled()) { return swa_manager; + } base::RunLoop run_loop; provider->on_registry_ready().Post(FROM_HERE, run_loop.QuitClosure()); @@ -307,13 +312,15 @@ } bool SystemWebAppManager::IsAppEnabled(SystemWebAppType type) const { - if (base::FeatureList::IsEnabled(features::kEnableAllSystemWebApps)) + if (base::FeatureList::IsEnabled(features::kEnableAllSystemWebApps)) { return true; + } const SystemWebAppDelegate* delegate = GetSystemWebApp(system_app_delegates_, type); - if (!delegate) + if (!delegate) { return false; + } return delegate->IsAppEnabled(); } @@ -444,16 +451,18 @@ std::optional<webapps::AppId> SystemWebAppManager::GetAppIdForSystemApp( SystemWebAppType type) const { - if (!provider_->is_registry_ready()) + if (!provider_->is_registry_ready()) { return std::nullopt; + } return web_app::GetAppIdForSystemApp(provider_->registrar_unsafe(), system_app_delegates_, type); } std::optional<SystemWebAppType> SystemWebAppManager::GetSystemAppTypeForAppId( const webapps::AppId& app_id) const { - if (!provider_->is_registry_ready()) + if (!provider_->is_registry_ready()) { return std::nullopt; + } return web_app::GetSystemAppTypeForAppId(provider_->registrar_unsafe(), system_app_delegates_, app_id); } @@ -488,8 +497,9 @@ const auto& origin_to_origin_trials = system_app->GetEnabledOriginTrials(); auto iter_trials = origin_to_origin_trials.find(url::Origin::Create(url)); - if (iter_trials == origin_to_origin_trials.end()) + if (iter_trials == origin_to_origin_trials.end()) { return nullptr; + } return &iter_trials->second; } @@ -499,12 +509,14 @@ content::NavigationHandle* navigation_handle) { // Perform tab-specific setup when a navigation in a System Web App is about // to be committed. - if (!IsSystemWebApp(app_id)) + if (!IsSystemWebApp(app_id)) { return; + } // No need to setup origin trials for intra-document navigation. - if (navigation_handle->IsSameDocument()) + if (navigation_handle->IsSameDocument()) { return; + } const std::optional<SystemWebAppType> type = GetSystemAppTypeForAppId(app_id); // This function should only be called when an navigation happens inside a @@ -523,26 +535,31 @@ std::optional<SystemWebAppType> SystemWebAppManager::GetSystemAppForURL( const GURL& url) const { - if (!HasSystemWebAppScheme(url)) + if (!HasSystemWebAppScheme(url)) { return std::nullopt; + } - if (!provider_->is_registry_ready()) + if (!provider_->is_registry_ready()) { return std::nullopt; + } std::optional<webapps::AppId> app_id = provider_->registrar_unsafe().FindAppWithUrlInScope(url); - if (!app_id.has_value()) + if (!app_id.has_value()) { return std::nullopt; + } std::optional<SystemWebAppType> type = GetSystemAppTypeForAppId(app_id.value()); - if (!type.has_value()) + if (!type.has_value()) { return std::nullopt; + } const SystemWebAppDelegate* delegate = GetSystemWebApp(system_app_delegates_, type.value()); - if (!delegate) + if (!delegate) { return std::nullopt; + } return type; } @@ -556,8 +573,9 @@ const SystemWebAppDelegate* delegate = GetSystemWebApp(system_app_delegates_, type.value()); - if (!delegate->ShouldCaptureNavigations()) + if (!delegate->ShouldCaptureNavigations()) { return std::nullopt; + } // TODO(crbug://1051229): Expand ShouldCaptureNavigation to take a GURL, and // move this into the camera one. @@ -565,8 +583,10 @@ GURL::Replacements replacements; replacements.ClearQuery(); replacements.ClearRef(); - if (url.ReplaceComponents(replacements).spec() != kChromeUICameraAppMainURL) + if (url.ReplaceComponents(replacements).spec() != + kChromeUICameraAppMainURL) { return std::nullopt; + } } return type; @@ -692,8 +712,9 @@ // Report install duration only if the install pipeline actually installs // all the apps (e.g. on version upgrade). - if (did_force_install_apps) + if (did_force_install_apps) { RecordSystemWebAppInstallDuration(install_duration); + } RecordSystemWebAppInstallResults(install_results); @@ -770,14 +791,17 @@ } bool SystemWebAppManager::ShouldForceInstallApps() const { - if (base::FeatureList::IsEnabled(features::kAlwaysReinstallSystemWebApps)) + if (base::FeatureList::IsEnabled(features::kAlwaysReinstallSystemWebApps)) { return true; + } - if (update_policy_ == UpdatePolicy::kAlwaysUpdate) + if (update_policy_ == UpdatePolicy::kAlwaysUpdate) { return true; + } - if (PreviousSessionHadBrokenIcons()) + if (PreviousSessionHadBrokenIcons()) { return true; + } base::Version current_installed_version( pref_service_->GetString(prefs::kSystemWebAppLastUpdateVersion));
diff --git a/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto b/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto index a0759a7..cb4ee8da 100644 --- a/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto +++ b/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto
@@ -38,6 +38,7 @@ VC_BACKGROUND = 25; PRINT_PREVIEW_CROS = 26; BOCA = 27; + MALL = 28; }; optional SystemWebAppType system_app_type = 1;
diff --git a/chrome/browser/ash/web_handwriting_integration_test.cc b/chrome/browser/ash/web_handwriting_integration_test.cc index 9dfa2294..a47b977 100644 --- a/chrome/browser/ash/web_handwriting_integration_test.cc +++ b/chrome/browser/ash/web_handwriting_integration_test.cc
@@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <vector> + #include "base/files/file_path.h" +#include "base/strings/string_split.h" +#include "base/system/sys_info.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -48,6 +52,20 @@ }; IN_PROC_BROWSER_TEST_F(WebHandwritingIntegrationTest, Recognition) { + // The full board name may have the form "glimmer-signed-mp-v4keys" and we + // just want "glimmer". + std::vector<std::string> board = + base::SplitString(base::SysInfo::GetLsbReleaseBoard(), "-", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + if (board.empty()) { + LOG(ERROR) << "Unable to determine LSB release board"; + GTEST_SKIP(); + } + // TODO(b/342174514): Fails on jacuzzi. + if (board[0] == "jacuzzi") { + GTEST_SKIP(); + } + // Navigate to the appropriate test page, based on whether handwriting // recognition is supported or not. const char* test_file =
diff --git a/chrome/browser/browser_switcher/README.md b/chrome/browser/browser_switcher/README.md index ff1c7818..8ff1932 100644 --- a/chrome/browser/browser_switcher/README.md +++ b/chrome/browser/browser_switcher/README.md
@@ -69,7 +69,7 @@ `chrome://browser-switch/internals` page to view the state of LBS. This page displays the list of rules, and lets you re-download XML sitelists immediately. -## BHO +## BHO (unsupported) On Windows, a BHO (an IE add-on) can be used to automatically bounce back to Chrome from IE when visiting a non-whitelisted URL. @@ -86,3 +86,18 @@ This is the same mechanism that the old extension uses, so this feature is compatible with the old BHO. + +## Edge extension + +When Edge switched to a Chromium-based fork, they added an IE integration mode. +This is how Microsoft recommends running legacy applications, and standalone IE +is [unsupported since June +2022](https://learn.microsoft.com/en-us/lifecycle/faq/internet-explorer-microsoft-edge). +For instance, Windows 11's version of IExplore.exe cannot be used as an actual +browser. + +We offer an Edge extension, which is functionally and architecturally similar to +the old IE BHO. + +You can find the extension here: +https://microsoftedge.microsoft.com/addons/detail/legacy-browser-support-fo/acallcpknnnjahhhapgkajgnkfencieh
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 790a4d1..8c42683 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -512,6 +512,7 @@ #include "chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.h" #include "chrome/browser/web_applications/locks/app_lock.h" #include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/browser/webid/digital_identity_provider_desktop.h" #include "third_party/blink/public/mojom/installedapp/related_application.mojom.h" #endif // !BUILDFLAG(IS_ANDROID) @@ -7880,12 +7881,16 @@ base::BindOnce(&RunDigitalIdentityCallback, std::move(bridge), std::move(callback))); } +#endif std::unique_ptr<content::DigitalIdentityProvider> ChromeContentBrowserClient::CreateDigitalIdentityProvider() { +#if BUILDFLAG(IS_ANDROID) return std::make_unique<DigitalIdentityProviderAndroid>(); -} +#else + return std::make_unique<DigitalIdentityProviderDesktop>(); #endif +} bool ChromeContentBrowserClient::SuppressDifferentOriginSubframeJSDialogs( content::BrowserContext* browser_context) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 4fda00e..75c28b5 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -911,10 +911,10 @@ const url::Origin& origin, bool is_only_requesting_age, DigitalIdentityInterstitialCallback callback) override; +#endif std::unique_ptr<content::DigitalIdentityProvider> CreateDigitalIdentityProvider() override; -#endif #if !BUILDFLAG(IS_ANDROID) base::TimeDelta GetKeepaliveTimerTimeout(content::BrowserContext* context);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 46d8eba..83252ff 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -109,6 +109,8 @@ "mahi/mahi_browser_util.h", "mahi/mahi_content_extraction_delegate.cc", "mahi/mahi_content_extraction_delegate.h", + "mahi/mahi_prefs_controller.cc", + "mahi/mahi_prefs_controller.h", "mahi/mahi_tab_helper.cc", "mahi/mahi_tab_helper.h", "mahi/mahi_web_contents_manager.cc", @@ -414,6 +416,8 @@ "extensions/login_screen/login/login_api_lock_handler.h", "extensions/login_screen/login/shared_session_handler.cc", "extensions/login_screen/login/shared_session_handler.h", + "mahi/mahi_prefs_controller_ash.cc", + "mahi/mahi_prefs_controller_ash.h", "reporting/websites/website_metrics_retriever_ash.cc", "reporting/websites/website_metrics_retriever_ash.h", "reporting/websites/website_usage_telemetry_periodic_collector_ash.cc", @@ -453,6 +457,8 @@ "extensions/login_screen/login/cleanup/cleanup_manager_lacros.h", "extensions/login_screen/login/cleanup/cleanup_manager_lacros_factory.cc", "extensions/login_screen/login/cleanup/cleanup_manager_lacros_factory.h", + "mahi/mahi_prefs_controller_lacros.cc", + "mahi/mahi_prefs_controller_lacros.h", "policy/dlp/dlp_browser_helper_lacros.cc", "policy/dlp/dlp_browser_helper_lacros.h", "policy/dlp/dlp_content_manager_lacros.cc",
diff --git a/chrome/browser/chromeos/mahi/DEPS b/chrome/browser/chromeos/mahi/DEPS index a6764d1..4a42bc90 100644 --- a/chrome/browser/chromeos/mahi/DEPS +++ b/chrome/browser/chromeos/mahi/DEPS
@@ -2,6 +2,7 @@ # Guarded by IS_CHROMEOS_ASH or in is_chromeos_ash sources. # This is a temporary dependence to support ash chrome. We should remove this dependence when # Lacros is enabled by default. + "+ash", "+chrome/browser/ash/crosapi", "+chrome/browser/ash/mahi", ]
diff --git a/chrome/browser/chromeos/mahi/mahi_browser_client_impl.cc b/chrome/browser/chromeos/mahi/mahi_browser_client_impl.cc index f09a40b..5aa39042 100644 --- a/chrome/browser/chromeos/mahi/mahi_browser_client_impl.cc +++ b/chrome/browser/chromeos/mahi/mahi_browser_client_impl.cc
@@ -12,6 +12,7 @@ #include "base/unguessable_token.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/chromeos/mahi/mahi_browser_util.h" +#include "chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h" #include "chromeos/components/mahi/public/cpp/mahi_util.h" #include "chromeos/crosapi/mojom/mahi.mojom.h" #include "ui/gfx/image/image_skia.h" @@ -114,6 +115,15 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) remote_->OnFocusedPageChanged(std::move(page_info), std::move(callback)); #else // BUILDFLAG(IS_CHROMEOS_ASH) + // Do not notify browser delegate if the top level native window is observed + // by media app content provider (i.e. the web_content is from a media app + // window), to avoid overriding media app focus status. + CHECK(chromeos::MahiMediaAppContentManager::Get()); + if (chromeos::MahiMediaAppContentManager::Get()->ObservingWindow( + web_content_state.top_level_native_window)) { + return; + } + mahi_browser_delegate().OnFocusedPageChanged(std::move(page_info), std::move(callback)); #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/chromeos/mahi/mahi_browser_util.h b/chrome/browser/chromeos/mahi/mahi_browser_util.h index ab55bc7..dbd44e74 100644 --- a/chrome/browser/chromeos/mahi/mahi_browser_util.h +++ b/chrome/browser/chromeos/mahi/mahi_browser_util.h
@@ -8,8 +8,10 @@ #include <optional> #include <string> +#include "base/memory/raw_ptr_exclusion.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "ui/accessibility/ax_tree_update.h" +#include "ui/aura/window.h" #include "ui/gfx/image/image_skia.h" #include "url/gurl.h" @@ -25,6 +27,9 @@ ukm::SourceId ukm_source_id = ukm::kInvalidSourceId; ui::AXTreeUpdate snapshot; + // It's not a raw_ptr because we only use its address as identifier and never + // dereference it. + RAW_PTR_EXCLUSION aura::Window* top_level_native_window = nullptr; WebContentState(const WebContentState& state); WebContentState& operator=(const WebContentState& state) = default;
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller.cc b/chrome/browser/chromeos/mahi/mahi_prefs_controller.cc new file mode 100644 index 0000000..f7ce21b --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller.cc
@@ -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. + +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" + +#include "chrome/browser/chromeos/mahi/mahi_web_contents_manager.h" + +namespace mahi { + +namespace { + +MahiPrefsController* g_mahi_prefs_controller = nullptr; + +} // namespace + +// static +MahiPrefsController* MahiPrefsController::Get() { + return g_mahi_prefs_controller; +} + +MahiPrefsController::MahiPrefsController() { + DCHECK(!g_mahi_prefs_controller); + g_mahi_prefs_controller = this; +} + +MahiPrefsController::~MahiPrefsController() { + DCHECK_EQ(g_mahi_prefs_controller, this); + g_mahi_prefs_controller = nullptr; +} + +bool MahiPrefsController::GetMahiEnabled() { + return MahiWebContentsManager::Get()->GetPrefValue(); +} + +} // namespace mahi
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller.h b/chrome/browser/chromeos/mahi/mahi_prefs_controller.h new file mode 100644 index 0000000..6ab8007 --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller.h
@@ -0,0 +1,29 @@ +// 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_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_H_ +#define CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_H_ + +namespace mahi { + +// A class that controls Mahi related prefs. +class MahiPrefsController { + public: + static MahiPrefsController* Get(); + + MahiPrefsController(); + + MahiPrefsController(const MahiPrefsController&) = delete; + MahiPrefsController& operator=(const MahiPrefsController&) = delete; + + virtual ~MahiPrefsController(); + + // Sets/gets the enable state of Mahi. + virtual void SetMahiEnabled(bool enabled) = 0; + bool GetMahiEnabled(); +}; + +} // namespace mahi + +#endif // CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_H_
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.cc b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.cc new file mode 100644 index 0000000..848c98e --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.cc
@@ -0,0 +1,83 @@ +// 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/chromeos/mahi/mahi_prefs_controller_ash.h" + +#include "ash/constants/ash_pref_names.h" +#include "ash/session/session_controller_impl.h" +#include "ash/shell.h" +#include "base/functional/bind.h" +#include "components/prefs/pref_change_registrar.h" +#include "components/prefs/pref_service.h" + +namespace mahi { + +MahiPrefsControllerAsh::MahiPrefsControllerAsh() { + // `Shell` might not be available in tests. + if (!ash::Shell::HasInstance()) { + return; + } + + auto* session_controller = ash::Shell::Get()->session_controller(); + CHECK(session_controller); + + session_observation_.Observe(session_controller); + + // Register pref changes if use session already started. + if (session_controller->IsActiveUserSessionStarted()) { + PrefService* prefs = session_controller->GetActivePrefService(); + CHECK(prefs); + RegisterPrefChanges(prefs); + } +} + +MahiPrefsControllerAsh::~MahiPrefsControllerAsh() = default; + +void MahiPrefsControllerAsh::OnFirstSessionStarted() { + CHECK(ash::Shell::Get()->session_controller()); + PrefService* prefs = + ash::Shell::Get()->session_controller()->GetActivePrefService(); + RegisterPrefChanges(prefs); +} + +void MahiPrefsControllerAsh::OnChromeTerminating() { + session_observation_.Reset(); +} + +void MahiPrefsControllerAsh::OnShellDestroying() { + session_observation_.Reset(); + shell_observation_.Reset(); +} + +void MahiPrefsControllerAsh::RegisterPrefChanges(PrefService* pref_service) { + pref_change_registrar_.reset(); + + if (!pref_service) { + return; + } + + // Register preference changes. + pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); + pref_change_registrar_->Init(pref_service); + pref_change_registrar_->Add( + ash::prefs::kMahiEnabled, + base::BindRepeating(&MahiPrefsControllerAsh::OnMahiEnableStateChanged, + base::Unretained(this))); + + OnMahiEnableStateChanged(); +} + +void MahiPrefsControllerAsh::SetMahiEnabled(bool enabled) { + pref_change_registrar_->prefs()->SetBoolean(ash::prefs::kMahiEnabled, + enabled); +} + +void MahiPrefsControllerAsh::OnMahiEnableStateChanged() { + if (GetMahiEnabled()) { + // TODO(b/341485303): If the user turn on Mahi in settings, set the Magic + // Boost consented status to true. + } +} + +} // namespace mahi
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.h b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.h new file mode 100644 index 0000000..33d230cf --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.h
@@ -0,0 +1,63 @@ +// 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_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_ASH_H_ +#define CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_ASH_H_ + +#include "ash/public/cpp/session/session_observer.h" +#include "ash/shell_observer.h" +#include "base/scoped_observation.h" +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" + +class PrefChangeRegistrar; +class PrefService; + +namespace ash { +class SessionController; +class Shell; +} // namespace ash + +namespace mahi { + +// An ash implementation of `MahiPrefsController`. +class MahiPrefsControllerAsh : public ash::SessionObserver, + public ash::ShellObserver, + public MahiPrefsController { + public: + MahiPrefsControllerAsh(); + + MahiPrefsControllerAsh(const MahiPrefsControllerAsh&) = delete; + MahiPrefsControllerAsh& operator=(const MahiPrefsControllerAsh&) = delete; + + ~MahiPrefsControllerAsh() override; + + // MahiPrefsController: + void SetMahiEnabled(bool enabled) override; + + private: + // ash::SessionObserver: + void OnFirstSessionStarted() override; + void OnChromeTerminating() override; + + // ash::ShellObserver: + void OnShellDestroying() override; + + void RegisterPrefChanges(PrefService* pref_service); + + // Called when the related preferences are obtained from the pref service. + void OnMahiEnableStateChanged(); + + // Observes user profile prefs for the Assistant. + std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; + + base::ScopedObservation<ash::SessionController, ash::SessionObserver> + session_observation_{this}; + + base::ScopedObservation<ash::Shell, ash::ShellObserver> shell_observation_{ + this}; +}; + +} // namespace mahi + +#endif // CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_ASH_H_
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash_unittest.cc b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash_unittest.cc new file mode 100644 index 0000000..ee6c56f --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller_ash_unittest.cc
@@ -0,0 +1,50 @@ +// 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/chromeos/mahi/mahi_prefs_controller_ash.h" + +#include "ash/constants/ash_pref_names.h" +#include "ash/session/session_controller_impl.h" +#include "ash/shell.h" +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" +#include "chrome/test/base/chrome_ash_test_base.h" +#include "chromeos/constants/chromeos_features.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/testing_pref_service.h" + +namespace mahi { + +namespace { + +PrefService* GetPrefService() { + return ash::Shell::Get()->session_controller()->GetActivePrefService(); +} + +using MahiPrefsControllerAshTest = ChromeAshTestBase; + +TEST_F(MahiPrefsControllerAshTest, GetMahiEnabled) { + MahiPrefsControllerAsh controller; + + GetPrefService()->SetBoolean(ash::prefs::kMahiEnabled, true); + EXPECT_TRUE(controller.GetMahiEnabled()); + + GetPrefService()->SetBoolean(ash::prefs::kMahiEnabled, false); + EXPECT_FALSE(controller.GetMahiEnabled()); +} + +TEST_F(MahiPrefsControllerAshTest, SetMahiEnabled) { + MahiPrefsControllerAsh controller; + + controller.SetMahiEnabled(true); + EXPECT_TRUE(GetPrefService()->GetBoolean(ash::prefs::kMahiEnabled)); + EXPECT_TRUE(controller.GetMahiEnabled()); + + controller.SetMahiEnabled(false); + EXPECT_FALSE(GetPrefService()->GetBoolean(ash::prefs::kMahiEnabled)); + EXPECT_FALSE(controller.GetMahiEnabled()); +} + +} // namespace + +} // namespace mahi
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.cc b/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.cc new file mode 100644 index 0000000..a0b5767f --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.cc
@@ -0,0 +1,58 @@ +// 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/chromeos/mahi/mahi_prefs_controller_lacros.h" + +#include "base/functional/bind.h" +#include "base/functional/callback.h" +#include "base/logging.h" +#include "base/values.h" +#include "chromeos/lacros/lacros_service.h" +#include "components/prefs/pref_service.h" + +namespace { + +void SetPref(crosapi::mojom::PrefPath path, base::Value value) { + auto* lacros_service = chromeos::LacrosService::Get(); + if (!lacros_service || + !lacros_service->IsAvailable<crosapi::mojom::Prefs>()) { + LOG(WARNING) << "crosapi: Prefs API not available"; + return; + } + return lacros_service->GetRemote<crosapi::mojom::Prefs>()->SetPref( + path, std::move(value), /*callback=*/base::DoNothing()); +} + +} // namespace + +namespace mahi { + +MahiPrefsControllerLacros::MahiPrefsControllerLacros() { + // The observers are fired immediate with the current pref value on + // initialization. + // TODO(b/341844502): Consolidate the observer in `PrefsAshObserver` into this + // one. + mahi_enabled_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kMahiEnabled, + base::BindRepeating(&MahiPrefsControllerLacros::OnMahiEnableStateChanged, + base::Unretained(this))); +} + +MahiPrefsControllerLacros::~MahiPrefsControllerLacros() = default; + +void MahiPrefsControllerLacros::SetMahiEnabled(bool enabled) { + SetPref(crosapi::mojom::PrefPath::kMahiEnabled, base::Value(enabled)); +} + +void MahiPrefsControllerLacros::OnMahiEnableStateChanged(base::Value value) { + DCHECK(value.is_bool()); + bool mahi_enabled = value.GetBool(); + + if (mahi_enabled) { + // TODO(b/341485303): If the user turn on Mahi in settings, set the Magic + // Boost consented status to true. + } +} + +} // namespace mahi
diff --git a/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.h b/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.h new file mode 100644 index 0000000..5b5c341c --- /dev/null +++ b/chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.h
@@ -0,0 +1,38 @@ +// 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_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_LACROS_H_ +#define CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_LACROS_H_ + +#include "base/values.h" +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" +#include "chromeos/lacros/crosapi_pref_observer.h" + +namespace mahi { + +// A lacros implementation of `MahiPrefsController`. +class MahiPrefsControllerLacros : public MahiPrefsController { + public: + MahiPrefsControllerLacros(); + + MahiPrefsControllerLacros(const MahiPrefsControllerLacros&) = delete; + MahiPrefsControllerLacros& operator=(const MahiPrefsControllerLacros&) = + delete; + + ~MahiPrefsControllerLacros() override; + + private: + // MahiPrefsController: + void SetMahiEnabled(bool enabled) override; + + // Called when the related preferences are obtained from the pref service. + void OnMahiEnableStateChanged(base::Value value); + + // Observers to track pref changes from ash. + std::unique_ptr<CrosapiPrefObserver> mahi_enabled_observer_; +}; + +} // namespace mahi + +#endif // CHROME_BROWSER_CHROMEOS_MAHI_MAHI_PREFS_CONTROLLER_LACROS_H_
diff --git a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc index 4b4bab3..465d894 100644 --- a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc +++ b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc
@@ -44,6 +44,11 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "ash/session/session_controller_impl.h" +#include "ash/shell.h" +#endif + #if DCHECK_IS_ON() #include "base/functional/callback_helpers.h" #include "chromeos/constants/chromeos_features.h" @@ -153,6 +158,7 @@ weak_pointer_factory_.GetWeakPtr())); content_extraction_delegate_ = std::make_unique<MahiContentExtractionDelegate>(); + is_initialized_ = true; } @@ -163,7 +169,7 @@ } if (ShouldSkip(web_contents)) { - ClearFocusedWebContentState(); + ClearFocusedWebContentState(web_contents->GetTopLevelNativeWindow()); return; } @@ -174,6 +180,8 @@ WebContentState(focused_web_contents_->GetLastCommittedURL(), focused_web_contents_->GetTitle()); focused_web_content_state_.favicon = GetFavicon(focused_web_contents_); + focused_web_content_state_.top_level_native_window = + web_contents->GetTopLevelNativeWindow(); // Skip the distillable check for PDF content. if (IsPDFWebContents(web_contents)) { @@ -199,10 +207,14 @@ focused_web_content_state_.page_id, start_time)); } -void MahiWebContentsManager::ClearFocusedWebContentState() { +void MahiWebContentsManager::ClearFocusedWebContentState( + raw_ptr<aura::Window> top_level_window) { focused_web_contents_ = nullptr; is_pdf_focused_web_contents_ = false; focused_web_content_state_ = WebContentState(/*url=*/GURL(), /*title=*/u""); + if (top_level_window != nullptr) { + focused_web_content_state_.top_level_native_window = top_level_window; + } if (!is_initialized_) { return; } @@ -214,7 +226,7 @@ void MahiWebContentsManager::WebContentsDestroyed( content::WebContents* web_contents) { if (focused_web_contents_ == web_contents) { - ClearFocusedWebContentState(); + ClearFocusedWebContentState(web_contents->GetTopLevelNativeWindow()); } } @@ -239,11 +251,13 @@ bool MahiWebContentsManager::GetPrefValue() const { #if BUILDFLAG(IS_CHROMEOS_ASH) - Profile* profile = ProfileManager::GetActiveUserProfile(); - if (!profile || !profile->GetPrefs()) { + auto* session_controller = ash::Shell::Get()->session_controller(); + + if (!session_controller || !session_controller->GetActivePrefService()) { return false; } - return profile->GetPrefs()->GetBoolean(ash::prefs::kMahiEnabled); + return session_controller->GetActivePrefService()->GetBoolean( + ash::prefs::kMahiEnabled); #endif #if BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h index db7712d..ba67e81 100644 --- a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h +++ b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h
@@ -86,7 +86,11 @@ virtual void OnFocusedPageLoadComplete(content::WebContents* web_contents); // Clears the focused web content state, and notifies mahi manager. - void ClearFocusedWebContentState(); + // Passes the `top_level_window` downstream if it is set. This may suppress + // the notification if it is a media app window that is observed by media app + // content manager. + void ClearFocusedWebContentState( + raw_ptr<aura::Window> top_level_window = nullptr); // Clears the focused web content and its state if the focused content is // destroyed.
diff --git a/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc b/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc index b3640656..e357334 100644 --- a/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc +++ b/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc
@@ -80,6 +80,9 @@ if (reason_ != ContentAnalysisRequest::UNKNOWN) { request->set_reason(reason_); } + + request->set_blocking(analysis_settings_->block_until_verdict != + BlockUntilVerdict::kNoBlock); } safe_browsing::BinaryUploadService*
diff --git a/chrome/browser/enterprise/identifiers/BUILD.gn b/chrome/browser/enterprise/identifiers/BUILD.gn deleted file mode 100644 index 2e9a025..0000000 --- a/chrome/browser/enterprise/identifiers/BUILD.gn +++ /dev/null
@@ -1,24 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -source_set("identifiers") { - public = [ - "profile_id_delegate_impl.h", - "profile_id_service_factory.h", - ] - - sources = [ - "profile_id_delegate_impl.cc", - "profile_id_service_factory.cc", - ] - - deps = [ - "//base", - "//chrome/browser/profiles:profile", - "//components/enterprise", - "//components/enterprise/browser/identifiers", - "//components/policy/core/common", - "//components/prefs", - ] -}
diff --git a/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.cc b/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.cc index baaa0b7..45589ad7c 100644 --- a/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.cc +++ b/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.cc
@@ -9,6 +9,7 @@ #include "base/uuid.h" #include "build/buildflag.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" #include "components/enterprise/browser/identifiers/identifiers_prefs.h" #include "components/prefs/pref_service.h" #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ @@ -28,17 +29,74 @@ namespace { // Creates and persists the profile GUID if one does not already exist -void CreateProfileGUID(PrefService* prefs) { - if (prefs->GetString(kProfileGUIDPref).empty()) { - prefs->SetString(kProfileGUIDPref, - base::Uuid::GenerateRandomV4().AsLowercaseString()); +void CreateProfileGUID(Profile* profile, const base::FilePath& profile_path) { + auto* prefs = profile->GetPrefs(); + if (!prefs->GetString(kProfileGUIDPref).empty()) { + return; } + + auto* preset_profile_management_data = + PresetProfileManagmentData::Get(profile); + std::string preset_profile_guid = preset_profile_management_data->GetGuid(); + + std::string new_profile_guid = + (preset_profile_guid.empty()) + ? base::Uuid::GenerateRandomV4().AsLowercaseString() + : std::move(preset_profile_guid); + + prefs->SetString(kProfileGUIDPref, new_profile_guid); + preset_profile_management_data->ClearGuid(); +} + +} // namespace + +PresetProfileManagmentData* PresetProfileManagmentData::Get(Profile* profile) { + CHECK(profile); + + if (!profile->GetUserData(kPresetProfileManagementData)) { + profile->SetUserData( + kPresetProfileManagementData, + std::make_unique<PresetProfileManagmentData>(std::string())); + } + + return static_cast<PresetProfileManagmentData*>( + profile->GetUserData(kPresetProfileManagementData)); +} + +void PresetProfileManagmentData::SetGuid(std::string guid) { + CHECK(!guid.empty()); + CHECK(guid_.empty()); + + guid_ = guid; +} + +std::string PresetProfileManagmentData::GetGuid() { + return guid_; +} + +void PresetProfileManagmentData::ClearGuid() { + guid_ = std::string(); +} + +PresetProfileManagmentData::PresetProfileManagmentData(std::string preset_guid) + : guid_(preset_guid) {} + +ProfileIdDelegateImpl::ProfileIdDelegateImpl(Profile* profile) + : profile_(profile) { + CHECK(profile_); + CreateProfileGUID(profile_, profile->GetPath()); +} + +ProfileIdDelegateImpl::~ProfileIdDelegateImpl() = default; + +std::string ProfileIdDelegateImpl::GetDeviceId() { + return ProfileIdDelegateImpl::GetId(); } #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_ANDROID) // Gets the device ID from the BrowserDMTokenStorage. -std::string GetId() { +std::string ProfileIdDelegateImpl::GetId() { std::string device_id = policy::BrowserDMTokenStorage::Get()->RetrieveClientId(); @@ -56,7 +114,7 @@ } #else // Gets the device ID from cloud policy. -std::string GetId() { +std::string ProfileIdDelegateImpl::GetId() { std::string device_id = policy::GetDeviceName(); // On LACROS, the GetDeviceName method returns the host name when the device @@ -71,17 +129,4 @@ #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_ANDROID) -} // namespace - -ProfileIdDelegateImpl::ProfileIdDelegateImpl(Profile* profile) - : profile_(profile) { - DCHECK(profile_); - CreateProfileGUID(profile_->GetPrefs()); -} -ProfileIdDelegateImpl::~ProfileIdDelegateImpl() = default; - -std::string ProfileIdDelegateImpl::GetDeviceId() { - return GetId(); -} - } // namespace enterprise
diff --git a/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h b/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h index c382210e..ac0f9b4 100644 --- a/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h +++ b/chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h
@@ -5,16 +5,44 @@ #ifndef CHROME_BROWSER_ENTERPRISE_IDENTIFIERS_PROFILE_ID_DELEGATE_IMPL_H_ #define CHROME_BROWSER_ENTERPRISE_IDENTIFIERS_PROFILE_ID_DELEGATE_IMPL_H_ -#include "components/enterprise/browser/identifiers/profile_id_delegate.h" - #include <string> #include "base/memory/raw_ptr.h" +#include "base/supports_user_data.h" +#include "components/enterprise/browser/identifiers/profile_id_delegate.h" class Profile; namespace enterprise { +const void* const kPresetProfileManagementData = &kPresetProfileManagementData; + +// This class manages the collection of data needed for profile management, +// before the new profile is fully initialized. For now this class only contains +// the preset profile GUID for a newly created profile. +class PresetProfileManagmentData : public base::SupportsUserData::Data { + public: + explicit PresetProfileManagmentData(std::string preset_guid); + ~PresetProfileManagmentData() override = default; + + PresetProfileManagmentData(const PresetProfileManagmentData&) = delete; + PresetProfileManagmentData& operator=(const PresetProfileManagmentData&) = + delete; + + static PresetProfileManagmentData* Get(Profile* profile); + void SetGuid(std::string guid); + std::string GetGuid(); + void ClearGuid(); + + // The preset GUID will be used instead of a new random GUID when a profile is + // first created. This does not overwrite if a GUID has already been set for a + // profile. + std::string guid() { return guid_; } + + private: + std::string guid_; +}; + // Implementation of the profile Id delegate. class ProfileIdDelegateImpl : public ProfileIdDelegate { public: @@ -24,6 +52,8 @@ // ProfileIdDelegate std::string GetDeviceId() override; + static std::string GetId(); + private: raw_ptr<Profile> profile_; };
diff --git a/chrome/browser/enterprise/identifiers/profile_id_service_factory_unittest.cc b/chrome/browser/enterprise/identifiers/profile_id_service_factory_unittest.cc index 0ccf5ee..8a4ad2c 100644 --- a/chrome/browser/enterprise/identifiers/profile_id_service_factory_unittest.cc +++ b/chrome/browser/enterprise/identifiers/profile_id_service_factory_unittest.cc
@@ -7,6 +7,14 @@ #include "base/base64url.h" #include "base/hash/sha1.h" #include "base/memory/raw_ptr.h" +#include "base/scoped_observation.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/bind.h" +#include "base/uuid.h" +#include "chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_manager_observer.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/enterprise/browser/identifiers/identifiers_prefs.h" @@ -19,7 +27,6 @@ !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) #include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" #if BUILDFLAG(IS_WIN) -#include "base/strings/utf_string_conversions.h" #include "base/win/wmi.h" #endif // BUILDFLAG(IS_WIN) #else @@ -43,7 +50,8 @@ } // namespace -class ProfileIdServiceFactoryTest : public testing::Test { +class ProfileIdServiceFactoryTest : public testing::Test, + public ProfileManagerObserver { public: ProfileIdServiceFactoryTest() : profile_manager_(TestingBrowserProcess::GetGlobal()) { @@ -76,6 +84,8 @@ service_ = ProfileIdServiceFactory::GetForProfile(profile_); EXPECT_TRUE(service_); + + profile_manager_observer_.Observe(profile_manager_.profile_manager()); } Profile* CreateProfile(const std::string& profile_name) { @@ -101,10 +111,47 @@ service_ = ProfileIdServiceFactory::GetForProfile(profile); } + void OnProfileCreationStarted(Profile* profile) override { + if (!preset_guid_.empty()) { + enterprise::PresetProfileManagmentData::Get(profile)->SetGuid( + preset_guid_); + } + } + +// TODO(b/341267441): Enable this test for chrome os ash when +// `OnProfileCreationStarted` is fixed for `FakeProfileManager`. +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) + Profile* CreateNewProfileWithPresetGuid(std::string preset_guid) { + Profile* new_profile = nullptr; + // Making sure no two profiles have duplicate names/paths. + std::string new_profile_name = + "Profile " + base::Uuid::GenerateRandomV4().AsLowercaseString(); + preset_guid_ = preset_guid; + + base::RunLoop run_loop; + + ProfileManager::CreateMultiProfileAsync( + base::UTF8ToUTF16(new_profile_name), /*icon_index=*/0, + /*is_hidden=*/false, + base::BindLambdaForTesting([&new_profile, &run_loop](Profile* profile) { + ASSERT_TRUE(profile); + new_profile = profile; + run_loop.Quit(); + })); + + run_loop.Run(); + return new_profile; + } +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) + content::BrowserTaskEnvironment task_environment_; TestingProfileManager profile_manager_; raw_ptr<TestingProfile> profile_; raw_ptr<ProfileIdService> service_; + std::string preset_guid_; + base::ScopedObservation<ProfileManager, ProfileManagerObserver> + profile_manager_observer_{this}; + #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_ANDROID) || \ BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_ASH) && \ @@ -165,4 +212,46 @@ EXPECT_FALSE(service_); } +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) +TEST_F(ProfileIdServiceFactoryTest, GetProfileIdWithPresetGuid) { + std::string random_guid = base::Uuid::GenerateRandomV4().AsLowercaseString(); + std::string device_id = kFakeDeviceID; +#if BUILDFLAG(IS_WIN) + device_id += + base::WideToUTF8(base::win::WmiComputerSystemInfo::Get().serial_number()); +#endif // (BUILDFLAG(IS_WIN) + std::string expected_profile_id = + service_->GetProfileIdWithGuidAndDeviceId(random_guid, device_id).value(); + + auto* new_profile = CreateNewProfileWithPresetGuid(random_guid); + SetProfileIdService(new_profile); + + auto new_profile_id = service_->GetProfileId(); + EXPECT_EQ(new_profile_id, expected_profile_id); +} + +TEST_F(ProfileIdServiceFactoryTest, PresetGuidIdUniqueness) { + auto old_profile_id = service_->GetProfileId(); + std::string random_guid = base::Uuid::GenerateRandomV4().AsLowercaseString(); + + auto* new_profile = CreateNewProfileWithPresetGuid(random_guid); + SetProfileIdService(new_profile); + + EXPECT_NE(service_->GetProfileId(), old_profile_id); +} + +TEST_F(ProfileIdServiceFactoryTest, PresetGuidDataIsOneOff) { + std::string random_guid = base::Uuid::GenerateRandomV4().AsLowercaseString(); + + auto* preset_guid_profile = CreateNewProfileWithPresetGuid(random_guid); + SetProfileIdService(preset_guid_profile); + auto preset_guid_profile_id = service_->GetProfileId(); + + auto* no_preset_guid_profile = CreateNewProfileWithPresetGuid(std::string()); + SetProfileIdService(no_preset_guid_profile); + + EXPECT_NE(service_->GetProfileId(), preset_guid_profile_id); +} +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) + } // namespace enterprise
diff --git a/chrome/browser/enterprise/signals/BUILD.gn b/chrome/browser/enterprise/signals/BUILD.gn index e054737..25f0017b 100644 --- a/chrome/browser/enterprise/signals/BUILD.gn +++ b/chrome/browser/enterprise/signals/BUILD.gn
@@ -13,7 +13,6 @@ ] deps = [ - "//chrome/browser/enterprise/identifiers", "//chrome/common:constants", "//components/component_updater", "//components/enterprise/browser/identifiers",
diff --git a/chrome/browser/enterprise/signin/managed_profile_creator.cc b/chrome/browser/enterprise/signin/managed_profile_creator.cc index 146e3a96..c6048a39 100644 --- a/chrome/browser/enterprise/signin/managed_profile_creator.cc +++ b/chrome/browser/enterprise/signin/managed_profile_creator.cc
@@ -10,6 +10,7 @@ #include "base/memory/raw_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_manager.h" @@ -18,16 +19,22 @@ const std::string& id, const std::u16string& local_profile_name, std::unique_ptr<ManagedProfileCreationDelegate> delegate, - base::OnceCallback<void(base::WeakPtr<Profile>)> callback) + base::OnceCallback<void(base::WeakPtr<Profile>)> callback, + std::string preset_guid) : source_profile_(source_profile), id_(id), delegate_(std::move(delegate)), expected_profile_path_(g_browser_process->profile_manager() ->GetNextExpectedProfileDirectoryPath()), - callback_(std::move(callback)) { + callback_(std::move(callback)), + preset_guid_(preset_guid) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + profile_manager_observer_.Observe(profile_manager); + ProfileAttributesStorage& storage = - g_browser_process->profile_manager()->GetProfileAttributesStorage(); + profile_manager->GetProfileAttributesStorage(); profile_observation_.Observe(&storage); + auto icon_index = storage.ChooseAvatarIconIndexForNewProfile(); std::u16string name = local_profile_name.empty() ? storage.ChooseNameForNewProfile(icon_index) @@ -77,6 +84,15 @@ delegate_->SetManagedAttributesForProfile(entry); } +void ManagedProfileCreator::OnProfileCreationStarted(Profile* profile) { + if (expected_profile_path_ != profile->GetPath() || preset_guid_.empty()) { + return; + } + + enterprise::PresetProfileManagmentData::Get(profile)->SetGuid(preset_guid_); + profile_manager_observer_.Reset(); +} + void ManagedProfileCreator::OnNewProfileCreated(Profile* new_profile) { if (!new_profile || expected_profile_path_ != new_profile->GetPath()) { return;
diff --git a/chrome/browser/enterprise/signin/managed_profile_creator.h b/chrome/browser/enterprise/signin/managed_profile_creator.h index e465d2c..e3efc25 100644 --- a/chrome/browser/enterprise/signin/managed_profile_creator.h +++ b/chrome/browser/enterprise/signin/managed_profile_creator.h
@@ -13,6 +13,8 @@ #include "base/scoped_observation.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_manager_observer.h" using ProfileCreationCallback = base::OnceCallback<void(base::WeakPtr<Profile>)>; @@ -40,7 +42,8 @@ }; // Base level class for creating managed profiles. -class ManagedProfileCreator : public ProfileAttributesStorageObserver { +class ManagedProfileCreator : public ProfileAttributesStorageObserver, + public ProfileManagerObserver { public: // Creates a new managed profile by using the provided `delegate`. // The callback is called with the new profile or nullptr in case of failure. @@ -52,7 +55,8 @@ const std::string& id, const std::u16string& local_profile_name, std::unique_ptr<ManagedProfileCreationDelegate> delegate, - ProfileCreationCallback callback); + ProfileCreationCallback callback, + std::string preset_guid = std::string()); // Uses this version when the profile already exists at `target_profile_path` // but may not be loaded in memory. The profile is loaded if necessary. @@ -69,6 +73,10 @@ // ProfileAttributesStorageObserver: void OnProfileAdded(const base::FilePath& profile_path) override; + // ProfileManagerObserver: + void OnProfileCreationStarted(Profile* profile) override; + void OnProfileAdded(Profile* profile) override {} + private: void OnNewProfileCreated(Profile* new_profile); void OnNewProfileInitialized(Profile* new_profile); @@ -78,9 +86,12 @@ std::unique_ptr<ManagedProfileCreationDelegate> delegate_; base::FilePath expected_profile_path_; ProfileCreationCallback callback_; + std::string preset_guid_; base::ScopedObservation<ProfileAttributesStorage, ProfileAttributesStorage::Observer> profile_observation_{this}; + base::ScopedObservation<ProfileManager, ProfileManagerObserver> + profile_manager_observer_{this}; base::WeakPtrFactory<ManagedProfileCreator> weak_pointer_factory_{this}; };
diff --git a/chrome/browser/enterprise/signin/managed_profile_creator_unittest.cc b/chrome/browser/enterprise/signin/managed_profile_creator_unittest.cc index 4a4bb44..f0eb576 100644 --- a/chrome/browser/enterprise/signin/managed_profile_creator_unittest.cc +++ b/chrome/browser/enterprise/signin/managed_profile_creator_unittest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/task_environment.h" +#include "chrome/browser/enterprise/identifiers/profile_id_service_factory.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_manager.h" @@ -17,12 +18,23 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" +#include "components/enterprise/browser/identifiers/profile_id_service.h" #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if BUILDFLAG(IS_WIN) +#include "base/strings/utf_string_conversions.h" +#include "base/win/wmi.h" +#endif // BUILDFLAG(IS_WIN) + +using enterprise::ProfileIdServiceFactory; using testing::_; +const char kExampleGuid[] = "GUID-1234"; +constexpr char kFakeDeviceID[] = "fake-id"; + class MockManagedProfileCreationDelegate : public ManagedProfileCreationDelegate { public: @@ -52,6 +64,8 @@ ASSERT_TRUE(profile_manager_->SetUp()); profile_ = profile_manager_->CreateTestingProfile("test_profile"); mock_delegate_ = std::make_unique<MockManagedProfileCreationDelegate>(); + policy::BrowserDMTokenStorage::SetForTesting(&storage_); + storage_.SetClientId(kFakeDeviceID); } // Callback for the ManagedProfileCreator. @@ -80,6 +94,7 @@ raw_ptr<Profile> created_profile_; bool creator_callback_called_ = false; std::unique_ptr<MockManagedProfileCreationDelegate> mock_delegate_; + policy::FakeBrowserDMTokenStorage storage_; }; TEST_F(ManagedProfileCreatorTest, CreatesNewProfile) { @@ -92,8 +107,11 @@ ManagedProfileCreator creator( profile_, "id", u"local_profile_name", std::move(mock_delegate_), base::BindOnce(&ManagedProfileCreatorTest::OnProfileCreated, - base::Unretained(this), loop.QuitClosure())); + base::Unretained(this), loop.QuitClosure()), + kExampleGuid); + loop.Run(); + EXPECT_TRUE(creator_callback_called_); ASSERT_TRUE(created_profile_); @@ -104,6 +122,19 @@ ASSERT_TRUE(entry); EXPECT_EQ("id", entry->GetProfileManagementId()); EXPECT_EQ(u"local_profile_name", entry->GetName()); + + std::string device_id = kFakeDeviceID; +#if BUILDFLAG(IS_WIN) + device_id += + base::WideToUTF8(base::win::WmiComputerSystemInfo::Get().serial_number()); +#endif // (BUILDFLAG(IS_WIN) + + EXPECT_EQ(ProfileIdServiceFactory::GetForProfile(profile_) + ->GetProfileIdWithGuidAndDeviceId(kExampleGuid, device_id) + .value(), + ProfileIdServiceFactory::GetForProfile(created_profile_) + ->GetProfileId() + .value()); } TEST_F(ManagedProfileCreatorTest, LoadsExistingProfile) {
diff --git a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.cc b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.cc index 602a2b52..2f473a31 100644 --- a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.cc +++ b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.cc
@@ -12,6 +12,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/uuid.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/enterprise/identifiers/profile_id_delegate_impl.h" +#include "chrome/browser/enterprise/identifiers/profile_id_service_factory.h" #include "chrome/browser/enterprise/profile_management/profile_management_features.h" #include "chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.h" #include "chrome/browser/enterprise/signin/oidc_managed_profile_creation_delegate.h" @@ -38,6 +40,8 @@ #include "chrome/common/webui_url_constants.h" #include "components/device_signals/core/browser/pref_names.h" #include "components/enterprise/browser/controller/browser_dm_token_storage.h" +#include "components/enterprise/browser/identifiers/identifiers_prefs.h" +#include "components/enterprise/browser/identifiers/profile_id_service.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" @@ -56,6 +60,8 @@ using profile_management::features::kOidcAuthStubUserEmail; using profile_management::features::kOidcAuthStubUserName; +using enterprise::ProfileIdServiceFactory; + namespace { bool IsValidOidcToken(ProfileManagementOicdTokens oidc_tokens) { @@ -193,9 +199,34 @@ client_for_testing_ = nullptr; } -void OidcAuthenticationSigninInterceptor::StartOidcRegistration( - ClientRegisterCallback callback) { +void OidcAuthenticationSigninInterceptor::StartOidcRegistration() { + std::string preset_profile_guid = + base::Uuid::GenerateRandomV4().AsLowercaseString(); + + auto device_id = enterprise::ProfileIdDelegateImpl::GetId(); + // We are supplying the GUID and only using current profile's ID service to + // calculate the new profile ID. Since the two profiles share the same device, + // the device id should be the same. + std::optional<std::string> preset_profile_id = + ProfileIdServiceFactory::GetForProfile(profile_) + ->GetProfileIdWithGuidAndDeviceId(preset_profile_guid, device_id); + + if (preset_profile_id == std::nullopt || preset_profile_id.value().empty()) { + VLOG_POLICY(2, OIDC_ENROLLMENT) + << "Failed to create a preset profile ID for the new profile"; + interception_status_ = OidcInterceptionStatus::kError; + Reset(); + + return; + } + preset_profile_id_ = preset_profile_id.value(); + + VLOG_POLICY(2, OIDC_ENROLLMENT) + << "Starting OIDC registration process for profile " + << preset_profile_id_; + VLOG_POLICY(2, OIDC_ENROLLMENT) << "Starting OIDC registration process"; + policy::DeviceManagementService* device_management_service = g_browser_process->browser_policy_connector() ->device_management_service(); @@ -209,9 +240,7 @@ auto client = client_for_testing_ ? std::move(client_for_testing_) : std::make_unique<CloudPolicyClient>( - /*profile_id=*/base::Uuid::GenerateRandomV4() - .AsLowercaseString(), - device_management_service, + preset_profile_id_, device_management_service, g_browser_process->shared_url_loader_factory(), CloudPolicyClient::DeviceDMTokenCallback()); @@ -221,9 +250,9 @@ // Using a raw pointer to |this| is okay, because the service owns // |registration_helper_for_temporary_client_|. - auto registration_callback = - base::BindOnce(&OidcAuthenticationSigninInterceptor::OnClientRegistered, - base::Unretained(this), std::move(client)); + auto registration_callback = base::BindOnce( + &OidcAuthenticationSigninInterceptor::OnClientRegistered, + base::Unretained(this), std::move(client), preset_profile_guid); registration_helper_for_temporary_client_->StartRegistrationWithOidcTokens( oidc_tokens_.auth_token, oidc_tokens_.id_token, std::string(), @@ -231,7 +260,8 @@ } void OidcAuthenticationSigninInterceptor::OnClientRegistered( - std::unique_ptr<CloudPolicyClient> client) { + std::unique_ptr<CloudPolicyClient> client, + std::string preset_profile_guid) { if (client->last_dm_status() != policy::DM_STATUS_SUCCESS) { LOG_POLICY(ERROR, OIDC_ENROLLMENT) << "OIDC client registration failed with DM Status: " @@ -285,7 +315,8 @@ user_display_name_, user_email_), base::BindOnce( &OidcAuthenticationSigninInterceptor::OnNewSignedInProfileCreated, - base::Unretained(this))); + base::Unretained(this)), + preset_profile_guid); } void OidcAuthenticationSigninInterceptor::OnProfileCreationChoice( @@ -315,10 +346,8 @@ base::Unretained(this))); } else { kOidcAuthStubDmToken.Get().empty() - ? StartOidcRegistration(base::BindOnce( - &OidcAuthenticationSigninInterceptor::OnClientRegistered, - weak_factory_.GetWeakPtr())) - : OnClientRegistered(nullptr); + ? StartOidcRegistration() + : OnClientRegistered(nullptr, std::string()); } } @@ -354,8 +383,14 @@ policy::UserPolicyOidcSigninServiceFactory::GetForProfile( new_profile.get()); + CHECK_EQ(ProfileIdServiceFactory::GetForProfile(new_profile.get()) + ->GetProfileId() + .value(), + preset_profile_id_); + VLOG_POLICY(2, OIDC_ENROLLMENT) << "Starting policy fetch process for OIDC-managed profile"; + interception_status_ = OidcInterceptionStatus::kPolicyFetch; policy_service->FetchPolicyForSignedInUser(
diff --git a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.h b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.h index b8360f0..d5654a58 100644 --- a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.h +++ b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.h
@@ -42,8 +42,6 @@ class Profile; class ProfileAttributesEntry; -using ClientRegisterCallback = - base::OnceCallback<void(std::unique_ptr<policy::CloudPolicyClient>)>; using OidcInterceptionCallback = base::OnceCallback<void()>; using policy::CloudPolicyClient; @@ -95,11 +93,12 @@ void Reset(); // Try to send OIDC tokens to DM server for registration. - void StartOidcRegistration(ClientRegisterCallback callback); + void StartOidcRegistration(); // Called when OIDC registration finishes, the client should be registered // (aka has a dm token) and various information should be included, most // importantly, if the 3P user identity is sync-ed to Google or not. - void OnClientRegistered(std::unique_ptr<CloudPolicyClient> client); + void OnClientRegistered(std::unique_ptr<CloudPolicyClient> client, + std::string preset_profile_guid); // Called when user makes a decision on the profile creation dialog. void OnProfileCreationChoice(SigninInterceptionResult create); @@ -125,6 +124,7 @@ // the IDP. std::string subject_id_; bool dasher_based_ = true; + std::string preset_profile_id_; raw_ptr<const ProfileAttributesEntry> switch_to_entry_ = nullptr; SkColor profile_color_; // TODO(b/319479021): utilize the status variable to have better error
diff --git a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.cc b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.cc index 25bb0530..e0a90d0 100644 --- a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.cc +++ b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.h" +#include "chrome/browser/enterprise/identifiers/profile_id_service_factory.h" #include "chrome/browser/enterprise/profile_management/profile_management_features.h" #include "chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor.h" #include "chrome/browser/profiles/profile.h" @@ -29,7 +30,9 @@ OidcAuthenticationSigninInterceptorFactory:: OidcAuthenticationSigninInterceptorFactory() - : ProfileKeyedServiceFactory("OidcAuthenticationSigninInterceptor") {} + : ProfileKeyedServiceFactory("OidcAuthenticationSigninInterceptor") { + DependsOn(enterprise::ProfileIdServiceFactory::GetInstance()); +} OidcAuthenticationSigninInterceptorFactory:: ~OidcAuthenticationSigninInterceptorFactory() = default;
diff --git a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_unittest.cc b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_unittest.cc index 74900ce..3fee6e7 100644 --- a/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_unittest.cc +++ b/chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_file_util.h" +#include "chrome/browser/enterprise/identifiers/profile_id_service_factory.h" #include "chrome/browser/enterprise/profile_management/profile_management_features.h" #include "chrome/browser/enterprise/signin/mock_oidc_authentication_signin_interceptor.h" #include "chrome/browser/enterprise/signin/oidc_authentication_signin_interceptor_factory.h" @@ -32,6 +33,7 @@ #include "chrome/test/base/fake_profile_manager.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "components/enterprise/browser/identifiers/profile_id_service.h" #include "components/policy/core/common/cloud/cloud_external_data_manager.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/policy/core/common/cloud/mock_cloud_policy_store.h" @@ -114,6 +116,12 @@ bool will_policy_fetch_succeed_; }; +std::unique_ptr<KeyedService> CreateProfileIDService( + content::BrowserContext* context) { + static constexpr char kFakeProfileID[] = "fake-profile-id"; + return std::make_unique<enterprise::ProfileIdService>(kFakeProfileID); +} + std::unique_ptr<KeyedService> BuildMockInterceptor( int number_of_windows, content::BrowserContext* context) { @@ -158,6 +166,10 @@ base::BindRepeating(&BuildMockInterceptor, std::move(number_of_windows_))); + builder.AddTestingFactory( + enterprise::ProfileIdServiceFactory::GetInstance(), + base::BindRepeating(&CreateProfileIDService)); + return IdentityTestEnvironmentProfileAdaptor:: CreateProfileForIdentityTestEnvironment(builder); } @@ -252,6 +264,12 @@ BrowserWithTestWindowTest::TearDown(); } + // BrowserWithTestWindowTest overrides. + TestingProfile::TestingFactories GetTestingFactories() override { + return {{enterprise::ProfileIdServiceFactory::GetInstance(), + base::BindRepeating(&CreateProfileIDService)}}; + } + // If the 3P identity is not synced to Google, the interceptor should follow // the Dasherless workflow. bool is_3p_identity_synced() { return GetParam(); }
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index 3f4e489..b47feaa 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -7766,6 +7766,12 @@ blank_resp_header_action}, {12, 200, "modifyHeaders", "f.test2", blank_header_condition, std::nullopt, blank_resp_header_action}, + + // Used for sub-test 7. + {13, 1000, "modifyHeaders", "g.test", std::nullopt, + blank_req_header_action}, + {14, 102, "allow", "g.test"}, + {15, 101, "block", "g.test", blank_header_condition}, }; std::vector<TestRule> rules; @@ -7832,6 +7838,13 @@ // header conditions in the onHeadersReceived phase. {"f.test", "1"}, {"f.test2", "12"}, + + // Sub-test 7: + // In OnBeforeRequest, rule 13 (modify request headers) matches since it + // outprioritizes rule 14 (allow). However, rule 14 carries over to + // OnHeadersReceived where it outprioritizes both rules 1 and 15 (it + // prevents the latter rule from blocking the request) so it is matched. + {"g.test", "13,14"}, }; for (const auto& test_case : test_cases) { @@ -7905,12 +7918,11 @@ // In onBeforeRequest, `extension_2_allow` takes precedence over // `before_request_allow` since extension 2 was more recently installed. - // Once the request reaches onHeadersReceived, it should match with + // Once the request reaches onHeadersReceived, `headers_received_allow` + // matches, but only `extension_2_allow` should be tracked since it + // carries over to onHeadersReceived and outprioritizes // `headers_received_allow`. - // TODO(crbug.com/40727004): this should not match anything for - // `extension_1` since `extension_2_allow` carries over to - // onHeadersReceived and should outprioritize `headers_received_allow`. - {"google.xyz", "2", "3"}, + {"google.xyz", "", "3"}, }; for (const auto& test_case : test_cases) {
diff --git a/chrome/browser/file_system_access/file_system_file_handle_browsertest.cc b/chrome/browser/file_system_access/file_system_file_handle_browsertest.cc index e37f340e..1ea068e 100644 --- a/chrome/browser/file_system_access/file_system_file_handle_browsertest.cc +++ b/chrome/browser/file_system_access/file_system_file_handle_browsertest.cc
@@ -19,7 +19,7 @@ constexpr char kInitialUrl[] = "/run_async_code_on_worker.html"; constexpr char kSuccessMessage[] = "success"; constexpr char kSecurityErrorMessage[] = - "SecurityError: File System access is denied."; + "SecurityError: Storage directory access is denied."; } // namespace
diff --git a/chrome/browser/file_system_access/file_system_observer_storage_access_browsertest.cc b/chrome/browser/file_system_access/file_system_observer_storage_access_browsertest.cc new file mode 100644 index 0000000..e9352c1 --- /dev/null +++ b/chrome/browser/file_system_access/file_system_observer_storage_access_browsertest.cc
@@ -0,0 +1,203 @@ +// 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 "base/files/file_path.h" +#include "base/files/file_util.h" +#include "chrome/browser/content_settings/cookie_settings_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/content_settings/core/browser/cookie_settings.h" +#include "components/content_settings/core/common/content_settings.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/file_system_chooser_test_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/shell_dialogs/select_file_dialog.h" +#include "url/gurl.h" + +namespace { + +#define GET_FILE \ + "const [file] = await self.showOpenFilePicker();" \ + "self.entry = file;" + +#define TRY_CATCH_OBSERVE_FILE \ + "async function onChange(records, observer) {" \ + " numRecords += records.length;" \ + "};" \ + "const observer = new FileSystemObserver(onChange);" \ + "try {" \ + " await observer.observe(self.entry);" \ + "} catch (e) {" \ + " return e.toString();" \ + "}" \ + "return 'success';" + +constexpr char kSuccessMessage[] = "success"; +constexpr char kSecurityErrorMessage[] = + "SecurityError: Storage directory access is denied."; + +} // namespace + +class FileSystemObserverStorageAccessTest : public InProcessBrowserTest { + public: + FileSystemObserverStorageAccessTest() = default; + ~FileSystemObserverStorageAccessTest() override = default; + + FileSystemObserverStorageAccessTest( + const FileSystemObserverStorageAccessTest&) = delete; + FileSystemObserverStorageAccessTest& operator=( + const FileSystemObserverStorageAccessTest&) = delete; + + void SetUpOnMainThread() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); +#if BUILDFLAG(IS_WIN) + // Convert path to long format to avoid mixing long and 8.3 formats in test. + ASSERT_TRUE(temp_dir_.Set(base::MakeLongFilePath(temp_dir_.Take()))); +#endif // BUILDFLAG(IS_WIN) + ASSERT_TRUE(embedded_test_server()->Start()); + test_url_ = embedded_test_server()->GetURL("/title1.html"); + + InProcessBrowserTest::SetUpOnMainThread(); + } + + void TearDown() override { + ASSERT_TRUE(temp_dir_.Delete()); + ui::SelectFileDialog::SetFactory(nullptr); + InProcessBrowserTest::TearDown(); + } + + content::WebContents* GetWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + base::FilePath CreateFileToBePicked() { + base::FilePath file_path; + { + base::ScopedAllowBlockingForTesting allow_blocking; + EXPECT_TRUE( + base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path)); + EXPECT_TRUE(base::WriteFile(file_path, "observe me")); + } + + ui::SelectFileDialog::SetFactory( + std::make_unique<content::FakeSelectFileDialogFactory>( + std::vector<base::FilePath>{file_path})); + EXPECT_TRUE(NavigateToURL(GetWebContents(), test_url_)); + return file_path; + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + // Enable experimental web platform features to enable read/write access. + command_line->AppendSwitch( + switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, + "FileSystemObserver"); + } + + void ConfigureCookieSetting(const GURL& url, ContentSetting setting) { + CookieSettingsFactory::GetForProfile(browser()->profile()) + ->SetCookieSetting(url, setting); + } + + protected: + base::ScopedTempDir temp_dir_; + GURL test_url_; +}; + +IN_PROC_BROWSER_TEST_F(FileSystemObserverStorageAccessTest, + StorageAccessAllowed) { + CreateFileToBePicked(); + ConfigureCookieSetting(test_url_, CONTENT_SETTING_ALLOW); + + // Start observing the file. + std::string script = + // clang-format off + "(async () => {" + GET_FILE + TRY_CATCH_OBSERVE_FILE + "})()"; + // clang-format on + EXPECT_EQ(EvalJs(GetWebContents(), script), kSuccessMessage); +} + +IN_PROC_BROWSER_TEST_F(FileSystemObserverStorageAccessTest, + StorageAccessBlocked) { + CreateFileToBePicked(); + ConfigureCookieSetting(test_url_, CONTENT_SETTING_ALLOW); + + // Pick a file to observe. + std::string script = + // clang-format off + "(async () => {" + GET_FILE + "})()"; + // clang-format on + EXPECT_TRUE(ExecJs(GetWebContents(), script)); + + ConfigureCookieSetting(test_url_, CONTENT_SETTING_BLOCK); + // Attempt to observe the file. This should fail as the storage access is + // blocked. + script = + // clang-format off + "(async () => {" + TRY_CATCH_OBSERVE_FILE + "})()"; + // clang-format on + EXPECT_EQ(EvalJs(GetWebContents(), script), kSecurityErrorMessage); +} + +IN_PROC_BROWSER_TEST_F(FileSystemObserverStorageAccessTest, + StateChangeFromAllowedToBlocked) { + CreateFileToBePicked(); + ConfigureCookieSetting(test_url_, CONTENT_SETTING_ALLOW); + + // Start observing the file. + std::string script = + // clang-format off + "(async () => {" + GET_FILE + TRY_CATCH_OBSERVE_FILE + "})()"; + // clang-format on + EXPECT_EQ(EvalJs(GetWebContents(), script), kSuccessMessage); + + ConfigureCookieSetting(test_url_, CONTENT_SETTING_BLOCK); + + // The cached value will be used. So, the new state will be ignored. + EXPECT_EQ(EvalJs(GetWebContents(), script), kSuccessMessage); +} + +IN_PROC_BROWSER_TEST_F(FileSystemObserverStorageAccessTest, + StorageAccessChangeFromBlockedToAllowed) { + CreateFileToBePicked(); + ConfigureCookieSetting(test_url_, CONTENT_SETTING_ALLOW); + + // Pick a file to observe. + std::string script = + // clang-format off + "(async () => {" + GET_FILE + "})()"; + // clang-format on + EXPECT_TRUE(ExecJs(GetWebContents(), script)); + + ConfigureCookieSetting(test_url_, CONTENT_SETTING_BLOCK); + // Attempt to observe the file. This should fail as the storage access is + // blocked. + script = + // clang-format off + "(async () => {" + TRY_CATCH_OBSERVE_FILE + "})()"; + // clang-format on + EXPECT_EQ(EvalJs(GetWebContents(), script), kSecurityErrorMessage); + + ConfigureCookieSetting(test_url_, CONTENT_SETTING_ALLOW); + + // The cached value will be used. So, the new state will be ignored. + EXPECT_EQ(EvalJs(GetWebContents(), script), kSecurityErrorMessage); +}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 28826ba..562b182 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -230,6 +230,11 @@ "expiry_milestone": 125 }, { + "name": "app-info-tab-resumption-module", + "owners": [ "chrome-connective-tissue@google.com", "jinsukkim@chromium.org" ], + "expiry_milestone": 140 + }, + { "name": "app-install-service-uri", "owners": [ "tsergeant@chromium.org", @@ -7536,6 +7541,14 @@ "expiry_milestone": 127 }, { + "name": "ruby-short-heuristics", + "owners": [ + "tkent@chromium.org", + "layout-dev@chromium.org" + ], + "expiry_milestone": 138 + }, + { "name": "run-video-capture-service-in-browser", "owners": [ "agpalak@chromium.org", "herre@chromium.org", "video-cmi-apis@google.com" ], "expiry_milestone": 140
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 50442e7..ddb95b5 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2487,12 +2487,6 @@ "When enabled, the color of the toolbar and the status bar will be " "synchronized."; -const char kOmniboxModernizeVisualUpdateName[] = - "Omnibox Modernize Visual Update"; -const char kOmniboxModernizeVisualUpdateDescription[] = - "When enabled, Omnibox will show a new UI which is visually " - "updated. This flag is for the step 1 in the Clank Omnibox revamp plan."; - const char kOmniboxMostVisitedTilesHorizontalRenderGroupName[] = "Omnibox MV Tiles Horizontal Render Group"; const char kOmniboxMostVisitedTilesHorizontalRenderGroupDescription[] = @@ -3111,6 +3105,11 @@ "Specifies the radius of rounded windows in DIPs (Device Independent " "Pixels)"; +const char kRubyShortHeuristicsName[] = "Short ruby heuristics"; +const char kRubyShortHeuristicsDescription[] = + "When enabled, line breaking doesn't happen inside <ruby>s with shorter " + "contents even if `text-wrap: nowrap` is not specified."; + const char kMBIModeName[] = "MBI Scheduling Mode"; const char kMBIModeDescription[] = "Enables independent agent cluster scheduling, via the " @@ -3991,6 +3990,12 @@ "Animate the omnibox suggestions list when it appears instead of " "immediately setting it to visible"; +const char kAppInfoTabResumptionModuleName[] = + "Show app information in Tab Resumption module"; +const char kAppInfoTabResumptionModuleNameDescription[] = + "Show the information of the app that opened history via Custom Tabs " + "in Tab Resumption module."; + const char kAppSpecificHistoryName[] = "Allow app specific history"; const char kAppSpecificHistoryDescription[] = "If enabled, history results will also be categorized by application."; @@ -5462,13 +5467,6 @@ #if BUILDFLAG(IS_MAC) -#if BUILDFLAG(ENABLE_PRINTING) -const char kCupsIppPrintingBackendName[] = "CUPS IPP Printing Backend"; -const char kCupsIppPrintingBackendDescription[] = - "Use the CUPS IPP printing backend instead of the original CUPS backend " - "that calls the PPD API."; -#endif // BUILDFLAG(ENABLE_PRINTING) - const char kEnableExtensibleEnterpriseSSOName[] = "Extensible Enterprise SSO"; const char kEnableExtensibleEnterpriseSSODescription[] = "Enables support for extensible enterprise SSO in Chrome"; @@ -7931,6 +7929,13 @@ const char kRestartToGainAccessToKeychainDescription[] = "Controls whether the Chrome shows bubbles and banner, prompting the user " "to restart Chrome to gain access to computer's password manager."; + +#if BUILDFLAG(ENABLE_PRINTING) +const char kCupsIppPrintingBackendName[] = "CUPS IPP Printing Backend"; +const char kCupsIppPrintingBackendDescription[] = + "Use the CUPS IPP printing backend instead of the original CUPS backend " + "that calls the PPD API."; +#endif // BUILDFLAG(ENABLE_PRINTING) #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 656dbab..7571364 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1461,9 +1461,6 @@ extern const char kOmniboxMlUrlSearchBlendingName[]; extern const char kOmniboxMlUrlSearchBlendingDescription[]; -extern const char kOmniboxModernizeVisualUpdateName[]; -extern const char kOmniboxModernizeVisualUpdateDescription[]; - extern const char kOmniboxMatchToolbarAndStatusBarColorName[]; extern const char kOmniboxMatchToolbarAndStatusBarColorDescription[]; @@ -1809,6 +1806,9 @@ extern const char kRoundedWindows[]; extern const char kRoundedWindowsDescription[]; +extern const char kRubyShortHeuristicsName[]; +extern const char kRubyShortHeuristicsDescription[]; + extern const char kMBIModeName[]; extern const char kMBIModeDescription[]; @@ -2347,6 +2347,9 @@ extern const char kAndroidTabGroupStableIdsName[]; extern const char kAndroidTabGroupStableIdsDescription[]; +extern const char kAppInfoTabResumptionModuleName[]; +extern const char kAppInfoTabResumptionModuleNameDescription[]; + extern const char kAppSpecificHistoryName[]; extern const char kAppSpecificHistoryDescription[]; @@ -3182,11 +3185,6 @@ #if BUILDFLAG(IS_MAC) -#if BUILDFLAG(ENABLE_PRINTING) -extern const char kCupsIppPrintingBackendName[]; -extern const char kCupsIppPrintingBackendDescription[]; -#endif // BUILDFLAG(ENABLE_PRINTING) - extern const char kEnableExtensibleEnterpriseSSOName[]; extern const char kEnableExtensibleEnterpriseSSODescription[]; @@ -4599,6 +4597,11 @@ extern const char kRestartToGainAccessToKeychainName[]; extern const char kRestartToGainAccessToKeychainDescription[]; + +#if BUILDFLAG(ENABLE_PRINTING) +extern const char kCupsIppPrintingBackendName[]; +extern const char kCupsIppPrintingBackendDescription[]; +#endif // BUILDFLAG(ENABLE_PRINTING) #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 43417f57..75def75 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -166,6 +166,7 @@ &kAndroidTabDeclutterRescueKillswitch, &kAndroidToolbarScrollAblation, &kAnimatedImageDragShadow, + &kAppInfoTabResumptionModule, &kAppSpecificHistory, &kArchiveTabService, &kAsyncNotificationManager, @@ -180,7 +181,6 @@ &kBrowserControlsEarlyResize, &kCacheActivityTaskID, &kCastDeviceFilter, - &kClearOmniboxFocusAfterNavigation, &kCCTBeforeUnload, &kCCTClientDataHeader, &kCCTExtendTrustedCdnPublisher, @@ -455,6 +455,10 @@ "AnimatedImageDragShadow", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kAppInfoTabResumptionModule, + "AppInfoTabResumptionModule", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kAppSpecificHistory, "AppSpecificHistory", base::FEATURE_DISABLED_BY_DEFAULT); @@ -492,10 +496,6 @@ "CastDeviceFilter", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kClearOmniboxFocusAfterNavigation, - "ClearOmniboxFocusAfterNavigation", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kCCTBeforeUnload, "CCTBeforeUnload", base::FEATURE_ENABLED_BY_DEFAULT); @@ -524,7 +524,7 @@ "CCTIntentFeatureOverrides", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kCCTMinimized, "CCTMinimized", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kCCTMinimized, "CCTMinimized", base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kCCTMinimizedEnabledByDefault, "CCTMinimizedEnabledByDefault",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 01c237c..4d35edc 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -31,6 +31,7 @@ BASE_DECLARE_FEATURE(kAndroidToolbarScrollAblation); BASE_DECLARE_FEATURE(kAnimatedImageDragShadow); BASE_DECLARE_FEATURE(kAppSpecificHistory); +BASE_DECLARE_FEATURE(kAppInfoTabResumptionModule); BASE_DECLARE_FEATURE(kArchiveTabService); BASE_DECLARE_FEATURE(kAsyncNotificationManager); BASE_DECLARE_FEATURE(kAuxiliarySearchDonation); @@ -43,7 +44,6 @@ BASE_DECLARE_FEATURE(kBlockIntentsWhileLocked); BASE_DECLARE_FEATURE(kBrowserControlsEarlyResize); BASE_DECLARE_FEATURE(kCacheActivityTaskID); -BASE_DECLARE_FEATURE(kClearOmniboxFocusAfterNavigation); BASE_DECLARE_FEATURE(kCastDeviceFilter); BASE_DECLARE_FEATURE(kCCTBeforeUnload); BASE_DECLARE_FEATURE(kCCTClientDataHeader);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 86298f0..148bfe25 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -173,6 +173,7 @@ "AndroidTabDeclutterRescueKillswitch"; public static final String ANDROID_TAB_GROUP_STABLE_IDS = "AndroidTabGroupStableIds"; public static final String ANIMATED_IMAGE_DRAG_SHADOW = "AnimatedImageDragShadow"; + public static final String APP_INFO_TAB_RESUMPTION_MODULE = "AppInfoTabResumptionModule"; public static final String APP_SPECIFIC_HISTORY = "AppSpecificHistory"; public static final String ARCHIVE_TAB_SERVICE = "ArchiveTabService"; public static final String ASYNC_NOTIFICATION_MANAGER = "AsyncNotificationManager"; @@ -253,8 +254,6 @@ public static final String CCT_TAB_MODAL_DIALOG = "CCTTabModalDialog"; public static final String CHROME_SURVEY_NEXT_ANDROID = "ChromeSurveyNextAndroid"; public static final String CHROME_SHARE_PAGE_INFO = "ChromeSharePageInfo"; - public static final String CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION = - "ClearOmniboxFocusAfterNavigation"; public static final String COLLECT_ANDROID_FRAME_TIMELINE_METRICS = "CollectAndroidFrameTimelineMetrics"; public static final String COMMAND_LINE_ON_NON_ROOTED = "CommandLineOnNonRooted"; @@ -531,6 +530,8 @@ public static final CachedFlag sAndroidHub = newCachedFlag(ANDROID_HUB, true); public static final CachedFlag sAndroidTabGroupStableIds = newCachedFlag(ANDROID_TAB_GROUP_STABLE_IDS, true); + public static final CachedFlag sAppInfoTabResumptionModule = + newCachedFlag(APP_INFO_TAB_RESUMPTION_MODULE, false); public static final CachedFlag sAppSpecificHistory = newCachedFlag(APP_SPECIFIC_HISTORY, false); public static final CachedFlag sArchiveTabService = newCachedFlag(ARCHIVE_TAB_SERVICE, false); public static final CachedFlag sAsyncNotificationManager = @@ -552,7 +553,7 @@ newCachedFlag(CCT_INCOGNITO_AVAILABLE_TO_THIRD_PARTY, false); public static final CachedFlag sCctIntentFeatureOverrides = newCachedFlag(CCT_INTENT_FEATURE_OVERRIDES, true); - public static final CachedFlag sCctMinimized = newCachedFlag(CCT_MINIMIZED, false); + public static final CachedFlag sCctMinimized = newCachedFlag(CCT_MINIMIZED, true); public static final CachedFlag sCctPageInsightsHub = newCachedFlag(CCT_PAGE_INSIGHTS_HUB, true); public static final CachedFlag sCctNavigationalPrefetch = newCachedFlag(CCT_NAVIGATIONAL_PREFETCH, false); @@ -690,6 +691,7 @@ sAndroidElegantTextHeight, sAndroidHub, sAndroidTabGroupStableIds, + sAppInfoTabResumptionModule, sAppSpecificHistory, sArchiveTabService, sAsyncNotificationManager,
diff --git a/chrome/browser/google/google_update_policy_fetcher_win.cc b/chrome/browser/google/google_update_policy_fetcher_win.cc index 3e4fc12..feafead6 100644 --- a/chrome/browser/google/google_update_policy_fetcher_win.cc +++ b/chrome/browser/google/google_update_policy_fetcher_win.cc
@@ -44,6 +44,8 @@ constexpr char kUpdatesSuppressedDurationMin[] = "UpdatesSuppressedDurationMin"; constexpr char kUpdatesSuppressedStartHour[] = "UpdatesSuppressedStartHour"; constexpr char kUpdatesSuppressedStartMinute[] = "UpdatesSuppressedStartMinute"; +constexpr char kCloudPolicyOverridesPlatformPolicy[] = + "CloudPolicyOverridesPlatformPolicy"; // Adds the policy |policy_name| extracted from |policy| into |policies|. // |value_override_function| is an optional function that modifies and overrides @@ -95,6 +97,18 @@ AddPolicy(kDownloadPreference, policy.Get(), *policies); } { + Microsoft::WRL::ComPtr<IPolicyStatus4> policy_status4; + Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; + if (SUCCEEDED(policy_status->QueryInterface( + install_static::IsSystemInstall() ? __uuidof(IPolicyStatus4System) + : __uuidof(IPolicyStatus4User), + IID_PPV_ARGS_Helper(&policy_status4))) && + SUCCEEDED( + policy_status4->get_cloudPolicyOverridesPlatformPolicy(&policy))) { + AddPolicy(kCloudPolicyOverridesPlatformPolicy, policy.Get(), *policies); + } + } + { Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; if (SUCCEEDED(policy_status->get_forceInstallApps( install_static::IsSystemInstall(), &policy))) { @@ -231,6 +245,7 @@ {kUpdatesSuppressedDurationMin, policy::Schema()}, {kUpdatesSuppressedStartHour, policy::Schema()}, {kUpdatesSuppressedStartMinute, policy::Schema()}, + {kCloudPolicyOverridesPlatformPolicy, policy::Schema()}, }}; }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java index 80fb29c9..d961fe1 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java
@@ -36,7 +36,7 @@ private boolean mAppLanguagePromptShown; private String mCurrentLanguage; private boolean mIsPageTranslated; - private final Map<Long, TranslationObserver> mObservers = new HashMap<>(); + private final Map<WebContents, Map<Long, TranslationObserver>> mObservers = new HashMap<>(); private static long sObserverPtr; public FakeTranslateBridgeJni( @@ -173,21 +173,37 @@ @Override public long addTranslationObserver(WebContents webContents, TranslationObserver observer) { long ptr = ++sObserverPtr; - mObservers.put(ptr, observer); + if (!mObservers.containsKey(webContents)) { + mObservers.put(webContents, new HashMap<>()); + } + mObservers.get(webContents).put(ptr, observer); return ptr; } @Override public void removeTranslationObserver(WebContents webContents, long observerNativePtr) { - mObservers.remove(observerNativePtr); + var observersForWebContents = mObservers.get(webContents); + if (observersForWebContents != null) { + observersForWebContents.remove(observerNativePtr); + } } public int getObserverCount() { - return mObservers.keySet().size(); + int count = 0; + for (var observersForWebContents : mObservers.values()) { + count += observersForWebContents.size(); + } + return count; + } + + public int getObserverCount(WebContents webContents) { + var observersForWebContents = mObservers.get(webContents); + return observersForWebContents == null ? 0 : observersForWebContents.size(); } /** * Set the web content's current language for testing. + * * @param language String value of what getCurrentLanguage should return. */ public void setCurrentLanguage(String language) {
diff --git a/chrome/browser/manta/manta_service_factory.cc b/chrome/browser/manta/manta_service_factory.cc index 3314a3a..c9db3815 100644 --- a/chrome/browser/manta/manta_service_factory.cc +++ b/chrome/browser/manta/manta_service_factory.cc
@@ -52,6 +52,9 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) Profile* const profile = Profile::FromBrowserContext(context); + + bool is_otr_profile = !profile->IsRegularProfile(); + std::string chrome_version, locale; if (PrefService* pref_service = profile->GetPrefs()) { chrome_version = pref_service->GetString(prefs::kProfileCreatedByVersion); @@ -62,7 +65,7 @@ profile->GetDefaultStoragePartition() ->GetURLLoaderFactoryForBrowserProcess(), IdentityManagerFactory::GetForProfile(profile), is_demo_mode, - chrome_version, locale); + is_otr_profile, chrome_version, locale); } } // namespace manta
diff --git a/chrome/browser/net/chrome_shared_dictionary_browsertest.cc b/chrome/browser/net/chrome_shared_dictionary_browsertest.cc index 7149cf9e..bbf9e0a3 100644 --- a/chrome/browser/net/chrome_shared_dictionary_browsertest.cc +++ b/chrome/browser/net/chrome_shared_dictionary_browsertest.cc
@@ -46,22 +46,25 @@ namespace { constexpr std::string_view kTestDictionaryString = "A dictionary"; -constexpr std::string_view kTestDictionaryHashBase64 = - ":CqNpAU9/qzcL6UB0aYVFx7uTLsRhJSePN780qwKjWuw=:"; constexpr std::string_view kCompressedDataOriginalString = "This is compressed test data using a test dictionary"; // kBrotliCompressedData is generated using the following commands: -// $ echo -n "A dictionary" > /tmp/dict -// $ echo -n "This is compressed test data using a test dictionary" > /tmp/data -// $ ./brotli -o /tmp/out.sbr -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.sbr +// $ echo -n "A dictionary" > /tmp/dict +// $ echo -n "This is compressed test data using a test dictionary" > /tmp/data +// $ echo -en '\xffDCB' > /tmp/out.dcb +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb +// $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb +// $ xxd -i /tmp/out.dcb constexpr uint8_t kBrotliCompressedData[] = { - 0xa1, 0x98, 0x01, 0x80, 0x22, 0xe0, 0x26, 0x4b, 0x95, 0x5c, 0x19, - 0x18, 0x9d, 0xc1, 0xc3, 0x44, 0x0e, 0x5c, 0x6a, 0x09, 0x9d, 0xf0, - 0xb0, 0x01, 0x47, 0x14, 0x87, 0x14, 0x6d, 0xfb, 0x60, 0x96, 0xdb, - 0xae, 0x9e, 0x79, 0x54, 0xe3, 0x69, 0x03, 0x29}; + 0xff, 0x44, 0x43, 0x42, 0x0a, 0xa3, 0x69, 0x01, 0x4f, 0x7f, 0xab, + 0x37, 0x0b, 0xe9, 0x40, 0x74, 0x69, 0x85, 0x45, 0xc7, 0xbb, 0x93, + 0x2e, 0xc4, 0x61, 0x25, 0x27, 0x8f, 0x37, 0xbf, 0x34, 0xab, 0x02, + 0xa3, 0x5a, 0xec, 0xa1, 0x98, 0x01, 0x80, 0x22, 0xe0, 0x26, 0x4b, + 0x95, 0x5c, 0x19, 0x18, 0x9d, 0xc1, 0xc3, 0x44, 0x0e, 0x5c, 0x6a, + 0x09, 0x9d, 0xf0, 0xb0, 0x01, 0x47, 0x14, 0x87, 0x14, 0x6d, 0xfb, + 0x60, 0x96, 0xdb, 0xae, 0x9e, 0x79, 0x54, 0xe3, 0x69, 0x03, 0x29}; // NOLINTNEXTLINE(runtime/string) const std::string kBrotliCompressedDataString = @@ -69,17 +72,23 @@ sizeof(kBrotliCompressedData)); // kZstdCompressedData is generated using the following commands: -// $ echo -n "A dictionary" > /tmp/dict -// $ echo -n "This is compressed test data using a test dictionary" > /tmp/data -// $ zstd -o /tmp/out.szstd -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.szstd +// $ echo -n "A dictionary" > /tmp/dict +// $ echo -n "This is compressed test data using a test dictionary" > /tmp/data +// $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz +// $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data +// $ cat /tmp/tmp.zstd >> /tmp/out.dcz +// $ xxd -i /tmp/out.dcz constexpr uint8_t kZstdCompressedData[] = { - 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x34, 0xa1, 0x01, 0x00, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, - 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x64, 0x69, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x72, 0x79, 0x9e, 0x99, 0xf2, 0xbc}; + 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00, 0x0a, 0xa3, 0x69, 0x01, + 0x4f, 0x7f, 0xab, 0x37, 0x0b, 0xe9, 0x40, 0x74, 0x69, 0x85, 0x45, 0xc7, + 0xbb, 0x93, 0x2e, 0xc4, 0x61, 0x25, 0x27, 0x8f, 0x37, 0xbf, 0x34, 0xab, + 0x02, 0xa3, 0x5a, 0xec, 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x34, 0xa1, 0x01, + 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x64, 0x69, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x72, 0x79, 0x9e, 0x99, 0xf2, 0xbc}; // NOLINTNEXTLINE(runtime/string) const std::string kZstdCompressedDataString = @@ -372,8 +381,6 @@ response->set_content_type("text/html"); response->AddCustomHeader("content-encoding", network::GetSharedBrotliContentEncodingName()); - response->AddCustomHeader("content-dictionary", - kTestDictionaryHashBase64); response->set_content(kBrotliCompressedDataString); return response; } else if (request.relative_url == "/path/zstd_compressed") { @@ -381,8 +388,6 @@ response->set_content_type("text/html"); response->AddCustomHeader("content-encoding", network::GetSharedZstdContentEncodingName()); - response->AddCustomHeader("content-dictionary", - kTestDictionaryHashBase64); response->set_content(kZstdCompressedDataString); return response; } @@ -914,9 +919,13 @@ if (request.relative_url == "/shared_dictionary/path/target") { auto response = std::make_unique<net::test_server::BasicHttpResponse>(); - response->AddCustomHeader("Content-Encoding", "br-d"); - response->AddCustomHeader("Content-Dictionary", - "Invalid Content-Dictionary"); + response->AddCustomHeader("Content-Encoding", "dcb"); + std::string data = + std::string(base::as_string_view(kBrotliCompressedData)); + // Change the first byte of the compressed data to trigger + // UNEXPECTED_CONTENT_DICTIONARY_HEADER error. + ++data[0]; + response->set_content(data); return response; } return nullptr;
diff --git a/chrome/browser/new_tab_page/chrome_colors/BUILD.gn b/chrome/browser/new_tab_page/chrome_colors/BUILD.gn index fe880f7..59abdd3 100644 --- a/chrome/browser/new_tab_page/chrome_colors/BUILD.gn +++ b/chrome/browser/new_tab_page/chrome_colors/BUILD.gn
@@ -4,6 +4,21 @@ import("//build/compiled_action.gni") +source_set("chrome_colors") { + sources = [ + "chrome_colors_util.cc", + "chrome_colors_util.h", + ] + public_deps = [ + "//skia", + "//ui/base/mojom", + ] + deps = [ + ":generate_chrome_colors_info", + "//chrome/browser/ui/webui/cr_components/theme_color_picker", + ] +} + executable("generate_colors_info") { sources = [ "generate_colors_info.cc",
diff --git a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.cc b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.cc index 1094a86..73eb25b 100644 --- a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.cc +++ b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.cc
@@ -16,38 +16,6 @@ namespace { -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class ChromeColorType { - kChromeColor = 0, - kDynamicChromeColor = 1, - kMaxValue = kDynamicChromeColor, -}; - -int GetDynamicColorId(const SkColor color, - ui::mojom::BrowserColorVariant variant) { - auto it = base::ranges::find_if(kDynamicCustomizeChromeColors, - [&](const DynamicColorInfo& dynamic_color) { - return dynamic_color.color == color && - dynamic_color.variant == variant; - }); - return it == kDynamicCustomizeChromeColors.end() ? kOtherDynamicColorId - : it->id; -} - -void RecordChromeColorsColorType(ChromeColorType type) { - base::UmaHistogramEnumeration("ChromeColors.ColorType", type); -} - -void RecordChromeColorsDynamicColor(int color_id) { - base::UmaHistogramExactLinear( - "ChromeColors.DynamicColorOnLoad", color_id, - base::ranges::max_element(kDynamicCustomizeChromeColors, {}, - &DynamicColorInfo::id) - ->id); - RecordChromeColorsColorType(ChromeColorType::kDynamicChromeColor); -} - } // namespace ChromeColorsService::ChromeColorsService(Profile* profile) @@ -55,36 +23,6 @@ ChromeColorsService::~ChromeColorsService() = default; -// static -int ChromeColorsService::GetColorId(const SkColor color) { - for (chrome_colors::ColorInfo color_info : - chrome_colors::kGeneratedColorsInfo) { - if (color == color_info.color) - return color_info.id; - } - - return kOtherColorId; -} - -// static -void ChromeColorsService::RecordColorOnLoadHistogram(SkColor color) { - base::UmaHistogramExactLinear("ChromeColors.ColorOnLoad", GetColorId(color), - kNumColorsInfo); - RecordChromeColorsColorType(ChromeColorType::kChromeColor); -} - -// static -void ChromeColorsService::RecordDynamicColorOnLoadHistogramForGrayscale() { - RecordChromeColorsDynamicColor(kGrayscaleDynamicColorId); -} - -// static -void ChromeColorsService::RecordDynamicColorOnLoadHistogram( - SkColor color, - ui::mojom::BrowserColorVariant variant) { - RecordChromeColorsDynamicColor(GetDynamicColorId(color, variant)); -} - void ChromeColorsService::ApplyDefaultTheme(content::WebContents* tab) { SaveThemeRevertState(tab); theme_service_->UseDefaultTheme();
diff --git a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h index a9c06bf..0bc4550 100644 --- a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h +++ b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h
@@ -17,13 +17,6 @@ namespace chrome_colors { -// These constants have to match the values of ChromeColorsInfo and -// DynamicChromeColorsInfo in enums.xml. -constexpr int kDefaultColorId = -1; -constexpr int kOtherColorId = 0; -constexpr int kOtherDynamicColorId = 0; -constexpr int kGrayscaleDynamicColorId = 1; - // Supports theme changes originating from the NTP customization menu. Users can // apply a Chrome color or the default theme, which will then either be reverted // or confirmed and made permanent. If third party themes are present, users @@ -38,17 +31,6 @@ ~ChromeColorsService() override; - // Returns id for the given |color| if it is in the predefined set, and - // |kOtherColorId| otherwise. - static int GetColorId(const SkColor color); - - // Record installed color id to UMA histograms. - static void RecordColorOnLoadHistogram(SkColor color); - static void RecordDynamicColorOnLoadHistogramForGrayscale(); - static void RecordDynamicColorOnLoadHistogram( - SkColor color, - ui::mojom::BrowserColorVariant variant); - // Applies a theme that can be reverted by saving the previous theme state and // the |tab| that changes are made from. virtual void ApplyDefaultTheme(content::WebContents* tab);
diff --git a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service_unittest.cc b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service_unittest.cc index d60ba2c..1ef216c 100644 --- a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service_unittest.cc +++ b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_service_unittest.cc
@@ -3,10 +3,12 @@ // found in the LICENSE file. #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h" + #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_factory.h" +#include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h" #include "chrome/browser/new_tab_page/chrome_colors/generated_colors_info.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" @@ -182,20 +184,19 @@ TEST_F(TestChromeColorsService, RecordColorOnLoadHistogram) { constexpr size_t kTestColorIndex = 3; - chrome_colors::ChromeColorsService::RecordColorOnLoadHistogram( + chrome_colors::RecordColorOnLoadHistogram( chrome_colors::kGeneratedColorsInfo[kTestColorIndex].color); EXPECT_EQ(1, histogram_tester_.GetBucketCount( "ChromeColors.ColorOnLoad", chrome_colors::kGeneratedColorsInfo[kTestColorIndex].id)); - chrome_colors::ChromeColorsService::RecordColorOnLoadHistogram(SK_ColorWHITE); + chrome_colors::RecordColorOnLoadHistogram(SK_ColorWHITE); EXPECT_EQ(1, histogram_tester_.GetBucketCount("ChromeColors.ColorOnLoad", chrome_colors::kOtherColorId)); } TEST_F(TestChromeColorsService, RecordDynamicColorOnLoadHistogramForGrayscale) { - chrome_colors::ChromeColorsService:: - RecordDynamicColorOnLoadHistogramForGrayscale(); + chrome_colors::RecordDynamicColorOnLoadHistogramForGrayscale(); EXPECT_EQ(1, histogram_tester_.GetBucketCount( "ChromeColors.DynamicColorOnLoad", chrome_colors::kGrayscaleDynamicColorId)); @@ -203,14 +204,14 @@ TEST_F(TestChromeColorsService, RecordDynamicColorOnLoadHistogram) { constexpr size_t kTestColorIndex = 3; - chrome_colors::ChromeColorsService::RecordDynamicColorOnLoadHistogram( + chrome_colors::RecordDynamicColorOnLoadHistogram( kDynamicCustomizeChromeColors[kTestColorIndex].color, kDynamicCustomizeChromeColors[kTestColorIndex].variant); EXPECT_EQ(1, histogram_tester_.GetBucketCount( "ChromeColors.DynamicColorOnLoad", kDynamicCustomizeChromeColors[kTestColorIndex].id)); - chrome_colors::ChromeColorsService::RecordDynamicColorOnLoadHistogram( + chrome_colors::RecordDynamicColorOnLoadHistogram( SK_ColorWHITE, ui::mojom::BrowserColorVariant::kTonalSpot); EXPECT_EQ( 1, histogram_tester_.GetBucketCount("ChromeColors.DynamicColorOnLoad",
diff --git a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.cc b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.cc new file mode 100644 index 0000000..e5ff44a --- /dev/null +++ b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.cc
@@ -0,0 +1,76 @@ +// 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/new_tab_page/chrome_colors/chrome_colors_util.h" + +#include <iterator> + +#include "base/metrics/histogram_functions.h" +#include "base/ranges/algorithm.h" +#include "chrome/browser/new_tab_page/chrome_colors/generated_colors_info.h" +#include "chrome/browser/ui/webui/cr_components/theme_color_picker/customize_chrome_colors.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/mojom/themes.mojom.h" + +namespace chrome_colors { + +namespace { + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class ChromeColorType { + kChromeColor = 0, + kDynamicChromeColor = 1, + kMaxValue = kDynamicChromeColor, +}; + +void RecordChromeColorsColorType(ChromeColorType type) { + base::UmaHistogramEnumeration("ChromeColors.ColorType", type); +} + +void RecordChromeColorsDynamicColor(int color_id) { + base::UmaHistogramExactLinear( + "ChromeColors.DynamicColorOnLoad", color_id, + base::ranges::max_element(kDynamicCustomizeChromeColors, {}, + &DynamicColorInfo::id) + ->id); + RecordChromeColorsColorType(ChromeColorType::kDynamicChromeColor); +} + +int GetDynamicColorId(const SkColor color, + ui::mojom::BrowserColorVariant variant) { + auto it = base::ranges::find_if(kDynamicCustomizeChromeColors, + [&](const DynamicColorInfo& dynamic_color) { + return dynamic_color.color == color && + dynamic_color.variant == variant; + }); + return it == kDynamicCustomizeChromeColors.end() ? kOtherDynamicColorId + : it->id; +} + +} // namespace + +void RecordColorOnLoadHistogram(SkColor color) { + base::UmaHistogramExactLinear("ChromeColors.ColorOnLoad", + GetChromeColorsInfo(color), kNumColorsInfo); + RecordChromeColorsColorType(ChromeColorType::kChromeColor); +} + +void RecordDynamicColorOnLoadHistogramForGrayscale() { + RecordChromeColorsDynamicColor(kGrayscaleDynamicColorId); +} + +void RecordDynamicColorOnLoadHistogram(SkColor color, + ui::mojom::BrowserColorVariant variant) { + RecordChromeColorsDynamicColor(GetDynamicColorId(color, variant)); +} + +int GetChromeColorsInfo(SkColor color) { + const auto it = base::ranges::find(chrome_colors::kGeneratedColorsInfo, color, + &chrome_colors::ColorInfo::color); + return it == std::end(chrome_colors::kGeneratedColorsInfo) ? kOtherColorId + : it->id; +} + +} // namespace chrome_colors
diff --git a/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h new file mode 100644 index 0000000..644de80e --- /dev/null +++ b/chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h
@@ -0,0 +1,34 @@ +// 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_NEW_TAB_PAGE_CHROME_COLORS_CHROME_COLORS_UTIL_H_ +#define CHROME_BROWSER_NEW_TAB_PAGE_CHROME_COLORS_CHROME_COLORS_UTIL_H_ + +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/mojom/themes.mojom.h" + +namespace chrome_colors { + +// These constants have to match the values of ChromeColorsInfo and +// DynamicChromeColorsInfo in enums.xml. +inline constexpr int kDefaultColorId = -1; +inline constexpr int kOtherColorId = 0; +inline constexpr int kOtherDynamicColorId = 0; +inline constexpr int kGrayscaleDynamicColorId = 1; + +void RecordColorOnLoadHistogram(SkColor color); +void RecordDynamicColorOnLoadHistogramForGrayscale(); +void RecordDynamicColorOnLoadHistogram(SkColor color, + ui::mojom::BrowserColorVariant variant); + +// Returns id for the given `color` if it is in the predefined set, and +// `kOtherColorId` otherwise. +// Do not confuse these integers (including the dynamically generated ones) with +// the color IDs from the color pipeline. These integers represent fixed color +// schemes, see the enums.xml file for more details. +int GetChromeColorsInfo(SkColor color); + +} // namespace chrome_colors + +#endif // CHROME_BROWSER_NEW_TAB_PAGE_CHROME_COLORS_CHROME_COLORS_UTIL_H_
diff --git a/chrome/browser/page_image_service/android/BUILD.gn b/chrome/browser/page_image_service/android/BUILD.gn index 01437f7f..d9d7ee2 100644 --- a/chrome/browser/page_image_service/android/BUILD.gn +++ b/chrome/browser/page_image_service/android/BUILD.gn
@@ -7,7 +7,10 @@ android_library("java") { srcjar_deps = [ ":jni_headers" ] - sources = [ "java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java", + "java/src/org/chromium/chrome/browser/page_image_service/ImageServiceMetrics.java", + ] deps = [ "//base:base_java", "//chrome/browser/profiles/android:java",
diff --git a/chrome/browser/page_image_service/android/image_service_bridge.cc b/chrome/browser/page_image_service/android/image_service_bridge.cc index 44fb917..3d97572 100644 --- a/chrome/browser/page_image_service/android/image_service_bridge.cc +++ b/chrome/browser/page_image_service/android/image_service_bridge.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/page_image_service/android/jni_headers/ImageServiceBridge_jni.h" #include "chrome/browser/page_image_service/image_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "components/page_image_service/metrics_util.h" #include "components/page_image_service/mojom/page_image_service.mojom.h" #include "url/gurl.h" @@ -40,6 +41,13 @@ return reinterpret_cast<intptr_t>(image_service_bridge); } +static std::string JNI_ImageServiceBridge_ClientIdToString( + JNIEnv* env, + const jint client_id) { + return page_image_service::ClientIdToString( + static_cast<page_image_service::mojom::ClientId>(client_id)); +} + ImageServiceBridge::ImageServiceBridge( page_image_service::ImageService* image_service, signin::IdentityManager* identity_manager)
diff --git a/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java b/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java index 705ea4e..d46e5f3 100644 --- a/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java +++ b/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridge.java
@@ -14,10 +14,10 @@ import org.chromium.base.Callback; import org.chromium.base.CallbackController; +import org.chromium.chrome.browser.page_image_service.ImageServiceMetrics.SalientImageUrlFetchResult; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.image_fetcher.ImageFetcher; import org.chromium.page_image_service.mojom.ClientId; -import org.chromium.page_image_service.mojom.ClientId.EnumType; import org.chromium.url.GURL; import java.util.HashMap; @@ -25,7 +25,7 @@ /** Allows java access to the native ImageService. */ public class ImageServiceBridge { - private final @EnumType int mClientId; + private final @ClientId.EnumType int mClientId; private final String mImageFetcherClientName; // Cache the results for repeated queries to avoid extra calls through the JNI/network. private final Map<GURL, GURL> mSalientImageUrlCache = new HashMap<>(); @@ -41,7 +41,7 @@ * @param imageFetcher The fetcher to fetch the image. */ public ImageServiceBridge( - @EnumType int clientId, + @ClientId.EnumType int clientId, @NonNull String imageFetcherClientName, @NonNull Profile profile, @NonNull ImageFetcher imageFetcher) { @@ -71,6 +71,7 @@ * @param imageSize The size of the salient image. * @param callback The callback to receive the salient image url. */ + @Deprecated public void fetchImageFor( boolean isAccountData, @NonNull GURL pageUrl, @@ -103,7 +104,13 @@ void fetchImageUrlFor( boolean isAccountData, @NonNull GURL pageUrl, @NonNull Callback<GURL> callback) { if (mSalientImageUrlCache.containsKey(pageUrl)) { - callback.onResult(mSalientImageUrlCache.get(pageUrl)); + GURL cacheResult = mSalientImageUrlCache.get(pageUrl); + callback.onResult(cacheResult); + ImageServiceMetrics.recordFetchImageUrlResult( + mClientId, + cacheResult == null + ? SalientImageUrlFetchResult.FAILED_FROM_CACHE + : SalientImageUrlFetchResult.SUCCEED_FROM_CACHE); return; } @@ -117,9 +124,19 @@ (salientImageUrl) -> { mSalientImageUrlCache.put(pageUrl, salientImageUrl); callback.onResult(salientImageUrl); + ImageServiceMetrics.recordFetchImageUrlResult( + mClientId, + salientImageUrl == null + ? SalientImageUrlFetchResult.FAILED_FROM_NETWORK + : SalientImageUrlFetchResult + .SUCCEED_FROM_NETWORK); })); } + static String clientIdToString(@ClientId.EnumType int clientId) { + return ImageServiceBridgeJni.get().clientIdToString(clientId); + } + boolean isUrlCachedForTesting(GURL pageUrl, GURL imageUrl) { return mSalientImageUrlCache.containsKey(pageUrl) && mSalientImageUrlCache.containsValue(imageUrl); @@ -131,8 +148,13 @@ @NativeMethods public interface Natives { + // Static methods. long init(@JniType("Profile*") Profile profile); + @JniType("std::string") + String clientIdToString(@ClientId.EnumType int clientId); + + // Instance methods. void destroy(long nativeImageServiceBridge); void fetchImageUrlFor(
diff --git a/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceMetrics.java b/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceMetrics.java new file mode 100644 index 0000000..59d4c8f --- /dev/null +++ b/chrome/browser/page_image_service/android/java/src/org/chromium/chrome/browser/page_image_service/ImageServiceMetrics.java
@@ -0,0 +1,45 @@ +// 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.page_image_service; + +import androidx.annotation.IntDef; + +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.page_image_service.mojom.ClientId.EnumType; + +/** Allows java access to the native ImageService. */ +public class ImageServiceMetrics { + static final String HISTOGRAM_SALIENT_IMAGE_URL_FETCH_RESULT = + "PageImageService.Android.SalientImageUrlFetchResult"; + + // These values are persisted to logs. Entries should not be renumbered and numeric values + // should never be reused. + // + // The values must be consistent with SalientImageUrlFetchResult in enums.xml. + @IntDef({ + SalientImageUrlFetchResult.FAILED_FROM_NETWORK, + SalientImageUrlFetchResult.FAILED_FROM_CACHE, + SalientImageUrlFetchResult.SUCCEED_FROM_NETWORK, + SalientImageUrlFetchResult.SUCCEED_FROM_CACHE, + SalientImageUrlFetchResult.NUM_ENTRIES + }) + @interface SalientImageUrlFetchResult { + int FAILED_FROM_NETWORK = 0; + int FAILED_FROM_CACHE = 1; + int SUCCEED_FROM_NETWORK = 2; + int SUCCEED_FROM_CACHE = 3; + int NUM_ENTRIES = 4; + } + + public static void recordFetchImageUrlResult( + @EnumType int clientId, @SalientImageUrlFetchResult int result) { + RecordHistogram.recordEnumeratedHistogram( + HISTOGRAM_SALIENT_IMAGE_URL_FETCH_RESULT + + "." + + ImageServiceBridge.clientIdToString(clientId), + result, + SalientImageUrlFetchResult.NUM_ENTRIES); + } +}
diff --git a/chrome/browser/page_image_service/android/junit/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridgeUnitTest.java b/chrome/browser/page_image_service/android/junit/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridgeUnitTest.java index 8cba50d..efddf4a 100644 --- a/chrome/browser/page_image_service/android/junit/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridgeUnitTest.java +++ b/chrome/browser/page_image_service/android/junit/src/org/chromium/chrome/browser/page_image_service/ImageServiceBridgeUnitTest.java
@@ -7,9 +7,11 @@ import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -29,7 +31,9 @@ import org.chromium.base.Callback; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.page_image_service.ImageServiceMetrics.SalientImageUrlFetchResult; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.image_fetcher.ImageFetcher; import org.chromium.page_image_service.mojom.ClientId; @@ -47,6 +51,9 @@ private static final GURL PAGE_URL = JUnitTestGURLs.URL_1; private static final GURL SALIENT_IMAGE_URL = JUnitTestGURLs.URL_2; private static final int CLIENT_ID = ClientId.BOOKMARKS; + private static final String STRING_CLIENT_ID = "Test"; + private static final String TEST_HISTOGRAM = + "PageImageService.Android.SalientImageUrlFetchResult." + STRING_CLIENT_ID; @Mock private ImageServiceBridge.Natives mImageServiceBridgeJni; @Mock private Profile mProfile; @@ -67,11 +74,18 @@ mProfile, mImageFetcher); verify(mImageServiceBridgeJni).init(eq(mProfile)); + doReturn(STRING_CLIENT_ID).when(mImageServiceBridgeJni).clientIdToString(anyInt()); } @Test @SmallTest public void testFetchImageUrlFor() { + HistogramWatcher histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + TEST_HISTOGRAM, SalientImageUrlFetchResult.FAILED_FROM_NETWORK) + .build(); + mImageServiceBridge.fetchImageUrlFor(/* isAccountData= */ true, PAGE_URL, mUrlCallback); verify(mImageServiceBridgeJni) @@ -85,11 +99,34 @@ // Verifies the case that no salient image URL is found. mUrlCallbackCaptor.getValue().onResult(null); verify(mUrlCallback).onResult(isNull()); + histogramWatcher.assertExpected(); + + histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + TEST_HISTOGRAM, SalientImageUrlFetchResult.FAILED_FROM_CACHE) + .build(); + + mImageServiceBridge.fetchImageUrlFor(/* isAccountData= */ true, PAGE_URL, mUrlCallback); + histogramWatcher.assertExpected(); + + histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + TEST_HISTOGRAM, SalientImageUrlFetchResult.SUCCEED_FROM_NETWORK) + .build(); // Verifies the case that a salient image URL if found. mUrlCallbackCaptor.getValue().onResult(SALIENT_IMAGE_URL); verify(mUrlCallback).onResult(eq(SALIENT_IMAGE_URL)); assertTrue(mImageServiceBridge.isUrlCachedForTesting(PAGE_URL, SALIENT_IMAGE_URL)); + histogramWatcher.assertExpected(); + + histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + TEST_HISTOGRAM, SalientImageUrlFetchResult.SUCCEED_FROM_CACHE) + .build(); // Verifies that the cached salient image URL will be used immediately if exists. mImageServiceBridge.fetchImageUrlFor(/* isAccountData= */ true, PAGE_URL, mUrlCallback);
diff --git a/chrome/browser/password_manager/android/account_storage_notice/BUILD.gn b/chrome/browser/password_manager/android/account_storage_notice/BUILD.gn index d246e5a..70a6006b 100644 --- a/chrome/browser/password_manager/android/account_storage_notice/BUILD.gn +++ b/chrome/browser/password_manager/android/account_storage_notice/BUILD.gn
@@ -37,6 +37,7 @@ ":resources", "//base:base_java", "//chrome/browser/flags:java", + "//chrome/browser/password_manager/android/account_storage_toggle:java", "//chrome/browser/preferences:java", "//chrome/browser/ui/android/strings:ui_strings_grd", "//components/browser_ui/bottomsheet/android:java",
diff --git a/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeCoordinator.java b/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeCoordinator.java index 98b6514..7a966be 100644 --- a/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeCoordinator.java +++ b/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeCoordinator.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.password_manager.account_storage_notice; import android.content.Intent; +import android.os.Bundle; import androidx.annotation.Nullable; @@ -12,6 +13,7 @@ import org.jni_zero.NativeMethods; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.password_manager.account_storage_toggle.AccountStorageToggleFragmentArgs; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; @@ -109,11 +111,15 @@ } private void onSettingsLinkClicked() { + Bundle fragmentArgs = new Bundle(); + fragmentArgs.putBoolean(AccountStorageToggleFragmentArgs.HIGHLIGHT, true); + // TODO(crbug.com/338576301): Launch the unified settings panel instead if + // ReplaceSyncPromosWithSignInPromos is enabled. Intent intent = mSettingsLauncher.createSettingsActivityIntent( mWindowAndroid.getContext().get(), SettingsFragment.GOOGLE_SERVICES, - /* fragmentArgs= */ null); + fragmentArgs); mWindowAndroid.showIntent(intent, this::onSettingsClosed, /* errorId= */ null); }
diff --git a/chrome/browser/password_manager/android/account_storage_toggle/BUILD.gn b/chrome/browser/password_manager/android/account_storage_toggle/BUILD.gn new file mode 100644 index 0000000..653d662 --- /dev/null +++ b/chrome/browser/password_manager/android/account_storage_toggle/BUILD.gn
@@ -0,0 +1,9 @@ +# 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("//build/config/android/rules.gni") + +android_library("java") { + sources = [ "java/src/org/chromium/chrome/browser/password_manager/account_storage_toggle/AccountStorageToggleFragmentArgs.java" ] +}
diff --git a/chrome/browser/password_manager/android/account_storage_toggle/java/src/org/chromium/chrome/browser/password_manager/account_storage_toggle/AccountStorageToggleFragmentArgs.java b/chrome/browser/password_manager/android/account_storage_toggle/java/src/org/chromium/chrome/browser/password_manager/account_storage_toggle/AccountStorageToggleFragmentArgs.java new file mode 100644 index 0000000..4cbae05 --- /dev/null +++ b/chrome/browser/password_manager/android/account_storage_toggle/java/src/org/chromium/chrome/browser/password_manager/account_storage_toggle/AccountStorageToggleFragmentArgs.java
@@ -0,0 +1,17 @@ +// 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.password_manager.account_storage_toggle; + +/** + * The account storage toggle controls whether signed-in non-syncing users have access to account + * passwords. It is housed by different fragments depending on certain feature flags. This class + * contains the common arguments used by such fragments to customize the look of the toggle. + */ +public class AccountStorageToggleFragmentArgs { + // Name for a boolean argument controlling whether to highlight the toggle. + public static final String HIGHLIGHT = "highlight_account_storage_toggle"; + + private AccountStorageToggleFragmentArgs() {} +}
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos_unittest.cc b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos_unittest.cc index e9f7bf6..4423d73e 100644 --- a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos_unittest.cc +++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos_unittest.cc
@@ -215,7 +215,7 @@ base::test::ScopedFeatureList feature_list; base::FieldTrialParams params; params["guest_reclaim_enabled"] = "true"; - feature_list.InitAndEnableFeatureWithParameters(arc::kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(arc::kGuestSwap, params); memory_instance()->set_reclaim_all_result(2, 1); // Making arc session trim result to be false to be sure it's not being used. FakeArcSessionHolder session_holder(arc_session_runner()); @@ -243,7 +243,7 @@ base::test::ScopedFeatureList feature_list; base::FieldTrialParams params; params["guest_reclaim_enabled"] = "true"; - feature_list.InitAndEnableFeatureWithParameters(arc::kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(arc::kGuestSwap, params); memory_instance()->set_reclaim_all_result(0, 0); std::optional<bool> result; @@ -269,7 +269,7 @@ base::FieldTrialParams params; params["guest_reclaim_enabled"] = "true"; params["guest_reclaim_only_anonymous"] = "true"; - feature_list.InitAndEnableFeatureWithParameters(arc::kGuestZram, params); + feature_list.InitAndEnableFeatureWithParameters(arc::kGuestSwap, params); memory_instance()->set_reclaim_all_result(0, 0); memory_instance()->set_reclaim_anon_result(2, 0); @@ -293,7 +293,7 @@ FakeArcSessionHolder session_holder(arc_session_runner()); session_holder.session()->set_trim_result(true, ""); base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(arc::kGuestZram); + feature_list.InitAndDisableFeature(arc::kGuestSwap); // If memory_instance is used then the trim operation should fail. memory_instance()->set_reclaim_all_result(0, 0); @@ -312,7 +312,7 @@ FakeArcSessionHolder session_holder(arc_session_runner()); session_holder.session()->set_trim_result(true, ""); base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(arc::kGuestZram); + feature_list.InitAndEnableFeature(arc::kGuestSwap); // If memory_instance is used then the trim operation should fail. memory_instance()->set_reclaim_all_result(0, 0);
diff --git a/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc index 25d12bf..9750c72 100644 --- a/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc
@@ -88,6 +88,62 @@ const base::FilePath::CharType kPictureInPictureDocumentPipPage[] = FILE_PATH_LITERAL("media/picture-in-picture/document-pip.html"); +// Observes a views::Widget and waits for it to be active or inactive. +class WidgetActivationWaiter : public views::WidgetObserver { + public: + explicit WidgetActivationWaiter(views::Widget* widget) : widget_(widget) { + CHECK(widget_); + widget_->AddObserver(this); + } + WidgetActivationWaiter(const WidgetActivationWaiter&) = delete; + WidgetActivationWaiter& operator=(const WidgetActivationWaiter&) = delete; + ~WidgetActivationWaiter() override { + if (widget_) { + widget_->RemoveObserver(this); + widget_ = nullptr; + } + } + + // Eventually returns true if the actual activation state matches `activated`. + // Returns false if the Widget is destroyed before that activation state ever + // matches `activated`. + bool WaitForActivationState(bool activated) { + if (!widget_) { + return false; + } + + if (widget_->IsActive() == activated) { + return true; + } + + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); + + if (!widget_) { + return false; + } + return widget_->IsActive() == activated; + } + + // views::WidgetObserver: + + void OnWidgetDestroying(views::Widget*) override { + widget_->RemoveObserver(this); + widget_ = nullptr; + run_loop_->Quit(); + } + + void OnWidgetActivationChanged(views::Widget*, bool active) override { + if (run_loop_) { + run_loop_->Quit(); + } + } + + private: + raw_ptr<views::Widget> widget_; + std::unique_ptr<base::RunLoop> run_loop_; +}; + class DocumentPictureInPictureWindowControllerBrowserTest : public InProcessBrowserTest, public testing::WithParamInterface<gfx::Size> { @@ -809,3 +865,29 @@ auto* browser_view = BrowserView::GetBrowserViewForBrowser(pip_browser); EXPECT_EQ(size, browser_view->GetContentsSize()); } + +// When `window.open()` is called from a picture-in-picture window, it must lose +// focus to the newly opened window to prevent multiple popunders from opening +// when a user types multiple keys in a picture-in-picture window. +IN_PROC_BROWSER_TEST_F(DocumentPictureInPictureWindowControllerBrowserTest, + WindowOpenLosesFocus) { + LoadTabAndEnterPictureInPicture(browser()); + auto* web_contents = window_controller()->GetChildWebContents(); + ASSERT_TRUE(web_contents); + views::Widget* pip_widget = views::Widget::GetWidgetForNativeWindow( + web_contents->GetTopLevelNativeWindow()); + ASSERT_TRUE(pip_widget); + WidgetActivationWaiter widget_activation_waiter(pip_widget); + + // Ensure that the picture-in-picture window has system focus. + pip_widget->Activate(); + ASSERT_TRUE(widget_activation_waiter.WaitForActivationState(true)); + + // Call `window.open()` to open a popup window. + EXPECT_TRUE( + ExecJs(web_contents, + "window.open('about:blank', '_blank', 'width=300,height=300');")); + + // The picture-in-picture window should no longer have system focus. + EXPECT_TRUE(widget_activation_waiter.WaitForActivationState(false)); +}
diff --git a/chrome/browser/platform_experience/win b/chrome/browser/platform_experience/win index 8789889..e11c66c 160000 --- a/chrome/browser/platform_experience/win +++ b/chrome/browser/platform_experience/win
@@ -1 +1 @@ -Subproject commit 8789889d7ba6da10e53a0bcca61418518dd7ad8d +Subproject commit e11c66cf5dcfd34a03fbd475d93b8a068b9479ee
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 9e541b3..324d066 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -2265,6 +2265,14 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_CHROMEOS_ASH) + handlers->AddHandler(std::make_unique<IntRangePolicyHandler>( + key::kMemorySaverModeSavings, + performance_manager::user_tuning::prefs::kMemorySaverModeAggressiveness, + static_cast<int>(performance_manager::user_tuning::prefs:: + MemorySaverModeAggressiveness::kConservative), + static_cast<int>(performance_manager::user_tuning::prefs:: + MemorySaverModeAggressiveness::kAggressive), + false)); handlers->AddHandler( std::make_unique<performance_manager::MemorySaverPolicyHandler>()); // Note: This needs to be created after `DefaultSearchPolicyHandler`.
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.cc b/chrome/browser/policy/messaging_layer/public/report_client.cc index 4bb87d5..0529517e 100644 --- a/chrome/browser/policy/messaging_layer/public/report_client.cc +++ b/chrome/browser/policy/messaging_layer/public/report_client.cc
@@ -11,6 +11,7 @@ #include "base/functional/callback.h" #include "base/memory/ptr_util.h" #include "base/memory/scoped_refptr.h" +#include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/path_service.h" #include "base/strings/strcat.h" @@ -26,6 +27,7 @@ #include "components/reporting/client/dm_token_retriever.h" #include "components/reporting/client/report_queue_configuration.h" #include "components/reporting/storage/storage_module_interface.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/reporting/util/statusor.h" @@ -347,6 +349,10 @@ std::move(start_uploader_cb) .Run(base::unexpected( Status(error::UNAVAILABLE, "Client not available"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::REPORTING_CLIENT_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } auto* const client = static_cast<ReportingClient*>(instance.get()); @@ -367,6 +373,10 @@ std::move(start_uploader_cb) .Run(base::unexpected( Status(error::UNAVAILABLE, "Uploader not available"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::UPLOAD_PROVIDER_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } upload_provider_ = CreateLocalUploadProvider(storage()); @@ -379,6 +389,10 @@ bool need_encryption_key, std::vector<EncryptedRecord> records, ScopedReservation scoped_reservation) { if (!upload_provider) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::UPLOAD_PROVIDER_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return Status{error::UNAVAILABLE, "Uploader not available"}; } upload_provider->RequestUploadEncryptedRecords(
diff --git a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc index 051fac4..84397b1 100644 --- a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc +++ b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc
@@ -11,6 +11,7 @@ #include "base/files/file.h" #include "base/files/file_util.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "base/sequence_checker.h" #include "base/strings/strcat.h" #include "base/strings/string_split.h" @@ -26,6 +27,7 @@ #include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "chrome/browser/policy/messaging_layer/upload/file_upload_job.h" #include "components/reporting/resources/resource_manager.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -166,6 +168,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -225,6 +231,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -241,6 +251,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -393,6 +407,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -435,6 +453,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -544,6 +566,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -680,6 +706,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } @@ -721,6 +751,10 @@ if (!delegate()) { Complete(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; }
diff --git a/chrome/browser/policy/messaging_layer/upload/file_upload_job.cc b/chrome/browser/policy/messaging_layer/upload/file_upload_job.cc index 2270b0c..460814a 100644 --- a/chrome/browser/policy/messaging_layer/upload/file_upload_job.cc +++ b/chrome/browser/policy/messaging_layer/upload/file_upload_job.cc
@@ -16,6 +16,7 @@ #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/sequence_checker.h" #include "base/strings/strcat.h" @@ -32,6 +33,7 @@ #include "components/reporting/proto/synced/upload_tracker.pb.h" #include "components/reporting/resources/resource_manager.h" #include "components/reporting/storage/storage_module_interface.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" namespace reporting { @@ -51,6 +53,10 @@ if (!delegate) { std::move(cb).Run(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_JOB_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } delegate->DoInitiate(origin_path, upload_parameters, std::move(cb)); @@ -68,6 +74,10 @@ if (!delegate) { std::move(cb).Run(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_JOB_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } delegate->DoNextStep(total, uploaded, session_token, @@ -81,6 +91,10 @@ if (!delegate) { std::move(cb).Run(base::unexpected( Status(error::UNAVAILABLE, "Delegate is unavailable"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_UPLOAD_JOB_DELEGATE_IS_NULL, + UnavailableErrorReason::MAX_VALUE); return; } delegate->DoFinalize(session_token, std::move(cb));
diff --git a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc index 96beed6a..70a3b5833 100644 --- a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc +++ b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc
@@ -16,6 +16,7 @@ #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/memory/singleton.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/strcat.h" #include "base/task/bind_post_task.h" #include "base/time/time.h" @@ -46,6 +47,7 @@ #include "components/reporting/proto/synced/record_constants.pb.h" #include "components/reporting/resources/resource_manager.h" #include "components/reporting/util/encrypted_reporting_json_keys.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/reporting/util/status_macros.h" #include "components/signin/public/identity_manager/identity_manager.h" @@ -206,6 +208,10 @@ Status no_dm_token_status{error::UNAVAILABLE, "Device DM token not set"}; std::move(enqueued_cb).Run(base::unexpected(no_dm_token_status)); std::move(callback).Run(base::unexpected(std::move(no_dm_token_status))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::DEVICE_DM_TOKEN_NOT_SET, + UnavailableErrorReason::MAX_VALUE); return; } context.Set(json_keys::kDevice, @@ -249,6 +255,10 @@ } if (!g_browser_process || !g_browser_process->platform_part() || !g_browser_process->platform_part()->browser_policy_connector_ash()) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_BROWSER, + UnavailableErrorReason::MAX_VALUE); return base::unexpected( Status(error::UNAVAILABLE, "Browser process not fit to retrieve CloudPolicyManager")); @@ -260,6 +270,10 @@ // Android doesn't have access to a device level CloudPolicyClient, so get // the PrimaryUserProfile CloudPolicyClient. if (!ProfileManager::GetPrimaryUserProfile()) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_PROFILE, + UnavailableErrorReason::MAX_VALUE); return base::unexpected(Status(error::UNAVAILABLE, "PrimaryUserProfile not fit to retrieve " "CloudPolicyManager")); @@ -267,6 +281,10 @@ return ProfileManager::GetPrimaryUserProfile()->GetUserCloudPolicyManager(); #else if (!g_browser_process || !g_browser_process->browser_policy_connector()) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_BROWSER, + UnavailableErrorReason::MAX_VALUE); return base::unexpected(Status(error::UNAVAILABLE, "Browser process not fit to retrieve " "CloudPolicyManager"));
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc index 753ca9c3..f5dd0b71 100644 --- a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc +++ b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc
@@ -7,6 +7,7 @@ #include <tuple> #include "base/functional/bind.h" +#include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/task/sequenced_task_runner.h" #include "base/trace_event/base_tracing.h" @@ -109,6 +110,9 @@ base::BindOnce(&PrewarmHttpDiskCacheManager::MaybeProcessNextQueuedJob, weak_factory_.GetWeakPtr())); } + + base::UmaHistogramCounts100("Blink.LCPP.PrewarmHttpDiskCacheURL.Count", + top_frame_subresource_urls.size()); } void PrewarmHttpDiskCacheManager::MaybeAddPrewarmJob( @@ -209,6 +213,8 @@ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "success", success); CHECK(!use_read_and_discard_body_option_); + base::UmaHistogramBoolean( + "Blink.LCPP.PrewarmHttpDiskCache.DownloadBody.CacheExists", success); DoComplete(); } @@ -217,13 +223,15 @@ } void PrewarmHttpDiskCacheManager::OnHeadersOnly( - scoped_refptr<net::HttpResponseHeaders> ignored) { + scoped_refptr<net::HttpResponseHeaders> headers) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); TRACE_EVENT_WITH_FLOW0("loading", "PrewarmHttpDiskCacheManager::OnHeadersOnly", TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); CHECK(use_read_and_discard_body_option_); + base::UmaHistogramBoolean( + "Blink.LCPP.PrewarmHttpDiskCache.HeadersOnly.CacheExists", bool(headers)); DoComplete(); }
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc index 7e02574..b9e4055 100644 --- a/chrome/browser/predictors/loading_predictor_tab_helper.cc +++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/timer/elapsed_timer.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/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h" @@ -173,6 +174,7 @@ // would be sent to the renderer process upon navigation commit. void MaybeSetLCPPNavigationHint(content::NavigationHandle& navigation_handle, LoadingPredictor& predictor) { + base::ElapsedTimer timer; if (!blink::LcppEnabled() || !navigation_handle.IsInOutermostMainFrame() || navigation_handle.IsSameDocument()) { return; @@ -202,6 +204,8 @@ base::UmaHistogramEnumeration( "LoadingPredictor.SetLCPPNavigationHint.Status", LcppHintStatus::kSucceedToSet); + base::UmaHistogramTimes("LoadingPredictor.SetLCPPNavigationHint.Time", + timer.Elapsed()); } else { base::UmaHistogramEnumeration( "LoadingPredictor.SetLCPPNavigationHint.Status",
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java index 9bf5cdc..a9a7a70 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -296,33 +296,36 @@ private static class TranslationObserverImpl implements TranslationObserver { private Tab mTab; private long mHandle; + private WebContents mWebContents; void observeTab(Tab tab) { - if (mTab != null) { - stopObservingTab(mTab); - } + stopObservingTab(mTab); + // A tab's WebContents can change and we'll only find out later, so keep track of the + // WebContents we registered the observer on. WebContents webContents = tab.getWebContents(); - if (webContents == null) { + if (webContents == null || webContents.isDestroyed()) { return; } - mHandle = TranslateBridge.addTranslationObserver(webContents, this); + mWebContents = webContents; + mHandle = TranslateBridge.addTranslationObserver(mWebContents, this); mTab = tab; } + // If `tab` isn't null, only stop observing if it matches the tab being observed. void stopObservingTab(Tab tab) { - if (mTab == null || mTab != tab) { + if (tab != null && mTab != tab) { return; } - WebContents webContents = tab.getWebContents(); - if (webContents != null && mHandle != 0L) { - TranslateBridge.removeTranslationObserver(webContents, mHandle); + if (mWebContents != null && !mWebContents.isDestroyed() && mHandle != 0L) { + TranslateBridge.removeTranslationObserver(mWebContents, mHandle); } mTab = null; mHandle = 0L; + mWebContents = null; } } @@ -498,6 +501,8 @@ @Override public void onTabSelected(Tab tab) { + mCurrentTabTranslationObserver.stopObservingTab(null); + // This method is called when a tab is manually selected by user or // other reason, for example opening a new tab. // For redirects, it will be called multiple times - for the original @@ -530,7 +535,7 @@ updatedRestored.restore(); tab.getUserDataHost().removeUserData(USER_DATA_KEY); } - addTranslationObserver(tab); + maybeAddTranslationObserver(tab); } } @@ -553,7 +558,12 @@ public void onContentChanged(Tab tab) { // Required to register the observer on navigation and reload, since it // isn't safe to do in onPageLoadStarted(). - addTranslationObserver(tab); + mCurrentTabTranslationObserver.stopObservingTab(tab); + maybeAddTranslationObserver(tab); + + if (tab == mCurrentlyPlayingTab) { + mPlayingTabTranslationObserver.stopObservingTab(tab); + } } @Override @@ -564,16 +574,11 @@ removeTranslationObservers(tab); } - private void addTranslationObserver(Tab tab) { + private void maybeAddTranslationObserver(Tab tab) { if (isURLReadAloudSupported(tab.getUrl())) { mCurrentTabTranslationObserver.observeTab(tab); } } - - private void removeTranslationObservers(Tab tab) { - mPlayingTabTranslationObserver.stopObservingTab(tab); - mCurrentTabTranslationObserver.stopObservingTab(tab); - } }; mIncognitoTabObserver = @@ -899,7 +904,7 @@ mPlayback = null; mPlayerCoordinator.recordPlaybackDuration(); } - mPlayingTabTranslationObserver.stopObservingTab(mCurrentlyPlayingTab); + mPlayingTabTranslationObserver.stopObservingTab(null); mCurrentlyPlayingTab = null; mGlobalRenderFrameId = null; mCurrentPlaybackData = null; @@ -921,6 +926,9 @@ if (mTabObserver != null) { mTabObserver.destroy(); } + + removeTranslationObservers(null); + mHighlightingEnabled.removeObserver(ReadAloudController.this::onHighlightingEnabledChanged); ApplicationStatus.unregisterApplicationStateListener(this); resetCurrentPlayback(); @@ -1413,6 +1421,11 @@ } } + private void removeTranslationObservers(Tab tab) { + mPlayingTabTranslationObserver.stopObservingTab(tab); + mCurrentTabTranslationObserver.stopObservingTab(tab); + } + // Tests. public void setHighlighterForTests(Highlighter highighter) { mHighlighter = highighter;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java index 377162a..358f9c4f 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
@@ -255,6 +255,7 @@ mClock = new FakeClock(); ReadAloudController.setClockForTesting(mClock); + doReturn(false).when(mWebContents).isDestroyed(); mTab = mTabModelSelector.getCurrentTab(); mTab.setGurlOverrideForTesting(sTestGURL); mTab.setWebContentsOverrideForTesting(mWebContents); @@ -1551,10 +1552,94 @@ public void testTranslationListenersUnregistered_nullWebContents() { assertEquals(1, mFakeTranslateBridge.getObserverCount()); - // If tab has null web contents, we should not try to remove translation observers. + // If tab has null web contents, we should still remove the observer from whatever + // WebContents it was added to. doReturn(null).when(mTab).getWebContents(); mController.getTabModelTabObserverforTests().onDestroyed(mTab); - assertEquals(1, mFakeTranslateBridge.getObserverCount()); + assertEquals(0, mFakeTranslateBridge.getObserverCount()); + } + + @Test + public void testTranslationListener_tabWebContentsChanged() { + // An observer is added during ReadAloudController creation through onTabSelected(). + assertEquals(1, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Simulate WebContents changing. + WebContents otherWebContents = Mockito.mock(WebContents.class); + mTab.setWebContentsOverrideForTesting(otherWebContents); + mController.getTabModelTabObserverforTests().onContentChanged(mTab); + + // Observer should have been removed from old WebContents and added to the new one. + assertEquals(0, mFakeTranslateBridge.getObserverCount(mWebContents)); + assertEquals(1, mFakeTranslateBridge.getObserverCount(otherWebContents)); + } + + @Test + public void testTranslationListener_unsupportedURLTabSelected() { + // An observer is added during ReadAloudController creation through onTabSelected(). + assertEquals(1, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Select a different tab with an invalid URL. + WebContents otherWebContents = Mockito.mock(WebContents.class); + MockTab tab = mTabModelSelector.addMockTab(); + tab.setWebContentsOverrideForTesting(otherWebContents); + tab.setUrl(new GURL("")); + mController.getTabModelTabObserverforTests().onTabSelected(tab); + + // The observer should have been removed from the original WebContents. No need to observe + // translation on the new tab since it's not readable: the observer will be added on + // onContentChanged() if the user navigates to a readable page. + assertEquals(0, mFakeTranslateBridge.getObserverCount(mWebContents)); + assertEquals(0, mFakeTranslateBridge.getObserverCount(otherWebContents)); + } + + @Test + public void testTranslationListener_playingTabWebContentsChanged() { + // An observer is added during ReadAloudController creation through onTabSelected(). + assertEquals(1, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Play tab. + requestAndStartPlayback(); + assertEquals(2, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Switching WebContents of playing tab should remove the "playing tab" translation observer + // and the "current tab" translation observer since mTab was also the currently selected + // tab. + WebContents otherWebContents = Mockito.mock(WebContents.class); + mTab.setWebContentsOverrideForTesting(otherWebContents); + mController.getTabModelTabObserverforTests().onContentChanged(mTab); + assertEquals(0, mFakeTranslateBridge.getObserverCount(mWebContents)); + } + + @Test + public void testTranslationListener_onTabSelected() { + // An observer is added during ReadAloudController creation through onTabSelected(). + assertEquals(1, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Select a different tab with a valid URL. + WebContents otherWebContents = Mockito.mock(WebContents.class); + MockTab tab = mTabModelSelector.addMockTab(); + tab.setWebContentsOverrideForTesting(otherWebContents); + tab.setUrl(new GURL("https://some.cool.website/")); + mController.getTabModelTabObserverforTests().onTabSelected(tab); + + // The observer should have been removed from the original WebContents and the new tab's + // WebContents should be observed. + assertEquals(0, mFakeTranslateBridge.getObserverCount(mWebContents)); + assertEquals(1, mFakeTranslateBridge.getObserverCount(otherWebContents)); + } + + @Test + public void testTranslationListenersRemovedWhenControllerDestroyed() { + // An observer is added during ReadAloudController creation through onTabSelected(). + assertEquals(1, mFakeTranslateBridge.getObserverCount(mWebContents)); + + // Play tab. + requestAndStartPlayback(); + assertEquals(2, mFakeTranslateBridge.getObserverCount(mWebContents)); + + mController.destroy(); + assertEquals(0, mFakeTranslateBridge.getObserverCount(mWebContents)); } @Test
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 3b1f6cf90..f83ef6c 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -4621,11 +4621,18 @@ // A PDF plugin exists in a child frame embedded inside the PDF extension's // frame. To trigger any plugin action, detect this child frame and trigger // the actions from there. - content::RenderFrameHost* extension_rfh = - chrome_pdf::features::IsOopifPdfEnabled() - ? pdf_frame_util::FindFullPagePdfExtensionHost(source_web_contents_) - : source_web_contents_->GetPrimaryMainFrame(); - plugin_rfh = pdf_frame_util::FindPdfChildFrame(extension_rfh); + content::RenderFrameHost* rfh = GetRenderFrameHost(); + if (chrome_pdf::features::IsOopifPdfEnabled() && IsFrameInPdfViewer(rfh)) { + // For OOPIF PDF viewer, the current frame should be the PDF plugin frame. + // The PDF extension frame shouldn't be performing any plugin actions. + CHECK(rfh->GetProcess()->IsPdf()); + plugin_rfh = rfh; + } else { + // For GuestView PDF viewer, find the plugin frame by using the PDF + // extension frame. + plugin_rfh = pdf_frame_util::FindPdfChildFrame( + source_web_contents_->GetPrimaryMainFrame()); + } #endif if (!plugin_rfh) plugin_rfh = source_web_contents_->GetPrimaryMainFrame();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc index f79011b..462e9ff 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -519,7 +519,6 @@ WebContents* web_contents = GetActiveWebContents(); - // The context menu will be created inside the extension frame. extension_frame_ = pdf_extension_test_util::GetOnlyPdfExtensionHost(web_contents); if (!extension_frame_) { @@ -528,7 +527,18 @@ } EXPECT_NE(extension_frame_, web_contents->GetPrimaryMainFrame()); - if (!UseOopif()) { + // The target frame for the context menu. + content::RenderFrameHost* target_frame; + + if (UseOopif()) { + // In OOPIF PDF viewer, the target frame should be the PDF plugin frame. + target_frame = + pdf_extension_test_util::GetOnlyPdfPluginFrame(web_contents); + if (!target_frame) { + ADD_FAILURE() << "Failed to get PDF plugin frame."; + return nullptr; + } + } else { content::BrowserPluginGuestManager* guest_manager = web_contents->GetBrowserContext()->GetGuestManager(); WebContents* guest_contents = @@ -538,11 +548,15 @@ return nullptr; } EXPECT_EQ(extension_frame_, guest_contents->GetPrimaryMainFrame()); + + // In GuestView PDF viewer, the target frame should be the PDF extension + // frame. + target_frame = extension_frame_; } content::ContextMenuParams params; params.page_url = page_url; - params.frame_url = extension_frame_->GetLastCommittedURL(); + params.frame_url = target_frame->GetLastCommittedURL(); params.media_type = blink::mojom::ContextMenuDataMediaType::kPlugin; params.media_flags |= blink::ContextMenuData::kMediaCanRotate; params.selection_text = info.selection_text; @@ -551,7 +565,7 @@ params.edit_flags |= blink::ContextMenuDataEditFlags::kCanCopy; auto menu = - std::make_unique<TestRenderViewContextMenu>(*extension_frame_, params); + std::make_unique<TestRenderViewContextMenu>(*target_frame, params); menu->Init(); return menu; } @@ -614,6 +628,40 @@ ASSERT_FALSE(menu.IsItemPresent(IDC_RELOAD)); } + // Helper method for testing rotation items in the context menu. + void TestRotate(std::unique_ptr<TestRenderViewContextMenu> menu, + content::RenderFrameHost* target_rfh) { + auto cb = [](base::OnceClosure quit_loop, + content::RenderFrameHost* expected_rfh, + blink::mojom::PluginActionType expected_action_type, + content::RenderFrameHost* rfh, + blink::mojom::PluginActionType action_type) { + EXPECT_EQ(expected_rfh, rfh); + EXPECT_EQ(expected_action_type, action_type); + std::move(quit_loop).Run(); + }; + + { + // Rotate clockwise. + base::RunLoop run_loop; + menu->RegisterExecutePluginActionCallbackForTesting( + base::BindOnce(cb, run_loop.QuitClosure(), target_rfh, + blink::mojom::PluginActionType::kRotate90Clockwise)); + menu->ExecuteCommand(IDC_CONTENT_CONTEXT_ROTATECW, 0); + run_loop.Run(); + } + + { + // Rotate counterclockwise. + base::RunLoop run_loop; + menu->RegisterExecutePluginActionCallbackForTesting(base::BindOnce( + cb, run_loop.QuitClosure(), target_rfh, + blink::mojom::PluginActionType::kRotate90Counterclockwise)); + menu->ExecuteCommand(IDC_CONTENT_CONTEXT_ROTATECCW, 0); + run_loop.Run(); + } + } + content::RenderFrameHost* extension_frame() { return extension_frame_; } private: @@ -2803,40 +2851,60 @@ } IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride, - Rotate) { + RotateInFullPagePdf) { std::unique_ptr<TestRenderViewContextMenu> menu = SetupAndCreateMenu(); ASSERT_TRUE(menu); content::RenderFrameHost* target_rfh = pdf_frame_util::FindPdfChildFrame(extension_frame()); - auto cb = [](base::OnceClosure quit_loop, - content::RenderFrameHost* expected_rfh, - blink::mojom::PluginActionType expected_action_type, - content::RenderFrameHost* rfh, - blink::mojom::PluginActionType action_type) { - EXPECT_EQ(expected_rfh, rfh); - EXPECT_EQ(expected_action_type, action_type); - std::move(quit_loop).Run(); - }; - { - // Rotate clockwise. - base::RunLoop run_loop; - menu->RegisterExecutePluginActionCallbackForTesting( - base::BindOnce(cb, run_loop.QuitClosure(), target_rfh, - blink::mojom::PluginActionType::kRotate90Clockwise)); - menu->ExecuteCommand(IDC_CONTENT_CONTEXT_ROTATECW, 0); - run_loop.Run(); - } + TestRotate(std::move(menu), target_rfh); +} - { - // Rotate counterclockwise. - base::RunLoop run_loop; - menu->RegisterExecutePluginActionCallbackForTesting(base::BindOnce( - cb, run_loop.QuitClosure(), target_rfh, - blink::mojom::PluginActionType::kRotate90Counterclockwise)); - menu->ExecuteCommand(IDC_CONTENT_CONTEXT_ROTATECCW, 0); - run_loop.Run(); - } +class OopifPdfPluginContextMenuBrowserTest + : public PdfPluginContextMenuBrowserTest { + public: + OopifPdfPluginContextMenuBrowserTest() = default; + + OopifPdfPluginContextMenuBrowserTest(const PdfPluginContextMenuBrowserTest&) = + delete; + OopifPdfPluginContextMenuBrowserTest& operator=( + const OopifPdfPluginContextMenuBrowserTest&) = delete; + + ~OopifPdfPluginContextMenuBrowserTest() override = default; + + bool UseOopif() const override { return true; } +}; + +IN_PROC_BROWSER_TEST_F(OopifPdfPluginContextMenuBrowserTest, + RotateInEmbeddedPdf) { + // Load a page with a PDF file inside. + const GURL page_url = embedded_test_server()->GetURL("/pdf/test-iframe.html"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url)); + + WebContents* web_contents = GetActiveWebContents(); + + // Wait for the PDF content frame to be created. + ASSERT_TRUE(GetTestPdfViewerStreamManager(web_contents) + ->WaitUntilPdfLoadedInFirstChild()); + + // Get the PDF content frame. + content::RenderFrameHost* content_frame = + pdf_extension_test_util::GetOnlyPdfPluginFrame(web_contents); + ASSERT_TRUE(content_frame); + + // Create a context menu in the PDF content frame. + content::ContextMenuParams params; + params.page_url = page_url; + params.frame_url = content_frame->GetLastCommittedURL(); + params.media_type = blink::mojom::ContextMenuDataMediaType::kPlugin; + auto menu = + std::make_unique<TestRenderViewContextMenu>(*content_frame, params); + menu->Init(); + + ASSERT_TRUE(menu); + content::RenderFrameHost* target_rfh = menu->GetRenderFrameHost(); + + TestRotate(std::move(menu), target_rfh); } // TODO(crbug.com/40268279): Stop testing both modes after OOPIF PDF viewer
diff --git a/chrome/browser/resources/about_sys/BUILD.gn b/chrome/browser/resources/about_sys/BUILD.gn index 56e5628..db626ac 100644 --- a/chrome/browser/resources/about_sys/BUILD.gn +++ b/chrome/browser/resources/about_sys/BUILD.gn
@@ -10,14 +10,17 @@ grd_prefix = "about_sys" static_files = [ "about_sys.html" ] web_component_files = [ "app.ts" ] + css_files = [ "app.css" ] non_web_component_files = [ "browser_proxy.ts" ] + html_to_wrapper_template = "detect" + ts_composite = true ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] ts_deps = [ "//chrome/browser/resources/key_value_pair_viewer_shared:build_ts", - "//third_party/polymer/v3_0:library", + "//third_party/lit/v3_0:build_ts", "//ui/webui/resources/js:build_ts", ] ts_path_mappings = [ "/shared/key_value_pair_viewer/*|" + rebase_path(
diff --git a/chrome/browser/resources/about_sys/app.css b/chrome/browser/resources/about_sys/app.css new file mode 100644 index 0000000..c297dbe5 --- /dev/null +++ b/chrome/browser/resources/about_sys/app.css
@@ -0,0 +1,50 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #scheme=relative + * #css_wrapper_metadata_end */ + +h1 { + margin: 0; +} + +#header { + background: rgb(60, 111, 235); + border: 1px solid rgb(58, 117, 189); + border-radius: 6px; + margin-bottom: 9px; + overflow: hidden; + padding: 6px 0; + text-shadow: 0 0 2px black; +} + +#header h1 { + color: white; + display: inline; + font-size: 0.92rem; + font-weight: bold; +} + +#header h1::before { + -webkit-mask-image: url(chrome://resources/images/icon_settings.svg); + -webkit-mask-position: center; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 24px; + background-color: white; + content: ''; + display: inline-block; + height: 20px; + vertical-align: middle; + width: 37px; +} + +#header p { + color: white; + display: inline; + font-size: 0.72rem; + font-style: italic; + padding-inline-start: 6px; +}
diff --git a/chrome/browser/resources/about_sys/app.html b/chrome/browser/resources/about_sys/app.html index dcb3d65d..7450872 100644 --- a/chrome/browser/resources/about_sys/app.html +++ b/chrome/browser/resources/about_sys/app.html
@@ -1,46 +1,3 @@ -<style> - h1 { - margin: 0; - } - - #header { - background: rgb(60, 111, 235); - border: 1px solid rgb(58, 117, 189); - border-radius: 6px; - margin-bottom: 9px; - overflow: hidden; - padding: 6px 0; - text-shadow: 0 0 2px black; - } - - #header h1 { - color: white; - display: inline; - font-size: 0.92rem; - font-weight: bold; - } - - #header h1::before { - -webkit-mask-image: url(chrome://resources/images/icon_settings.svg); - -webkit-mask-position: center; - -webkit-mask-repeat: no-repeat; - -webkit-mask-size: 24px; - background-color: white; - content: ''; - display: inline-block; - height: 20px; - vertical-align: middle; - width: 37px; - } - - #header p { - color: white; - display: inline; - font-size: 0.72rem; - font-style: italic; - padding-inline-start: 6px; - } -</style> <if expr="is_chromeos"> <link rel="stylesheet" href="chrome://resources/css/os_header.css"> </if> @@ -52,9 +9,9 @@ --> <div class="os-link-container-container" <if expr="chromeos_ash"> - hidden$="[[!isLacrosEnabled_]]" - on-click="onOsLinkContainerClick_" - on-auxclick="onOsLinkContainerAuxClick_" + ?hidden="${!this.isLacrosEnabled_}" + @click="${this.onOsLinkContainerClick_}" + @auxclick="${this.onOsLinkContainerAuxClick_}" </if> > <div class="os-link-container"> @@ -70,5 +27,5 @@ <p>$i18n{description}</p> </div> -<key-value-pair-viewer loading="[[loading_]]" entries="[[entries_]]"> -</key-value-pair-viewer> \ No newline at end of file +<key-value-pair-viewer ?loading="${this.loading_}" .entries="${this.entries_}"> +</key-value-pair-viewer>
diff --git a/chrome/browser/resources/about_sys/app.ts b/chrome/browser/resources/about_sys/app.ts index 89507238..afe156c 100644 --- a/chrome/browser/resources/about_sys/app.ts +++ b/chrome/browser/resources/about_sys/app.ts
@@ -6,43 +6,52 @@ import './strings.m.js'; import type {KeyValuePairEntry} from '/shared/key_value_pair_viewer/key_value_pair_entry.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; -import {getTemplate} from './app.html.js'; +import {getCss} from './app.css.js'; +import {getHtml} from './app.html.js'; import type {SystemLog} from './browser_proxy.js'; import {BrowserProxyImpl} from './browser_proxy.js'; -export interface SystemAppElement { +export interface AppElement { $: { title: HTMLElement, }; } -export class SystemAppElement extends PolymerElement { +export class AppElement extends CrLitElement { static get is() { return 'system-app'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - entries_: Array, + entries_: {type: Array}, + + // <if expr="chromeos_ash"> + isLacrosEnabled_: {type: Boolean}, + // </if> + loading_: { type: Boolean, - value: false, - reflectToAttribute: true, + reflect: true, }, }; } - private entries_: KeyValuePairEntry[]; + protected entries_: KeyValuePairEntry[] = []; // <if expr="chromeos_ash"> - private isLacrosEnabled_: boolean; + protected isLacrosEnabled_: boolean = false; // </if> - private loading_: boolean; + protected loading_: boolean = false; override async connectedCallback() { super.connectedCallback(); @@ -67,15 +76,17 @@ } // <if expr="chromeos_ash"> - private onOsLinkContainerClick_(event: MouseEvent) { + protected onOsLinkContainerClick_(event: MouseEvent) { this.handleOsLinkContainerClick_(event); } - private onOsLinkContainerAuxClick_(event: MouseEvent) { + + protected onOsLinkContainerAuxClick_(event: MouseEvent) { // Make middle-clicks have the same effects as Ctrl+clicks if (event.button === 1) { this.handleOsLinkContainerClick_(event); } } + private handleOsLinkContainerClick_(event: MouseEvent) { if (event.target instanceof Element && event.target.id === 'osLinkHref') { event.preventDefault(); @@ -87,8 +98,8 @@ declare global { interface HTMLElementTagNameMap { - 'system-app': SystemAppElement; + 'system-app': AppElement; } } -customElements.define(SystemAppElement.is, SystemAppElement); +customElements.define(AppElement.is, AppElement);
diff --git a/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.html b/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.html index dbf5b6e..ca4d17f 100644 --- a/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.html +++ b/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.html
@@ -143,6 +143,30 @@ label="Facial gesture"> </settings-dropdown-menu> </div> +<h2 class="hr">Press 'toggle overview' key</h2> +<div class="settings-box first"> + <div class="start settings-box-text" aria-hidden="true"> + Face gesture + </div> + <settings-dropdown-menu + id="keyPressToggleOverviewDropdown" + menu-options="[[keyPressToggleOverviewMenuOptions_]]" + pref="{{keyPressToggleOverviewPref_}}" + label="Facial gesture"> + </settings-dropdown-menu> +</div> +<h2 class="hr">Press 'media play/pause' key</h2> +<div class="settings-box first"> + <div class="start settings-box-text" aria-hidden="true"> + Face gesture + </div> + <settings-dropdown-menu + id="keyPressMediaPlayPauseDropdown" + menu-options="[[keyPressMediaPlayPauseMenuOptions_]]" + pref="{{keyPressMediaPlayPausePref_}}" + label="Facial gesture"> + </settings-dropdown-menu> +</div> <h2>Recognition confidence</h2> <div class="settings-box first"> <div class="start settings-box-text" aria-hidden="true">
diff --git a/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.ts b/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.ts index fc1424b..4b6bb36 100644 --- a/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.ts +++ b/chrome/browser/resources/ash/settings/os_a11y_page/facegaze_facial_expression_subpage.ts
@@ -85,6 +85,16 @@ value: () => [], }, + keyPressToggleOverviewMenuOptions_: { + type: Array, + value: () => [], + }, + + keyPressMediaPlayPauseMenuOptions_: { + type: Array, + value: () => [], + }, + leftClickPref_: { type: Object, value(): chrome.settingsPrivate.PrefObject { @@ -195,6 +205,28 @@ }, }, + keyPressToggleOverviewPref_: { + type: Object, + value(): chrome.settingsPrivate.PrefObject { + return { + value: '', + type: chrome.settingsPrivate.PrefType.STRING, + key: 'KEY_PRESS_TOGGLE_OVERVIEW_pref', + }; + }, + }, + + keyPressMediaPlayPausePref_: { + type: Object, + value(): chrome.settingsPrivate.PrefObject { + return { + value: '', + type: chrome.settingsPrivate.PrefType.STRING, + key: 'KEY_PRESS_MEDIA_PLAY_PAUSE_pref', + }; + }, + }, + browInnerUpPref_: { type: Object, computed: @@ -293,6 +325,8 @@ 'updateKeyPressLeftPref_(keyPressLeftPref_.*)', 'updateKeyPressRightPref_(keyPressRightPref_.*)', 'updateKeyPressUpPref_(keyPressUpPref_.*)', + 'updateKeyPressToggleOverviewPref_(keyPressToggleOverviewPref_.*)', + 'updateKeyPressMediaPlayPausePref_(keyPressMediaPlayPausePref_.*)', 'updateBrowInnerUpPref_(browInnerUpPref_.*)', 'updateBrowsDownPref_(browsDownPref_.*)', 'updateEyeSquintLeftPref_(eyeSquintLeftPref_.*)', @@ -321,6 +355,8 @@ private keyPressLeftMenuOptions_: DropdownMenuOptionList; private keyPressRightMenuOptions_: DropdownMenuOptionList; private keyPressUpMenuOptions_: DropdownMenuOptionList; + private keyPressToggleOverviewMenuOptions_: DropdownMenuOptionList; + private keyPressMediaPlayPauseMenuOptions_: DropdownMenuOptionList; private leftClickPref_: chrome.settingsPrivate.PrefObject<string>; private rightClickPref_: chrome.settingsPrivate.PrefObject<string>; private longClickLeftPref_: chrome.settingsPrivate.PrefObject<string>; @@ -331,6 +367,10 @@ private keyPressLeftPref_: chrome.settingsPrivate.PrefObject<string>; private keyPressRightPref_: chrome.settingsPrivate.PrefObject<string>; private keyPressUpPref_: chrome.settingsPrivate.PrefObject<string>; + private keyPressToggleOverviewPref_: + chrome.settingsPrivate.PrefObject<string>; + private keyPressMediaPlayPausePref_: + chrome.settingsPrivate.PrefObject<string>; private browInnerUpPref_: chrome.settingsPrivate.PrefObject<number>; private browsDownPref_: chrome.settingsPrivate.PrefObject<number>; private eyeSquintLeftPref_: chrome.settingsPrivate.PrefObject<number>; @@ -360,6 +400,8 @@ this.keyPressLeftMenuOptions_ = this.getGestureMenuOptions_(); this.keyPressRightMenuOptions_ = this.getGestureMenuOptions_(); this.keyPressUpMenuOptions_ = this.getGestureMenuOptions_(); + this.keyPressToggleOverviewMenuOptions_ = this.getGestureMenuOptions_(); + this.keyPressMediaPlayPauseMenuOptions_ = this.getGestureMenuOptions_(); this.updateVirtualPrefs_(); } @@ -466,6 +508,10 @@ this.updateVirtualPref_(macrosToGestures, MacroName.KEY_PRESS_RIGHT); this.keyPressUpPref_ = this.updateVirtualPref_(macrosToGestures, MacroName.KEY_PRESS_UP); + this.keyPressToggleOverviewPref_ = this.updateVirtualPref_( + macrosToGestures, MacroName.KEY_PRESS_TOGGLE_OVERVIEW); + this.keyPressMediaPlayPausePref_ = this.updateVirtualPref_( + macrosToGestures, MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE); } private updateVirtualPref_( @@ -536,6 +582,18 @@ MacroName.KEY_PRESS_UP, this.keyPressUpPref_.value); } + private updateKeyPressToggleOverviewPref_(): void { + this.updateFromVirtualPref_( + MacroName.KEY_PRESS_TOGGLE_OVERVIEW, + this.keyPressToggleOverviewPref_.value); + } + + private updateKeyPressMediaPlayPausePref_(): void { + this.updateFromVirtualPref_( + MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE, + this.keyPressMediaPlayPausePref_.value); + } + private setDropdownMenuOptionsHiddenForGesture_( menuOptions: DropdownMenuOptionList, gesture: string, hidden: boolean): void { @@ -569,6 +627,10 @@ const newKeyPressRightMenuOptions = Object.assign(this.keyPressRightMenuOptions_); const newKeyPressUpMenuOptions = Object.assign(this.keyPressUpMenuOptions_); + const newKeyPressToggleOverviewMenuOptions = + Object.assign(this.keyPressToggleOverviewMenuOptions_); + const newKeyPressMediaPlayPauseMenuOptions = + Object.assign(this.keyPressMediaPlayPauseMenuOptions_); const newMenuOptions = [ newLeftClickMenuOptions, newRightClickMenuOptions, @@ -580,6 +642,8 @@ newKeyPressLeftMenuOptions, newKeyPressRightMenuOptions, newKeyPressUpMenuOptions, + newKeyPressToggleOverviewMenuOptions, + newKeyPressMediaPlayPauseMenuOptions, ]; const assignedGestures = { ...this.get('prefs.settings.a11y.face_gaze.gestures_to_macros.value')}; @@ -649,6 +713,14 @@ this.setDropdownMenuOptionsHiddenForGesture_( newKeyPressUpMenuOptions, value, true); } + if (macro !== MacroName.KEY_PRESS_TOGGLE_OVERVIEW) { + this.setDropdownMenuOptionsHiddenForGesture_( + newKeyPressToggleOverviewMenuOptions, value, true); + } + if (macro !== MacroName.KEY_PRESS_MEDIA_PLAY_PAUSE) { + this.setDropdownMenuOptionsHiddenForGesture_( + newKeyPressMediaPlayPauseMenuOptions, value, true); + } } this.set( 'prefs.settings.a11y.face_gaze.gestures_to_macros.value', @@ -671,6 +743,10 @@ this.keyPressLeftMenuOptions_ = newKeyPressLeftMenuOptions; this.keyPressRightMenuOptions_ = newKeyPressRightMenuOptions; this.keyPressUpMenuOptions_ = newKeyPressUpMenuOptions; + this.keyPressToggleOverviewMenuOptions_ = + newKeyPressToggleOverviewMenuOptions; + this.keyPressMediaPlayPauseMenuOptions_ = + newKeyPressMediaPlayPauseMenuOptions; } private getGestureToConfidencePref_(gestureName: FacialGesture):
diff --git a/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.html b/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.html index 61b6754..79ff7cbd1 100644 --- a/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.html +++ b/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.html
@@ -1,6 +1,8 @@ -<div id="appParentalControlsList" class="hr"> - <template is="dom-repeat" items="[[appList_]]" as="app" - sort="alphabeticalSort_"> +<template is="dom-if" if="[[isVerified]]"> + <div id="appParentalControlsList" class="hr"> + <template is="dom-repeat" items="[[appList_]]" as="app" + sort="alphabeticalSort_"> <block-app-item app="[[app]]"></block-app-item> - </template> -</div> + </template> + </div> +</template>
diff --git a/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.ts b/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.ts index fe1dd64..2d624331 100644 --- a/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.ts +++ b/chrome/browser/resources/ash/settings/os_apps_page/app_parental_controls/app_parental_controls_subpage.ts
@@ -7,6 +7,7 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {App, AppParentalControlsHandlerInterface, AppParentalControlsObserverReceiver} from '../../mojom-webui/app_parental_controls_handler.mojom-webui.js'; +import {Router, routes} from '../../router.js'; import {getTemplate} from './app_parental_controls_subpage.html.js'; import {getAppParentalControlsProvider} from './mojo_interface_provider.js'; @@ -26,10 +27,16 @@ type: Array, value: [], }, + + isVerified: { + type: Boolean, + value: false, + }, }; } private appList_: App[]; + private isVerified: boolean; private mojoInterfaceProvider: AppParentalControlsHandlerInterface; private observerReceiver: AppParentalControlsObserverReceiver|null; @@ -49,6 +56,13 @@ this.observerReceiver = new AppParentalControlsObserverReceiver(this); this.mojoInterfaceProvider.addObserver( this.observerReceiver.$.bindNewPipeAndPassRemote()); + + if (!this.isVerified) { + // Redirect to the apps page if the PIN is not verified. + setTimeout(() => { + Router.getInstance().navigateTo(routes.APPS); + }); + } } override disconnectedCallback(): void {
diff --git a/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.html b/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.html index 1cb4356..d091868 100644 --- a/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.html +++ b/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.html
@@ -262,7 +262,8 @@ <template is="dom-if" if="[[isAppParentalControlsFeatureAvailable_]]"> <template is="dom-if" route-path="/app-parental-controls"> <os-settings-subpage page-title="$i18n{appParentalControlsTitle}"> - <settings-app-parental-controls-subpage> + <settings-app-parental-controls-subpage + is-verified="[[isPinVerified_]]"> </settings-app-parental-controls-subpage> </os-settings-subpage> </template>
diff --git a/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.ts b/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.ts index b7b5e121..48bc5cb 100644 --- a/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.ts +++ b/chrome/browser/resources/ash/settings/os_apps_page/os_apps_page.ts
@@ -214,6 +214,11 @@ value: false, }, + isPinVerified_: { + type: Boolean, + value: false, + }, + /** * Used by DeepLinkingMixin to focus this page's deep links. */ @@ -269,6 +274,7 @@ private appsWithNotifications_: AppWithNotifications[]; private isArcVmManageUsbAvailable_: boolean; private isDndEnabled_: boolean; + private isPinVerified_: boolean; private readonly isPlayStoreAvailable_: boolean; private isPluginVmAvailable_: boolean; private isRevampWayfindingEnabled_: boolean; @@ -382,6 +388,7 @@ this.showParentalControlsVerifyPinDialog_ = false; // TODO(b/332936481): Only navigate to the subpage on successful PIN // verification. + this.isPinVerified_ = true; Router.getInstance().navigateTo(routes.APP_PARENTAL_CONTROLS); }
diff --git a/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.html b/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.html index 628b8f8..30e5b8b65 100644 --- a/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.html +++ b/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.html
@@ -172,7 +172,7 @@ if="[[isDriveFsMirrorSyncEnabled_]]" restamp> <div class="hr"></div> - <h2>$i18n{googleDriveFileSyncSectionTitle}</h2> + <h2 class="subsection-header">$i18n{googleDriveFileSyncSectionTitle}</h2> <!-- TODO(b/338154540): Move Bulk pinning into File Sync section. --> <div class="subsection"> <settings-toggle-button
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts index 51d9c91..0bd85f41 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts
@@ -274,6 +274,16 @@ } /** + * Advance the index of the current active menu item by |delta|. + * @param delta The number to add to the active menu item index. + */ + advanceItemBy(delta: number): void { + if (this.activeMenu_) { + this.activeMenu_.advanceItemBy(delta); + } + } + + /** * Clear any previous menus. The menus are all regenerated each time the * menus are opened. */ @@ -578,6 +588,16 @@ this.searchMenu_.activateItem(0); } + /** Sets the index of the current active menu to be the last index. */ + scrollToBottom(): void { + this.activeMenu_!.scrollToBottom(); + } + + /** Sets the index of the current active menu to be 0. */ + scrollToTop(): void { + this.activeMenu_!.scrollToTop(); + } + // The following getters and setters are temporary during the migration from // panel.js.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts index 7cad9434..67276f8 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts
@@ -394,28 +394,6 @@ } } - /** Sets the index of the current active menu to be 0. */ - private scrollToTop_(): void { - // TODO(b/314203187): Not nulls asserted, check that this is correct. - this.menuManager_.activeMenu!.scrollToTop(); - } - - /** Sets the index of the current active menu to be the last index. */ - private scrollToBottom_(): void { - // TODO(b/314203187): Not nulls asserted, check that this is correct. - this.menuManager_.activeMenu!.scrollToBottom(); - } - - /** - * Advance the index of the current active menu item by |delta|. - * @param delta The number to add to the active menu item index. - */ - private advanceItemBy_(delta: number): void { - if (this.menuManager_.activeMenu) { - this.menuManager_.activeMenu.advanceItemBy(delta); - } - } - /** * Called when a key is pressed. Handle arrow keys to navigate the menus, * Esc to close, and Enter/Space to activate an item. @@ -470,25 +448,25 @@ this.menuManager_.advanceActiveMenuBy(1); break; case 'ArrowUp': - this.advanceItemBy_(-1); + this.menuManager_.advanceItemBy(-1); break; case 'ArrowDown': - this.advanceItemBy_(1); + this.menuManager_.advanceItemBy(1); break; case 'Escape': this.closeMenusAndRestoreFocus(); break; case 'PageUp': - this.advanceItemBy_(10); + this.menuManager_.advanceItemBy(10); break; case 'PageDown': - this.advanceItemBy_(-10); + this.menuManager_.advanceItemBy(-10); break; case 'Home': - this.scrollToTop_(); + this.menuManager_.scrollToTop(); break; case 'End': - this.scrollToBottom_(); + this.menuManager_.scrollToBottom(); break; case 'Enter': case ' ':
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js index 62ded48..70a2804 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js
@@ -180,7 +180,7 @@ const originalGroup = Navigator.byItem.group_; assertEquals( - Navigator.byItem.node_.automationNode.htmlAttributes.id, 'group', + Navigator.byItem.node_.automationNode.htmlId, 'group', 'Did not move to group properly'); Navigator.byItem.enterGroup(); @@ -210,8 +210,7 @@ button1 instanceof BackButtonNode, 'button1 should not be a BackButtonNode'); assertEquals( - 'button1', button1.automationNode.htmlAttributes.id, - 'Current node is not button1'); + 'button1', button1.automationNode.htmlId, 'Current node is not button1'); Navigator.byItem.moveForward(); assertFalse( @@ -222,8 +221,7 @@ button2 instanceof BackButtonNode, 'button2 should not be a BackButtonNode'); assertEquals( - 'button2', button2.automationNode.htmlAttributes.id, - 'Current node is not button2'); + 'button2', button2.automationNode.htmlId, 'Current node is not button2'); Navigator.byItem.moveForward(); assertFalse( @@ -237,8 +235,7 @@ button3 instanceof BackButtonNode, 'button3 should not be a BackButtonNode'); assertEquals( - 'button3', button3.automationNode.htmlAttributes.id, - 'Current node is not button3'); + 'button3', button3.automationNode.htmlId, 'Current node is not button3'); Navigator.byItem.moveForward(); assertTrue( @@ -264,8 +261,7 @@ button1 instanceof BackButtonNode, 'button1 should not be a BackButtonNode'); assertEquals( - 'button1', button1.automationNode.htmlAttributes.id, - 'Current node is not button1'); + 'button1', button1.automationNode.htmlId, 'Current node is not button1'); Navigator.byItem.moveBackward(); assertTrue( @@ -281,8 +277,7 @@ button3 instanceof BackButtonNode, 'button3 should not be a BackButtonNode'); assertEquals( - 'button3', button3.automationNode.htmlAttributes.id, - 'Current node is not button3'); + 'button3', button3.automationNode.htmlId, 'Current node is not button3'); Navigator.byItem.moveBackward(); assertFalse( @@ -294,8 +289,7 @@ button2 instanceof BackButtonNode, 'button2 should not be a BackButtonNode'); assertEquals( - 'button2', button2.automationNode.htmlAttributes.id, - 'Current node is not button2'); + 'button2', button2.automationNode.htmlId, 'Current node is not button2'); Navigator.byItem.moveBackward(); assertTrue( @@ -316,7 +310,7 @@ button1 instanceof BackButtonNode, 'button1 should not be a BackButtonNode'); assertEquals( - 'button1', button1.automationNode.htmlAttributes.id, + 'button1', button1.automationNode.htmlId, 'Current node is not button1'); // Simulate the underlying node's deletion. Note that this is different @@ -342,7 +336,7 @@ Navigator.byItem.moveTo_(this.findNodeById('testinput')); const input = Navigator.byItem.node_; assertEquals( - 'testinput', input.automationNode.htmlAttributes.id, + 'testinput', input.automationNode.htmlId, 'Current node is not input'); input.performAction(MenuAction.KEYBOARD); @@ -379,7 +373,7 @@ Navigator.byItem.moveTo_(this.findNodeById('testinput')); const input = Navigator.byItem.node_; assertEquals( - 'testinput', input.automationNode.htmlAttributes.id, + 'testinput', input.automationNode.htmlId, 'Current node is not input'); input.performAction(MenuAction.KEYBOARD); @@ -442,8 +436,7 @@ Navigator.byItem.moveTo_(this.findNodeById('slider')); const slider = Navigator.byItem.node_; assertEquals( - 'slider', slider.automationNode.htmlAttributes.id, - 'Current node is not slider'); + 'slider', slider.automationNode.htmlId, 'Current node is not slider'); // Trigger a children changed on the group. const automationGroup =
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js index 0841a8f5..7f5319d 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js
@@ -55,7 +55,7 @@ * @return {!AutomationNode} */ findNodeById(id) { - const predicate = node => node.htmlAttributes.id === id; + const predicate = node => node.htmlId === id; const nodeString = 'node with id "' + id + '"'; return this.findNodeMatchingPredicate(predicate, nodeString); }
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_illo_icons.html b/chrome/browser/resources/chromeos/login/components/oobe_illo_icons.html index ebff3368..009e836e 100644 --- a/chrome/browser/resources/chromeos/login/components/oobe_illo_icons.html +++ b/chrome/browser/resources/chromeos/login/components/oobe_illo_icons.html
@@ -1281,8 +1281,17 @@ <path d="M281 187.434V240.781C281 242.708 279.32 244.215 277.174 244.215H217.826C215.68 244.215 214 242.708 214 240.781V187.434C214 185.507 215.68 184 217.826 184H277.174C279.227 184.084 281 185.591 281 187.434Z" fill="var(--cros-sys-illo-color1-1)"/> <path d="M264.802 224.936L254.195 214.472L260.814 211.011C261.899 210.437 261.819 208.857 260.671 208.411L235.452 198.521C234.287 198.058 233.139 199.239 233.617 200.403L243.97 225.59C244.432 226.723 246.011 226.787 246.554 225.67L249.856 218.923L260.463 229.387C261.022 229.945 261.931 229.929 262.473 229.371L264.818 226.962C265.361 226.404 265.361 225.495 264.802 224.936Z" fill="var(--cros-sys-illo-color1)"/> </g> - <g id="tuna-spark" viewBox="0 0 48 48" fill="var(--cros-sys-primary)"> - <path d="M24 43.6032C24 40.884 23.496 38.3448 22.4712 35.9712C21.4736 33.6473 20.0416 31.5351 18.252 29.7481C16.465 27.9585 14.3528 26.5264 12.0288 25.5289C9.617 24.4998 7.01887 23.9794 4.3968 24C7.116 24 9.6552 23.496 12.0288 22.4712C16.7271 20.4542 20.4671 16.7039 22.4712 12.0001C23.496 9.61925 24 7.08005 24 4.39685C24 7.07765 24.504 9.61925 25.5288 12.0001C27.532 16.7144 31.2856 20.4681 36 22.4712C38.3808 23.4936 40.92 24 43.6032 24C40.9224 24 38.3808 24.5041 36 25.5289C31.2958 27.5335 27.5453 31.2745 25.5288 35.9737C24.5004 38.384 23.98 40.9828 24 43.6032Z"></path> + <g id="tuna-spark" viewBox="0 0 400 400" fill="none"> + <path d="M200 400C200 372.333 194.667 346.333 184 322C173.667 297.667 159.5 276.5 141.5 258.5C123.5 240.5 102.333 226.333 78 216C53.6667 205.333 27.6667 200 0 200C27.6667 200 53.6667 194.833 78 184.5C102.333 173.833 123.5 159.5 141.5 141.5C159.5 123.5 173.667 102.333 184 78C194.667 53.6666 200 27.6667 200 0C200 27.6667 205.167 53.6666 215.5 78C226.167 102.333 240.5 123.5 258.5 141.5C276.5 159.5 297.667 173.833 322 184.5C346.333 194.833 372.333 200 400 200C372.333 200 346.333 205.333 322 216C297.667 226.333 276.5 240.5 258.5 258.5C240.5 276.5 226.167 297.667 215.5 322C205.167 346.333 200 372.333 200 400Z" fill="url(#paint0_linear_706_14049)"></path> + <defs> + <linearGradient id="paint0_linear_706_14049" x1="124.489" y1="258.555" x2="305.435" y2="105.998" gradientUnits="userSpaceOnUse"> + <stop stop-color="#406AFB"/> + <stop offset="0.258067" stop-color="#078EFB"/> + <stop offset="0.716295" stop-color="#939AFF"/> + <stop offset="1" stop-color="#CD9AEC"/> + <stop offset="1" stop-color="#D698FC"/> + </linearGradient> + </defs> </g> <g id="tuna-illo" viewBox="0 0 600 312" fill="none"> <g clip-path="url(#clip0_2640_137075)"> @@ -1305,6 +1314,59 @@ </clipPath> </defs> </g> + <g id="tuna-illo" viewBox="0 0 512 319" fill="none"> + <rect width="512" height="319" rx="32" fill="white"/> + <rect x="15" y="15" width="482" height="289" rx="19" stroke="#E8F0FE" stroke-width="2"/> + <path d="M14 285.5C14 274.73 22.7304 266 33.5 266H478.5C489.27 266 498 274.73 498 285.5C498 296.27 489.27 305 478.5 305H33.5C22.7305 305 14 296.27 14 285.5Z" fill="#E8F0FE"/> + <rect x="214" y="301" width="8" height="2" rx="1" fill="white"/> + <circle cx="218" cy="286" r="13" fill="white"/> + <circle cx="256" cy="286" r="13" fill="white"/> + <circle cx="294" cy="286" r="13" fill="white"/> + <g clip-path="url(#clip0_703_18141)"> + <path d="M225.953 285.969C224.858 285.969 223.847 285.761 222.884 285.351C221.921 284.928 221.072 284.352 220.36 283.638C219.647 282.924 219.072 282.073 218.65 281.108C218.241 280.143 218.034 279.129 218.034 278.032C218.034 278.014 218.02 278 218.003 278C217.985 278 217.971 278.014 217.971 278.032C217.971 279.129 217.757 280.142 217.335 281.108C216.926 282.073 216.358 282.924 215.645 283.638C214.933 284.352 214.084 284.928 213.121 285.351C212.158 285.761 211.146 285.969 210.051 285.969C210.034 285.969 210.02 285.983 210.02 286C210.02 286.018 210.034 286.032 210.051 286.032C211.146 286.032 212.158 286.246 213.121 286.669C214.084 287.079 214.933 287.649 215.645 288.363C216.358 289.077 216.926 289.928 217.335 290.893C217.757 291.858 217.971 292.871 217.971 293.968C217.971 293.986 217.985 294 218.003 294C218.02 294 218.034 293.986 218.034 293.968C218.034 292.871 218.241 291.858 218.65 290.893C219.072 289.928 219.647 289.077 220.36 288.363C221.072 287.649 221.921 287.079 222.884 286.669C223.847 286.246 224.859 286.032 225.953 286.032C225.971 286.032 225.985 286.018 225.985 286C225.985 285.983 225.971 285.969 225.953 285.969Z" fill="black"/> + <path d="M225.953 285.969C224.858 285.969 223.847 285.761 222.884 285.351C221.921 284.928 221.072 284.352 220.36 283.638C219.647 282.924 219.072 282.073 218.65 281.108C218.241 280.143 218.034 279.129 218.034 278.032C218.034 278.014 218.02 278 218.003 278C217.985 278 217.971 278.014 217.971 278.032C217.971 279.129 217.757 280.142 217.335 281.108C216.926 282.073 216.358 282.924 215.645 283.638C214.933 284.352 214.084 284.928 213.121 285.351C212.158 285.761 211.146 285.969 210.051 285.969C210.034 285.969 210.02 285.983 210.02 286C210.02 286.018 210.034 286.032 210.051 286.032C211.146 286.032 212.158 286.246 213.121 286.669C214.084 287.079 214.933 287.649 215.645 288.363C216.358 289.077 216.926 289.928 217.335 290.893C217.757 291.858 217.971 292.871 217.971 293.968C217.971 293.986 217.985 294 218.003 294C218.02 294 218.034 293.986 218.034 293.968C218.034 292.871 218.241 291.858 218.65 290.893C219.072 289.928 219.647 289.077 220.36 288.363C221.072 287.649 221.921 287.079 222.884 286.669C223.847 286.246 224.859 286.032 225.953 286.032C225.971 286.032 225.985 286.018 225.985 286C225.985 285.983 225.971 285.969 225.953 285.969Z" fill="url(#paint0_linear_703_18141)"/> + </g> + <rect x="27" y="26" width="458" height="231" rx="15" fill="#E8F0FE" stroke="#E8F0FE" stroke-width="2"/> + <g clip-path="url(#clip1_703_18141)"> + <rect width="435.38" height="72" transform="translate(37.9999 35)" fill="white"/> + <circle cx="55.9999" cy="53" r="10" fill="#E8F0FE"/> + <rect x="75.9999" y="43" width="234" height="16" rx="8" fill="#E8F0FE"/> + <rect x="75.9999" y="63" width="353" height="16" rx="8" fill="#E8F0FE"/> + <rect x="75.9999" y="83" width="119" height="16" rx="8" fill="#E8F0FE"/> + <rect width="435.38" height="92" transform="translate(37.9999 107)" fill="white"/> + <g clip-path="url(#clip2_703_18141)"> + <path d="M65.9413 124.961C64.5728 124.961 63.3083 124.701 62.1053 124.189C60.9016 123.66 59.8397 122.94 58.9494 122.047C58.0591 121.155 57.34 120.091 56.8124 118.884C56.3013 117.678 56.0423 116.411 56.0423 115.039C56.0423 115.018 56.0247 115 56.003 115C55.9812 115 55.9637 115.018 55.9637 115.039C55.9637 116.411 55.6962 117.678 55.1687 118.884C54.6574 120.091 53.9468 121.155 53.0565 122.047C52.1664 122.94 51.1045 123.66 49.9009 124.189C48.6973 124.701 47.4326 124.961 46.064 124.961C46.0422 124.961 46.0247 124.979 46.0247 125C46.0247 125.022 46.0422 125.04 46.064 125.04C47.4323 125.04 48.697 125.308 49.9009 125.837C51.1047 126.349 52.1665 127.061 53.0565 127.953C53.9468 128.846 54.6576 129.91 55.1687 131.117C55.6962 132.322 55.9637 133.589 55.9637 134.961C55.9637 134.982 55.9812 135 56.003 135C56.0247 135 56.0423 134.982 56.0423 134.961C56.0423 133.589 56.3013 132.322 56.8123 131.117C57.34 129.91 58.059 128.846 58.9494 127.953C59.8395 127.061 60.9011 126.349 62.1053 125.837C63.3088 125.308 64.573 125.04 65.9413 125.04C65.963 125.04 65.9806 125.022 65.9806 125C65.9806 124.979 65.963 124.961 65.9413 124.961Z" fill="black"/> + <path d="M65.9413 124.961C64.5728 124.961 63.3083 124.701 62.1053 124.189C60.9016 123.66 59.8397 122.94 58.9494 122.047C58.0591 121.155 57.34 120.091 56.8124 118.884C56.3013 117.678 56.0423 116.411 56.0423 115.039C56.0423 115.018 56.0247 115 56.003 115C55.9812 115 55.9637 115.018 55.9637 115.039C55.9637 116.411 55.6962 117.678 55.1687 118.884C54.6574 120.091 53.9468 121.155 53.0565 122.047C52.1664 122.94 51.1045 123.66 49.9009 124.189C48.6973 124.701 47.4326 124.961 46.064 124.961C46.0422 124.961 46.0247 124.979 46.0247 125C46.0247 125.022 46.0422 125.04 46.064 125.04C47.4323 125.04 48.697 125.308 49.9009 125.837C51.1047 126.349 52.1665 127.061 53.0565 127.953C53.9468 128.846 54.6576 129.91 55.1687 131.117C55.6962 132.322 55.9637 133.589 55.9637 134.961C55.9637 134.982 55.9812 135 56.003 135C56.0247 135 56.0423 134.982 56.0423 134.961C56.0423 133.589 56.3013 132.322 56.8123 131.117C57.34 129.91 58.059 128.846 58.9494 127.953C59.8395 127.061 60.9011 126.349 62.1053 125.837C63.3088 125.308 64.573 125.04 65.9413 125.04C65.963 125.04 65.9806 125.022 65.9806 125C65.9806 124.979 65.963 124.961 65.9413 124.961Z" fill="url(#paint1_linear_703_18141)"/> + </g> + <rect x="75.9999" y="115" width="378" height="16" rx="8" fill="#E8F0FE"/> + <rect x="75.9999" y="135" width="351" height="16" rx="8" fill="#E8F0FE"/> + <rect x="75.9999" y="155" width="378" height="16" rx="8" fill="#E8F0FE"/> + <rect x="75.9999" y="175" width="168" height="16" rx="8" fill="#E8F0FE"/> + </g> + <defs> + <linearGradient id="paint0_linear_703_18141" x1="214.988" y1="288.342" x2="222.224" y2="282.256" gradientUnits="userSpaceOnUse"> + <stop stop-color="#217BFE"/> + <stop offset="0.27" stop-color="#078EFB"/> + <stop offset="0.776981" stop-color="#A190FF"/> + <stop offset="1" stop-color="#BD99FE"/> + </linearGradient> + <linearGradient id="paint1_linear_703_18141" x1="52.2354" y1="127.928" x2="61.2793" y2="120.32" gradientUnits="userSpaceOnUse"> + <stop stop-color="#217BFE"/> + <stop offset="0.27" stop-color="#078EFB"/> + <stop offset="0.776981" stop-color="#A190FF"/> + <stop offset="1" stop-color="#BD99FE"/> + </linearGradient> + <clipPath id="clip0_703_18141"> + <rect width="16" height="16" fill="white" transform="translate(210 278)"/> + </clipPath> + <clipPath id="clip1_703_18141"> + <rect x="37.9999" y="35" width="436" height="164" rx="12" fill="white"/> + </clipPath> + <clipPath id="clip2_703_18141"> + <rect width="20" height="20" fill="white" transform="translate(45.9999 115)"/> + </clipPath> + </defs> + </g> </defs> </svg> </iron-iconset-svg>
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_personalized_apps_list.ts b/chrome/browser/resources/chromeos/login/components/oobe_personalized_apps_list.ts index 8f95ec2..11bfe75 100644 --- a/chrome/browser/resources/chromeos/login/components/oobe_personalized_apps_list.ts +++ b/chrome/browser/resources/chromeos/login/components/oobe_personalized_apps_list.ts
@@ -105,6 +105,7 @@ this.selectedAppsCount = 0; this.loadedIconsCount = 0; this.categoriesItemRendered = []; + this.appsList = []; for (const key in this.catgoriesMapApps) { this.categoriesItemRendered.push({'id': key, 'count': 0}); this.catgoriesMapApps[key].forEach(element => {
diff --git a/chrome/browser/resources/chromeos/login/screens/common/personalized_recommend_apps.ts b/chrome/browser/resources/chromeos/login/screens/common/personalized_recommend_apps.ts index cedf2c5..cf365871 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/personalized_recommend_apps.ts +++ b/chrome/browser/resources/chromeos/login/screens/common/personalized_recommend_apps.ts
@@ -100,6 +100,10 @@ return OobeUiState.ONBOARDING; } + override onBeforeShow(): void { + this.setUIStep(PersonalizedAppsStep.LOADING); + } + setCategoriesAppsMapData(categoriesData: CategoriesAppsMap): void { assert(categoriesData !== null); this.shadowRoot!
diff --git a/chrome/browser/resources/commerce/product_specifications/table.ts b/chrome/browser/resources/commerce/product_specifications/table.ts index ecf2d156..f2aa129 100644 --- a/chrome/browser/resources/commerce/product_specifications/table.ts +++ b/chrome/browser/resources/commerce/product_specifications/table.ts
@@ -63,7 +63,7 @@ } private onOpenTabButtonClick_(e: DomRepeatEvent<TableColumn, CustomEvent>) { - this.shoppingApi_.openUrlInNewTab( + this.shoppingApi_.switchToOrOpenTab( {url: this.columns[e.model.index].selectedItem.url}); }
diff --git a/chrome/browser/resources/extensions/detail_view.html b/chrome/browser/resources/extensions/detail_view.html index cee7b2e..8f597c8 100644 --- a/chrome/browser/resources/extensions/detail_view.html +++ b/chrome/browser/resources/extensions/detail_view.html
@@ -47,14 +47,15 @@ padding: var(--cr-section-vertical-padding) var(--cr-section-padding); } - .safety-check-warning-container { + .message-container { align-items: center; background-color: var(--google-grey-50); display: flex; padding: 15px; + margin-top: 2px; } - .safety-check-icon { + .message-icon { align-items: center; align-self: flex-start; display: flex; @@ -63,16 +64,20 @@ fill: var(--panel-icon-color); } - .safety-check-warning-container iron-icon { + .message-container iron-icon { height: var(--cr-icon-size); padding: 6px; width: var(--cr-icon-size); } + .message-text { + flex: 1; + margin-inline-start: 15px; + } + @media (prefers-color-scheme: dark) { - .safety-check-warning-container { - /* Google Grey 911 according to Extensions Safety Check mock. */ - background-color: rgb(53, 54, 58); + .message-container { + background-color: var(--google-grey-800); } } @@ -213,12 +218,13 @@ </cr-icon-button> </template> </div> - <div class="safety-check-warning-container" id="safetyCheckWarningContainer" + + <div id="safetyCheckWarningContainer" class="message-container" hidden$="[[!showSafetyCheck_]]"> <iron-icon aria-hidden="true" icon="extensions-icons:my_extensions" - class="safety-check-icon"> + class="message-icon"> </iron-icon> - <div class="safety-check-wrapper"> + <div class="message-text"> <span class="section-title" aria-level="2"> $i18n{safetyCheckExtensionsDetailPagePrimaryLabel} </span> @@ -233,6 +239,25 @@ $i18n{remove} </cr-button> </div> + + <div id="mv2DeprecationMessage" class="message-container" + hidden$="[[!showMv2DeprecationMessage_]]"> + <iron-icon aria-hidden="true" icon="extensions-icons:my_extensions" + class="message-icon"> + </iron-icon> + <div class="message-text"> + <span class="section-title" aria-level="2"> + $i18n{mv2DeprecationMessageWarningHeader} + </span> + <div class="section-content"> + $i18nRaw{mv2DeprecationMessageWarningSubtitle} + </div> + </div> + <cr-button class="find-alternative-button"> + $i18n{mv2DeprecationPanelFindAlternativeButton} + </cr-button> + </div> + <div class="cr-row first control-line" id="enable-section"> <span class$="[[computeEnabledStyle_(data.state)]]"> [[computeEnabledText_(data.state, '$i18nPolymer{itemOn}',
diff --git a/chrome/browser/resources/extensions/detail_view.ts b/chrome/browser/resources/extensions/detail_view.ts index 2edd55ce..5531de9b 100644 --- a/chrome/browser/resources/extensions/detail_view.ts +++ b/chrome/browser/resources/extensions/detail_view.ts
@@ -109,6 +109,13 @@ observer: 'onShowSafetyCheckChanged_', }, + /** Whether the mv2 deprecation message warning is shown. */ + showMv2DeprecationMessage_: { + type: Boolean, + computed: 'computeShowMv2DeprecationMessage_(' + + 'data.isAffectedByMV2Deprecation)', + }, + /** Whether the extensions blocklist text is shown. */ showBlocklistText_: { type: Boolean, @@ -138,6 +145,7 @@ showActivityLog: boolean; fromActivityLog: boolean; private showSafetyCheck_: boolean; + private showMv2DeprecationMessage_: boolean; private showBlocklistText_: boolean; private size_: string; private sortedViews_: chrome.developerPrivate.ExtensionView[]; @@ -454,6 +462,14 @@ this.data.acknowledgeSafetyCheckWarning !== true); } + /** + * Returns whether the mv2 deprecation message warning should be displayed. + */ + private computeShowMv2DeprecationMessage_(): boolean { + return loadTimeData.getBoolean('MV2DeprecationPanelEnabled') && + this.data.isAffectedByMV2Deprecation; + } + private onShowSafetyCheckChanged_() { if (this.showSafetyCheck_) { chrome.metricsPrivate.recordUserAction('SafetyCheck.DetailWarningShown');
diff --git a/chrome/browser/resources/extensions/item_list.html b/chrome/browser/resources/extensions/item_list.html index 5145136..4501ce5d 100644 --- a/chrome/browser/resources/extensions/item_list.html +++ b/chrome/browser/resources/extensions/item_list.html
@@ -95,21 +95,21 @@ <div id="container"> <managed-footnote hidden="[[filter]]"></managed-footnote> <div id="content-wrapper" style="--max-columns: [[maxColumns_]];"> - <!-- TODO(crbug.com/338528606): Safety Hub Panel adds an empty space when - extensions-review-panel can be shown but it's contents are not visible, - due to the styling of items-container--> - <div class="items-container panel"> - <template is="dom-if" if="[[showSafetyCheckReviewPanel_]]" restamp> - <extensions-review-panel extensions="[[extensions]]" delegate="[[delegate]]"> + <template is="dom-if" if="[[showSafetyCheckReviewPanel_]]" restamp> + <div class="items-container panel"> + <extensions-review-panel + extensions="[[unsafeExtensions_]]" + delegate="[[delegate]]"> </extensions-review-panel> - </template> - </div> + </div> + </template> <template is="dom-if" if="[[showMv2DeprecationPanel_]]" restamp> <div class="items-container panel"> <extensions-mv2-deprecation-panel extensions="[[mv2DeprecatedExtensions_]]" - delegate="[[delegate]]"> + delegate="[[delegate]]" + show-title="[[showSafetyCheckReviewPanel_]]"> </extensions-mv2-deprecation-panel> </div> </template>
diff --git a/chrome/browser/resources/extensions/item_list.ts b/chrome/browser/resources/extensions/item_list.ts index 64fbab0..a2ab3363 100644 --- a/chrome/browser/resources/extensions/item_list.ts +++ b/chrome/browser/resources/extensions/item_list.ts
@@ -61,6 +61,15 @@ }, /** + * List of potentially unsafe extensions that should be visible in the + * review panel. + */ + unsafeExtensions_: { + type: Array, + computed: 'computeUnsafeExtensions_(extensions.*)', + }, + + /** * List of extensions that are affected by the mv2 deprecation and should * be visible in the mv2 deprecation panel. */ @@ -79,10 +88,20 @@ value: 0, }, + /** + * Indicates whether the review panel is shown. + */ showSafetyCheckReviewPanel_: { type: Boolean, - value: () => loadTimeData.getBoolean('safetyCheckShowReviewPanel') || - loadTimeData.getBoolean('safetyHubShowReviewPanel'), + computed: 'computeShowSafetyCheckReviewPanel_(unsafeExtensions_)', + }, + + /** + * Indicates if the review panel has ever been shown. + */ + reviewPanelShown_: { + type: Boolean, + value: false, }, /* @@ -109,11 +128,13 @@ filter: string; private computedFilter_: string; private maxColumns_: number; + private unsafeExtensions_: chrome.developerPrivate.ExtensionInfo[]; private mv2DeprecatedExtensions_: chrome.developerPrivate.ExtensionInfo[]; private shownAppsCount_: number; private shownExtensionsCount_: number; private showMv2DeprecationPanel_: boolean; private showSafetyCheckReviewPanel_: boolean; + private reviewPanelShown_: boolean; private hasSafetyCheckTriggeringExtension_: boolean; getDetailsButton(id: string): HTMLElement|null { @@ -185,10 +206,43 @@ }); } + /** + * Computes the extensions that are potentially unsafe and should be visible + * in the review panel. + */ + private computeUnsafeExtensions_(): chrome.developerPrivate.ExtensionInfo[] { + return this.extensions?.filter( + extension => + !!(extension.safetyCheckText && + extension.safetyCheckText.panelString && + !extension.acknowledgeSafetyCheckWarning)); + } + + /** + * Returns whether the review deprecation panel should be visible. + */ private computeShowSafetyCheckReviewPanel_(): boolean { - return ( - loadTimeData.getBoolean('safetyCheckShowReviewPanel') || - loadTimeData.getBoolean('safetyHubShowReviewPanel')); + // Panel is hidden if neither safety feature is on. + if (!loadTimeData.getBoolean('safetyCheckShowReviewPanel') && + !loadTimeData.getBoolean('safetyHubShowReviewPanel')) { + return false; + } + + // If there are any unsafe extensions, they will be shown in the panel. + // Store this, so we can show the completion info in the panel when there + // are no unsafe extensions left after the user finished reviewing the + // extensions. + // Note: Unsafe extensions may not be initialized at construction, thus we + // check for their existence. + if (this.unsafeExtensions_?.length !== 0) { + this.reviewPanelShown_ = true; + } + + // Panel is visible if there are any unsafe extensions, or the there are + // none left after the user finished reviewing the extensions. + // Note: Unsafe extensions may not be initialized at construction, thus we + // check for their existence. + return this.unsafeExtensions_?.length !== 0 || this.reviewPanelShown_; } private computeHasSafetyCheckTriggeringExtension_(): boolean {
diff --git a/chrome/browser/resources/extensions/mv2_deprecation_panel.html b/chrome/browser/resources/extensions/mv2_deprecation_panel.html index 8a25f6f..0e8a7a6 100644 --- a/chrome/browser/resources/extensions/mv2_deprecation_panel.html +++ b/chrome/browser/resources/extensions/mv2_deprecation_panel.html
@@ -7,8 +7,23 @@ .extension-buttons { margin-inline-start: auto; } + + /* Reformat panel when the panel is the width of one extension card */ + /* clean-css ignore:start */ + @container (max-width:450px) { + /* Set a max width for the extension info so extension buttons can fit on + the same row */ + .panel-extension-info { + max-width: 116px; + } + } + /* clean-css ignore:end */ </style> +<h2 class="panel-title" hidden$="[[!showTitle]]"> + $i18n{mv2DeprecationPanelTitle} +</h2> + <div class="panel-background" id="panelContainer"> <div class="panel-header"> <iron-icon aria-hidden="true" icon="extensions-icons:my_extensions"
diff --git a/chrome/browser/resources/extensions/mv2_deprecation_panel.ts b/chrome/browser/resources/extensions/mv2_deprecation_panel.ts index b7f3237..776d4eb 100644 --- a/chrome/browser/resources/extensions/mv2_deprecation_panel.ts +++ b/chrome/browser/resources/extensions/mv2_deprecation_panel.ts
@@ -50,6 +50,11 @@ }, /** + * Whether the panel title should be shown. + */ + showTitle: Boolean, + + /** * The string for the panel's header. */ headerString_: String, @@ -72,6 +77,7 @@ extensions: chrome.developerPrivate.ExtensionInfo[]; delegate: ItemDelegate&Mv2DeprecationPanelDelegate; + showTitle: boolean; private headerString_: string; private subtitleString_: string; private extensionWithActionMenuOpened_: chrome.developerPrivate.ExtensionInfo;
diff --git a/chrome/browser/resources/extensions/review_panel.html b/chrome/browser/resources/extensions/review_panel.html index 37c4211a..6813825 100644 --- a/chrome/browser/resources/extensions/review_panel.html +++ b/chrome/browser/resources/extensions/review_panel.html
@@ -11,17 +11,6 @@ margin-inline-start: 15px; } - .header-with-icon { - align-items: center; - display: flex; - } - - #safetyHubTitleContainer { - font-size: 15px; - font-weight: 400; - margin: 0 0 16px 5px; - } - cr-icon[icon='cr:check'] { padding-inline-start: 10px; fill: var(--google-green-700); @@ -52,36 +41,19 @@ .cr-row { padding: 0; } - - /* When the panel is the width of one extension card, it will reformat - itself. */ - /* clean-css ignore:start */ - @container (max-width:450px) { - .header-with-icon { - display: grid; - grid-template-columns: auto auto; - } - - #removeAllButton { - grid-column: 2; - margin-inline-start: 20px; - margin-inline-end: auto; - margin-top: 10px; - } - } - /* clean-css ignore:end */ - </style> -<h2 id="safetyHubTitleContainer" + +<h2 id="safetyHubTitleContainer" class="panel-title" hidden$="[[!shouldShowSafetyHubHeader_]]"> $i18n{safetyHubHeader} </h2> -<div class="panel-background" hidden$="[[shouldHideUnsafePanel_]]"> - <cr-expand-button class="panel-header" no-hover + +<div class="panel-background"> + <cr-expand-button no-hover id="expandButton" expanded="{{unsafeExtensionsReviewListExpanded_}}" hidden$="[[!shouldShowUnsafeExtensions_]]"> - <div class="header-with-icon" id="reviewPanelContainer"> + <div class="panel-header" id="reviewPanelContainer"> <cr-icon aria-hidden="true" icon="extensions-icons:my_extensions" class="panel-header-icon"> </cr-icon> @@ -104,7 +76,7 @@ <cr-collapse class="panel-extensions" opened="[[unsafeExtensionsReviewListExpanded_]]" hidden$="[[!shouldShowUnsafeExtensions_]]"> - <template is="dom-repeat" items="[[unsafeExtensions_]]"> + <template is="dom-repeat" items="[[extensions]]"> <div class="panel-extension-row cr-row"> <img class="panel-extension-icon" src="[[item.iconUrl]]" role="presentation">
diff --git a/chrome/browser/resources/extensions/review_panel.ts b/chrome/browser/resources/extensions/review_panel.ts index 71e5b887..027328b2 100644 --- a/chrome/browser/resources/extensions/review_panel.ts +++ b/chrome/browser/resources/extensions/review_panel.ts
@@ -51,6 +51,11 @@ return { delegate: Object, + /** + * List of potentially unsafe extensions. If this list is empty, all the + * unsafe extensions were reviewed and the completion info should be + * visible. + */ extensions: { type: Array, notify: true, @@ -72,14 +77,11 @@ completionMessage_: String, /** - * List of potentially unsafe extensions. This list being empty - * indicates that there are no unsafe extensions to review. + * Indicates whether to show the panel header. */ - unsafeExtensions_: Array, - shouldShowSafetyHubHeader_: { type: Boolean, - computed: 'computeShouldShowSafetyHubHeader_(shouldHideUnsafePanel_)', + value: () => loadTimeData.getBoolean('safetyHubShowReviewPanel'), }, /** @@ -101,15 +103,6 @@ }, /** - * Indicates whether to show any part of the Review Panel. - */ - shouldHideUnsafePanel_: { - type: Boolean, - computed: - 'computeShouldHideUnsafePanel_(shouldShowUnsafeExtensions_, shouldShowCompletionInfo_)', - }, - - /** * Indicates if the list of unsafe extensions is expanded or collapsed. */ unsafeExtensionsReviewListExpanded_: { @@ -150,7 +143,6 @@ private numberOfExtensionsChanged_: number; private reviewPanelShown_: boolean; private completionMetricLogged_: boolean; - private unsafeExtensions_: chrome.developerPrivate.ExtensionInfo[]; private headerString_: string; private subtitleString_: string; private unsafeExtensionsReviewListExpanded_: boolean; @@ -158,42 +150,28 @@ private shouldShowSafetyHubHeader_: boolean; private shouldShowCompletionInfo_: boolean; private shouldShowUnsafeExtensions_: boolean; - private shouldHideUnsafePanel_: boolean; private lastClickedExtensionId_: string; private lastClickedExtensionTriggerReason_: chrome.developerPrivate.SafetyCheckWarningReason; private async onExtensionsChanged_() { - this.unsafeExtensions_ = this.getUnsafeExtensions_(this.extensions); this.headerString_ = await PluralStringProxyImpl.getInstance().getPluralString( - 'safetyCheckTitle', this.unsafeExtensions_.length); + 'safetyCheckTitle', this.extensions.length); this.subtitleString_ = await PluralStringProxyImpl.getInstance().getPluralString( - 'safetyCheckDescription', this.unsafeExtensions_.length); + 'safetyCheckDescription', this.extensions.length); this.completionMessage_ = await PluralStringProxyImpl.getInstance().getPluralString( 'safetyCheckAllDoneForNow', this.numberOfExtensionsChanged_); } - private getUnsafeExtensions_(extensions: - chrome.developerPrivate.ExtensionInfo[]): - chrome.developerPrivate.ExtensionInfo[] { - return extensions?.filter( - extension => - !!(extension.safetyCheckText && - extension.safetyCheckText.panelString && - extension.acknowledgeSafetyCheckWarning !== true)); - } - /** - * Determines whether or not to show the completion info after the user - * finished reviewing extensions. + * Determines whether or not to show the completion info when there are no + * unsafe extensions left. */ private computeShouldShowCompletionInfo_(): boolean { - const updatedUnsafeExtensions = - this.getUnsafeExtensions_(this.extensions) || []; - if (this.reviewPanelShown_ && updatedUnsafeExtensions.length === 0) { + if (this.extensions?.length === 0) { if (!this.completionMetricLogged_) { this.completionMetricLogged_ = true; chrome.metricsPrivate.recordUserAction('SafetyCheck.ReviewCompletion'); @@ -205,12 +183,10 @@ } private computeShouldShowUnsafeExtensions_(): boolean { - const updatedUnsafeExtensions = - this.getUnsafeExtensions_(this.extensions) || []; - if (updatedUnsafeExtensions.length !== 0) { + if (this.extensions?.length !== 0) { if (!this.shouldShowUnsafeExtensions_) { chrome.metricsPrivate.recordUserAction('SafetyCheck.ReviewPanelShown'); - for (const extension of updatedUnsafeExtensions) { + for (const extension of this.extensions) { chrome.metricsPrivate.recordEnumerationValue( SAFETY_HUB_EXTENSION_SHOWN_HISTOGRAM_NAME, convertSafetyCheckReason(extension.safetyCheckWarningReason), @@ -218,7 +194,6 @@ } } this.completionMetricLogged_ = false; - this.reviewPanelShown_ = true; ExtensionsHatsBrowserProxyImpl.getInstance().panelShown(true); return true; } else { @@ -228,13 +203,7 @@ } private computeShouldShowSafetyHubHeader_(): boolean { - return loadTimeData.getBoolean('safetyHubShowReviewPanel') && - !this.shouldHideUnsafePanel_; - } - - private computeShouldHideUnsafePanel_(): boolean { - return !( - this.shouldShowUnsafeExtensions_ || this.shouldShowCompletionInfo_); + return loadTimeData.getBoolean('safetyHubShowReviewPanel'); } /** @@ -298,18 +267,18 @@ chrome.metricsPrivate.recordUserAction( 'SafetyCheck.ReviewPanelRemoveAllClicked'); ExtensionsHatsBrowserProxyImpl.getInstance().removeAllAction( - this.unsafeExtensions_.length); + this.extensions.length); event.stopPropagation(); try { - this.numberOfExtensionsChanged_ = this.unsafeExtensions_.length; - this.unsafeExtensions_.forEach(extension => { + this.numberOfExtensionsChanged_ = this.extensions.length; + this.extensions.forEach(extension => { chrome.metricsPrivate.recordEnumerationValue( SAFETY_HUB_EXTENSION_REMOVED_HISTOGRAM_NAME, convertSafetyCheckReason(extension.safetyCheckWarningReason), SAFETY_HUB_WARNING_REASON_MAX_SIZE); }); await this.delegate.deleteItems( - this.unsafeExtensions_.map(extension => extension.id)); + this.extensions.map(extension => extension.id)); } catch (_) { // The error was almost certainly the user cancelling the dialog. // Reset `numberOfExtensionsChanged_`.
diff --git a/chrome/browser/resources/extensions/shared_style.css b/chrome/browser/resources/extensions/shared_style.css index 24c2213..bcb8692 100644 --- a/chrome/browser/resources/extensions/shared_style.css +++ b/chrome/browser/resources/extensions/shared_style.css
@@ -44,11 +44,6 @@ margin: 0 8px; } -.safety-check-wrapper { - flex: 1; - margin-inline-start: 15px; -} - .matching-restricted-sites-warning { align-items: flex-start; display: flex; @@ -110,6 +105,12 @@ min-width: var(--cr-icon-size); } +.panel-title { + font-size: 15px; + font-weight: 400; + margin: 0 0 16px 5px; +} + .panel-background { background-color: var(--cr-card-background-color); border-radius: var(--cr-card-border-radius); @@ -162,10 +163,15 @@ width: var(--cr-icon-size); } +/* Reformat panel when the panel is the width of one extension card */ /* clean-css ignore:start */ @container (max-width:450px) { .panel-header-icon { - margin-top: 40px; + display: none; + } + + .panel-header-text { + padding-inline-start: 0; } } /* clean-css ignore:end */
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn b/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn index 61a14ed..589e984f 100644 --- a/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn +++ b/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn
@@ -17,9 +17,16 @@ non_web_component_files = [ "key_value_pair_parser.ts" ] + css_files = [ + "key_value_pair_viewer.css", + "key_value_pair_entry.css", + ] + + html_to_wrapper_template = "detect" + ts_composite = true ts_deps = [ - "//third_party/polymer/v3_0:library", + "//third_party/lit/v3_0:build_ts", "//ui/webui/resources/js:build_ts", ]
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.css b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.css new file mode 100644 index 0000000..95a3f8f0 --- /dev/null +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.css
@@ -0,0 +1,59 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #scheme=relative + * #css_wrapper_metadata_end */ + +:host { + display: flex; + font-family: 'Courier New', monospace; + gap: 1rem; + font-size: 0.72rem; + + --cell-border: 1px solid rgb(181, 198, 222); +} + +.name-cell, +.button-cell, +.value-cell { + padding: 8px 6px; +} + +.name-cell { + border-inline-end: var(--cell-border); + width: 200px; + min-width: 200px; + overflow-wrap: break-word; +} + +.button-cell { + text-align: center; + width: 80px; + min-width: 80px; +} + +.value-cell { + border-inline-start: var(--cell-border); + overflow: auto; +} + +.value-cell span { + text-overflow: ellipsis; + white-space: pre-wrap; +} + +:host([collapsible_][collapsed]) .stat-value { + display: none; +} + +.stat-name-link { + color: inherit; + text-decoration: none; +} + +.stat-name-link:hover { + text-decoration: underline; +}
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.html b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.html index 51350bb..74b8d28 100644 --- a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.html +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.html
@@ -1,67 +1,14 @@ -<style> - :host { - display: flex; - font-family: 'Courier New', monospace; - gap: 1rem; - font-size: 0.72rem; - - --cell-border: 1px solid rgb(181, 198, 222); - } - - .name-cell, - .button-cell, - .value-cell { - padding: 8px 6px; - } - - .name-cell { - border-inline-end: var(--cell-border); - width: 200px; - min-width: 200px; - overflow-wrap: break-word; - } - - .button-cell { - text-align: center; - width: 80px; - min-width: 80px; - } - - .value-cell { - border-inline-start: var(--cell-border); - overflow: auto; - } - - .value-cell span { - text-overflow: ellipsis; - white-space: pre-wrap; - } - - :host([collapsible_][collapsed]) .stat-value { - display: none; - } - - .stat-name-link { - color: inherit; - text-decoration: none; - } - - .stat-name-link:hover { - text-decoration: underline; - } -</style> - <div class="name-cell" role="cell"> - <a class="stat-name-link" href="[[getHref_(entry.key)]]" target="_blank" - name="[[entry.key]]"> - 🔗 [[entry.key]] + <a class="stat-name-link" href="${this.getHref_()}" target="_blank" + name="${this.entry.key}"> + 🔗 ${this.entry.key} </a> </div> <div class="button-cell" role="cell"> - <button on-click="onButtonClick_" hidden="[[!collapsible_]]"> - [[getButtonText_(collapsed)]] + <button @click="${this.onButtonClick_}" ?hidden="${!this.collapsible_}"> + ${this.getButtonText_()} </button> </div> <div class="value-cell" role="cell"> - <span class="stat-value">[[entry.value]]</span> + <span class="stat-value">${this.entry.value}</span> </div>
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.ts b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.ts index a4836b1..5a1a57488 100644 --- a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.ts +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_entry.ts
@@ -3,9 +3,11 @@ // found in the LICENSE file. import {assert} from 'chrome://resources/js/assert.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; +import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js'; -import {getTemplate} from './key_value_pair_entry.html.js'; +import {getCss} from './key_value_pair_entry.css.js'; +import {getHtml} from './key_value_pair_entry.html.js'; export const COLLAPSE_THRESHOLD = 200; @@ -20,38 +22,48 @@ 'https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/debugd/docs/log_entries.md'; // </if> -export class KeyValuePairEntryElement extends PolymerElement { +export class KeyValuePairEntryElement extends CrLitElement { static get is() { return 'key-value-pair-entry'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - entry: Object, + entry: {type: Object}, collapsible_: { type: Boolean, - reflectToAttribute: true, - computed: 'computeCollabsible_(entry.statValue)', + reflect: true, }, collapsed: { type: Boolean, - value: true, - reflectToAttribute: true, + reflect: true, }, }; } - entry: KeyValuePairEntry; - collapsed: boolean; - private collapsible_: boolean; + entry: KeyValuePairEntry = {key: '', value: ''}; + collapsed: boolean = true; + protected collapsible_: boolean = false; - private getHref_(): string { + override willUpdate(changedProperties: PropertyValues<this>) { + super.willUpdate(changedProperties); + + if (changedProperties.has('entry')) { + this.collapsible_ = this.entry.value.length > COLLAPSE_THRESHOLD; + } + } + + protected getHref_(): string { // Let URL be anchor to the section of this page by default. let urlPrefix = ''; @@ -64,16 +76,12 @@ return `${urlPrefix}#${this.entry.key}`; } - private computeCollabsible_(): boolean { - return this.entry.value.length > COLLAPSE_THRESHOLD; - } - - private onButtonClick_() { + protected onButtonClick_() { assert(this.collapsible_); this.collapsed = !this.collapsed; } - private getButtonText_(): string { + protected getButtonText_(): string { return this.collapsed ? 'Expand…' : 'Collapse…'; } }
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.css b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.css new file mode 100644 index 0000000..98eb14c9 --- /dev/null +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.css
@@ -0,0 +1,52 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #scheme=relative + * #css_wrapper_metadata_end */ + +h2 { + margin: 0; +} + +#header p { + color: white; + display: inline; + font-size: 0.72rem; + font-style: italic; + padding-inline-start: 6px; +} + +#second-row { + display: flex; + gap: 0.5rem; +} + +#second-row h2 { + color: rgb(58, 117, 189); + display: inline-block; + font-size: 0.92rem; + font-weight: normal; +} + +#spinner { + display: none; + background-image: url(chrome://resources/images/throbber_small.svg); + background-size: 100%; + height: 20px; + width: 20px; +} + +:host([loading]) #spinner { + display: block; +} + +key-value-pair-entry:nth-child(odd) { + background: rgb(239, 243, 255); +} + +button { + font-family: inherit; +}
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.html b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.html index be7d2c8..da3adbb3 100644 --- a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.html +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.html
@@ -1,55 +1,9 @@ -<style> - h2 { - margin: 0; - } - - #header p { - color: white; - display: inline; - font-size: 0.72rem; - font-style: italic; - padding-inline-start: 6px; - } - - #second-row { - display: flex; - gap: 0.5rem; - } - - #second-row h2 { - color: rgb(58, 117, 189); - display: inline-block; - font-size: 0.92rem; - font-weight: normal; - } - - #spinner { - display: none; - background-image: url(chrome://resources/images/throbber_small.svg); - background-size: 100%; - height: 20px; - width: 20px; - } - - :host([loading]) #spinner { - display: block; - } - - key-value-pair-entry:nth-child(odd) { - background: rgb(239, 243, 255); - } - - button { - font-family: inherit; - } -</style> - <div id="second-row"> <h2 id="tableTitle">$i18n{tableTitle}</h2> - <button id="expandAll" on-click="onExpandAllClick_"> + <button id="expandAll" @click="${this.onExpandAllClick_}"> $i18n{expandAllBtn} </button> - <button id="collapseAll" on-click="onCollapseAllClick_"> + <button id="collapseAll" @click="${this.onCollapseAllClick_}"> $i18n{collapseAllBtn} </button> </div> @@ -58,7 +12,7 @@ <div id="spinner" id="spinner"></div> <div id="table"> - <template is="dom-repeat" items="[[entries]]"> - <key-value-pair-entry entry="[[item]]" role="row"></key-value-pair-entry> - </template> + ${this.entries.map(item => html` + <key-value-pair-entry .entry="${item}" role="row"></key-value-pair-entry> + `)} </div>
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.ts b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.ts index 7641820..938dd4c 100644 --- a/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.ts +++ b/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_viewer.ts
@@ -6,11 +6,12 @@ import {EventTracker} from 'chrome://resources/js/event_tracker.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import type {KeyValuePairEntry, KeyValuePairEntryElement} from './key_value_pair_entry.js'; import {parseKeyValuePairEntry} from './key_value_pair_parser.js'; -import {getTemplate} from './key_value_pair_viewer.html.js'; +import {getCss} from './key_value_pair_viewer.css.js'; +import {getHtml} from './key_value_pair_viewer.html.js'; // Limit file size to 10 MiB to prevent hanging on accidental upload. const MAX_FILE_SIZE = 10485760; @@ -26,28 +27,32 @@ }; } -export class KeyValuePairViewerElement extends PolymerElement { +export class KeyValuePairViewerElement extends CrLitElement { static get is() { return 'key-value-pair-viewer'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - entries: String, + entries: {type: String}, + loading: { type: Boolean, - value: false, - reflectToAttribute: true, + reflect: true, }, }; } - loading: boolean; - entries: KeyValuePairEntry[]; + loading: boolean = false; + entries: KeyValuePairEntry[] = []; private eventTracker_: EventTracker = new EventTracker(); @@ -68,7 +73,7 @@ this.eventTracker_.removeAll(); } - private onExpandAllClick_() { + protected onExpandAllClick_() { const entries = this.shadowRoot!.querySelectorAll<KeyValuePairEntryElement>( 'key-value-pair-entry[collapsed]'); for (const entry of entries) { @@ -76,7 +81,7 @@ } } - private onCollapseAllClick_() { + protected onCollapseAllClick_() { const entries = this.shadowRoot!.querySelectorAll<KeyValuePairEntryElement>( 'key-value-pair-entry:not([collapsed])'); for (const entry of entries) {
diff --git a/chrome/browser/resources/lens/overlay/cursor_tooltip.html b/chrome/browser/resources/lens/overlay/cursor_tooltip.html index 659baa0..ae23061 100644 --- a/chrome/browser/resources/lens/overlay/cursor_tooltip.html +++ b/chrome/browser/resources/lens/overlay/cursor_tooltip.html
@@ -4,7 +4,7 @@ background-color: #131D1ECC; border-radius: 8px; left: var(--offset-left); - padding: 6px 16px 6px 12px; + padding: 6px 12px 6px 12px; pointer-events: none; position: absolute; transform: translateX(-50%); @@ -26,7 +26,7 @@ </style> <div id="cursorTooltipContainer" class$="[[getHiddenCursorClass(isPointerInside, - canShowTooltipFromPrefs, disableRendering)]]"> + canShowTooltipFromPrefs, tooltipHidden, isNoneType)]]"> <div id="cursorTooltip"> <span class="tooltip-text">[[tooltipMessage]]</span> </div>
diff --git a/chrome/browser/resources/lens/overlay/cursor_tooltip.ts b/chrome/browser/resources/lens/overlay/cursor_tooltip.ts index f128d222..504ae7b0 100644 --- a/chrome/browser/resources/lens/overlay/cursor_tooltip.ts +++ b/chrome/browser/resources/lens/overlay/cursor_tooltip.ts
@@ -16,10 +16,11 @@ } export enum CursorTooltipType { - REGION_SEARCH = 0, - TEXT_HIGHLIGHT = 1, - CLICK_SEARCH = 2, - LIVE_PAGE = 3, + NONE = 0, + REGION_SEARCH = 1, + TEXT_HIGHLIGHT = 2, + CLICK_SEARCH = 3, + LIVE_PAGE = 4, } export interface CursorTooltipElement { @@ -56,7 +57,13 @@ reflectToAttribute: true, }, - disableRendering: { + tooltipHidden: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + + isNoneType: { type: Boolean, value: false, reflectToAttribute: true, @@ -69,6 +76,9 @@ // The tooltip message string. private tooltipMessage: string; + // The queued tooltip type. + private queuedTooltipType?: CursorTooltipType; + // The queued tooltip message string. private queuedTooltipMessage: string; @@ -81,8 +91,12 @@ // The queued tooltip offset pixels. private queuedOffsetTopPx = 0; - // Whether or not to disable rendering the tooltip. - private disableRendering: boolean; + // Whether or not the tooltip is hidden. + private tooltipHidden: boolean; + + // Whether or not the type is NONE and the tooltip should not be + // rendered. + private isNoneType: boolean; // Whether or not to pause tooltip changes. If true, the tooltip changes // will be queued and applied when this becomes unset. This allows the @@ -100,26 +114,41 @@ } hideTooltip() { - this.disableRendering = true; + this.tooltipHidden = true; } - showTooltip() { - this.disableRendering = false; + unhideTooltip() { + this.tooltipHidden = false; } setPauseTooltipChanges(shouldPauseTooltipChanges: boolean) { this.shouldPauseTooltipChanges = shouldPauseTooltipChanges; - if (!shouldPauseTooltipChanges) { - this.setTooltipFromQueued(); + if (!shouldPauseTooltipChanges && this.queuedTooltipType) { + this.setTooltipImmediately(this.queuedTooltipType); } } setTooltip(type: CursorTooltipType) { + if (this.shouldPauseTooltipChanges) { + this.queuedTooltipType = type; + } else { + this.setTooltipImmediately(type); + } + } + + private setTooltipImmediately(type: CursorTooltipType) { + if (type === CursorTooltipType.NONE) { + this.isNoneType = true; + return; + } + this.queuedTooltipType = undefined; + this.isNoneType = false; let offsetLeftPx = 0; let offsetTopPx = 0; + let tooltipMessage = ''; if (type === CursorTooltipType.LIVE_PAGE) { offsetTopPx = 24; - this.queuedTooltipMessage = this.i18n('cursorTooltipLivePageMessage'); + tooltipMessage = this.i18n('cursorTooltipLivePageMessage'); } else { // Add half the width of the cursor tooltip icon. offsetLeftPx += 16; @@ -129,36 +158,29 @@ if (type === CursorTooltipType.REGION_SEARCH) { offsetTopPx += 6; offsetLeftPx += 3; - this.queuedTooltipMessage = this.i18n('cursorTooltipDragMessage'); + tooltipMessage = this.i18n('cursorTooltipDragMessage'); } else if (type === CursorTooltipType.TEXT_HIGHLIGHT) { offsetTopPx += 8; offsetLeftPx += 3; - this.queuedTooltipMessage = - this.i18n('cursorTooltipTextHighlightMessage'); + tooltipMessage = this.i18n('cursorTooltipTextHighlightMessage'); } else if (type === CursorTooltipType.CLICK_SEARCH) { offsetTopPx += 8; offsetLeftPx += 4; - this.queuedTooltipMessage = this.i18n('cursorTooltipClickMessage'); + tooltipMessage = this.i18n('cursorTooltipClickMessage'); } // LINT.ThenChange(//chrome/browser/resources/lens/overlay/selection_overlay.ts:CursorOffsetValues) } - this.queuedOffsetLeftPx = offsetLeftPx; - this.queuedOffsetTopPx = offsetTopPx; - if (!this.shouldPauseTooltipChanges) { - this.setTooltipFromQueued(); - } - } - private setTooltipFromQueued() { - this.style.setProperty('--offset-top', toPixels(this.queuedOffsetTopPx)); - this.style.setProperty('--offset-left', toPixels(this.queuedOffsetLeftPx)); - this.tooltipMessage = this.queuedTooltipMessage; + this.style.setProperty('--offset-top', toPixels(offsetTopPx)); + this.style.setProperty('--offset-left', toPixels(offsetLeftPx)); + this.tooltipMessage = tooltipMessage; } private getHiddenCursorClass( isPointerInside: boolean, canShowTooltipFromPrefs: boolean, - disableRendering: boolean): string { - return (isPointerInside && canShowTooltipFromPrefs && !disableRendering) ? + tooltipHidden: boolean, isNoneType: boolean): string { + return (isPointerInside && canShowTooltipFromPrefs && !tooltipHidden && + !isNoneType) ? '' : 'hidden'; }
diff --git a/chrome/browser/resources/lens/overlay/initial_toast.html b/chrome/browser/resources/lens/overlay/initial_toast.html index 7f53dfc6..8985aeec 100644 --- a/chrome/browser/resources/lens/overlay/initial_toast.html +++ b/chrome/browser/resources/lens/overlay/initial_toast.html
@@ -60,7 +60,7 @@ <div id="initialToastScrim"></div> </div> <div id="initialToastContainer"> - <div id="initialToast"> + <div id="initialToast" aria-label="$i18n{initialToastLabel}"> <span class="toast-text">$i18n{initialToastMessage}</span> </div> </div> \ No newline at end of file
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts index 2d16c9a..6855e95 100644 --- a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts +++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts
@@ -125,7 +125,7 @@ } private handlePointerLeaveActionButton() { - this.$.cursorTooltip.showTooltip(); + this.$.cursorTooltip.unhideTooltip(); } private onBackgroundScrimClicked() {
diff --git a/chrome/browser/resources/lens/overlay/selection_overlay.ts b/chrome/browser/resources/lens/overlay/selection_overlay.ts index e5ad7e04..343e1f6 100644 --- a/chrome/browser/resources/lens/overlay/selection_overlay.ts +++ b/chrome/browser/resources/lens/overlay/selection_overlay.ts
@@ -137,6 +137,7 @@ private screenshotDataUri: string; private cursorImgUri: string = 'lens.svg'; private isPointerInside = false; + private isPointerInsideContextMenu = false; // The current gesture event. The coordinate values are only accurate if a // gesture has started. private currentGesture: GestureEvent = emptyGestureEvent(); @@ -325,12 +326,14 @@ private handlePointerEnter() { this.isPointerInside = true; - this.dispatchEvent( - new CustomEvent<CursorTooltipData>('set-cursor-tooltip', { - bubbles: true, - composed: true, - detail: {tooltipType: CursorTooltipType.REGION_SEARCH}, - })); + if (!this.isPointerInsideContextMenu) { + this.dispatchEvent( + new CustomEvent<CursorTooltipData>('set-cursor-tooltip', { + bubbles: true, + composed: true, + detail: {tooltipType: CursorTooltipType.REGION_SEARCH}, + })); + } } private handlePointerLeave(event: PointerEvent) { @@ -343,7 +346,7 @@ boundingRect.top <= event.clientY && boundingRect.right >= event.clientX && boundingRect.bottom >= event.clientY; - if (!pointerInBounds) { + if (!pointerInBounds && !this.isPointerInsideContextMenu) { this.dispatchEvent( new CustomEvent<CursorTooltipData>('set-cursor-tooltip', { bubbles: true, @@ -594,11 +597,20 @@ // Make the cursor disappear over the context menu, as if leaving the overlay. private handlePointerEnterContextMenu() { this.isPointerInside = false; + this.isPointerInsideContextMenu = true; + // Hide the cursor tooltip. + this.dispatchEvent( + new CustomEvent<CursorTooltipData>('set-cursor-tooltip', { + bubbles: true, + composed: true, + detail: {tooltipType: CursorTooltipType.NONE}, + })); unfocusShimmer(this, ShimmerControlRequester.CURSOR); } private handlePointerLeaveContextMenu() { this.isPointerInside = true; + this.isPointerInsideContextMenu = false; } }
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html index 86526cf6..6b1a371 100644 --- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html +++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
@@ -28,6 +28,14 @@ z-index: 0; } + #loadingResultsImage { + background-color: white; + } + + :host([dark-mode]) #loadingResultsImage { + background-color: #1F1F1F; + } + :host(:not([is-loading-results])) #loadingResultsImage { z-index: 0; } @@ -120,6 +128,10 @@ margin-inline-start: 8px; margin-inline-end: 12px; } + + :host([dark-mode]) cr-icon-button.icon-arrow-back { + color: #70757A; + } </style> <div id="realboxContainer"> <template is="dom-if" if="[[isBackArrowVisible]]">
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.ts b/chrome/browser/resources/settings/settings_menu/settings_menu.ts index 41cbdf0..4cb617d 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.ts +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
@@ -79,10 +79,10 @@ // <if expr="_google_chrome"> if (loadTimeData.getBoolean('showGetTheMostOutOfChromeSection') && newRoute === this.routes_.GET_MOST_CHROME) { - const about = - this.shadowRoot!.querySelector<HTMLAnchorElement>('#about-menu'); + const about = this.shadowRoot!.querySelector('#about-menu'); assert(about); - this.setSelectedUrl_(about.href); + // Purposefully grabbing the 'href' attribute and not the property. + this.setSelectedPath_(about.getAttribute('href')!); return; } // </if> @@ -90,15 +90,16 @@ // Focus the initially selected path. const anchors = this.shadowRoot!.querySelectorAll('a'); for (let i = 0; i < anchors.length; ++i) { - const anchorRoute = Router.getInstance().getRouteForPath( - anchors[i].getAttribute('href')!); + // Purposefully grabbing the 'href' attribute and not the property. + const pathname = anchors[i].getAttribute('href')!; + const anchorRoute = Router.getInstance().getRouteForPath(pathname); if (anchorRoute && anchorRoute.contains(newRoute)) { - this.setSelectedUrl_(anchors[i].href); + this.setSelectedPath_(pathname); return; } } - this.setSelectedUrl_(''); // Nothing is selected. + this.setSelectedPath_(''); // Nothing is selected. } focusFirstItem() { @@ -120,16 +121,17 @@ } /** - * Keeps both menus in sync. |url| needs to come from |element.href| because - * |iron-list| uses the entire url. Using |getAttribute| will not work. + * Keeps both menus in sync. `path` needs to come from + * `element.getAttribute('href')`. Using `element.href` will not work as it + * would pass the entire URL instead of just the path. */ - private setSelectedUrl_(url: string) { - this.$.menu.selected = url; + private setSelectedPath_(path: string) { + this.$.menu.selected = path; } private onSelectorActivate_(event: CustomEvent<{selected: string}>) { const path = event.detail.selected; - this.setSelectedUrl_(path); + this.setSelectedPath_(path); const route = Router.getInstance().getRouteForPath(path); assert(route, 'settings-menu has an entry with an invalid route.');
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts index 85e441f..364b8a2 100644 --- a/chrome/browser/resources/side_panel/read_anything/app.ts +++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -21,7 +21,7 @@ import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './app.html.js'; -import {minOverflowLengthToScroll, validatedFontName} from './common.js'; +import {minOverflowLengthToScroll, playFromSelectionTimeout, validatedFontName} from './common.js'; import type {ReadAnythingToolbarElement} from './read_anything_toolbar.js'; import {areVoicesEqual, AVAILABLE_GOOGLE_TTS_LOCALES, convertLangOrLocaleForVoicePackManager, convertLangToAnAvailableLangIfPresent, createInitialListOfEnabledLanguages, errorCodeToVoicePackStatusEnum, mojoVoicePackStatusToVoicePackStatusEnum, VoicePackStatus} from './voice_language_util.js'; @@ -442,39 +442,28 @@ if (!this.hasContent_ || !this.speechPlayingState.paused) { return; } - const selection = this.getSelection(); + const selection: Selection = this.getSelection(); assert(selection, 'no selection'); - const {anchorNode, anchorOffset, focusNode, focusOffset} = selection; - if (!anchorNode || !focusNode) { + if (!selection.anchorNode || !selection.focusNode) { // The selection was collapsed by clicking inside the selection. chrome.readingMode.onCollapseSelection(); return; } - let anchorNodeId = this.domNodeToAxNodeIdMap_.get(anchorNode); - let focusNodeId = this.domNodeToAxNodeIdMap_.get(focusNode); - let adjustedAnchorOffset = anchorOffset; - let adjustedFocusOffset = focusOffset; - // If the node was highlighted, then we need to find the parent node which - // we stored in the map, rather than the node itself - if (!anchorNodeId) { - anchorNodeId = this.getHighlightedAncestorId_(anchorNode); - adjustedAnchorOffset += this.getOffsetInAncestor(anchorNode); - } - if (!focusNodeId) { - focusNodeId = this.getHighlightedAncestorId_(focusNode); - adjustedFocusOffset += this.getOffsetInAncestor(focusNode); - } + + const {anchorNodeId, anchorOffset, focusNodeId, focusOffset} = + this.getSelectedIds(); if (!anchorNodeId || !focusNodeId) { return; } chrome.readingMode.onSelectionChange( - anchorNodeId, adjustedAnchorOffset, focusNodeId, adjustedFocusOffset); + anchorNodeId, anchorOffset, focusNodeId, focusOffset); // If there's been a selection, clear the current // Read Aloud highlight. - const element = document.querySelector('.' + currentReadHighlightClass); - if (element && anchorNodeId && focusNodeId) { - element.classList.remove(currentReadHighlightClass); + const elements = + document.querySelectorAll('.' + currentReadHighlightClass); + if (elements.length > 0 && anchorNodeId && focusNodeId) { + elements.forEach(el => el.classList.remove(currentReadHighlightClass)); } // Clear the previously read highlight if there's been a selection. @@ -1320,22 +1309,37 @@ playSpeech() { const container = this.$.container; + const {anchorNode, anchorOffset, focusNode, focusOffset} = + this.getSelection(); + const hasSelection = + anchorNode !== focusNode || anchorOffset !== focusOffset; if (this.speechPlayingState.speechStarted && this.speechPlayingState.paused) { const pausedFromButton = this.speechPlayingState.pauseSource === PauseActionSource.BUTTON_CLICK; - // If word boundaries aren't supported for the given voice, we should - // still continue to use synth.resume, as this is preferable to - // restarting the current message. - if (pausedFromButton && - this.wordBoundaryState.mode !== WordBoundaryMode.BOUNDARY_DETECTED) { - this.synth.resume(); - } else { + let playedFromSelection = false; + if (hasSelection) { this.synth.cancel(); - if (!this.highlightAndPlayInterruptedMessage()) { - // Ensure we're updating Read Aloud state if there's no text to speak. - this.onSpeechFinished(); + chrome.readingMode.onRestartReadAloud(); + playedFromSelection = this.playFromSelection(); + } + + if (!playedFromSelection) { + if (pausedFromButton && + this.wordBoundaryState.mode !== + WordBoundaryMode.BOUNDARY_DETECTED) { + // If word boundaries aren't supported for the given voice, we should + // still continue to use synth.resume, as this is preferable to + // restarting the current message. + this.synth.resume(); + } else { + this.synth.cancel(); + if (!this.highlightAndPlayInterruptedMessage()) { + // Ensure we're updating Read Aloud state if there's no text to + // speak. + this.onSpeechFinished(); + } } } @@ -1351,14 +1355,17 @@ this.updateLinks(); // Now that links are toggled, ensure that the new nodes are also // highlighted. - this.highlightNodes(chrome.readingMode.getCurrentText()); + if (!playedFromSelection) { + this.highlightNodes(chrome.readingMode.getCurrentText()); + } } // If the current read highlight has been cleared from a call to // updateContent, such as for links being toggled on or off via a Read // Aloud play / pause or via a preference change, rehighlight the nodes // after a pause. - if (!container.querySelector('.' + currentReadHighlightClass)) { + if (!playedFromSelection && + !container.querySelector('.' + currentReadHighlightClass)) { this.highlightNodes(chrome.readingMode.getCurrentText()); } @@ -1375,9 +1382,10 @@ this.updateLinks(); } - // TODO(crbug.com/40927698): There should be a way to use AXPosition so - // that this step can be skipped. - if (this.firstTextNodeSetForReadAloud) { + const playedFromSelection = hasSelection && this.playFromSelection(); + if (!playedFromSelection && this.firstTextNodeSetForReadAloud) { + // TODO(crbug.com/40927698): There should be a way to use AXPosition so + // that this step can be skipped. chrome.readingMode.initAxPositionWithNode( this.firstTextNodeSetForReadAloud); if (!this.highlightAndPlayMessage()) { @@ -1388,6 +1396,101 @@ } } + private getSelectedIds(): { + anchorNodeId: number|undefined, + anchorOffset: number, + focusNodeId: number|undefined, + focusOffset: number, + } { + const {anchorNode, anchorOffset, focusNode, focusOffset} = + this.getSelection(); + let anchorNodeId = this.domNodeToAxNodeIdMap_.get(anchorNode); + let focusNodeId = this.domNodeToAxNodeIdMap_.get(focusNode); + let adjustedAnchorOffset = anchorOffset; + let adjustedFocusOffset = focusOffset; + if (!anchorNodeId) { + anchorNodeId = this.getHighlightedAncestorId_(anchorNode); + adjustedAnchorOffset += this.getOffsetInAncestor(anchorNode); + } + if (!focusNodeId) { + focusNodeId = this.getHighlightedAncestorId_(focusNode); + adjustedFocusOffset += this.getOffsetInAncestor(focusNode); + } + return { + anchorNodeId: anchorNodeId, + anchorOffset: adjustedAnchorOffset, + focusNodeId: focusNodeId, + focusOffset: adjustedFocusOffset, + }; + } + + playFromSelection(): boolean { + const selection = this.getSelection(); + if (!this.firstTextNodeSetForReadAloud || !selection) { + return false; + } + + const {anchorNodeId, anchorOffset, focusNodeId, focusOffset} = + this.getSelectedIds(); + // If only one of the ids is present, use that one. + let startingNodeId: number|undefined = + anchorNodeId ? anchorNodeId : focusNodeId; + let startingOffset = anchorNodeId ? anchorOffset : focusOffset; + // If both are present, start with the node that is sooner in the page. + if (anchorNodeId && focusNodeId) { + const pos = + selection.anchorNode.compareDocumentPosition(selection.focusNode); + const focusIsFirst = pos === Node.DOCUMENT_POSITION_PRECEDING; + startingNodeId = focusIsFirst ? focusNodeId : anchorNodeId; + startingOffset = focusIsFirst ? focusOffset : anchorOffset; + } + + if (!startingNodeId) { + return false; + } + + // Clear the selection so we don't keep trying to play from the same + // selection every time they press play. + selection.removeAllRanges(); + // Iterate through the page from the beginning until we get to the + // selection. This is so clicking previous works before the selection and + // so the previous highlights are properly set. + chrome.readingMode.initAxPositionWithNode( + this.firstTextNodeSetForReadAloud); + + // Iterate through the nodes asynchronously so that we can show the spinner + // in the toolbar while we move up to the selection. + setTimeout(() => { + this.movePlaybackToNode_(startingNodeId, startingOffset); + // Set everything to previous and then play the next granularity, which + // includes the selection. + this.resetPreviousHighlight(); + if (!this.highlightAndPlayMessage()) { + this.onSpeechFinished(); + } + }, playFromSelectionTimeout); + + return true; + } + + private movePlaybackToNode_(nodeId: number, offset: number): void { + let currentTextIds = chrome.readingMode.getCurrentText(); + let hasCurrentText = currentTextIds.length > 0; + // Since a node could spread across multiple granularities, we use the + // offset to determine if the selected text is in this granularity or if + // we have to move to the next one. + let startOfSelectionIsInCurrentText = currentTextIds.includes(nodeId) && + chrome.readingMode.getCurrentTextEndIndex(nodeId) > offset; + while (hasCurrentText && !startOfSelectionIsInCurrentText) { + this.highlightNodes(currentTextIds, /*scrollIntoView=*/ false); + chrome.readingMode.movePositionToNextGranularity(); + currentTextIds = chrome.readingMode.getCurrentText(); + hasCurrentText = currentTextIds.length > 0; + startOfSelectionIsInCurrentText = currentTextIds.includes(nodeId) && + chrome.readingMode.getCurrentTextEndIndex(nodeId) > offset; + } + } + highlightAndPlayInterruptedMessage(): boolean { return this.highlightAndPlayMessage(/* isInterrupted = */ true); } @@ -1703,7 +1806,7 @@ this.highlightCurrentText_(startIndex, endIndex, element as HTMLElement); } - highlightNodes(nextTextIds: number[]) { + highlightNodes(nextTextIds: number[], scrollIntoView: boolean = true) { if (nextTextIds.length === 0) { return; } @@ -1720,7 +1823,8 @@ // If the start or end index is invalid, don't use this node. continue; } - this.highlightCurrentText_(start, end, element as HTMLElement); + this.highlightCurrentText_( + start, end, element as HTMLElement, scrollIntoView); } } @@ -1745,8 +1849,8 @@ // suffix text // </span> private highlightCurrentText_( - highlightStart: number, highlightEnd: number, - currentNode: HTMLElement): void { + highlightStart: number, highlightEnd: number, currentNode: HTMLElement, + scrollIntoView: boolean = true): void { const parentOfHighlight = document.createElement('span'); parentOfHighlight.classList.add(parentOfHighlightClass); @@ -1787,7 +1891,9 @@ this.replaceElement(currentNode, parentOfHighlight); // Automatically scroll the text so the highlight stays roughly centered. - readingHighlight.scrollIntoViewIfNeeded(); + if (scrollIntoView) { + readingHighlight.scrollIntoViewIfNeeded(); + } } private onSpeechFinished() {
diff --git a/chrome/browser/resources/side_panel/read_anything/common.ts b/chrome/browser/resources/side_panel/read_anything/common.ts index 94b5fe2..26755af 100644 --- a/chrome/browser/resources/side_panel/read_anything/common.ts +++ b/chrome/browser/resources/side_panel/read_anything/common.ts
@@ -8,6 +8,9 @@ // Determined by experimentation - can be adjusted to fine tune for different // platforms. export const minOverflowLengthToScroll = 75; +export const spinnerDebounceTimeout = 150; +export const playFromSelectionTimeout = spinnerDebounceTimeout + 25; + export const defaultFontName: string = 'sans-serif'; // Defines the valid font names that can be passed to front-end and maps
diff --git a/chrome/browser/resources/side_panel/read_anything/language_menu.ts b/chrome/browser/resources/side_panel/read_anything/language_menu.ts index b782d19..4fc7347 100644 --- a/chrome/browser/resources/side_panel/read_anything/language_menu.ts +++ b/chrome/browser/resources/side_panel/read_anything/language_menu.ts
@@ -12,6 +12,7 @@ import './icons.html.js'; import type {CrDialogElement} from '//resources/cr_elements/cr_dialog/cr_dialog.js'; +import type {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js'; import {I18nMixin} from '//resources/cr_elements/i18n_mixin.js'; import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js'; import type {DomRepeatEvent} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -81,6 +82,14 @@ // directly to better aid in testing. private baseLanguages = AVAILABLE_GOOGLE_TTS_LOCALES; + constructor() { + super(); + this.addEventListener('cr-dialog-open', () => { + this.$.languageMenu.querySelector<CrInputElement>('.search-field') + ?.focus(); + }); + } + private closeLanguageMenu_() { this.$.languageMenu.close(); }
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts index 830133f..ce65749 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
@@ -209,10 +209,15 @@ function onSelectionChange( anchorNodeId: number, anchorOffset: number, focusNodeId: number, focusOffset: number): void; + // Called when a user collapses the selection. This is usually accomplished // by clicking. function onCollapseSelection(): void; + // Called when we are restarting read aloud after we've already started + // playing speech. + function onRestartReadAloud(): void; + // Set the content. Used by tests only. // SnapshotLite is a data structure which resembles an AXTreeUpdate. E.g.: // const axTree = {
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.ts index 6b312b6..2535162 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_anything.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_anything.ts
@@ -10,7 +10,7 @@ export type {CrLazyRenderElement} from '//resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; export type {ReadAnythingElement, WordBoundaryState} from './app.js'; export {currentReadHighlightClass, PauseActionSource, previousReadHighlightClass, WordBoundaryMode} from './app.js'; -export {defaultFontName} from './common.js'; +export {defaultFontName, playFromSelectionTimeout} from './common.js'; export type {LanguageMenuElement} from './language_menu.js'; export {LANGUAGE_TOGGLE_EVENT} from './language_menu.js'; export type {ReadAnythingToolbarElement} from './read_anything_toolbar.js';
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts index 840b44f..868a992 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
@@ -23,7 +23,7 @@ import type {DomRepeatEvent} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {Debouncer, PolymerElement, timeOut} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {minOverflowLengthToScroll, openMenu, validatedFontName} from './common.js'; +import {minOverflowLengthToScroll, openMenu, spinnerDebounceTimeout, validatedFontName} from './common.js'; import {getTemplate} from './read_anything_toolbar.html.js'; import type {VoiceSelectionMenuElement} from './voice_selection_menu.js'; @@ -970,8 +970,8 @@ // scheduled. // TODO (b/339860819) improve debouncer logic so that the spinner disappears // immediately when speech starts playing, or when the paused button is hit. - this.debouncer_ = - Debouncer.debounce(this.debouncer_, timeOut.after(150), () => { + this.debouncer_ = Debouncer.debounce( + this.debouncer_, timeOut.after(spinnerDebounceTimeout), () => { if (paused) { this.hideSpinner = true; } else {
diff --git a/chrome/browser/resources/webui_gallery/BUILD.gn b/chrome/browser/resources/webui_gallery/BUILD.gn index d963c51..af3412d 100644 --- a/chrome/browser/resources/webui_gallery/BUILD.gn +++ b/chrome/browser/resources/webui_gallery/BUILD.gn
@@ -26,6 +26,9 @@ "demos/cr_slider/cr_slider_demo.css", "demos/cr_tabs/cr_tabs_demo.css", "demos/cr_toast/cr_toast_demo.css", + "demos/cr_toolbar/cr_toolbar_demo.css", + "demos/cr_tooltip/cr_tooltip_demo.css", + "demos/cr_url_list_item/cr_url_list_item_demo.css", "demos/demo.css", "demos/demo_lit.css", "demos/md_select/md_select_demo.css",
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.css b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.css new file mode 100644 index 0000000..5ed6f68a --- /dev/null +++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.css
@@ -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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #import=../demo_lit.css.js + * #scheme=relative + * #include=demo-lit + * #css_wrapper_metadata_end */ + +.content { + padding: 16px; +} + +cr-input { + --cr-input-error-display: none; +}
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html index 759629f..b60fc8f4 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html +++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html
@@ -1,25 +1,17 @@ -<style include="demo"> - .content { - padding: 16px; - } - - cr-input { - --cr-input-error-display: none; - } -</style> <cr-toolbar - page-name="[[pageName_]]" - search-prompt="[[searchPrompt_]]" - clear-label="[[clearLabel_]]" - menu-label="[[menuLabel_]]" - narrow="{{narrow_}}" - narrow-threshold="[[narrowThreshold_]]" - always-show-logo="[[alwaysShowLogo_]]" - show-menu="[[showMenu_]]" - show-search="[[showSearch_]]" - on-cr-toolbar-menu-click="onMenuClick_" - on-search-changed="onSearchChanged_"> - <div hidden$="[[!showSlottedContent_]]"> + .pageName="${this.pageName_}" + .searchPrompt="${this.searchPrompt_}" + .clearLabel="${this.clearLabel_}" + .menuLabel="${this.menuLabel_}" + ?narrow="${this.narrow_}" + @narrow-changed="${this.onNarrowChanged_}" + .narrowThreshold="${this.narrowThreshold_}" + ?always-show-logo="${this.alwaysShowLogo_}" + ?show-menu="${this.showMenu_}" + ?show-search="${this.showSearch_}" + @cr-toolbar-menu-click="${this.onMenuClick_}" + @search-changed="${this.onSearchChanged_}"> + <div ?hidden="${!this.showSlottedContent_}"> Slotted right-hand content </div> </cr-toolbar> @@ -27,24 +19,37 @@ <div class="content"> <h1>cr-toolbar</h1> <div class="demos"> - <cr-input label="Page name" value="{{pageName_}}"></cr-input> - <cr-input label="Search prompt" value="{{searchPrompt_}}"></cr-input> - <cr-input label="Clear label" value="{{clearLabel_}}"></cr-input> - <cr-input label="Menu label" value="{{menuLabel_}}"></cr-input> + <cr-input label="Page name" .value="${this.pageName_}" + @value-changed="${this.onPageNameChanged_}"></cr-input> + <cr-input label="Search prompt" .value="${this.searchPrompt_}" + @value-changed="${this.onSearchPromptChanged_}"></cr-input> + <cr-input label="Clear label" .value="${this.clearLabel_}" + @value-changed="${this.onClearLabelChanged_}"></cr-input> + <cr-input label="Menu label" .value="${this.menuLabel_}" + @value-changed="${this.onMenuLabelChanged_}"></cr-input> <cr-input label="Max window width for narrow mode" - value="{{narrowThreshold_}}"></cr-input> - <cr-checkbox checked="{{alwaysShowLogo_}}">Always show logo</cr-checkbox> - <cr-checkbox checked="{{showMenu_}}">Show menu button</cr-checkbox> - <cr-checkbox checked="{{showSearch_}}">Show search input</cr-checkbox> - <cr-checkbox checked="{{showSlottedContent_}}"> + .value="${this.narrowThreshold_}" + @value-changed="${this.onNarrowThresholdChanged_}"></cr-input> + <cr-checkbox ?checked="${this.alwaysShowLogo_}" + @checked-changed="${this.onAlwaysShowLogoChanged_}"> + Always show logo + </cr-checkbox> + <cr-checkbox ?checked="${this.showMenu_}" + @checked-changed="${this.onShowMenuChanged_}"> + Show menu button + </cr-checkbox> + <cr-checkbox ?checked="${this.showSearch_}" + @checked-changed="${this.onShowSearchChanged_}"> + Show search input + </cr-checkbox> + <cr-checkbox ?checked="${this.showSlottedContent_}" + @checked-changed="${this.onShowSlottedContentChanged_}"> Show right-hand content </cr-checkbox> </div> <div class="log"> - <div>Is narrow? [[narrow_]]</div> - <template is="dom-repeat" items="[[log_]]"> - <div>[[item]]</div> - </template> + <div>Is narrow? ${this.narrow_}</div> + ${this.log_.map(item => html`<div>${item}</div>`)} </div> </div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts index 6f4e5a5..db1d75ec 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts
@@ -5,59 +5,102 @@ import '//resources/cr_elements/cr_checkbox/cr_checkbox.js'; import '//resources/cr_elements/cr_input/cr_input.js'; import '//resources/cr_elements/cr_toolbar/cr_toolbar.js'; -import '../demo.css.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; -import {getTemplate} from './cr_toolbar_demo.html.js'; +import {getCss} from './cr_toolbar_demo.css.js'; +import {getHtml} from './cr_toolbar_demo.html.js'; -class CrToolbarDemoElement extends PolymerElement { +export class CrToolbarDemoElement extends CrLitElement { static get is() { return 'cr-toolbar-demo'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - alwaysShowLogo_: Boolean, - clearLabel_: String, - log_: Array, - menuLabel_: String, - narrow_: Boolean, - narrowThreshold_: Number, - pageName_: String, - searchPrompt_: String, - showMenu_: Boolean, - showSearch_: Boolean, - showSlottedContent_: Boolean, + alwaysShowLogo_: {type: Boolean}, + clearLabel_: {type: String}, + log_: {type: Array}, + menuLabel_: {type: String}, + narrow_: {type: Boolean}, + narrowThreshold_: {type: Number}, + pageName_: {type: String}, + searchPrompt_: {type: String}, + showMenu_: {type: Boolean}, + showSearch_: {type: Boolean}, + showSlottedContent_: {type: Boolean}, }; } - private alwaysShowLogo_: boolean = true; - private clearLabel_: string = 'Clear search'; - private log_: string[] = []; - private menuLabel_: string = 'Menu'; - private narrow_: boolean; - private narrowThreshold_: number = 1000; - private pageName_: string = 'Demo'; - private searchPrompt_: string = 'Search through some content'; - private showMenu_: boolean = true; - private showSearch_: boolean = true; - private showSlottedContent_: boolean = false; + protected alwaysShowLogo_: boolean = true; + protected clearLabel_: string = 'Clear search'; + protected log_: string[] = []; + protected menuLabel_: string = 'Menu'; + protected narrow_: boolean; + protected narrowThreshold_: number = 1000; + protected pageName_: string = 'Demo'; + protected searchPrompt_: string = 'Search through some content'; + protected showMenu_: boolean = true; + protected showSearch_: boolean = true; + protected showSlottedContent_: boolean = false; - private onMenuClick_() { - this.push('log_', 'Menu tapped.'); + protected onMenuClick_() { + this.log_.push('Menu tapped.'); + this.requestUpdate(); } - private onSearchChanged_(e: CustomEvent<string>) { - if (e.detail) { - this.push('log_', `Search term changed: ${e.detail}`); - } else { - this.push('log_', 'Search cleared.'); - } + protected onSearchChanged_(e: CustomEvent<string>) { + this.log_.push( + e.detail ? `Search term changed: ${e.detail}` : 'Search cleared.'); + this.requestUpdate(); + } + + protected onPageNameChanged_(e: CustomEvent<{value: string}>) { + this.pageName_ = e.detail.value; + } + + protected onSearchPromptChanged_(e: CustomEvent<{value: string}>) { + this.searchPrompt_ = e.detail.value; + } + + protected onClearLabelChanged_(e: CustomEvent<{value: string}>) { + this.clearLabel_ = e.detail.value; + } + + protected onNarrowThresholdChanged_(e: CustomEvent<{value: string}>) { + this.narrowThreshold_ = Number(e.detail.value); + } + + protected onMenuLabelChanged_(e: CustomEvent<{value: string}>) { + this.menuLabel_ = e.detail.value; + } + + protected onAlwaysShowLogoChanged_(e: CustomEvent<{value: boolean}>) { + this.alwaysShowLogo_ = e.detail.value; + } + + protected onShowMenuChanged_(e: CustomEvent<{value: boolean}>) { + this.showMenu_ = e.detail.value; + } + + protected onShowSearchChanged_(e: CustomEvent<{value: boolean}>) { + this.showSearch_ = e.detail.value; + } + + protected onShowSlottedContentChanged_(e: CustomEvent<{value: boolean}>) { + this.showSlottedContent_ = e.detail.value; + } + + protected onNarrowChanged_(e: CustomEvent<{value: boolean}>) { + this.narrow_ = e.detail.value; } }
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.css b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.css new file mode 100644 index 0000000..4833155e --- /dev/null +++ b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.css
@@ -0,0 +1,24 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #import=//resources/cr_elements/md_select_lit.css.js + * #import=../demo_lit.css.js + * #scheme=relative + * #include=demo-lit md-select-lit + * #css_wrapper_metadata_end */ + +.target { + border: 1px black; + padding: 8px; + margin: 40px; + width: fit-content; +} + +@media (prefers-color-scheme: dark) { + .target { + border: 1px white; + } +}
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.html index d5b4cba..7b12d5e 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.html +++ b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.html
@@ -1,16 +1,8 @@ -<style include="demo md-select"> - .target { - border: 1px black; - padding: 8px; - margin: 40px; - } -</style> - <h1>Automatic Tooltip (shows when mouse over target)</h1> <div class="demos"> <div class="target" id="target">This is a tooltip target</div> - <cr-tooltip for="target" position="[[tooltipPosition_]]" - offset="[[tooltipOffset_]]"> + <cr-tooltip for="target" .position="${this.tooltipPosition_}" + .offset="${this.tooltipOffset_}"> <span>Tooltip text</span> </cr-tooltip> </div> @@ -19,23 +11,24 @@ <div class="demos"> <div class="target" id="target1">Target 1</div> <div class="target" id="target2">Target 2</div> - <cr-tooltip id="manualTooltip" manual-mode position="[[tooltipPosition_]]" - offset="[[tooltipOffset_]]"> + <cr-tooltip id="manualTooltip" manual-mode + .position="${this.tooltipPosition_}" + .offset="${this.tooltipOffset_}"> <span>Tooltip text</span> </cr-tooltip> - <button on-click="showAtTarget1_">Show at Target 1</button> - <button on-click="showAtTarget2_">Show at Target 2</button> - <button on-click="hide_">Hide</button> + <button @click="${this.showAtTarget1_}">Show at Target 1</button> + <button @click="${this.showAtTarget2_}">Show at Target 2</button> + <button @click="${this.hide_}">Hide</button> </div> <h1>Customize tooltips</h1> <div class="demos"> - <cr-input type="number" min="0" max="24" value="[[tooltipOffset_]]" - on-input="onTooltipOffsetInput_" label="Tooltip offset (px)"> + <cr-input type="number" min="0" max="24" .value="${this.tooltipOffset_}" + @input="${this.onTooltipOffsetInput_}" label="Tooltip offset (px)"> </cr-input> <label>Tooltip position</label> - <select value="[[tooltipPosition_]]" class="md-select" - on-change="onTooltipPositionChange_"> + <select .value="${this.tooltipPosition_}" class="md-select" + @change="${this.onTooltipPositionChange_}"> <option value="top">top</option> <option value="bottom">bottom</option> <option value="left">left</option>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.ts index abbdea9..52fdef8 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_tooltip/cr_tooltip_demo.ts
@@ -5,15 +5,16 @@ import '//resources/cr_elements/cr_input/cr_input.js'; import '//resources/cr_elements/cr_tooltip/cr_tooltip.js'; import '//resources/cr_elements/md_select.css.js'; -import '../demo.css.js'; -import {getTemplate} from './cr_tooltip_demo.html.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js'; import type {CrTooltipElement} from '//resources/cr_elements/cr_tooltip/cr_tooltip.js'; import {TooltipPosition} from '//resources/cr_elements/cr_tooltip/cr_tooltip.js'; +import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; -interface CrTooltipDemoElement { +import {getCss} from './cr_tooltip_demo.css.js'; +import {getHtml} from './cr_tooltip_demo.html.js'; + +export interface CrTooltipDemoElement { $: { manualTooltip: CrTooltipElement, target1: HTMLElement, @@ -21,51 +22,55 @@ }; } -class CrTooltipDemoElement extends PolymerElement { +export class CrTooltipDemoElement extends CrLitElement { static get is() { return 'cr-tooltip-demo'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - tooltipPosition_: String, - tooltipOffset_: Number, + tooltipPosition_: {type: String}, + tooltipOffset_: {type: Number}, }; } // Default values. - private tooltipPosition_: TooltipPosition = TooltipPosition.BOTTOM; - private tooltipOffset_: number = 14; + protected tooltipPosition_: TooltipPosition = TooltipPosition.BOTTOM; + protected tooltipOffset_: number = 14; - private onTooltipPositionChange_(e: Event) { + protected onTooltipPositionChange_(e: Event) { const position = (e.target as HTMLSelectElement).value; this.tooltipPosition_ = position as TooltipPosition; this.shadowRoot!.querySelectorAll('cr-tooltip').forEach( tooltip => tooltip.updatePosition()); } - private onTooltipOffsetInput_(e: Event) { + protected onTooltipOffsetInput_(e: Event) { const offset = Number((e.target as CrInputElement).value); this.tooltipOffset_ = offset; this.shadowRoot!.querySelectorAll('cr-tooltip').forEach( tooltip => tooltip.updatePosition()); } - private hide_() { + protected hide_() { this.$.manualTooltip.hide(); } - private showAtTarget1_() { + protected showAtTarget1_() { this.$.manualTooltip.target = this.$.target1; this.$.manualTooltip.updatePosition(); this.$.manualTooltip.show(); } - private showAtTarget2_() { + protected showAtTarget2_() { this.$.manualTooltip.target = this.$.target2; this.$.manualTooltip.updatePosition(); this.$.manualTooltip.show();
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.css b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.css new file mode 100644 index 0000000..8218bc5 --- /dev/null +++ b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.css
@@ -0,0 +1,40 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #import=../demo_lit.css.js + * #scheme=relative + * #include=demo-lit + * #css_wrapper_metadata_end */ + +.badge { + align-items: center; + background: var(--google-grey-200); + border-radius: 100px; + display: inline-flex; + font-size: 12px; + gap: 4px; + height: 20px; + padding: 2px 8px 2px 6px; +} + +@media (prefers-color-scheme: dark) { + .badge { + background: var(--google-grey-700); + } +} + +cr-icon { + height: 12px; + width: 12px; +} + +cr-input { + --cr-input-error-display: none; +} + +cr-checkbox::part(label-container) { + display: none; +}
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.html index bb4ebbaf..9406cb2 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.html +++ b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.html
@@ -1,35 +1,3 @@ -<style include="demo"> - .badge { - align-items: center; - background: var(--google-grey-200); - border-radius: 100px; - display: inline-flex; - font-size: 12px; - gap: 4px; - height: 20px; - padding: 2px 8px 2px 6px; - } - - @media (prefers-color-scheme: dark) { - .badge { - background: var(--google-grey-700); - } - } - - cr-icon { - height: 12px; - width: 12px; - } - - cr-input { - --cr-input-error-display: none; - } - - cr-checkbox::part(label-container) { - display: none; - } -</style> - <h1>cr-url-list-item</h1> <div class="demos"> <cr-url-list-item count="23" title="A Bookmark Folder"
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.ts index bae6c55..df1a4b0 100644 --- a/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.ts +++ b/chrome/browser/resources/webui_gallery/demos/cr_url_list_item/cr_url_list_item_demo.ts
@@ -8,19 +8,23 @@ import '//resources/cr_elements/cr_input/cr_input.js'; import '//resources/cr_elements/cr_url_list_item/cr_url_list_item.js'; import '//resources/cr_elements/icons_lit.html.js'; -import '../demo.css.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; -import {getTemplate} from './cr_url_list_item_demo.html.js'; +import {getCss} from './cr_url_list_item_demo.css.js'; +import {getHtml} from './cr_url_list_item_demo.html.js'; -class CrUrlListItemDemoElement extends PolymerElement { +export class CrUrlListItemDemoElement extends CrLitElement { static get is() { return 'cr-url-list-item-demo'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); + } + + override render() { + return getHtml.bind(this)(); } }
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc index 760b2ca..c4c14cf8 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc
@@ -839,16 +839,11 @@ EXPECT_EQ(item->GetState(), download::DownloadItem::INTERRUPTED); } -// When the resumable protocol is used for deep scans, the fact that the -// a file is password protected does not affect whether it is blocked or -// not. The final verdict is determined by the server. So this test -// applies only to the multi-part upload protocol. +// Regardless of resumable or multipart upload protocol, when a file is password +// protected and the `block_password_protected` setting is on, the file should +// be blocked. IN_PROC_BROWSER_TEST_P(DownloadDeepScanningBrowserTest, - PasswordProtectedTxtFilesAreBlocked_MultipartOnly) { - if (is_resumable()) { - return; - } - + PasswordProtectedTxtFilesAreBlocked) { // This allows the blocking DM token reads happening on profile-Connector // triggers. base::ScopedAllowBlockingForTesting allow_blocking;
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc index 2a1dc31..e7e34a37 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/download/download_item_warning_data.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/offline_item_utils.h" +#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h" #include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" @@ -331,6 +332,15 @@ return false; } +bool EnterpriseResultIsFailure(BinaryUploadService::Result result, + bool block_large_files, + bool block_password_protected_files) { + return enterprise_connectors::IsResumableUploadEnabled() + ? enterprise_connectors::CloudResumableResultIsFailure( + result, block_large_files, block_password_protected_files) + : enterprise_connectors::CloudMultipartResultIsFailure(result); +} + } // namespace /* static */ @@ -473,8 +483,12 @@ base::UmaHistogramEnumeration("SBClientDownload.DeepScanTrigger", trigger_); - PopulateRequest(request.get(), profile, item_->GetFullPath()); - PrepareClientDownloadRequest(item_->GetFullPath(), std::move(request)); + FileAnalysisRequest* request_raw = request.get(); + PopulateRequest(request_raw, profile, item_->GetFullPath()); + request_raw->GetRequestData( + base::BindOnce(&DeepScanningRequest::OnGetFileRequestData, + weak_ptr_factory_.GetWeakPtr(), item_->GetFullPath(), + std::move(request))); } void DeepScanningRequest::StartSavePackageScan() { @@ -504,8 +518,9 @@ FileAnalysisRequest* request_raw = request.get(); PopulateRequest(request_raw, profile, file_location); request_raw->GetRequestData(base::BindOnce( - &DeepScanningRequest::OnGotRequestData, weak_ptr_factory_.GetWeakPtr(), - tmp_path_and_final_path.second, file_location, std::move(request))); + &DeepScanningRequest::OnGetPackageFileRequestData, + weak_ptr_factory_.GetWeakPtr(), tmp_path_and_final_path.second, + file_location, std::move(request))); DCHECK_LT(i, tasks.size()); tasks[i++].request = request_raw; } @@ -564,7 +579,7 @@ } } -void DeepScanningRequest::OnGotRequestData( +void DeepScanningRequest::OnGetPackageFileRequestData( const base::FilePath& final_path, const base::FilePath& current_path, std::unique_ptr<FileAnalysisRequest> request, @@ -573,14 +588,27 @@ file_metadata_.insert({current_path, enterprise_connectors::FileMetadata( final_path.AsUTF8Unsafe(), data.hash, data.mime_type, data.size)}); - - if (result == BinaryUploadService::Result::SUCCESS) { - OnDownloadRequestReady(current_path, std::move(request), nullptr); + if (ShouldTerminateEarly(result)) { + OnScanComplete(current_path, result, + enterprise_connectors::ContentAnalysisResponse()); return; } - OnScanComplete(current_path, result, - enterprise_connectors::ContentAnalysisResponse()); + OnDownloadRequestReady(current_path, std::move(request), nullptr); +} + +void DeepScanningRequest::OnGetFileRequestData( + const base::FilePath& file_path, + std::unique_ptr<FileAnalysisRequest> request, + BinaryUploadService::Result result, + BinaryUploadService::Request::Data data) { + if (ShouldTerminateEarly(result)) { + OnScanComplete(file_path, result, + enterprise_connectors::ContentAnalysisResponse()); + return; + } + + PrepareClientDownloadRequest(file_path, std::move(request)); } void DeepScanningRequest::OnDownloadRequestReady( @@ -892,6 +920,17 @@ return true; } +bool DeepScanningRequest::ShouldTerminateEarly( + BinaryUploadService::Result result) { + CHECK(analysis_settings_.cloud_or_local_settings.is_cloud_analysis()); + + return IsEnterpriseTriggered() + ? EnterpriseResultIsFailure( + result, analysis_settings_.block_large_files, + analysis_settings_.block_password_protected_files) + : result != BinaryUploadService::Result::SUCCESS; +} + void DeepScanningRequest::OpenDownload() { item_->OpenDownload(); FinishRequest(DownloadCheckResult::UNKNOWN);
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h index e31e271..4b2f20d 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h
@@ -146,6 +146,10 @@ base::OnceClosure close_callback, base::OnceClosure open_now_callback); + // Called to verify if `result` is considered as a failure and the scan should + // end early. + bool ShouldTerminateEarly(BinaryUploadService::Result result); + // Called to open the download. This is triggered by the timeout modal dialog. void OpenDownload(); @@ -161,13 +165,21 @@ const base::FilePath& current_path, std::unique_ptr<FileAnalysisRequest> deep_scan_request); - // Wrapper around OnDownloadRequestReady to facilitate opening files in - // parallel for save package scans. - void OnGotRequestData(const base::FilePath& final_path, - const base::FilePath& current_path, - std::unique_ptr<FileAnalysisRequest> request, - BinaryUploadService::Result result, - BinaryUploadService::Request::Data data); + // Callback invoked in `StartSingleFileScan` to check if `data` has been + // successfully fetched and ready for deep scanning if needed. + void OnGetFileRequestData(const base::FilePath& file_path, + std::unique_ptr<FileAnalysisRequest> request, + BinaryUploadService::Result result, + BinaryUploadService::Request::Data data); + + // Callback invoked in `StartSavePackageScan` to check if `data` of a file in + // package has been successfully fetched and ready for deep scanning if + // needed. + void OnGetPackageFileRequestData(const base::FilePath& final_path, + const base::FilePath& current_path, + std::unique_ptr<FileAnalysisRequest> request, + BinaryUploadService::Result result, + BinaryUploadService::Request::Data data); // Helper function to simplify checking if the report-only feature is set in // conjunction with the corresponding policy value.
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc index 0def579..3d79754 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
@@ -578,13 +578,22 @@ TEST_F(DeepScanningAPPRequestTest, GeneratesCorrectRequestForConsumer) { enterprise_connectors::AnalysisSettings settings; settings.tags = {{"malware", enterprise_connectors::TagSettings()}}; + base::RunLoop run_loop; DeepScanningRequest request( &item_, DownloadItemWarningData::DeepScanTrigger::TRIGGER_CONSUMER_PROMPT, - DownloadCheckResult::SAFE, base::DoNothing(), + DownloadCheckResult::SAFE, + base::BindRepeating( + [](base::RepeatingClosure closure, DownloadCheckResult result) { + if (result != DownloadCheckResult::ASYNC_SCANNING) { + closure.Run(); + } + }, + run_loop.QuitClosure()), &download_protection_service_, std::move(settings), /*password=*/std::nullopt); request.Start(); + run_loop.Run(); EXPECT_EQ(1, download_protection_service_.GetFakeBinaryUploadService() ->last_request()
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc index 91a24b6ab..249ed81 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -3554,23 +3554,24 @@ } TEST_F(DeepScanningDownloadTest, LargeFileBlockedByPreference) { - base::FilePath test_zip; - ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_zip)); - test_zip = test_zip.AppendASCII("safe_browsing") - .AppendASCII("download_protection") - .AppendASCII("encrypted.zip"); + constexpr int64_t kLargeSize = 51 * 1024 * 1024; + std::string file_contents = std::string(kLargeSize, 'a'); + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); NiceMockDownloadItem item; PrepareBasicDownloadItemWithFullPaths( - &item, {"http://www.evil.com/encrypted.zip"}, // url_chain - "http://www.google.com/", // referrer - test_zip, // tmp_path - temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("encrypted.zip"))); // final_path + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); - EXPECT_CALL(item, GetReceivedBytes()) - .WillRepeatedly(Return(100 * 1024 * 1024)); EXPECT_CALL(*sb_service_->mock_database_manager(), MatchDownloadAllowlistUrl(_, _)) .WillRepeatedly( @@ -3586,6 +3587,10 @@ enterprise_connectors::ContentAnalysisResponse()); { + EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _)); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageFeatures( + tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _)); enterprise_connectors::test::SetAnalysisConnector( profile()->GetPrefs(), enterprise_connectors::FILE_DOWNLOADED, R"( { @@ -3609,6 +3614,10 @@ } { + EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _)); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageFeatures( + tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _)); enterprise_connectors::test::SetAnalysisConnector( profile()->GetPrefs(), enterprise_connectors::FILE_DOWNLOADED, R"( { @@ -4426,11 +4435,21 @@ #if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS) TEST_F(DeepScanningDownloadTest, PolicyEnabled) { + std::string file_contents = "Normal file contents"; + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); EXPECT_CALL(*sb_service_->mock_database_manager(), MatchDownloadAllowlistUrl(_, _)) @@ -4480,11 +4499,21 @@ } TEST_F(DeepScanningDownloadTest, PolicyDisabled) { + std::string file_contents = "Normal file contents"; + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); EXPECT_CALL(*sb_service_->mock_database_manager(), MatchDownloadAllowlistUrl(_, _)) @@ -4533,11 +4562,25 @@ DownloadCheckResult::DANGEROUS_ACCOUNT_COMPROMISE}, }; for (const auto& response : responses) { + std::string file_contents = "Normal file contents"; + base::ScopedTempDir temporary_directory; + ASSERT_TRUE(temporary_directory.CreateUniqueTempDir()); + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temporary_directory.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temporary_directory.GetPath().Append( + FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); EXPECT_CALL(*sb_service_->mock_database_manager(), MatchDownloadAllowlistUrl(_, _)) @@ -4934,11 +4977,21 @@ #if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS) TEST_F(EnterpriseCsdDownloadTest, SkipsConsumerCsdWhenEnabled) { + std::string file_contents = "Normal file contents"; + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); enterprise_connectors::test::SetAnalysisConnector( @@ -4972,11 +5025,21 @@ } TEST_F(EnterpriseCsdDownloadTest, PopulatesCsdFieldWhenEnabled) { + std::string file_contents = "Normal file contents"; + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); enterprise_connectors::test::SetAnalysisConnector( @@ -5010,11 +5073,21 @@ } TEST_F(EnterpriseCsdDownloadTest, StillDoesMetadataCheckForLargeFile) { + std::string file_contents = "Normal file contents"; + base::FilePath file_path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &file_path)); + file_path = temp_dir_.GetPath().AppendASCII("foo.doc"); + + // Create the file. + base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + NiceMockDownloadItem item; - PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.exe")); // final_path + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/foo.doc"}, // url_chain + "http://www.google.com/", // referrer + file_path, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("foo.doc"))); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); EXPECT_CALL(*sb_service_->mock_database_manager(), MatchDownloadAllowlistUrl(_, _))
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java index 72729140..b117f04a 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java
@@ -12,7 +12,8 @@ /** Interface to expose sharing to external classes. */ public interface ShareDelegate { // These values are persisted to logs. Entries should not be renumbered and numeric values - // should never be reused. + // should never be reused. Ensure new values are also added to ShareOrigin in + // //tools/metrics/histograms/enums.xml. @IntDef({ ShareOrigin.OVERFLOW_MENU, ShareOrigin.TOP_TOOLBAR,
diff --git a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc index 835082c..e8fdc46 100644 --- a/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc +++ b/chrome/browser/shortcuts/create_shortcut_for_current_web_contents_task.cc
@@ -125,8 +125,6 @@ return; } - // TODO(crbug/339459710): Update icon_badging.cc to work once site with - // no-icon use-case has been fixed. gfx::ImageFamily badged_images = ApplyProductLogoBadgeToIcons(result.value()); CHECK(!badged_images.empty());
diff --git a/chrome/browser/shortcuts/icon_badging.cc b/chrome/browser/shortcuts/icon_badging.cc index 88bbadc..4fda391 100644 --- a/chrome/browser/shortcuts/icon_badging.cc +++ b/chrome/browser/shortcuts/icon_badging.cc
@@ -277,9 +277,7 @@ gfx::ImageFamily ApplyProductLogoBadgeToIcons(std::vector<SkBitmap> icons) { gfx::ImageFamily badged_icons; - if (icons.empty()) { - return badged_icons; - } + CHECK(!icons.empty()); base::flat_map<int, SkBitmap> sorted_icons; std::vector<int> icon_sizes;
diff --git a/chrome/browser/shortcuts/icon_badging_unittest.cc b/chrome/browser/shortcuts/icon_badging_unittest.cc index 3990f3c..b61eaf0 100644 --- a/chrome/browser/shortcuts/icon_badging_unittest.cc +++ b/chrome/browser/shortcuts/icon_badging_unittest.cc
@@ -129,8 +129,7 @@ // If badging behavior changes, the icons in the listed folders would need to be // updated. That can be done manually, or can be done automatically by using the // `rebaseline-shortcuts-icon-testing` command line flag. Example usage: -// out/Default/unit_tests -// --gtest_filter=*ImageManipulationUtilsTest* +// out/Default/unit_tests --gtest_filter=*IconBadgingTest* // --rebaseline-shortcuts-icon-testing TEST(IconBadgingTest, VerifyFromDisk) {
diff --git a/chrome/browser/single_tab/android/java/res/layout/single_tab_module_layout.xml b/chrome/browser/single_tab/android/java/res/layout/single_tab_module_layout.xml index b437659..8e97b1e 100644 --- a/chrome/browser/single_tab/android/java/res/layout/single_tab_module_layout.xml +++ b/chrome/browser/single_tab/android/java/res/layout/single_tab_module_layout.xml
@@ -23,15 +23,38 @@ android:foreground="@drawable/single_tab_card_ripple" android:orientation="vertical"> - <TextView - android:id="@+id/tab_switcher_title_description" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/single_tab_module_padding_top" - android:gravity="start" - android:singleLine="true" - android:text="@string/single_tab_module_title" - android:textAppearance="@style/TextAppearance.TextAccentMediumThick.Secondary" /> + android:baselineAligned="false" + android:orientation="horizontal" + android:singleLine="true"> + + <TextView + android:id="@+id/tab_switcher_title_description" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:singleLine="true" + android:text="@string/single_tab_module_title" + android:textAlignment="viewStart" + android:textAppearance="@style/TextAppearance.TextAccentMediumThick.Secondary" + /> + + <TextView + android:id="@+id/tab_switcher_see_more_link" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_weight="0" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:singleLine="true" + android:text="@string/tab_resumption_module_see_more" + android:textAlignment="viewEnd" + android:textAppearance="@style/TextAppearance.TextAccentMediumThick.Link" + /> + </LinearLayout> <LinearLayout android:id="@+id/tab_view"
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabModuleBuilder.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabModuleBuilder.java index 70f455d..ff82b85 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabModuleBuilder.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabModuleBuilder.java
@@ -22,9 +22,11 @@ import org.chromium.chrome.browser.tab_ui.TabContentManager; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.util.BrowserUiUtils.HostSurface; +import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.url.GURL; /** The {@link ModuleProviderBuilder} to build the single tab module on the magic stack. */ public class SingleTabModuleBuilder implements ModuleProviderBuilder, ModuleConfigChecker { @@ -60,6 +62,11 @@ (tabId) -> { moduleDelegate.onTabClicked(tabId, ModuleType.SINGLE_TAB); }; + Runnable seeMoreLinkClickedCallback = + () -> { + moduleDelegate.onUrlClicked( + new GURL(UrlConstants.RECENT_TABS_URL), ModuleType.SINGLE_TAB); + }; Runnable snapshotParentViewRunnable = () -> { moduleDelegateHost.onCaptureThumbnailStatusChanged(); @@ -81,6 +88,7 @@ moduleDelegateHost.showScrollableMvt(), isShownOnNtp ? moduleDelegate.getTrackingTab() : null, singleTabCardClickedCallback, + seeMoreLinkClickedCallback, snapshotParentViewRunnable, mTabContentManagerSupplier.get(), moduleDelegateHost.getUiConfig(),
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherCoordinator.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherCoordinator.java index 0d56a8cf..3b96875 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherCoordinator.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherCoordinator.java
@@ -65,6 +65,7 @@ boolean isScrollableMvtEnabled, Tab mostRecentTab, @Nullable Callback<Integer> singleTabCardClickedCallback, + @Nullable Runnable seeMoreLinkClickedCallback, @Nullable Runnable snapshotParentViewRunnable, @Nullable TabContentManager tabContentManager, @Nullable UiConfig uiConfig, @@ -117,6 +118,7 @@ mostRecentTab, isScrollableMvtEnabled, singleTabCardClickedCallback, + seeMoreLinkClickedCallback, mIsSurfacePolishEnabled ? tabContentManager : null, mIsSurfacePolishEnabled && isTablet ? uiConfig : null, isTablet,
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediator.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediator.java index bf85236..5a2c59b 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediator.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediator.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.FAVICON; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.IS_VISIBLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.LATERAL_MARGIN; +import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.SEE_MORE_LINK_CLICK_LISTENER; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TAB_THUMBNAIL; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TITLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.URL; @@ -24,6 +25,7 @@ import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; import org.chromium.chrome.browser.magic_stack.ModuleDelegate; @@ -45,6 +47,9 @@ /** Mediator of the single tab switcher in the new tab page on tablet. */ public class SingleTabSwitcherOnNtpMediator implements ConfigurationChangedObserver { + private static final String HISTOGRAM_SEE_MORE_LINK_CLICKED = + "MagicStack.Clank.SingleTab.SeeMoreLinkClicked"; + private final Context mContext; private final PropertyModel mPropertyModel; private final TabListFaviconProvider mTabListFaviconProvider; @@ -62,6 +67,7 @@ private boolean mIsScrollableMvtEnabled; private Callback<Integer> mSingleTabCardClickedCallback; + private Runnable mSeeMoreLinkClickedCallback; private boolean mIsSurfacePolishEnabled; private ThumbnailProvider mThumbnailProvider; private Size mThumbnailSize; @@ -77,6 +83,7 @@ Tab mostRecentTab, boolean isScrollableMvtEnabled, Callback<Integer> singleTabCardClickedCallback, + @Nullable Runnable seeMoreLinkClickedCallback, @Nullable TabContentManager tabContentManager, @Nullable UiConfig uiConfig, boolean isTablet, @@ -88,6 +95,7 @@ mMostRecentTab = mostRecentTab; mIsScrollableMvtEnabled = isScrollableMvtEnabled; mSingleTabCardClickedCallback = singleTabCardClickedCallback; + mSeeMoreLinkClickedCallback = seeMoreLinkClickedCallback; mIsSurfacePolishEnabled = tabContentManager != null; mUiConfig = uiConfig; mIsTablet = isTablet; @@ -134,6 +142,16 @@ mSingleTabCardClickedCallback = null; } }); + mPropertyModel.set( + SEE_MORE_LINK_CLICK_LISTENER, + () -> { + if (mSeeMoreLinkClickedCallback != null) { + mSeeMoreLinkClickedCallback.run(); + mSeeMoreLinkClickedCallback = null; + RecordHistogram.recordBooleanHistogram( + HISTOGRAM_SEE_MORE_LINK_CLICKED, true); + } + }); if (mUiConfig != null) { assert mIsSurfacePolishEnabled && mIsTablet;
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabView.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabView.java index 54d01bb..2728533 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabView.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabView.java
@@ -11,6 +11,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.View; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; @@ -23,6 +24,7 @@ /** View of the tab on the single tab tab switcher. */ class SingleTabView extends LinearLayout { + @Nullable private TextView mSeeMoreLinkView; private ImageView mFavicon; private TextView mTitle; @Nullable private TabThumbnailView mTabThumbnail; @@ -37,6 +39,7 @@ protected void onFinishInflate() { super.onFinishInflate(); + mSeeMoreLinkView = findViewById(R.id.tab_switcher_see_more_link); mFavicon = findViewById(R.id.tab_favicon_view); mTitle = findViewById(R.id.tab_title_view); mTabThumbnail = findViewById(R.id.tab_thumbnail); @@ -88,7 +91,22 @@ } /** + * Set the listener for "See more" link, which gets shown if `listener` is non-null. + * + * @param listener The given listener. + */ + public void setOnSeeMoreLinkClickListener(@Nullable Runnable listener) { + if (mSeeMoreLinkView != null) { + mSeeMoreLinkView.setVisibility((listener != null) ? View.VISIBLE : View.GONE); + if (listener != null) { + mSeeMoreLinkView.setOnClickListener(v -> listener.run()); + } + } + } + + /** * Set the favicon. + * * @param favicon The given favicon {@link Drawable}. */ public void setFavicon(Drawable favicon) {
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewBinder.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewBinder.java index 4e6a0656..3ac726e1 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewBinder.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewBinder.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.FAVICON; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.IS_VISIBLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.LATERAL_MARGIN; +import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.SEE_MORE_LINK_CLICK_LISTENER; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TAB_THUMBNAIL; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TITLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.URL; @@ -24,6 +25,9 @@ public static void bind(PropertyModel model, ViewGroup view, PropertyKey propertyKey) { if (propertyKey == CLICK_LISTENER) { view.setOnClickListener(model.get(CLICK_LISTENER)); + } else if (propertyKey == SEE_MORE_LINK_CLICK_LISTENER) { + ((SingleTabView) view) + .setOnSeeMoreLinkClickListener(model.get(SEE_MORE_LINK_CLICK_LISTENER)); } else if (propertyKey == FAVICON) { ((SingleTabView) view).setFavicon(model.get(FAVICON)); } else if (propertyKey == TAB_THUMBNAIL) {
diff --git a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewProperties.java b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewProperties.java index ec99e6d..a61227a 100644 --- a/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewProperties.java +++ b/chrome/browser/single_tab/android/java/src/org/chromium/chrome/browser/single_tab/SingleTabViewProperties.java
@@ -17,6 +17,8 @@ public static final PropertyModel.WritableObjectPropertyKey<View.OnClickListener> CLICK_LISTENER = new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyModel.WritableObjectPropertyKey<Runnable> + SEE_MORE_LINK_CLICK_LISTENER = new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyModel.WritableObjectPropertyKey<Drawable> FAVICON = new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyModel.WritableObjectPropertyKey<Bitmap> TAB_THUMBNAIL = @@ -33,6 +35,13 @@ public static final PropertyKey[] ALL_KEYS = new PropertyKey[] { - CLICK_LISTENER, FAVICON, TAB_THUMBNAIL, IS_VISIBLE, TITLE, URL, LATERAL_MARGIN + CLICK_LISTENER, + SEE_MORE_LINK_CLICK_LISTENER, + FAVICON, + TAB_THUMBNAIL, + IS_VISIBLE, + TITLE, + URL, + LATERAL_MARGIN }; }
diff --git a/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabModuleViewBinderUnitTest.java b/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabModuleViewBinderUnitTest.java index 7e18c785..85273ef 100644 --- a/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabModuleViewBinderUnitTest.java +++ b/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabModuleViewBinderUnitTest.java
@@ -18,6 +18,7 @@ import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.FAVICON; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.IS_VISIBLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.LATERAL_MARGIN; +import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.SEE_MORE_LINK_CLICK_LISTENER; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TAB_THUMBNAIL; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TITLE; import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.URL; @@ -70,6 +71,7 @@ private PropertyModel mPropertyModel; @Mock private View.OnClickListener mClickListener; + @Mock private Runnable mSeeMoreLinkClickListener; @Mock private TabModelSelector mTabModelSelector; @Mock private TabSwitcher.OnTabSelectingListener mOnTabSelectingListener; @Mock private TabListFaviconProvider mTabListFaviconProvider; @@ -187,6 +189,13 @@ mPropertyModel.set(CLICK_LISTENER, mClickListener); mSingleTabModuleView.performClick(); verify(mClickListener).onClick(any()); + + mPropertyModel.set(SEE_MORE_LINK_CLICK_LISTENER, mSeeMoreLinkClickListener); + TextView seeMoreLinkView = + mSingleTabModuleView.findViewById(R.id.tab_switcher_see_more_link); + assertNotNull(seeMoreLinkView); + seeMoreLinkView.performClick(); + verify(mSeeMoreLinkClickListener).run(); } @Test
diff --git a/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediatorUnitTest.java b/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediatorUnitTest.java index f46c56d56..bdbc02e3 100644 --- a/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediatorUnitTest.java +++ b/chrome/browser/single_tab/android/junit/src/org/chromium/chrome/browser/single_tab/SingleTabSwitcherOnNtpMediatorUnitTest.java
@@ -93,7 +93,8 @@ @Mock private ActivityLifecycleDispatcher mActivityLifecycleDispatcher; @Mock private UiConfig mUiConfig; @Mock private ModuleDelegate mModuleDelegate; - @Mock Callback<Integer> mSingleTabClickedCallback; + @Mock private Callback<Integer> mSingleTabClickedCallback; + @Mock private Runnable mSeeMoreLinkClickedCallback; @Captor private ArgumentCaptor<DisplayStyleObserver> mDisplayStyleObserverCaptor; @Captor private ArgumentCaptor<ConfigurationChangedObserver> mConfigurationChangedObserver; @@ -134,6 +135,7 @@ mTab, false, mSingleTabClickedCallback, + mSeeMoreLinkClickedCallback, null, null, isTablet, @@ -189,6 +191,7 @@ mTab, false, mSingleTabClickedCallback, + mSeeMoreLinkClickedCallback, mTabContentManager, null, isTablet, @@ -252,6 +255,7 @@ null, false, null, + /* seeMoreLinkClickedCallback= */ null, null, null, true, @@ -287,6 +291,7 @@ mTab, false, null, + /* seeMoreLinkClickedCallback= */ null, null, null, isTablet, @@ -334,6 +339,7 @@ mTab3, false, null, + /* seeMoreLinkClickedCallback= */ null, null, null, isTablet, @@ -358,6 +364,7 @@ mTab3, /* isScrollableMvtEnabled= */ true, null, + /* seeMoreLinkClickedCallback= */ null, null, null, true, @@ -404,6 +411,7 @@ mTab3, /* isScrollableMvtEnabled= */ true, /* singleTabCardClickedCallback= */ null, + /* seeMoreLinkClickedCallback= */ null, /* tabContentManager= */ null, /* uiConfig= */ null, /* isTablet= */ false, @@ -437,6 +445,7 @@ mTab3, /* isScrollableMvtEnabled= */ true, null, + /* seeMoreLinkClickedCallback= */ null, mTabContentManager, null, /* isTablet= */ false, @@ -473,6 +482,7 @@ mTab3, /* isScrollableMvtEnabled= */ false, null, + /* seeMoreLinkClickedCallback= */ null, null, null, true, @@ -518,6 +528,7 @@ mTab3, /* isScrollableMvtEnabled= */ false, null, + /* seeMoreLinkClickedCallback= */ null, tabContentManager, null, true, @@ -545,6 +556,7 @@ mTab3, /* isScrollableMvtEnabled= */ false, callback, + /* seeMoreLinkClickedCallback= */ null, null, null, true, @@ -571,6 +583,7 @@ mTab3, /* isScrollableMvtEnabled= */ true, null, + /* seeMoreLinkClickedCallback= */ null, mTabContentManager, mUiConfig, true,
diff --git a/chrome/browser/tab_resumption/java/res/layout/tab_resumption_module_layout.xml b/chrome/browser/tab_resumption/java/res/layout/tab_resumption_module_layout.xml index 8ff37b1..68739a1 100644 --- a/chrome/browser/tab_resumption/java/res/layout/tab_resumption_module_layout.xml +++ b/chrome/browser/tab_resumption/java/res/layout/tab_resumption_module_layout.xml
@@ -35,7 +35,7 @@ <TextView android:id="@+id/tab_resumption_title_description" android:layout_width="wrap_content" - android:layout_weight="2" + android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="start" android:singleLine="true" @@ -47,7 +47,7 @@ android:id="@+id/tab_resumption_see_more_link" android:visibility="gone" android:layout_width="wrap_content" - android:layout_weight="1" + android:layout_weight="0" android:layout_height="wrap_content" android:layout_gravity="end" android:singleLine="true"
diff --git a/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/TabResumptionTileContainerView.java b/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/TabResumptionTileContainerView.java index 171ea9f..483fdc3c 100644 --- a/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/TabResumptionTileContainerView.java +++ b/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/TabResumptionTileContainerView.java
@@ -17,12 +17,13 @@ import android.widget.LinearLayout; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import org.chromium.base.Callback; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab_resumption.TabResumptionModuleMetricsUtils.ClickInfo; import org.chromium.chrome.browser.tab_resumption.TabResumptionModuleMetricsUtils.ModuleShowConfig; import org.chromium.chrome.browser.tab_resumption.TabResumptionModuleUtils.SuggestionClickCallbacks; -import org.chromium.chrome.browser.tab_resumption.UrlImageProvider.UrlImageCallback; import org.chromium.chrome.browser.tab_ui.ThumbnailProvider; /** The view containing suggestion tiles on the tab resumption module. */ @@ -235,28 +236,41 @@ } /** Loads the main URL image of a {@link TabResumptionTileView}. */ - private void loadTileUrlImage( + @VisibleForTesting + void loadTileUrlImage( SuggestionEntry entry, UrlImageProvider urlImageProvider, TabResumptionTileView tileView, boolean isSingle, boolean useSalientImage) { - UrlImageCallback callback = - (Bitmap bitmap) -> { - onImageAvailable( - bitmap, tileView, useSalientImage, /* isSalientImage= */ false); + Runnable fetchRegularImage = + () -> { + urlImageProvider.fetchImageForUrl( + entry.url, + (bitmap) -> { + onImageAvailable( + bitmap, + tileView, + useSalientImage, + /* isSalientImage= */ false); + }); }; if (useSalientImage) { - urlImageProvider.fetchSalientImageWithFallback( - entry.url, - isSingle, + Callback<Bitmap> fetchSalientImageCallback = (bitmap) -> { - onImageAvailable( - bitmap, tileView, useSalientImage, /* isSalientImage= */ true); - }, - callback); + if (bitmap != null) { + onImageAvailable( + bitmap, + tileView, + /* useSalientImage= */ true, + /* isSalientImage= */ true); + } else { + fetchRegularImage.run(); + } + }; + urlImageProvider.fetchSalientImage(entry.url, isSingle, fetchSalientImageCallback); } else { - urlImageProvider.fetchImageForUrl(entry.url, callback); + fetchRegularImage.run(); } }
diff --git a/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/UrlImageProvider.java b/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/UrlImageProvider.java index 2df4bb3..0f7e98e 100644 --- a/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/UrlImageProvider.java +++ b/chrome/browser/tab_resumption/java/src/org/chromium/chrome/browser/tab_resumption/UrlImageProvider.java
@@ -124,25 +124,14 @@ * Asynchronously fetches a salient image for a URL, and fallback to fetch the favicon if there * isn't any salient image available. */ - public void fetchSalientImageWithFallback( + public void fetchSalientImage( @NonNull GURL pageUrl, boolean showBigImage, - Callback<Bitmap> onSalientImageReadyCallback, - UrlImageCallback fallback) { + Callback<Bitmap> onSalientImageReadyCallback) { assert mUseSalientImage && mImageServiceBridge != null; int imageSize = showBigImage ? mSalientImageSizeBigPx : mSalientImageSizeSmallPx; mImageServiceBridge.fetchImageFor( - /* isAccountData= */ true, - pageUrl, - imageSize, - (bitmap) -> { - if (bitmap != null) { - onSalientImageReadyCallback.onResult((Bitmap) bitmap); - } else { - // Fallback to fetch the favicon. - fetchImageForUrl(pageUrl, fallback); - } - }); + /* isAccountData= */ true, pageUrl, imageSize, onSalientImageReadyCallback); } }
diff --git a/chrome/browser/tab_resumption/junit/src/org/chromium/chrome/browser/tab_resumption/TabResumptionModuleViewUnitTest.java b/chrome/browser/tab_resumption/junit/src/org/chromium/chrome/browser/tab_resumption/TabResumptionModuleViewUnitTest.java index c05e8865..b465dba 100644 --- a/chrome/browser/tab_resumption/junit/src/org/chromium/chrome/browser/tab_resumption/TabResumptionModuleViewUnitTest.java +++ b/chrome/browser/tab_resumption/junit/src/org/chromium/chrome/browser/tab_resumption/TabResumptionModuleViewUnitTest.java
@@ -4,14 +4,17 @@ package org.chromium.chrome.browser.tab_resumption; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.util.Size; import android.view.LayoutInflater; import android.view.View; @@ -30,6 +33,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; @@ -37,6 +41,7 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Features.JUnitProcessor; +import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; @@ -223,13 +228,11 @@ // Capture call to fetch image. verify(mUrlImageProvider, atLeastOnce()) - .fetchSalientImageWithFallback( + .fetchSalientImage( mFetchImagePageUrlCaptor.capture(), eq(true), - mFetchSalientImageCallbackCaptor.capture(), - mFetchImageCallbackCaptor.capture()); + mFetchSalientImageCallbackCaptor.capture()); Assert.assertEquals(1, mFetchImagePageUrlCaptor.getAllValues().size()); - Assert.assertEquals(1, mFetchSalientImageCallbackCaptor.getAllValues().size()); Assert.assertEquals( JUnitTestGURLs.GOOGLE_URL_DOG, mFetchImagePageUrlCaptor.getAllValues().get(0)); @@ -265,6 +268,66 @@ @Test @SmallTest + public void testLoadTileUrlImageWithSalientImage() { + String histogramName = "MagicStack.Clank.TabResumption.IsSalientImageAvailable"; + GURL expectedUrl = JUnitTestGURLs.BLUE_3; + SuggestionEntry entry1 = + new SuggestionEntry( + /* sourceName= */ "My Tablet", + /* url= */ expectedUrl, + /* title= */ "Blue website with a very long title that might not fit", + /* timestamp= */ makeTimestamp(24 - 1, 60 - 16, 0), + /* id= */ 50); + TabResumptionTileView tile1 = Mockito.mock(TabResumptionTileView.class); + + mTileContainerView.loadTileUrlImage( + entry1, + mUrlImageProvider, + tile1, + /* isSingle= */ false, + /* usSalientImage= */ true); + + verify(mUrlImageProvider) + .fetchSalientImage( + eq(expectedUrl), + /* isSingle= */ eq(false), + mFetchSalientImageCallbackCaptor.capture()); + + // Verifies the case that a salient image is returned. + Bitmap bitmap = makeBitmap(100, 100); + var histogramWatcher = + HistogramWatcher.newBuilder().expectBooleanRecord(histogramName, true).build(); + mFetchSalientImageCallbackCaptor.getValue().onResult(bitmap); + verify(tile1).setImageDrawable(any(Drawable.class)); + verify(tile1).updateForSalientImage(); + histogramWatcher.assertExpected(); + + // Verifies the case that no salient image is available. + mFetchSalientImageCallbackCaptor.getValue().onResult(null); + verify(mUrlImageProvider) + .fetchImageForUrl(eq(expectedUrl), mFetchImageCallbackCaptor.capture()); + + // Verifies the case there isn't a fallback image is available. + histogramWatcher = + HistogramWatcher.newBuilder().expectBooleanRecord(histogramName, false).build(); + mFetchImageCallbackCaptor.getValue().onBitmap(null); + verify(tile1, times(2)).setImageDrawable(any(Drawable.class)); + // Verifies that the tile isn't updated for salient image. + verify(tile1).updateForSalientImage(); + histogramWatcher.assertExpected(); + + // Verifies the case there is a fallback image available. + histogramWatcher = + HistogramWatcher.newBuilder().expectBooleanRecord(histogramName, false).build(); + mFetchImageCallbackCaptor.getValue().onBitmap(bitmap); + verify(tile1, times(3)).setImageDrawable(any(Drawable.class)); + // Verifies that the tile isn't updated for salient image. + verify(tile1).updateForSalientImage(); + histogramWatcher.assertExpected(); + } + + @Test + @SmallTest public void testRenderSingleLocalView() { SuggestionEntry entry1 = new LocalTabSuggestionEntry(mTab); mSuggestionBundle.entries.add(entry1);
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 4d86dd2..1b81629 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -32,7 +32,7 @@ #include "build/build_config.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/theme_installed_infobar_delegate.h" -#include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h" +#include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/background/ntp_custom_background_service.h" #include "chrome/browser/themes/browser_theme_pack.h" @@ -726,8 +726,7 @@ std::string current_id = GetThemeID(); if (current_id == ThemeHelper::kDefaultThemeID) { if (GetIsGrayscale()) { - chrome_colors::ChromeColorsService:: - RecordDynamicColorOnLoadHistogramForGrayscale(); + chrome_colors::RecordDynamicColorOnLoadHistogramForGrayscale(); } UseTheme(GetDefaultSystemTheme()); return; @@ -736,14 +735,14 @@ if (current_id == kAutogeneratedThemeID) { SkColor color = GetAutogeneratedThemeColor(); BuildAutogeneratedThemeFromColor(color); - chrome_colors::ChromeColorsService::RecordColorOnLoadHistogram(color); + chrome_colors::RecordColorOnLoadHistogram(color); return; } if (current_id == kUserColorThemeID) { const auto user_color = GetUserColor(); if (user_color.has_value()) { - chrome_colors::ChromeColorsService::RecordDynamicColorOnLoadHistogram( + chrome_colors::RecordDynamicColorOnLoadHistogram( *user_color, GetBrowserColorVariant()); } return;
diff --git a/chrome/browser/tpcd/metadata/devtools_observer.cc b/chrome/browser/tpcd/metadata/devtools_observer.cc index 788c81f4..01857f04 100644 --- a/chrome/browser/tpcd/metadata/devtools_observer.cc +++ b/chrome/browser/tpcd/metadata/devtools_observer.cc
@@ -50,18 +50,25 @@ cookie_settings_->GetThirdPartyCookieAllowMechanism( details.url, details.first_party_url, details.cookie_setting_overrides))) { - EmitMetadataGrantDevtoolsIssue(details.url, details.first_party_url); + EmitMetadataGrantDevtoolsIssue(details.url, details.first_party_url, + details.type); } } void TpcdMetadataDevtoolsObserver::EmitMetadataGrantDevtoolsIssue( const GURL& third_party_url, - const GURL& first_party_url) { + const GURL& first_party_url, + const content::CookieAccessDetails::Type cookie_access_type) { auto details = blink::mojom::InspectorIssueDetails::New(); auto metadata_issue_details = blink::mojom::CookieDeprecationMetadataIssueDetails::New(); metadata_issue_details->allowed_sites.push_back(third_party_url.host()); + metadata_issue_details->operation = + cookie_access_type == content::CookieAccessDetails::Type::kRead + ? blink::mojom::CookieOperation::kReadCookie + : blink::mojom::CookieOperation::kSetCookie; + if (tpcd_metadata_manager_) { content_settings::SettingInfo out_info; bool allowed = tpcd_metadata_manager_->IsAllowed(
diff --git a/chrome/browser/tpcd/metadata/devtools_observer.h b/chrome/browser/tpcd/metadata/devtools_observer.h index 62dbac95..3c92ec5 100644 --- a/chrome/browser/tpcd/metadata/devtools_observer.h +++ b/chrome/browser/tpcd/metadata/devtools_observer.h
@@ -7,6 +7,7 @@ #include "chrome/browser/dips/dips_service.h" #include "chrome/browser/tpcd/heuristics/opener_heuristic_tab_helper.h" +#include "content/public/browser/cookie_access_details.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" @@ -33,9 +34,11 @@ void OnCookiesAccessedImpl(const content::CookieAccessDetails& details); // Emit a devtools issue when `third_party_url` is allowed cookie access as a - // third-party site on the current page. - void EmitMetadataGrantDevtoolsIssue(const GURL& third_party_url, - const GURL& first_party_url); + // third-party site on `first_party_url`. + void EmitMetadataGrantDevtoolsIssue( + const GURL& third_party_url, + const GURL& first_party_url, + const content::CookieAccessDetails::Type cookie_access_type); scoped_refptr<content_settings::CookieSettings> cookie_settings_; raw_ptr<tpcd::metadata::Manager> tpcd_metadata_manager_;
diff --git a/chrome/browser/tpcd/metadata/devtools_observer_browsertest.cc b/chrome/browser/tpcd/metadata/devtools_observer_browsertest.cc index 0afd8543..7bad33ef4 100644 --- a/chrome/browser/tpcd/metadata/devtools_observer_browsertest.cc +++ b/chrome/browser/tpcd/metadata/devtools_observer_browsertest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/tpcd/metadata/devtools_observer.h" #include "base/files/file_path.h" +#include "base/test/values_test_util.h" +#include "base/values.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/dips/dips_service.h" @@ -18,6 +20,7 @@ #include "components/prefs/pref_service.h" #include "components/subresource_filter/core/common/test_ruleset_utils.h" #include "components/tpcd/metadata/browser/parser.h" +#include "content/public/browser/cookie_access_details.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_devtools_protocol_client.h" #include "net/dns/mock_host_resolver.h" @@ -161,6 +164,9 @@ EXPECT_EQ( metadata_issue_details->FindBool("isOptOutTopLevel").value_or(false), is_opt_out_top_level); + EXPECT_THAT( + *metadata_issue_details, + base::test::DictionaryHasValue("operation", base::Value("ReadCookie"))); // Clear existing notifications so subsequent calls don't fail by checking // `sites` against old notifications. @@ -180,6 +186,8 @@ auto metadata_issue_details = blink::mojom::CookieDeprecationMetadataIssueDetails::New(); metadata_issue_details->allowed_sites.push_back("dummy.test"); + metadata_issue_details->operation = + blink::mojom::CookieOperation::kReadCookie; details->cookie_deprecation_metadata_issue_details = std::move(metadata_issue_details);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index fc2f53c..ce8cb95 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -16,7 +16,7 @@ import("//components/enterprise/buildflags/buildflags.gni") import("//components/feed/features.gni") import("//components/lens/features.gni") -import("//components/metrics/generate_histograms_variants_allowlist.gni") +import("//components/metrics/generate_allowlist_from_histograms_file.gni") import("//components/metrics/structured/buildflags/buildflags.gni") import("//components/nacl/features.gni") import("//components/offline_pages/buildflags/features.gni") @@ -35,9 +35,10 @@ assert(enable_supervised_users) assert(!is_fuchsia, "Fuchsia shouldn't use anything in //chrome") -generate_histograms_variants_allowlist("webui_name_variants") { +generate_allowlist_from_histograms_file("webui_name_variants") { namespace = "views_metrics" input_xml_file = "//tools/metrics/histograms/metadata/page/histograms.xml" + tag = "variant" output_file = "webui_name_variants.h" allow_list_name = "WebUIName" } @@ -1743,8 +1744,6 @@ "webui/cr_components/history_embeddings/history_embeddings_handler.h", "webui/cr_components/most_visited/most_visited_handler.cc", "webui/cr_components/most_visited/most_visited_handler.h", - "webui/cr_components/theme_color_picker/customize_chrome_colors.cc", - "webui/cr_components/theme_color_picker/customize_chrome_colors.h", "webui/cr_components/theme_color_picker/theme_color_picker_handler.cc", "webui/cr_components/theme_color_picker/theme_color_picker_handler.h", "webui/customize_themes/chrome_customize_themes_handler.cc", @@ -2100,6 +2099,7 @@ "//chrome/browser/media/router", "//chrome/browser/media/router/discovery:discovery", "//chrome/browser/media/router/discovery/access_code:access_code_sink_service", + "//chrome/browser/new_tab_page/chrome_colors", "//chrome/browser/new_tab_page/chrome_colors:generate_chrome_colors_info", "//chrome/browser/new_tab_page/chrome_colors:generate_colors_info", "//chrome/browser/new_tab_page/modules/feed:mojo_bindings", @@ -2123,6 +2123,7 @@ "//chrome/browser/ui/tabs", "//chrome/browser/ui/webui/access_code_cast:mojo_bindings", "//chrome/browser/ui/webui/app_service_internals:mojo_bindings", + "//chrome/browser/ui/webui/cr_components/theme_color_picker", "//chrome/browser/ui/webui/downloads:mojo_bindings", "//chrome/browser/ui/webui/hats:mojo_bindings", "//chrome/browser/ui/webui/internals/user_education:mojo_bindings", @@ -3800,6 +3801,7 @@ "//ash/webui/focus_mode", "//ash/webui/help_app_ui", "//ash/webui/help_app_ui/search:mojo_bindings", + "//ash/webui/mall:url_constants", "//ash/webui/media_app_ui", "//ash/webui/multidevice_debug", "//ash/webui/network_ui:network_diagnostics_resource_provider",
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn index e50adbd..36fa672 100644 --- a/chrome/browser/ui/android/omnibox/BUILD.gn +++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -524,6 +524,7 @@ "//components/ukm/android:java", "//components/user_prefs/android:java", "//content/public/android:content_java", + "//content/public/android:content_main_dex_jni_java", "//content/public/test/android:content_java_test_support", "//testing/android/junit:junit_test_support", "//third_party/android_deps:espresso_java",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java index 95799db3..b1a50b10 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
@@ -25,6 +25,8 @@ import org.chromium.components.browser_ui.widget.text.VerticallyFixedEditText; import org.chromium.ui.text.EmptyTextWatcher; +import java.util.Optional; + /** An {@link EditText} that shows autocomplete text at the end. */ public class AutocompleteEditText extends VerticallyFixedEditText implements AutocompleteEditTextModelBase.Delegate { @@ -133,6 +135,16 @@ } /** + * @return Additional text presented in the omnibox, indicating the destination of the default + * match. + */ + @VisibleForTesting + public Optional<String> getAdditionalText() { + if (mModel == null) return Optional.empty(); + return mModel.getAdditionalText(); + } + + /** * @return Whether any autocomplete information is specified on the current text. */ @VisibleForTesting @@ -199,12 +211,18 @@ * * @param userText user The text entered by the user. * @param inlineAutocompleteText The suggested autocompletion for the user's text. + * @param additionalText This string is displayed adjacent to the omnibox if this match is the + * default. Will usually be URL when autocompleting a title, and empty otherwise. */ public void setAutocompleteText( - @NonNull CharSequence userText, @Nullable CharSequence inlineAutocompleteText) { + @NonNull CharSequence userText, + @Nullable CharSequence inlineAutocompleteText, + Optional<String> additionalText) { boolean emptyAutocomplete = TextUtils.isEmpty(inlineAutocompleteText); if (!emptyAutocomplete) mDisableTextScrollingFromAutocomplete = true; - if (mModel != null) mModel.setAutocompleteText(userText, inlineAutocompleteText); + if (mModel != null) { + mModel.setAutocompleteText(userText, inlineAutocompleteText, additionalText); + } } /**
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java index e6a7ec3..c345b90 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
@@ -15,6 +15,8 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import java.util.Optional; + /** An abstraction of the text model to show, keep track of, and update autocomplete. */ public interface AutocompleteEditTextModelBase { /** An embedder should implement this. */ @@ -173,12 +175,19 @@ String getTextWithoutAutocomplete(); /** - * Returns the length of the autocomplete text currently displayed, zero if none is currently - * displayed. + * @return The length of the autocomplete text currently displayed, zero if none is currently + * displayed. */ int getAutocompleteTextLength(); /** + * @return The additional text presented in the omnibox, indicating the destination of the + * default match. + */ + @VisibleForTesting + Optional<String> getAdditionalText(); + + /** * Sets whether text changes should trigger autocomplete. * * @param ignore Whether text changes should be ignored and no auto complete. @@ -191,9 +200,13 @@ * * @param userText user The text entered by the user. * @param inlineAutocompleteText The suggested autocompletion for the user's text. + * @param additionalText This string is displayed adjacent to the omnibox if this match is the + * default. Will usually be URL when autocompleting a title, and empty otherwise. */ void setAutocompleteText( - @NonNull CharSequence userText, @Nullable CharSequence inlineAutocompleteText); + @NonNull CharSequence userText, + @Nullable CharSequence inlineAutocompleteText, + Optional<String> additionalText); /** * Whether we want to be showing inline autocomplete results. We don't want to show them as the
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java index b6b914ba..82c97ce 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
@@ -44,6 +44,7 @@ import org.chromium.base.test.util.Features; import org.chromium.ui.accessibility.AccessibilityState; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -301,11 +302,12 @@ if (DEBUG) Log.i(TAG, "setUp finished."); } - private void assertTexts(String userText, String autocompleteText) { + private void assertTexts(String userText, String autocompleteText, String additionalText) { assertEquals(userText, mAutocomplete.getTextWithoutAutocomplete()); assertEquals(userText + autocompleteText, mAutocomplete.getTextWithAutocomplete()); assertEquals(autocompleteText.length(), mAutocomplete.getAutocompleteLength()); assertEquals(!TextUtils.isEmpty(autocompleteText), mAutocomplete.hasAutocomplete()); + assertEquals(additionalText, mAutocomplete.getAdditionalText().orElse("")); } private void assertVerifierCallCounts( @@ -352,7 +354,7 @@ assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("h", "ello world"); + mAutocomplete.setAutocompleteText("h", "ello world", Optional.empty()); assertFalse(mAutocomplete.isCursorVisible()); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "h", -1, 1, -1, 0, 10); @@ -379,11 +381,11 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("he", "llo world"); + mAutocomplete.setAutocompleteText("he", "llo world", Optional.empty()); assertFalse(mAutocomplete.isCursorVisible()); mInOrder.verifyNoMoreInteractions(); - assertTexts("he", "llo world"); + assertTexts("he", "llo world", ""); assertTrue(mAutocomplete.shouldAutocomplete()); // User types "hello". @@ -405,11 +407,11 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); assertFalse(mAutocomplete.isCursorVisible()); assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); assertTrue(mAutocomplete.shouldAutocomplete()); // User types a space inside a batch edit. @@ -426,7 +428,7 @@ assertLastBatchEdit(mInputConnection.endBatchEdit()); // Autocomplete text gets redrawn. - assertTexts("hello ", "world"); + assertTexts("hello ", "world", ""); assertTrue(mAutocomplete.shouldAutocomplete()); mInOrder.verify(mVerifier).onUpdateSelection(6, 6); verifyOnPopulateAccessibilityEvent( @@ -450,9 +452,151 @@ mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); assertVerifierCallCounts(2, 2); - mAutocomplete.setAutocompleteText("hello ", "world"); + mAutocomplete.setAutocompleteText("hello ", "world", Optional.of("foo.com")); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("hello ", "world"); + assertTexts("hello ", "world", "foo.com"); + assertVerifierCallCounts(0, 0); + mInOrder.verifyNoMoreInteractions(); + } + + @Test + public void testAppendWithAdditionalText_CommitText() { + // User types "h". + assertTrue(mInputConnection.commitText("h", 1)); + mInOrder.verify(mVerifier).onUpdateSelection(1, 1); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "h", "", -1, 0, -1, 0, 1); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, "h", "", 1, 1, 1, -1, -1); + mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); + assertVerifierCallCounts(2, 2); + + mInOrder.verifyNoMoreInteractions(); + assertTrue(mAutocomplete.shouldAutocomplete()); + + // The controller kicks in. + mAutocomplete.setAutocompleteText("h", "ello world", Optional.of("www.foo.com")); + assertFalse(mAutocomplete.isCursorVisible()); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, + "hello world - www.foo.com", + "h", + -1, + 1, + -1, + 0, + 10); + assertVerifierCallCounts(0, 1); + mInOrder.verifyNoMoreInteractions(); + assertTrue(mAutocomplete.shouldAutocomplete()); + + // User types "he". + assertTrue(mInputConnection.commitText("e", 1)); + mInOrder.verify(mVerifier).onUpdateSelection(2, 2); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, + "hello world - www.foo.com", + "", + 25, + 2, + 2, + -1, + -1); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, + "hello world - www.foo.com", + "he", + -1, + 2, + -1, + 0, + 9); + mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); + assertVerifierCallCounts(2, 2); + mInOrder.verifyNoMoreInteractions(); + assertTrue(mAutocomplete.shouldAutocomplete()); + // The controller kicks in. + mAutocomplete.setAutocompleteText("he", "llo world", Optional.of("www.bar.com")); + assertFalse(mAutocomplete.isCursorVisible()); + + mInOrder.verifyNoMoreInteractions(); + assertTexts("he", "llo world", "www.bar.com"); + assertTrue(mAutocomplete.shouldAutocomplete()); + + // User types "hello". + assertTrue(mInputConnection.commitText("llo", 1)); + mInOrder.verify(mVerifier).onUpdateSelection(5, 5); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, + "hello world - www.bar.com", + "", + 25, + 5, + 5, + -1, + -1); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, + "hello world - www.bar.com", + "hello", + -1, + 5, + -1, + 0, + 6); + mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); + assertVerifierCallCounts(2, 2); + mInOrder.verifyNoMoreInteractions(); + assertTrue(mAutocomplete.shouldAutocomplete()); + // The controller kicks in. + mAutocomplete.setAutocompleteText("hello", " world", Optional.of("www.foobar.com")); + assertFalse(mAutocomplete.isCursorVisible()); + assertVerifierCallCounts(0, 0); + mInOrder.verifyNoMoreInteractions(); + assertTexts("hello", " world", "www.foobar.com"); + assertTrue(mAutocomplete.shouldAutocomplete()); + + // User types a space inside a batch edit. + assertTrue(mInputConnection.beginBatchEdit()); + // We should still show the intermediate autocomplete text to the user even in the middle of + // a batch edit. Otherwise, the user may see flickering of autocomplete text. + assertEquals("hello world - www.foobar.com", mAutocomplete.getText().toString()); + assertTrue(mInputConnection.commitText(" ", 1)); + assertEquals("hello world - www.foobar.com", mAutocomplete.getText().toString()); + assertFalse(mAutocomplete.shouldAutocomplete()); + assertEquals("hello world - www.foobar.com", mAutocomplete.getText().toString()); + + mInOrder.verifyNoMoreInteractions(); + assertLastBatchEdit(mInputConnection.endBatchEdit()); + + // Autocomplete text gets redrawn. + assertTexts("hello ", "world", "www.foobar.com"); + assertTrue(mAutocomplete.shouldAutocomplete()); + mInOrder.verify(mVerifier).onUpdateSelection(6, 6); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, + "hello world - www.foobar.com", + "", + 28, + 6, + 6, + -1, + -1); + verifyOnPopulateAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, + "hello world - www.foobar.com", + "hello ", + -1, + 6, + -1, + 0, + 5); + mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); + assertVerifierCallCounts(2, 2); + + mAutocomplete.setAutocompleteText("hello ", "world", Optional.of("www.foobar.com")); + assertFalse(mAutocomplete.isCursorVisible()); + assertTexts("hello ", "world", "www.foobar.com"); assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); } @@ -474,11 +618,11 @@ // The old model does not allow autocompletion here. assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("h", "ello world"); + mAutocomplete.setAutocompleteText("h", "ello world", Optional.empty()); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "h", -1, 1, -1, 0, 10); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("h", "ello world"); + assertTexts("h", "ello world", ""); assertVerifierCallCounts(0, 1); mInOrder.verifyNoMoreInteractions(); @@ -499,14 +643,14 @@ mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); assertVerifierCallCounts(2, 2); mInOrder.verifyNoMoreInteractions(); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); // The old model does not allow autocompletion here. assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); @@ -552,12 +696,12 @@ mInOrder.verifyNoMoreInteractions(); // Autocomplete text has been drawn at endBatchEdit(). - assertTexts("hello ", "world"); + assertTexts("hello ", "world", ""); // The old model can also autocomplete now. assertTrue(mAutocomplete.shouldAutocomplete()); - mAutocomplete.setAutocompleteText("hello ", "world"); - assertTexts("hello ", "world"); + mAutocomplete.setAutocompleteText("hello ", "world", Optional.of("foo.com")); + assertTexts("hello ", "world", "foo.com"); assertFalse(mAutocomplete.isCursorVisible()); assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); @@ -579,7 +723,7 @@ assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("h", "ello world"); + mAutocomplete.setAutocompleteText("h", "ello world", Optional.empty()); // The non-spannable model changes selection in two steps. verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "h", -1, 1, -1, 0, 10); @@ -605,16 +749,16 @@ AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "he", -1, 2, -1, 0, 9); mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); // The new model tries to reuse autocomplete text. - assertTexts("he", "llo world"); + assertTexts("he", "llo world", ""); assertVerifierCallCounts(2, 2); mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("he", "llo world"); + mAutocomplete.setAutocompleteText("he", "llo world", Optional.of("foo.com")); assertFalse(mAutocomplete.isCursorVisible()); assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); - assertTexts("he", "llo world"); + assertTexts("he", "llo world", "foo.com"); assertTrue(mAutocomplete.shouldAutocomplete()); mInOrder.verifyNoMoreInteractions(); } @@ -633,12 +777,12 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "hello", -1, 5, -1, 0, 6); assertVerifierCallCounts(0, 1); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); mInOrder.verifyNoMoreInteractions(); // User deletes autocomplete. @@ -656,7 +800,7 @@ assertVerifierCallCounts(3, 1); mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); // Keyboard app checks the current state. assertEquals("hello", mInputConnection.getTextBeforeCursor(10, 0)); @@ -664,7 +808,7 @@ assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); } private boolean isComposing() { @@ -687,11 +831,11 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "hello", -1, 5, -1, 0, 6); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); assertVerifierCallCounts(0, 1); mInOrder.verifyNoMoreInteractions(); @@ -710,7 +854,7 @@ assertVerifierCallCounts(3, 1); mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); // Keyboard app checks the current state. assertEquals("hello", mInputConnection.getTextBeforeCursor(10, 0)); @@ -718,7 +862,7 @@ assertVerifierCallCounts(0, 0); mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); } @Test @@ -729,14 +873,14 @@ assertTrue(isComposing()); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); - assertTexts("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); + assertTexts("hello", " world", ""); // User deletes autocomplete. assertTrue(mInputConnection.setComposingText("hell", 1)); // Remove autocomplete. assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); // Make sure that we do not finish composing text for Samsung keyboard - it does not update // its internal states when we ask this. (crbug.com/766888). assertTrue(isComposing()); @@ -757,9 +901,9 @@ assertVerifierCallCounts(2, 2); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); assertFalse(mAutocomplete.isCursorVisible()); - assertTexts("hello", " world"); + assertTexts("hello", " world", ""); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "hello", -1, 5, -1, 0, 6); mInOrder.verifyNoMoreInteractions(); @@ -791,7 +935,7 @@ AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello", "hello world", -1, 5, -1, 6, 0); mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello", ""); + assertTexts("hello", "", ""); mInOrder.verifyNoMoreInteractions(); assertVerifierCallCounts(3, 1); } @@ -810,8 +954,8 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); - assertTexts("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); + assertTexts("hello", " world", ""); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "hello", -1, 5, -1, 0, 6); assertFalse(mAutocomplete.isCursorVisible()); @@ -833,7 +977,7 @@ assertVerifierCallCounts(2, 1); mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); - assertTexts("hello world", ""); + assertTexts("hello world", "", ""); } @Test @@ -850,8 +994,8 @@ mInOrder.verifyNoMoreInteractions(); assertTrue(mAutocomplete.shouldAutocomplete()); // The controller kicks in. - mAutocomplete.setAutocompleteText("hello", " world"); - assertTexts("hello", " world"); + mAutocomplete.setAutocompleteText("hello", " world", Optional.empty()); + assertTexts("hello", " world", ""); verifyOnPopulateAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, "hello world", "hello", -1, 5, -1, 0, 6); assertFalse(mAutocomplete.isCursorVisible()); @@ -870,7 +1014,7 @@ mInOrder.verifyNoMoreInteractions(); assertFalse(mAutocomplete.shouldAutocomplete()); // Autocomplete text is removed. - assertTexts("hello", ""); + assertTexts("hello", "", ""); } @Test @@ -902,7 +1046,7 @@ @Test public void testOnSaveInstanceStateDoesNotCrash() { mInputConnection.setComposingText("h", 1); - mAutocomplete.setAutocompleteText("h", "ello world"); + mAutocomplete.setAutocompleteText("h", "ello world", Optional.of("foo.com")); // On Android JB, TextView#onSaveInstanceState() calls new SpannableString(mText). This // should not crash. new SpannableString(mAutocomplete.getText()); @@ -989,7 +1133,7 @@ // User types "h". assertTrue(mInputConnection.commitText("h", 1)); assertTrue(mAutocomplete.shouldAutocomplete()); - mAutocomplete.setAutocompleteText("h", "ello world"); + mAutocomplete.setAutocompleteText("h", "ello world", Optional.empty()); mAutocomplete.setIgnoreTextChangesForAutocomplete(true); mAutocomplete.setText("abcde"); mAutocomplete.setIgnoreTextChangesForAutocomplete(false); @@ -1009,7 +1153,7 @@ // User types "goo". assertTrue(mInputConnection.setComposingText("goo", 1)); assertTrue(mAutocomplete.shouldAutocomplete()); - mAutocomplete.setAutocompleteText("goo", "gle.com"); + mAutocomplete.setAutocompleteText("goo", "gle.com", Optional.empty()); assertEquals("google.com", mAutocomplete.getText().toString()); // User presses 'GO' key on the keyboard. @@ -1020,13 +1164,29 @@ assertEquals("google.com", mAutocomplete.getText().toString()); } + @Test + public void testPerformEditorAction_withAdditionText() { + // User types "goo". + assertTrue(mInputConnection.setComposingText("goo", 1)); + assertTrue(mAutocomplete.shouldAutocomplete()); + mAutocomplete.setAutocompleteText("goo", "gle.com", Optional.of("www.google.com")); + assertEquals("google.com - www.google.com", mAutocomplete.getText().toString()); + + // User presses 'GO' key on the keyboard. + assertTrue(mInputConnection.commitText("goo", 1)); + assertEquals("google.com - www.google.com", mAutocomplete.getText().toString()); + + assertTrue(mInputConnection.performEditorAction(EditorInfo.IME_ACTION_GO)); + assertEquals("google.com", mAutocomplete.getText().toString()); + } + // crbug.com/810704 @Test public void testPerformEditorActionInBatchEdit() { // User types "goo". assertTrue(mInputConnection.setComposingText("goo", 1)); assertTrue(mAutocomplete.shouldAutocomplete()); - mAutocomplete.setAutocompleteText("goo", "gle.com"); + mAutocomplete.setAutocompleteText("goo", "gle.com", Optional.empty()); assertEquals("google.com", mAutocomplete.getText().toString()); // User presses 'GO' key on the keyboard.
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java index 03e110e..e5d04a3 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
@@ -22,6 +22,7 @@ import android.view.inputmethod.InputConnectionWrapper; import android.view.inputmethod.InputContentInfo; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -366,6 +367,11 @@ } @Override + public Optional<String> getAdditionalText() { + return mCurrentState.getAdditionalText(); + } + + @Override public void setIgnoreTextChangeFromAutocomplete(boolean ignore) { if (DEBUG) Log.i(TAG, "setIgnoreText: " + ignore); mIgnoreTextChangeFromAutocomplete = ignore; @@ -373,26 +379,31 @@ @Override public void setAutocompleteText( - @NonNull CharSequence userText, @Nullable CharSequence inlineAutocompleteText) { + @NonNull CharSequence userText, + @Nullable CharSequence inlineAutocompleteText, + Optional<String> additionalText) { // Note: this is invoked when the Autocomplete text is supplied by the Autocomplete // subsystem. These changes should be ignored for Autocomplete, specifically should not // be sent back to the Autocomplete subsystem to trigger suggestions fetch. setIgnoreTextChangeFromAutocomplete(true); setAutocompleteTextInternal( userText.toString(), - inlineAutocompleteText != null ? inlineAutocompleteText.toString() : null); + inlineAutocompleteText != null ? inlineAutocompleteText.toString() : null, + additionalText); setIgnoreTextChangeFromAutocomplete(false); } private void setAutocompleteTextInternal( - @NonNull String userText, @Nullable String autocompleteText) { + @NonNull String userText, + @Nullable String autocompleteText, + Optional<String> additionalText) { if (DEBUG) Log.i(TAG, "setAutocompleteText: %s[%s]", userText, autocompleteText); mPreviouslySetState.set( userText, TextUtils.isEmpty(autocompleteText) ? Optional.empty() : Optional.of(autocompleteText), - Optional.empty(), + additionalText, userText.length(), userText.length()); // TODO(changwan): avoid any unnecessary removal and addition of autocomplete text when it @@ -516,6 +527,16 @@ editable.append(spanString); } + if (state.getAdditionalText().isPresent()) { + String additionalText = " - " + state.getAdditionalText().get(); + SpannableString additionalTextSpanString = new SpannableString(additionalText); + // TODO(b/341744198) : Update the color for the additional text. + final @ColorInt int gray = 0; + additionalTextSpanString.setSpan( + gray, 0, additionalText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.append(additionalTextSpanString); + } + // Keep the original selection before adding spannable string. Selection.setSelection(editable, sel, sel); setCursorVisible(false);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java index 9380601..144ad7af 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
@@ -7,6 +7,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build; +import android.text.TextUtils; import android.view.ActionMode; import androidx.annotation.ColorInt; @@ -21,6 +22,8 @@ import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import java.util.Optional; + /** Handles translating the UrlBar model data to the view state. */ class UrlBarViewBinder { private static final String TAG = "UrlBarViewBinder"; @@ -38,7 +41,12 @@ } else if (UrlBarProperties.AUTOCOMPLETE_TEXT.equals(propertyKey)) { AutocompleteText autocomplete = model.get(UrlBarProperties.AUTOCOMPLETE_TEXT); if (view.shouldAutocomplete()) { - view.setAutocompleteText(autocomplete.userText, autocomplete.autocompleteText); + view.setAutocompleteText( + autocomplete.userText, + autocomplete.autocompleteText, + TextUtils.isEmpty(autocomplete.additionalText) + ? Optional.empty() + : Optional.of(autocomplete.additionalText)); } } else if (UrlBarProperties.DELEGATE.equals(propertyKey)) { view.setDelegate(model.get(UrlBarProperties.DELEGATE));
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java index 5978251..3c705bd 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -78,7 +78,6 @@ private final @NonNull Supplier<ModalDialogManager> mModalDialogManagerSupplier; private final @NonNull OmniboxSuggestionsDropdownAdapter mAdapter; private final @NonNull Optional<PreWarmingRecycledViewPool> mRecycledViewPool; - private final @NonNull PropertyModel mListModel; private @Nullable OmniboxSuggestionsDropdown mDropdown; private @NonNull ObserverList<OmniboxSuggestionsDropdownScrollListener> mScrollListenerList = new ObserverList<>(); @@ -115,7 +114,7 @@ Context context = parent.getContext(); ModelList listItems = new ModelList(); - mListModel = + PropertyModel listModel = new PropertyModel.Builder(SuggestionListProperties.ALL_KEYS) .with(SuggestionListProperties.EMBEDDER, dropdownEmbedder) .with(SuggestionListProperties.OMNIBOX_SESSION_ACTIVE, false) @@ -128,7 +127,7 @@ context, delegate, urlBarEditingTextProvider, - mListModel, + listModel, new Handler(), modalDialogManagerSupplier, activityTabSupplier, @@ -147,12 +146,12 @@ mScrollListenerList.addObserver(scrollListener); } mScrollListenerList.addObserver(mMediator); - mListModel.set(SuggestionListProperties.GESTURE_OBSERVER, mMediator); - mListModel.set( + listModel.set(SuggestionListProperties.GESTURE_OBSERVER, mMediator); + listModel.set( SuggestionListProperties.DROPDOWN_HEIGHT_CHANGE_LISTENER, mMediator::onSuggestionDropdownHeightChanged); - mListModel.set(SuggestionListProperties.DROPDOWN_SCROLL_LISTENER, this::dropdownScrolled); - mListModel.set( + listModel.set(SuggestionListProperties.DROPDOWN_SCROLL_LISTENER, this::dropdownScrolled); + listModel.set( SuggestionListProperties.DROPDOWN_SCROLL_TO_TOP_LISTENER, this::dropdownOverscrolledToTop); @@ -163,7 +162,7 @@ mDropdown = holder.dropdown; }); LazyConstructionPropertyMcp.create( - mListModel, + listModel, SuggestionListProperties.OMNIBOX_SESSION_ACTIVE, viewProvider, SuggestionListViewBinder::bind); @@ -501,11 +500,6 @@ mMediator.stopAutocomplete(clearResults); } - /** Returns the model of the Suggestions Dropdown. */ - public @NonNull PropertyModel getSuggestionsDropdownModelForTest() { - return mListModel; - } - /** * Notify the {@link OmniboxSuggestionsDropdownScrollListener} that the dropdown is scrolled. */
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index c978045e..b8ac83d 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -25,7 +25,6 @@ import org.chromium.base.TraceEvent; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.TopResumedActivityChangedObserver; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; @@ -100,7 +99,6 @@ private final @NonNull DropdownItemViewInfoListManager mDropdownViewInfoListManager; private final @NonNull Callback<Tab> mBringTabToFrontCallback; private final @NonNull Supplier<TabWindowManager> mTabWindowManagerSupplier; - private final @NonNull Runnable mClearFocusCallback; private final @NonNull OmniboxActionDelegate mOmniboxActionDelegate; private final @NonNull ActivityLifecycleDispatcher mLifecycleDispatcher; private final @NonNull SuggestionsListAnimationDriver mAnimationDriver; @@ -115,8 +113,6 @@ private boolean mIsInZeroPrefixContext; private AutocompleteController mAutocomplete; private long mUrlFocusTime; - private boolean mClearFocusAfterNavigation; - private boolean mClearFocusAfterNavigationAsynchronously; // When set, indicates an active omnibox session. private boolean mIsActive; // When set, specifies the system time of the most recent suggestion list request. @@ -208,7 +204,6 @@ mDropdownViewInfoListBuilder.setShareDelegateSupplier(shareDelegateSupplier); mDropdownViewInfoListManager = new DropdownItemViewInfoListManager(mSuggestionModels, context); - mClearFocusCallback = this::finishInteraction; OmniboxResourceProvider.invalidateDrawableCache(); mLifecycleDispatcher = lifecycleDispatcher; mLifecycleDispatcher.register(this); @@ -267,7 +262,7 @@ if (mNativeInitialized) { OmniboxActionFactoryImpl.get().destroyNativeFactory(); } - mHandler.removeCallbacks(mClearFocusCallback); + mHandler.removeCallbacks(null); mDropdownViewInfoListBuilder.destroy(); mLifecycleDispatcher.unregister(this); } @@ -375,15 +370,6 @@ void onNativeInitialized() { mNativeInitialized = true; OmniboxActionFactoryImpl.get().initNativeFactory(); - // TODO(b/277805322): remove this Feature and parameter once we've run a holdback - // experiment. - mClearFocusAfterNavigation = - ChromeFeatureList.isEnabled(ChromeFeatureList.CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION); - mClearFocusAfterNavigationAsynchronously = - ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION, - "clear_focus_asynchronously", - true); mDropdownViewInfoListManager.onNativeInitialized(); mDropdownViewInfoListBuilder.onNativeInitialized(); runPendingAutocompleteRequests(); @@ -421,6 +407,17 @@ mOmniboxFocusResultedInNavigation = false; mSuggestionsListScrolled = false; mUrlFocusTime = System.currentTimeMillis(); + + // Ask directly for zero-suggestions related to current input, unless the user is + // currently visiting SearchActivity and the input is populated from the launch intent. + // In all contexts, the input will most likely be empty, triggering the same response + // (starting zero suggestions), but if the SearchActivity was launched with a QUERY, + // then the query might point to a different URL than the reported Page, and the + // suggestion would take the user to the DSE home page. + // This is tracked by MobileStartup.LaunchCause / EXTERNAL_SEARCH_ACTION_INTENT + // metric. + String text = mUrlBarEditingTextProvider.getTextWithoutAutocomplete(); + onTextChanged(text); } else { stopMeasuringSuggestionRequestToUiModelTime(); cancelAutocompleteRequests(); @@ -441,6 +438,9 @@ mEditSessionState = EditSessionState.INACTIVE; mNewOmniboxEditSessionTimestamp = -1; + // Prevent any upcoming omnibox suggestions from showing once a URL is loaded (and as + // a consequence the omnibox is unfocused). + clearSuggestions(); } } @@ -969,22 +969,6 @@ // This normally happens when the target site loads and focus is moved to the // webcontents. On Android T we occasionally observe focus events to be lost, resulting // with Suggestions list obscuring the view. - // TODO(crbug.com/40233313): clearing the Omnibox focus is slow, so we want to - // experiment - // with two alternatives: - // 1) Clear the Omnibox focus in a follow-up task. From a latency perspective, this is - // the best option: the navigation gets kicked off right away, and important - // navigation tasks can get scheduled between the current task and the task clearing - // the Omnibox focus. The ClearOmniboxFocusAfterNavigation feature with the - // clear_focus_asynchronously = false parameter (default) implements this option. - // 2) Clear the Omnibox focus synchronously *after* the navigation has been kicked off. - // This allows some navigation work outside the browser process (e.g. running - // beforeunload handlers) to start ASAP. This is implemented by the setting the - // clear_focus_asynchronously = true parameter. - if (!mClearFocusAfterNavigation) { - finishInteraction(); - } - var autocompleteLoadCallback = new AutocompleteLoadCallback() { @Override @@ -1013,11 +997,7 @@ .build()); } - if (mClearFocusAfterNavigationAsynchronously) { - mHandler.post(mClearFocusCallback); - } else if (mClearFocusAfterNavigation) { - finishInteraction(); - } + mHandler.post(this::finishInteraction); } } @@ -1068,30 +1048,13 @@ @VisibleForTesting void propagateOmniboxSessionStateChange(boolean isActive) { boolean wasActive = mListPropertyModel.get(SuggestionListProperties.OMNIBOX_SESSION_ACTIVE); - if (isActive == wasActive) return; - mListPropertyModel.set(SuggestionListProperties.OMNIBOX_SESSION_ACTIVE, isActive); - if (isActive) { - // Ask directly for zero-suggestions related to current input, unless the user is - // currently visiting SearchActivity and the input is populated from the launch intent. - // In all contexts, the input will most likely be empty, triggering the same response - // (starting zero suggestions), but if the SearchActivity was launched with a QUERY, - // then the query might point to a different URL than the reported Page, and the - // suggestion would take the user to the DSE home page. - // This is tracked by MobileStartup.LaunchCause / EXTERNAL_SEARCH_ACTION_INTENT - // metric. - String text = mUrlBarEditingTextProvider.getTextWithoutAutocomplete(); - onTextChanged(text); - } else { - // Prevent any upcoming omnibox suggestions from showing once a URL is loaded (and as - // a consequence the omnibox is unfocused). - clearSuggestions(); + if (isActive != wasActive) { + mIgnoreOmniboxItemSelection |= isActive; // Reset to default value. + mOmniboxSuggestionsVisualStateObserver.ifPresent( + (observer) -> observer.onOmniboxSessionStateChange(isActive)); } - - mIgnoreOmniboxItemSelection |= isActive; // Reset to default value. - mOmniboxSuggestionsVisualStateObserver.ifPresent( - (observer) -> observer.onOmniboxSessionStateChange(isActive)); } /**
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java index d6b488e..2b0d6400 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -59,7 +59,6 @@ import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; import org.chromium.chrome.browser.omnibox.OmniboxMetrics; @@ -114,10 +113,6 @@ AutocompleteMediatorUnitTest.ShadowTemplateUrlServiceFactory.class, ShadowLooper.class }) -@EnableFeatures({ - ChromeFeatureList.CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION, - OmniboxFeatureList.GROUPING_FRAMEWORK_FOR_NON_ZPS -}) public class AutocompleteMediatorUnitTest { private static final int SUGGESTION_MIN_HEIGHT = 20; private static final int HEADER_MIN_HEIGHT = 15; @@ -535,9 +530,9 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); // Simulate URL being focus changes. - mMediator.propagateOmniboxSessionStateChange(true); - mMediator.propagateOmniboxSessionStateChange(false); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(false); + mMediator.onOmniboxSessionStateChange(true); ShadowLooper.runUiThreadTasks(); verify(mAutocompleteController, never()).startZeroSuggest(any(), any(), anyInt(), any()); @@ -850,7 +845,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(url.getSpec()); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); ShadowLooper.runUiThreadTasks(); verify(mAutocompleteController) .startZeroSuggest(url.getSpec(), url, pageClassification, title); @@ -872,7 +867,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); // Signal focus prior to initializing native; confirm that zero suggest is not triggered. - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); ShadowLooper.runUiThreadTasks(); verify(mAutocompleteController, never()).startZeroSuggest(any(), any(), anyInt(), any()); @@ -1042,7 +1037,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); verify(mAutocompleteController).startZeroSuggest("", url, pageClassification, title); verifySuggestionRequestToUiModelHistograms(0, null, 0, null); @@ -1077,7 +1072,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); verify(mAutocompleteController).startZeroSuggest("", url, pageClassification, title); verifySuggestionRequestToUiModelHistograms(0, null, 0, null); @@ -1087,7 +1082,7 @@ verifySuggestionRequestToUiModelHistograms(1, 10, 0, null); // Cancel the interaction. - mMediator.propagateOmniboxSessionStateChange(false); + mMediator.onOmniboxSessionStateChange(false); // Report last results. Observe no final report. verifySuggestionRequestToUiModelHistograms(1, 10, 0, null); @@ -1108,12 +1103,12 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); verify(mAutocompleteController).startZeroSuggest("", url, pageClassification, title); verifySuggestionRequestToUiModelHistograms(0, null, 0, null); // Cancel the interaction. - mMediator.propagateOmniboxSessionStateChange(false); + mMediator.onOmniboxSessionStateChange(false); // Report first results. Observe no report (no focus). mMediator.onSuggestionsReceived(mAutocompleteResult, /* isFinal= */ false); @@ -1139,7 +1134,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); verify(mAutocompleteController).startZeroSuggest("", url, pageClassification, title); verifySuggestionRequestToUiModelHistograms(0, null, 0, null); @@ -1164,7 +1159,7 @@ when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); - mMediator.propagateOmniboxSessionStateChange(true); + mMediator.onOmniboxSessionStateChange(true); verify(mAutocompleteController).startZeroSuggest("", url, pageClassification, title); verifySuggestionRequestToUiModelHistograms(0, null, 0, null);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java index 7cb910a1..078cc459 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.omnibox.suggestions; -import androidx.annotation.VisibleForTesting; - import org.chromium.base.Callback; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyKey; @@ -15,8 +13,7 @@ import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; /** The properties controlling the state of the list of suggestion items. */ -@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) -public @interface SuggestionListProperties { +@interface SuggestionListProperties { static final WritableFloatPropertyKey ALPHA = new WritableFloatPropertyKey(); static final WritableFloatPropertyKey CHILD_TRANSLATION_Y = new WritableFloatPropertyKey();
diff --git a/chrome/browser/ui/android/signin/java/res/layout/history_sync_landscape_view.xml b/chrome/browser/ui/android/signin/java/res/layout/history_sync_landscape_view.xml index e389a70..a8ffce8 100644 --- a/chrome/browser/ui/android/signin/java/res/layout/history_sync_landscape_view.xml +++ b/chrome/browser/ui/android/signin/java/res/layout/history_sync_landscape_view.xml
@@ -8,7 +8,6 @@ <org.chromium.chrome.browser.ui.signin.history_sync.HistorySyncView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:background="@macro/default_bg_color" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingStart="14dp"
diff --git a/chrome/browser/ui/android/signin/java/res/layout/history_sync_portrait_view.xml b/chrome/browser/ui/android/signin/java/res/layout/history_sync_portrait_view.xml index 2b7b8bb0..fa2dd5f 100644 --- a/chrome/browser/ui/android/signin/java/res/layout/history_sync_portrait_view.xml +++ b/chrome/browser/ui/android/signin/java/res/layout/history_sync_portrait_view.xml
@@ -8,7 +8,6 @@ <org.chromium.chrome.browser.ui.signin.history_sync.HistorySyncView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:background="@macro/default_bg_color" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="24dp"
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAndHistoryOptInCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAndHistoryOptInCoordinator.java index 40f7344f..7d20013 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAndHistoryOptInCoordinator.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAndHistoryOptInCoordinator.java
@@ -7,6 +7,7 @@ import android.app.Activity; import android.content.res.Configuration; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import androidx.activity.ComponentActivity; @@ -26,6 +27,7 @@ import org.chromium.chrome.browser.ui.signin.history_sync.HistorySyncCoordinator; import org.chromium.chrome.browser.ui.signin.history_sync.HistorySyncHelper; import org.chromium.components.browser_ui.device_lock.DeviceLockActivityLauncher; +import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.signin.AccountManagerFacadeProvider; import org.chromium.components.signin.identitymanager.ConsentLevel; import org.chromium.components.signin.identitymanager.IdentityManager; @@ -436,7 +438,9 @@ mDidShowSigninStep && mIsHistorySyncDedicatedFlow, null); assert mDialogModel != null; - mDialogModel.set(ModalDialogProperties.CUSTOM_VIEW, mHistorySyncCoordinator.getView()); + View view = mHistorySyncCoordinator.getView(); + view.setBackgroundColor(SemanticColorUtils.getDefaultBgColor(mActivity)); + mDialogModel.set(ModalDialogProperties.CUSTOM_VIEW, view); ModalDialogManager manager = mModalDialogManagerSupplier.get(); assert manager != null; manager.showDialog(
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS index 45da89f..c750aceb2 100644 --- a/chrome/browser/ui/ash/DEPS +++ b/chrome/browser/ui/ash/DEPS
@@ -298,6 +298,9 @@ "birch_self_share_provider\.cc": [ "+chrome/browser/favicon/favicon_utils.h", "+chrome/browser/sync/send_tab_to_self_sync_service_factory.h", + ], + "birch_keyed_service_unittest\.cc": [ + "+chrome/browser/sync/send_tab_to_self_sync_service_factory.h", ] }
diff --git a/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc b/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc index 68dc8f6..826a58f 100644 --- a/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc +++ b/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc
@@ -13,7 +13,9 @@ #include "ash/constants/ash_switches.h" #include "ash/shell.h" #include "base/files/file_path.h" +#include "base/functional/bind.h" #include "base/functional/callback_forward.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "base/version_info/version_info.h" @@ -23,19 +25,27 @@ #include "chrome/browser/ash/file_suggest/mock_file_suggest_keyed_service.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/ash/release_notes/release_notes_storage.h" +#include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h" #include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/ui/ash/birch/birch_file_suggest_provider.h" #include "chrome/browser/ui/ash/birch/birch_keyed_service_factory.h" +#include "chrome/browser/ui/ash/birch/birch_self_share_provider.h" #include "chrome/browser/ui/ash/holding_space/scoped_test_mount_point.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/browser_with_test_window_test.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 "components/favicon/core/test/mock_favicon_service.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" +#include "components/send_tab_to_self/send_tab_to_self_model.h" +#include "components/send_tab_to_self/test_send_tab_to_self_model.h" #include "components/sessions/core/serialized_navigation_entry_test_helper.h" #include "components/signin/public/identity_manager/identity_test_utils.h" +#include "components/sync/test/fake_model_type_controller_delegate.h" #include "components/sync/test/test_sync_service.h" #include "components/sync_sessions/open_tabs_ui_delegate.h" #include "components/sync_sessions/session_sync_service.h" @@ -199,6 +209,113 @@ return std::make_unique<syncer::TestSyncService>(); } +class SendTabToSelfModelMock : public send_tab_to_self::TestSendTabToSelfModel { + public: + SendTabToSelfModelMock() = default; + + ~SendTabToSelfModelMock() override = default; + + MOCK_METHOD1(DeleteEntry, void(const std::string&)); + MOCK_METHOD1(DismissEntry, void(const std::string&)); + + send_tab_to_self::SendTabToSelfEntry* AddEntry( + const GURL& url, + const std::string& title, + const std::string& target_device_cache_guid) override { + const std::string guid = "guid"; + + auto entry = std::make_unique<send_tab_to_self::SendTabToSelfEntry>( + guid, url, title, base::Time::Now(), "device_info", + target_device_cache_guid); + + auto* result = entry.get(); + + entries_.emplace(guid, std::move(entry)); + + return result; + } + + const send_tab_to_self::SendTabToSelfEntry* GetEntryByGUID( + const std::string& guid) const override { + auto it = entries_.find(guid); + return it != entries_.end() ? it->second.get() : nullptr; + } + + std::vector<std::string> GetAllGuids() const override { + std::vector<std::string> keys; + for (const auto& it : entries_) { + DCHECK_EQ(it.first, it.second->GetGUID()); + keys.push_back(it.first); + } + return keys; + } + + void MarkEntryOpened(const std::string& guid) override { + auto it = entries_.find(guid); + if (it != entries_.end()) { + if (auto* entry = it->second.get()) { + entry->MarkOpened(); + } + } + } + + private: + std::map<std::string, std::unique_ptr<send_tab_to_self::SendTabToSelfEntry>> + entries_; +}; + +class TestSendTabToSelfSyncService + : public send_tab_to_self::SendTabToSelfSyncService { + public: + TestSendTabToSelfSyncService() : fake_delegate_(syncer::SEND_TAB_TO_SELF) {} + + ~TestSendTabToSelfSyncService() override = default; + + send_tab_to_self::SendTabToSelfModel* GetSendTabToSelfModel() override { + return &model_mock_; + } + + base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate() + override { + return fake_delegate_.GetWeakPtr(); + } + + protected: + syncer::FakeModelTypeControllerDelegate fake_delegate_; + SendTabToSelfModelMock model_mock_; +}; + +std::unique_ptr<KeyedService> BuildTestSendTabToSelfSyncService( + content::BrowserContext* context) { + return std::make_unique<TestSendTabToSelfSyncService>(); +} + +class FaviconServiceMock : public favicon::MockFaviconService { + public: + FaviconServiceMock() = default; + ~FaviconServiceMock() override = default; + FaviconServiceMock(const FaviconServiceMock&) = delete; + FaviconServiceMock& operator=(const FaviconServiceMock&) = delete; + + base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL( + const GURL& page_url, + favicon_base::FaviconImageCallback callback, + base::CancelableTaskTracker* tracker) override { + favicon_base::FaviconImageResult result; + result.image = gfx::Image(); + result.icon_url = GURL("https://example.com/favicon.ico"); + + std::move(callback).Run(result); + + return base::CancelableTaskTracker::kBadTaskId; + } +}; + +std::unique_ptr<KeyedService> BuildFaviconServiceMock( + content::BrowserContext* context) { + return std::make_unique<FaviconServiceMock>(); +} + } // namespace // TODO(https://crbug.com/1370774): move `ScopedTestMountPoint` out of holding @@ -242,6 +359,14 @@ SyncServiceFactory::GetForProfile(profile())); SetSessionServiceToReturnOpenTabsDelegate(true); + + send_tab_to_self_model_ = static_cast<SendTabToSelfModelMock*>( + SendTabToSelfSyncServiceFactory::GetForProfile(GetProfile()) + ->GetSendTabToSelfModel()); + + favicon_service_ = + static_cast<FaviconServiceMock*>(FaviconServiceFactory::GetForProfile( + GetProfile(), ServiceAccessType::EXPLICIT_ACCESS)); } void SetSessionServiceToReturnOpenTabsDelegate(bool return_delegate) { @@ -251,12 +376,14 @@ } void TearDown() override { + send_tab_to_self_model_ = nullptr; mount_point_.reset(); birch_keyed_service_ = nullptr; file_suggest_service_ = nullptr; session_sync_service_ = nullptr; sync_service_ = nullptr; release_notes_storage_ = nullptr; + favicon_service_ = nullptr; fake_user_manager_.Reset(); BrowserWithTestWindowTest::TearDown(); switches::SetIgnoreForestSecretKeyForTest(false); @@ -288,6 +415,13 @@ signin::ConsentLevel::kSignin); } + void AddNewChromeSyncEntry() { + const GURL kUrl("https://www.example.com"); + const std::string kTitle("example"); + const std::string kTargetDeviceSyncCacheGuid("target"); + send_tab_to_self_model_->AddEntry(kUrl, kTitle, kTargetDeviceSyncCacheGuid); + } + void ClearReleaseNotesSurfacesTimesLeftToShowPref() { GetProfile()->GetPrefs()->ClearPref( prefs::kReleaseNotesSuggestionChipTimesLeftToShow); @@ -318,6 +452,12 @@ return session_sync_service_; } + SendTabToSelfModelMock* send_tab_to_self_model() { + return send_tab_to_self_model_; + } + + FaviconServiceMock* favicon_service() { return favicon_service_; } + syncer::TestSyncService* sync_service() { return sync_service_; } BirchKeyedService* birch_keyed_service() { return birch_keyed_service_; } @@ -334,6 +474,10 @@ temp_dir_.GetPath())}, {SessionSyncServiceFactory::GetInstance(), base::BindRepeating(&BuildMockSessionSyncService)}, + {SendTabToSelfSyncServiceFactory::GetInstance(), + base::BindRepeating(&BuildTestSendTabToSelfSyncService)}, + {FaviconServiceFactory::GetInstance(), + base::BindRepeating(&BuildFaviconServiceMock)}, }; } @@ -353,6 +497,10 @@ raw_ptr<syncer::TestSyncService> sync_service_; + raw_ptr<SendTabToSelfModelMock> send_tab_to_self_model_; + + raw_ptr<FaviconServiceMock> favicon_service_; + MockOpenTabsUIDelegate open_tabs_delegate_; std::unique_ptr<ReleaseNotesStorage> release_notes_storage_; @@ -369,6 +517,7 @@ EXPECT_TRUE(birch_keyed_service()->GetCalendarProvider()); EXPECT_TRUE(birch_keyed_service()->GetFileSuggestProvider()); EXPECT_TRUE(birch_keyed_service()->GetRecentTabsProvider()); + EXPECT_TRUE(birch_keyed_service()->GetSelfShareProvider()); } TEST_F(BirchKeyedServiceTest, BirchFileSuggestProvider) { @@ -580,4 +729,27 @@ EXPECT_TRUE(session_sync_service()->IsSubscribersEmpty()); } +TEST_F(BirchKeyedServiceTest, SelfShareProvider) { + BirchModel* model = Shell::Get()->birch_model(); + BirchDataProvider* self_share_provider = + birch_keyed_service()->GetSelfShareProvider(); + + EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u); + + AddNewChromeSyncEntry(); + self_share_provider->RequestBirchDataFetch(); + model->SetCalendarItems(std::vector<BirchCalendarItem>()); + model->SetRecentTabItems(std::vector<BirchTabItem>()); + model->SetFileSuggestItems(std::vector<BirchFileItem>()); + model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>()); + task_environment()->RunUntilIdle(); + EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 1u); + + // Mark Self Share Item as opened, the provider should now return zero items. + model->GetSelfShareItemsForTest()[0].PerformAction(); + self_share_provider->RequestBirchDataFetch(); + task_environment()->RunUntilIdle(); + EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u); +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/birch/birch_self_share_provider.cc b/chrome/browser/ui/ash/birch/birch_self_share_provider.cc index b0f4b2fe..07dfb47 100644 --- a/chrome/browser/ui/ash/birch/birch_self_share_provider.cc +++ b/chrome/browser/ui/ash/birch/birch_self_share_provider.cc
@@ -81,7 +81,9 @@ items_.emplace_back( base::UTF8ToUTF16(entry_guid), base::UTF8ToUTF16(entry->GetTitle()), entry->GetURL(), entry->GetSharedTime(), - base::UTF8ToUTF16(entry->GetDeviceName()), empty_favicon_url); + base::UTF8ToUTF16(entry->GetDeviceName()), empty_favicon_url, + base::BindRepeating(&BirchSelfShareProvider::OnItemPressed, + weak_factory_.GetWeakPtr(), entry_guid)); favicon_service->GetFaviconImageForPageURL( entry->GetURL(), base::BindOnce(&BirchSelfShareProvider::OnFavIconDataAvailable, @@ -117,4 +119,10 @@ } } +void BirchSelfShareProvider::OnItemPressed(const std::string& guid) { + send_tab_to_self::SendTabToSelfModel* model = + sync_service_->GetSendTabToSelfModel(); + model->MarkEntryOpened(guid); +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/birch/birch_self_share_provider.h b/chrome/browser/ui/ash/birch/birch_self_share_provider.h index 29fc89f..144fc0d3 100644 --- a/chrome/browser/ui/ash/birch/birch_self_share_provider.h +++ b/chrome/browser/ui/ash/birch/birch_self_share_provider.h
@@ -33,7 +33,13 @@ // BirchDataProvider: void RequestBirchDataFetch() override; + protected: + // Marks the entry as opened when the suggestion is pressed. + void OnItemPressed(const std::string& guid); + private: + friend class BirchKeyedServiceTest; + void OnFavIconDataAvailable( const std::string& guid, const favicon_base::FaviconImageResult& image_result);
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc index f51051a..73fa145 100644 --- a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc +++ b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
@@ -915,91 +915,4 @@ EXPECT_EQ(error_view->GetButtonForTest()->GetText(), u"Dismiss"); } -// ----------------------------------------------------------------------------- - -// TODO(b/338917100): Consider converting these browsertests to unittests. -class GlanceablesTasksAndClassroomTest : public GlanceablesBrowserTest { - public: - GlanceablesTasksAndClassroomTest() { - features_.InitWithFeatures( - /*enabled_features=*/ - {features::kGlanceablesTimeManagementTasksView, - features::kGlanceablesTimeManagementClassroomStudentView}, - /*disabled_features=*/{}); - } - - void SetUpOnMainThread() override { - GlanceablesBrowserTest::SetUpOnMainThread(); - ASSERT_TRUE(glanceables_controller()->GetTasksClient()); - ASSERT_TRUE(glanceables_controller()->GetClassroomClient()); - } - - private: - base::test::ScopedFeatureList features_; -}; - -IN_PROC_BROWSER_TEST_F(GlanceablesTasksAndClassroomTest, Basics) { - ToggleDateTray(); - - EXPECT_TRUE(GetGlanceableTrayBubble()); - auto* const tasks_view = GetTasksView(); - EXPECT_TRUE(tasks_view); - auto* const classroom_view = GetStudentView(); - EXPECT_TRUE(classroom_view); - - // Check that both views have their own backgrounds. - EXPECT_TRUE(tasks_view->GetBackground()); - EXPECT_TRUE(classroom_view->GetBackground()); - - // Check that both views contain their expand buttons. - EXPECT_TRUE(GetTasksExpandButtonView()); - EXPECT_TRUE(GetStudentExpandButtonView()); -} - -IN_PROC_BROWSER_TEST_F(GlanceablesTasksAndClassroomTest, - TimeManagementExpandStates) { - ToggleDateTray(); - - EXPECT_TRUE(GetGlanceableTrayBubble()); - auto* const tasks_view = - views::AsViewClass<GlanceablesTasksView>(GetTasksView()); - auto* const classroom_view = - views::AsViewClass<GlanceablesClassroomStudentView>(GetStudentView()); - - // Initially both views are expanded. - // TODO(b/338917100): Consider having a half folded state. - EXPECT_TRUE(tasks_view->is_expanded()); - EXPECT_TRUE(classroom_view->is_expanded()); - - // Expanding/Collapsing `tasks_view` will collapse/expand `classroom_view`. - auto* const tasks_expand_button = GetTasksExpandButtonView(); - ASSERT_TRUE(tasks_expand_button); - GetEventGenerator()->MoveMouseTo( - tasks_expand_button->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(tasks_view->is_expanded()); - EXPECT_TRUE(classroom_view->is_expanded()); - - GetEventGenerator()->MoveMouseTo( - tasks_expand_button->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); - EXPECT_TRUE(tasks_view->is_expanded()); - EXPECT_FALSE(classroom_view->is_expanded()); - - // Same for `classroom_view`. - auto* const classroom_expand_button = GetStudentExpandButtonView(); - ASSERT_TRUE(classroom_expand_button); - GetEventGenerator()->MoveMouseTo( - classroom_expand_button->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(tasks_view->is_expanded()); - EXPECT_TRUE(classroom_view->is_expanded()); - - GetEventGenerator()->MoveMouseTo( - classroom_expand_button->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); - EXPECT_TRUE(tasks_view->is_expanded()); - EXPECT_FALSE(classroom_view->is_expanded()); -} - } // namespace ash
diff --git a/chrome/browser/ui/ash/picker/picker_client_impl.cc b/chrome/browser/ui/ash/picker/picker_client_impl.cc index 7f852f3..6d744c5 100644 --- a/chrome/browser/ui/ash/picker/picker_client_impl.cc +++ b/chrome/browser/ui/ash/picker/picker_client_impl.cc
@@ -429,6 +429,13 @@ return gaia::IsGoogleInternalAccountEmail(profile_->GetProfileUserName()); } +void PickerClientImpl::FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) { + CHECK(thumbnail_loader_); + thumbnail_loader_->Load({path, size}, std::move(callback)); +} + void PickerClientImpl::ActiveUserChanged(user_manager::User* active_user) { if (!active_user) { SetProfile(nullptr); @@ -462,6 +469,7 @@ zero_state_links_search_engine_.reset(); file_suggester_ = std::make_unique<PickerFileSuggester>(profile_); + thumbnail_loader_ = std::make_unique<ash::ThumbnailLoader>(profile_); } std::unique_ptr<app_list::SearchProvider>
diff --git a/chrome/browser/ui/ash/picker/picker_client_impl.h b/chrome/browser/ui/ash/picker/picker_client_impl.h index 87c815c..a6319b31 100644 --- a/chrome/browser/ui/ash/picker/picker_client_impl.h +++ b/chrome/browser/ui/ash/picker/picker_client_impl.h
@@ -35,6 +35,7 @@ } namespace ash { +class ThumbnailLoader; class PickerController; } @@ -77,6 +78,9 @@ void GetRecentDriveFileResults(RecentFilesCallback callback) override; void GetSuggestedLinkResults(SuggestedLinksCallback callback) override; bool IsFeatureAllowedForDogfood() override; + void FetchFileThumbnail(const base::FilePath& path, + const gfx::Size& size, + FetchFileThumbnailCallback callback) override; // user_manager::UserManager::UserSessionStateObserver: void ActiveUserChanged(user_manager::User* active_user) override; @@ -149,6 +153,8 @@ std::optional<std::string> current_gif_search_query_; std::unique_ptr<EndpointFetcher> current_gif_fetcher_; + std::unique_ptr<ash::ThumbnailLoader> thumbnail_loader_; + base::ScopedObservation<user_manager::UserManager, user_manager::UserManager::UserSessionStateObserver> user_session_state_observation_{this};
diff --git a/chrome/browser/ui/ash/picker/picker_file_suggester.cc b/chrome/browser/ui/ash/picker/picker_file_suggester.cc index 701cdb35..0af2e651 100644 --- a/chrome/browser/ui/ash/picker/picker_file_suggester.cc +++ b/chrome/browser/ui/ash/picker/picker_file_suggester.cc
@@ -23,6 +23,7 @@ using DriveFile = PickerFileSuggester::DriveFile; constexpr base::TimeDelta kMaxFileRecencyDelta = base::Days(30); +constexpr base::TimeDelta kScanTimeout = base::Seconds(1); storage::FileSystemContext* GetFileSystemContextForProfile(Profile* profile) { content::StoragePartition* storage = profile->GetDefaultStoragePartition(); @@ -44,6 +45,7 @@ } ash::RecentModelOptions options = { .now_delta = kMaxFileRecencyDelta, + .scan_timeout = kScanTimeout, .file_type = file_type, };
diff --git a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc index a7bdb9a2..9ec5e14 100644 --- a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc +++ b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
@@ -446,4 +446,6 @@ })); } +// TODO: b/330786933: Add interactive UI test for file previews. + } // namespace
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc index 0dcb355..1b74330 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc
@@ -9,6 +9,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/extension_apps_utils.h" @@ -17,6 +18,8 @@ #include "chrome/browser/ash/app_list/extension_app_utils.h" #include "chrome/browser/ash/app_restore/full_restore_service.h" #include "chrome/browser/ash/borealis/borealis_window_manager.h" +#include "chrome/browser/ash/bruschetta/bruschetta_service.h" +#include "chrome/browser/ash/bruschetta/bruschetta_util.h" #include "chrome/browser/ash/crosapi/browser_manager.h" #include "chrome/browser/ash/crostini/crostini_manager.h" #include "chrome/browser/ash/crostini/crostini_util.h" @@ -35,6 +38,7 @@ #include "chrome/browser/ui/ash/shelf/browser_shortcut_shelf_item_controller.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h" +#include "chrome/browser/ui/ash/shelf/shelf_context_menu.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/views/crostini/crostini_app_restart_dialog.h" #include "chrome/browser/ui/webui/ash/settings/app_management/app_management_uma.h" @@ -120,7 +124,8 @@ ui::ImageModel AppServiceShelfContextMenu::GetIconForCommandId( int command_id) const { - if (command_id == ash::LAUNCH_NEW) { + if (command_id == ash::LAUNCH_NEW || + command_id == ash::SHUTDOWN_BRUSCHETTA_OS) { const gfx::VectorIcon& icon = GetCommandIdVectorIcon(command_id, launch_new_string_id_); return ui::ImageModel::FromVectorIcon( @@ -137,6 +142,11 @@ << item().id.app_id << "; app type = " << apps::EnumToString(app_type_) << "; submenu items count = " << submenu_->GetItemCount(); return l10n_util::GetStringUTF16(launch_new_string_id_); + } else if (command_id == ash::SHUTDOWN_BRUSCHETTA_OS) { + return l10n_util::GetStringFUTF16( + IDS_BRUSCHETTA_SHUT_DOWN_LINUX_MENU_ITEM, + base::UTF8ToUTF16( + bruschetta::GetBruschettaDisplayName(controller()->profile()))); } return ShelfContextMenu::GetLabelForCommandId(command_id); } @@ -206,6 +216,16 @@ } break; + case ash::SHUTDOWN_BRUSCHETTA_OS: + if (item().id.app_id == guest_os::kTerminalSystemAppId) { + bruschetta::BruschettaService::GetForProfile(controller()->profile()) + ->StopRunningVms(); + } else { + LOG(ERROR) << "App " << item().id.app_id + << " should not have a shutdown Bruschetta command."; + } + break; + case ash::USE_LAUNCH_TYPE_TABBED_WINDOW: [[fallthrough]]; case ash::USE_LAUNCH_TYPE_REGULAR: @@ -317,6 +337,7 @@ bool AppServiceShelfContextMenu::IsItemForCommandIdDynamic( int command_id) const { return command_id == ash::LAUNCH_NEW || + command_id == ash::SHUTDOWN_BRUSCHETTA_OS || ShelfContextMenu::IsItemForCommandIdDynamic(command_id); }
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu_browsertest.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu_browsertest.cc index 510e6a8b..09a78bd 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu_browsertest.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu_browsertest.cc
@@ -8,12 +8,15 @@ #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr_exclusion.h" #include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/metrics/user_action_tester.h" #include "base/test/scoped_feature_list.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/ash/bruschetta/bruschetta_service.h" +#include "chrome/browser/ash/bruschetta/bruschetta_util.h" #include "chrome/browser/ash/crostini/crostini_manager.h" #include "chrome/browser/ash/crostini/crostini_test_helper.h" #include "chrome/browser/ash/crostini/crostini_util.h" @@ -430,3 +433,40 @@ .vector_icon(), &kShutdownGuestOsIcon); } + +IN_PROC_BROWSER_TEST_F(AppServiceShelfContextMenuCrostiniAppBrowserTest, + ShutDownBruschettaOs) { + ash::SystemWebAppManager::Get(browser()->profile()) + ->InstallSystemAppsForTesting(); + auto menu_section = GetContextMenuSectionForAppCommand( + guest_os::kTerminalSystemAppId, ash::SHUTDOWN_BRUSCHETTA_OS); + ASSERT_FALSE(menu_section); + + guest_os::GuestId id(guest_os::VmType::BRUSCHETTA, + bruschetta::kBruschettaVmName, ""); + guest_os::GuestOsSessionTracker::GetForProfile(browser()->profile()) + ->AddGuestForTesting(id, guest_os::GuestInfo{id, 0, {}, {}, {}, {}}); + + auto* bruschetta_service = + bruschetta::BruschettaService::GetForProfile(browser()->profile()); + bruschetta_service->RegisterVmLaunch(bruschetta::kBruschettaVmName, + bruschetta::RunningVmPolicy{false}); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + + menu_section = GetContextMenuSectionForAppCommand( + guest_os::kTerminalSystemAppId, ash::SHUTDOWN_BRUSCHETTA_OS); + ASSERT_TRUE(menu_section); + + EXPECT_GT(menu_section->command_index, 0u); + EXPECT_FALSE( + menu_section->menu_model->GetSubmenuModelAt(menu_section->command_index)); + EXPECT_NE(menu_section->menu_model->GetLabelAt(menu_section->command_index) + .find(base::ASCIIToUTF16(bruschetta::GetBruschettaDisplayName( + browser()->profile()))), + std::string::npos); + EXPECT_EQ(menu_section->menu_model->GetIconAt(menu_section->command_index) + .GetVectorIcon() + .vector_icon(), + &kShutdownGuestOsIcon); +}
diff --git a/chrome/browser/ui/ash/shelf/shelf_context_menu.cc b/chrome/browser/ui/ash/shelf/shelf_context_menu.cc index 066d7e5..bbf784da 100644 --- a/chrome/browser/ui/ash/shelf/shelf_context_menu.cc +++ b/chrome/browser/ui/ash/shelf/shelf_context_menu.cc
@@ -248,6 +248,8 @@ return gfx::kNoneIcon; case ash::SHUTDOWN_GUEST_OS: return kShutdownGuestOsIcon; + case ash::SHUTDOWN_BRUSCHETTA_OS: + return kShutdownGuestOsIcon; case ash::CROSTINI_USE_HIGH_DENSITY: return views::kLinuxHighDensityIcon; case ash::CROSTINI_USE_LOW_DENSITY:
diff --git a/chrome/browser/ui/autofill/autofill_context_menu_manager.cc b/chrome/browser/ui/autofill/autofill_context_menu_manager.cc index 9f32a14..e2f797f 100644 --- a/chrome/browser/ui/autofill/autofill_context_menu_manager.cc +++ b/chrome/browser/ui/autofill/autofill_context_menu_manager.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/passwords/ui_utils.h" +#include "chrome/browser/user_education/user_education_service.h" #include "chrome/grit/generated_resources.h" #include "components/autofill/content/browser/content_autofill_client.h" #include "components/autofill/content/browser/content_autofill_driver.h" @@ -364,7 +365,11 @@ ui::ImageModel::FromVectorIcon( vector_icons::kLocationOnChromeRefreshIcon, ui::kColorIcon, kContextMenuIconSize)); - menu_model_->SetIsNewFeatureAt(menu_model_->GetItemCount() - 1, true); + menu_model_->SetIsNewFeatureAt( + menu_model_->GetItemCount() - 1, + UserEducationService::MaybeShowNewBadge( + delegate_->GetBrowserContext(), + features::kAutofillForUnclassifiedFieldsAvailable)); } if (add_payments_fallback) { menu_model_->AddItemWithStringIdAndIcon( @@ -372,7 +377,11 @@ IDS_CONTENT_CONTEXT_AUTOFILL_FALLBACK_PAYMENTS, ui::ImageModel::FromVectorIcon(kCreditCardChromeRefreshIcon, ui::kColorIcon, kContextMenuIconSize)); - menu_model_->SetIsNewFeatureAt(menu_model_->GetItemCount() - 1, true); + menu_model_->SetIsNewFeatureAt( + menu_model_->GetItemCount() - 1, + UserEducationService::MaybeShowNewBadge( + delegate_->GetBrowserContext(), + features::kAutofillForUnclassifiedFieldsAvailable)); } if (add_passwords_fallback) { AddPasswordsManualFallbackItems(*password_manager_driver); @@ -628,6 +637,9 @@ AutofillSuggestionTriggerSource::kManualFallbackPayments); LogManualFallbackContextMenuEntryAccepted(autofill_driver, FillingProduct::kCreditCard); + UserEducationService::MaybeNotifyPromoFeatureUsed( + delegate_->GetBrowserContext(), + features::kAutofillForUnclassifiedFieldsAvailable); } void AutofillContextMenuManager::ExecuteFallbackForPasswordsCommand( @@ -723,6 +735,9 @@ } LogManualFallbackContextMenuEntryAccepted(autofill_driver, FillingProduct::kAddress); + UserEducationService::MaybeNotifyPromoFeatureUsed( + delegate_->GetBrowserContext(), + features::kAutofillForUnclassifiedFieldsAvailable); } AutofillField* AutofillContextMenuManager::GetAutofillField(
diff --git a/chrome/browser/ui/browser_actions.cc b/chrome/browser/ui/browser_actions.cc index 3e50f03e..2be20433 100644 --- a/chrome/browser/ui/browser_actions.cc +++ b/chrome/browser/ui/browser_actions.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" #include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h" -#include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h" #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h" #include "chrome/browser/ui/side_panel/companion/companion_utils.h" #include "chrome/browser/ui/side_panel/history_clusters/history_clusters_side_panel_utils.h" @@ -43,6 +42,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" #include "ui/base/ui_base_features.h" +#include "ui/gfx/text_utils.h" #include "ui/gfx/vector_icon_types.h" namespace { @@ -52,10 +52,13 @@ int title_id, int tooltip_id, const gfx::VectorIcon& icon) { + auto clean_text = [](int str_id) { + return gfx::RemoveAccelerator(l10n_util::GetStringUTF16(str_id)); + }; return actions::ActionItem::Builder(callback) .SetActionId(action_id) - .SetText(l10n_util::GetStringUTF16(title_id)) - .SetTooltipText(l10n_util::GetStringUTF16(tooltip_id)) + .SetText(clean_text(title_id)) + .SetTooltipText(clean_text(tooltip_id)) .SetImage(ui::ImageModel::FromVectorIcon(icon, ui::kColorIcon)) .SetProperty(actions::kActionItemPinnableKey, true); } @@ -303,16 +306,4 @@ kDevicesChromeRefreshIcon) .SetEnabled(chrome::CanSendTabToSelf(&(browser_.get()))) .Build()); - - root_action_item_->AddChild( - ChromeMenuAction(base::BindRepeating( - [](Browser* browser, actions::ActionItem* item, - actions::ActionInvocationContext context) { - chrome::GenerateQRCode(browser); - }, - base::Unretained(browser)), - kActionQrCodeGenerator, IDS_APP_MENU_CREATE_QR_CODE, - IDS_APP_MENU_CREATE_QR_CODE, kQrCodeChromeRefreshIcon) - .SetEnabled(false) - .Build()); }
diff --git a/chrome/browser/ui/browser_actions_unittest.cc b/chrome/browser/ui/browser_actions_unittest.cc index 455a6ff..370e85c 100644 --- a/chrome/browser/ui/browser_actions_unittest.cc +++ b/chrome/browser/ui/browser_actions_unittest.cc
@@ -34,8 +34,7 @@ std::vector<actions::ActionId> browser_action_ids = { kActionNewIncognitoWindow, kActionPrint, kActionClearBrowsingData, - kActionTaskManager, kActionDevTools, kActionSendTabToSelf, - kActionQrCodeGenerator}; + kActionTaskManager, kActionDevTools, kActionSendTabToSelf}; ASSERT_NE(browser_actions->root_action_item(), nullptr); @@ -60,6 +59,4 @@ chrome::CanPrint(browser())); EXPECT_EQ(action_manager.FindAction(kActionSendTabToSelf)->GetEnabled(), chrome::CanSendTabToSelf(browser())); - EXPECT_EQ(action_manager.FindAction(kActionQrCodeGenerator)->GetEnabled(), - false); }
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index 147c3824..16f254a 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -1611,8 +1611,8 @@ UpdateCommandAndActionEnabled(IDC_SEND_TAB_TO_SELF, kActionSendTabToSelf, CanSendTabToSelf(browser_)); - UpdateCommandAndActionEnabled(IDC_QRCODE_GENERATOR, kActionQrCodeGenerator, - CanGenerateQrCode(browser_)); + command_updater_.UpdateCommandEnabled(IDC_QRCODE_GENERATOR, + CanGenerateQrCode(browser_)); if (features::IsChromeRefresh2023()) { ChromeTranslateClient* chrome_translate_client =
diff --git a/chrome/browser/ui/chromeos/magic_boost/BUILD.gn b/chrome/browser/ui/chromeos/magic_boost/BUILD.gn index 14d2a85..50c979c4 100644 --- a/chrome/browser/ui/chromeos/magic_boost/BUILD.gn +++ b/chrome/browser/ui/chromeos/magic_boost/BUILD.gn
@@ -16,6 +16,7 @@ ] deps = [ "//base", + "//chrome/browser/chromeos", "//chrome/browser/resources:component_extension_resources", "//chrome/browser/ui/views/editor_menu:utils", "//chromeos/ui/vector_icons",
diff --git a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc index 39df95a..29b3fc9c0 100644 --- a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc +++ b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc
@@ -5,10 +5,19 @@ #include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" #include "base/no_destructor.h" +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" #include "chrome/browser/ui/chromeos/magic_boost/magic_boost_disclaimer_view.h" #include "chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.h" #include "ui/views/widget/unique_widget_ptr.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller_ash.h" +#endif + +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller_lacros.h" +#endif + namespace chromeos { namespace { @@ -26,7 +35,13 @@ return instance.get(); } -MagicBoostController::MagicBoostController() = default; +MagicBoostController::MagicBoostController() { +#if BUILDFLAG(IS_CHROMEOS_ASH) + mahi_prefs_controller_ = std::make_unique<mahi::MahiPrefsControllerAsh>(); +#elif BUILDFLAG(IS_CHROMEOS_LACROS) + mahi_prefs_controller_ = std::make_unique<mahi::MahiPrefsControllerLacros>(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) +} MagicBoostController::~MagicBoostController() = default; @@ -54,8 +69,8 @@ } bool MagicBoostController::ShouldQuickAnswersAndMahiShowOptIn() { - // TODO(b/339043693): Implement this function. - return false; + // TODO(b/341485303): Check for Magic Boost consent status. + return true; } void MagicBoostController::SetAllFeaturesState(bool enabled) { @@ -64,7 +79,9 @@ } void MagicBoostController::SetQuickAnswersAndMahiFeaturesState(bool enabled) { - // TODO(b/339043693): Implement this function. + mahi_prefs_controller_->SetMahiEnabled(enabled); + + // TODO(b/339043693): Enable/disable Quick Answers. } void MagicBoostController::SetIsOrcaIncludedForTest(bool include) {
diff --git a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h index 25a4c37..de1b1629 100644 --- a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h +++ b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_MAGIC_BOOST_CONTROLLER_H_ #define CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_MAGIC_BOOST_CONTROLLER_H_ +#include <memory> + #include "base/no_destructor.h" #include "ui/views/widget/unique_widget_ptr.h" @@ -16,20 +18,11 @@ class Widget; } // namespace views -namespace chromeos { +namespace mahi { +class MahiPrefsController; +} // namespace mahi -enum class HMRConsentStatus : int { - // User has agreed to consent by pressing "Yes/Agree" button to all dialogs - // from the consent window. - kApproved = 0, - // User has disagreed to consent by pressing "No/Disagree" button to any - // dialog from the consent window. - kDeclined = 1, - // No explicit consent to use the feature has been received yet. - kPending = 2, - // No request has been sent to users to collect their consent. - kUnset = 3, -}; +namespace chromeos { // The controller that manages the lifetime of opt-in and disclaimer widgets. // Some functions in this controller are virtual for testing. @@ -82,6 +75,8 @@ views::UniqueWidgetPtr opt_in_widget_; views::UniqueWidgetPtr disclaimer_widget_; + + std::unique_ptr<::mahi::MahiPrefsController> mahi_prefs_controller_; }; // Helper class to automatically set and reset the `MagicBoostController` global
diff --git a/chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.cc b/chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.cc index caa7d415..7843d36 100644 --- a/chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.cc +++ b/chrome/browser/ui/chromeos/magic_boost/magic_boost_opt_in_card.cc
@@ -6,6 +6,7 @@ #include <string> +#include "chrome/browser/chromeos/mahi/mahi_prefs_controller.h" #include "chrome/browser/ui/chromeos/magic_boost/magic_boost_constants.h" #include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" #include "chrome/browser/ui/views/editor_menu/utils/utils.h" @@ -249,7 +250,9 @@ auto* controller = MagicBoostController::Get(); controller->CloseOptInUi(); // TODO(b/341158134): Disable opt-in card from showing again when "No thanks" - // is pressed. + // is pressed. We should also use `MagicBoostState::Get()` here instead when + // it is available. + mahi::MahiPrefsController::Get()->SetMahiEnabled(false); } BEGIN_METADATA(MagicBoostOptInCard)
diff --git a/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc b/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc index 21f8cad..970bdba1 100644 --- a/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc +++ b/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc
@@ -238,7 +238,7 @@ // Mock EntryPointInfo returned by ShoppingService. std::set<GURL> urls = {GURL(kTestUrl2), GURL(kTestUrl3), GURL(kTestUrl4)}; auto info = std::make_optional<commerce::EntryPointInfo>(kTitle, urls); - mock_shopping_service_->SetResponseForGetEntryPointInfoForNavigation(info); + mock_cluster_manager_->SetResponseForGetEntryPointInfoForNavigation(info); // Set up observer. EXPECT_CALL(*observer_, ShowEntryPointWithTitle(kTitle)).Times(1); @@ -274,7 +274,7 @@ // Mock EntryPointInfo returned by ShoppingService. std::set<GURL> urls = {GURL(kTestUrl2), GURL(kTestUrl3), GURL(kTestUrl4)}; auto info = std::make_optional<commerce::EntryPointInfo>(kTitle, urls); - mock_shopping_service_->SetResponseForGetEntryPointInfoForNavigation(info); + mock_cluster_manager_->SetResponseForGetEntryPointInfoForNavigation(info); // Set up observer. EXPECT_CALL(*observer_, ShowEntryPointWithTitle(kTitle)).Times(1);
diff --git a/chrome/browser/ui/lens/lens_untrusted_ui.cc b/chrome/browser/ui/lens/lens_untrusted_ui.cc index 4a7c4f9..4c352acc 100644 --- a/chrome/browser/ui/lens/lens_untrusted_ui.cc +++ b/chrome/browser/ui/lens/lens_untrusted_ui.cc
@@ -46,6 +46,8 @@ html_source->AddLocalizedString("dismiss", IDS_LENS_OVERLAY_TOAST_DISMISS_MESSAGE); html_source->AddLocalizedString("info", IDS_LENS_OVERLAY_INFO_BUTTON_LABEL); + html_source->AddLocalizedString("initialToastLabel", + IDS_LENS_OVERLAY_INITIAL_TOAST_LABEL); html_source->AddLocalizedString("initialToastMessage", IDS_LENS_OVERLAY_INITIAL_TOAST_MESSAGE); html_source->AddLocalizedString("sendFeedback", IDS_LENS_SEND_FEEDBACK_LABEL);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index fcfd07bd..82e3b995 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -2088,7 +2088,6 @@ WebContents* active_contents = GetActiveWebContents(); WebContents* raw_contents = tab->contents(); CHECK_EQ(this, tab->owning_model()); - tab->set_pinned(pin); if ((add_types & ADD_INHERIT_OPENER) && active_contents) { if (active) { // Forget any existing relationships, we don't want to make things too @@ -2107,40 +2106,7 @@ tab->set_blocked(manager->IsDialogActive()); } - // Force the group value to be set since we perform contiguity checks on the - // tab groups when rendered in views. this will not inform the observers of - // the group change until GroupTab called after OnTabStripModelChanged. - tab->set_group(group); - - TabStripSelectionChange selection(GetActiveWebContents(), selection_model_); - - GetContentsDataAsVector().insert(GetContentsDataAsVector().begin() + index, - std::move(tab)); - - selection_model_.IncrementFrom(index); - - if (active) { - ui::ListSelectionModel new_model = selection_model_; - new_model.SetSelectedIndex(index); - selection = SetSelection(std::move(new_model), - TabStripModelObserver::CHANGE_REASON_NONE, - /*triggered_by_other_operation=*/true); - } - - CHECK(empty() || selection_model_.active().has_value(), - base::NotFatalUntil::M124); - - TabStripModelChange::Insert insert; - insert.contents.push_back({raw_contents, index}); - TabStripModelChange change(std::move(insert)); - OnChange(change, selection); - - if (group_model_ && group.has_value()) { - // Unset the group at the index of the inserted WebContents so that the - // GroupTab functionality isn't skipped. - GetTabAtIndex(index)->set_group(std::nullopt); - GroupTab(index, group.value()); - } + InsertTabAtIndexImpl(std::move(tab), index, group, pin, active); return index; } @@ -2678,6 +2644,137 @@ delegate_->AddToReadLater(GetWebContentsAt(index)); } +void TabStripModel::InsertTabAtIndexImpl( + std::unique_ptr<tabs::TabModel> tab_model, + int index, + std::optional<tab_groups::TabGroupId> group, + bool pin, + bool active) { + WebContents* web_contents = tab_model->contents(); + + tab_model->set_group(group); + tab_model->set_pinned(pin); + + GetContentsDataAsVector().insert(GetContentsDataAsVector().begin() + index, + std::move(tab_model)); + + DCHECK(ValidateTabStripModel()); + + // Update selection model and send the notification. + TabStripSelectionChange selection(GetActiveWebContents(), selection_model_); + selection_model_.IncrementFrom(index); + if (active) { + ui::ListSelectionModel new_model = selection_model_; + new_model.SetSelectedIndex(index); + selection = SetSelection(std::move(new_model), + TabStripModelObserver::CHANGE_REASON_NONE, + /*triggered_by_other_operation=*/true); + } + + CHECK(empty() || selection_model_.active().has_value()); + + TabStripModelChange::Insert insert; + insert.contents.push_back({web_contents, index}); + TabStripModelChange change(std::move(insert)); + OnChange(change, selection); + + if (group_model_ && group.has_value()) { + TabGroupStateChanged(index, web_contents, std::nullopt, group); + } +} + +void TabStripModel::TabGroupStateChanged( + int index, + WebContents* web_contents, + const std::optional<tab_groups::TabGroupId> initial_group, + const std::optional<tab_groups::TabGroupId> new_group) { + if (!group_model_) { + return; + } + + if (initial_group == new_group) { + return; + } + + if (initial_group.has_value()) { + // Send the observation + for (auto& observer : observers_) { + observer.TabGroupedStateChanged(std::nullopt, web_contents, index); + } + // Update the group model. + RemoveTabFromGroupModel(initial_group.value()); + } + + if (new_group.has_value()) { + // Send the observation + for (auto& observer : observers_) { + observer.TabGroupedStateChanged(new_group.value(), web_contents, index); + } + // Update the group model. + AddTabToGroupModel(new_group.value()); + } +} + +void TabStripModel::RemoveTabFromGroupModel( + const tab_groups::TabGroupId& group) { + if (!group_model_) { + return; + } + + TabGroup* tab_group = group_model_->GetTabGroup(group); + tab_group->RemoveTab(); + + if (tab_group->IsEmpty()) { + group_model_->RemoveTabGroup(group); + } +} + +void TabStripModel::AddTabToGroupModel(const tab_groups::TabGroupId& group) { + if (!group_model_) { + return; + } + + TabGroup* tab_group = group_model_->GetTabGroup(group); + tab_group->AddTab(); +} + +bool TabStripModel::ValidateTabStripModel() { + if (empty()) { + return true; + } + + // Check for pinned validity. + bool unpinned_found = IsTabPinned(0) ? false : true; + for (int i = 1; i < count(); i++) { + if (!unpinned_found) { + if (!IsTabPinned(i)) { + unpinned_found = true; + } + } else { + if (IsTabPinned(i)) { + return false; + } + } + } + + // If tab groups are not supported return true. + if (!group_model_) { + return true; + } + + for (const auto& group_id : group_model_->ListTabGroups()) { + gfx::Range tabs_in_group = group_model()->GetTabGroup(group_id)->ListTabs(); + if (!tabs_in_group.is_empty()) { + for (size_t index = tabs_in_group.start(); index < tabs_in_group.end(); + ++index) { + DCHECK(GetTabGroupForTab(index) == group_id); + } + } + } + + return true; +} + std::optional<tab_groups::TabGroupId> TabStripModel::UngroupTab(int index) { if (!group_model_) { return std::nullopt;
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h index 90d8c7d..1a3afcf49 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.h +++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -857,6 +857,32 @@ // index would change. void GroupTab(int index, const tab_groups::TabGroupId& group); + // Updates the `contents_data_` and sends out observer notifications for + // inserting a new tab in the tabstrip. + void InsertTabAtIndexImpl(std::unique_ptr<tabs::TabModel> tab_model, + int index, + std::optional<tab_groups::TabGroupId> group, + bool pin, + bool active); + + // Sends group notifications for a tab at `index` based on its initial_group + // and `final_group` and updates the `group_model_`. + void TabGroupStateChanged( + int index, + content::WebContents* web_contents, + const std::optional<tab_groups::TabGroupId> initial_group, + const std::optional<tab_groups::TabGroupId> new_group); + + // Updates the `group_model` by decrementing the tab count of `group`. + void RemoveTabFromGroupModel(const tab_groups::TabGroupId& group); + + // Updates the `group_model` by incrementing the tab count of `group`. + void AddTabToGroupModel(const tab_groups::TabGroupId& group); + + // Checks if the `contents_data_` is in a valid order. This checks for + // pinned tabs placement and group contiguity. + bool ValidateTabStripModel(); + // Changes the pinned state of the tab at `index`, moving it in the process if // necessary. Returns the new index of the tab. int SetTabPinnedImpl(int index, bool pinned);
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper_interactive_uitest.cc b/chrome/browser/ui/thumbnails/thumbnail_tab_helper_interactive_uitest.cc index 3795011..894b151 100644 --- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper_interactive_uitest.cc +++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper_interactive_uitest.cc
@@ -20,6 +20,7 @@ #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "chrome/test/interaction/interactive_browser_test.h" #include "content/public/browser/navigation_controller.h" #include "content/public/test/browser_test.h" #include "url/gurl.h" @@ -155,24 +156,60 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// TODO(crbug.com/40883117) flakes on ChromeOS and MSAN/TSAN/ASAN builders. -// TODO(crbug.com/335997050) timeout on ARM64 debug builder. -#if BUILDFLAG(IS_CHROMEOS) || defined(THREAD_SANITIZER) || \ - defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ - (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64) && !defined(NDEBUG)) -#define MAYBE_TabLoadTriggersScreenshot DISABLED_TabLoadTriggersScreenshot -#else -#define MAYBE_TabLoadTriggersScreenshot TabLoadTriggersScreenshot -#endif // BUILDFLAG(IS_CHROMEOS) +// Updated test fixture for testing interaction of thumbnail tab helper and +// browser, specifically testing interaction of tab load and thumbnail capture. +class ThumbnailTabHelperUpdatedInteractiveTest : public InteractiveBrowserTest { + protected: + void SetUp() override { + // This flag causes the thumbnail tab helper system to engage. Otherwise + // there is no ThumbnailTabHelper created. Note that there *are* other flags + // that also trigger the existence of the helper. + scoped_feature_list_.InitAndEnableFeature(features::kTabHoverCardImages); + InteractiveBrowserTest::SetUp(); + } -IN_PROC_BROWSER_TEST_F(ThumbnailTabHelperInteractiveTest, - MAYBE_TabLoadTriggersScreenshot) { - ui_test_utils::NavigateToURLWithDisposition( - browser(), url2_, WindowOpenDisposition::NEW_BACKGROUND_TAB, - ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); + int GetTabCount() { return browser()->tab_strip_model()->count(); } - DCHECK_EQ(2, browser()->tab_strip_model()->count()); - WaitForAndVerifyThumbnail(browser(), 1); + auto CheckTabHasThumbnailData(int tab_index, bool has_data) { + return CheckResult( + [=]() { + return ThumbnailTabHelper::FromWebContents( + browser()->tab_strip_model()->GetWebContentsAt(tab_index)) + ->thumbnail() + ->has_data(); + }, + has_data); + } + + auto WaitForAndVerifyThumbnail(int tab_index) { + return Check([=]() { + auto* const thumbnail_tab_helper = ThumbnailTabHelper::FromWebContents( + browser()->tab_strip_model()->GetWebContentsAt(tab_index)); + auto thumbnail = thumbnail_tab_helper->thumbnail(); + + ThumbnailWaiter waiter; + const std::optional<gfx::ImageSkia> data = + waiter.WaitForThumbnail(thumbnail.get()); + return data && !data->isNull(); + }); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(ThumbnailTabHelperUpdatedInteractiveTest, + TabLoadTriggersScreenshot) { + RunTestSequence( + Do([this]() { + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL(chrome::kChromeUINewTabURL), + WindowOpenDisposition::NEW_BACKGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); + }), + CheckResult([this]() { return GetTabCount(); }, 2), + CheckTabHasThumbnailData(0, false), CheckTabHasThumbnailData(1, false), + WaitForAndVerifyThumbnail(0), CheckTabHasThumbnailData(0, true)); } // TODO(crbug.com/40883117) flakes on ChromeOS and MSAN/TSAN/ASAN builders.
diff --git a/chrome/browser/ui/user_education/user_education_configuration_provider_browsertest.cc b/chrome/browser/ui/user_education/user_education_configuration_provider_browsertest.cc new file mode 100644 index 0000000..6e973b0 --- /dev/null +++ b/chrome/browser/ui/user_education/user_education_configuration_provider_browsertest.cc
@@ -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. + +#include "chrome/browser/user_education/user_education_configuration_provider.h" + +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/feature_engagement/tracker_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/feature_engagement/public/configuration.h" +#include "components/feature_engagement/public/feature_constants.h" +#include "components/feature_engagement/public/tracker.h" +#include "components/feature_engagement/test/scoped_iph_feature_list.h" +#include "components/user_education/common/user_education_features.h" +#include "content/public/test/browser_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +constexpr char kExtendedParamName[] = "x_param"; +constexpr char kExtendedParamValue[] = "x_param_value"; +} // namespace + +class UserEducationConfigurationProviderBrowsertest + : public InProcessBrowserTest, + public testing::WithParamInterface<bool> { + public: + UserEducationConfigurationProviderBrowsertest() = default; + ~UserEducationConfigurationProviderBrowsertest() override = default; + + void SetUp() override { + if (UseV2()) { + feature_list_.InitAndEnableFeaturesWithParameters( + // Enable features: + {base::test::FeatureRefAndParams( + feature_engagement::kIPHWebUiHelpBubbleTestFeature, + {{kExtendedParamName, kExtendedParamValue}}), + base::test::FeatureRefAndParams( + user_education::features::kUserEducationExperienceVersion2, + {})}); + } else { + feature_list_.InitAndEnableFeaturesWithParameters( + // Enable features: + {base::test::FeatureRefAndParams( + feature_engagement::kIPHWebUiHelpBubbleTestFeature, + {{kExtendedParamName, kExtendedParamValue}})}, + // Disable features: + {user_education::features::kUserEducationExperienceVersion2}); + } + InProcessBrowserTest::SetUp(); + } + + protected: + bool UseV2() const { return GetParam(); } + + private: + feature_engagement::test::ScopedIphFeatureList feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(, + UserEducationConfigurationProviderBrowsertest, + testing::Bool()); + +// Ensure that a feature which has field trial params that are not part of the +// FE config still gets proper automatic configuration. +IN_PROC_BROWSER_TEST_P(UserEducationConfigurationProviderBrowsertest, + AutoConfigureWithExtendedParam) { + auto* const tracker = + feature_engagement::TrackerFactory::GetForBrowserContext( + browser()->profile()); + auto* const config = tracker->GetConfigurationForTesting(); + const feature_engagement::FeatureConfig& feature_config = + config->GetFeatureConfig( + feature_engagement::kIPHWebUiHelpBubbleTestFeature); + ASSERT_TRUE(feature_config.valid); + EXPECT_FALSE(feature_config.trigger.name.empty()); + if (UseV2()) { + EXPECT_EQ(feature_engagement::ANY, feature_config.trigger.comparator.type); + EXPECT_EQ(0U, feature_config.trigger.comparator.value); + } else { + EXPECT_EQ(feature_engagement::LESS_THAN, + feature_config.trigger.comparator.type); + EXPECT_GT(feature_config.trigger.comparator.value, 0U); + } + EXPECT_FALSE(feature_config.used.name.empty()); + EXPECT_EQ(feature_engagement::EQUAL, feature_config.used.comparator.type); + EXPECT_EQ(0U, feature_config.used.comparator.value); + EXPECT_TRUE(feature_config.event_configs.empty()); + EXPECT_EQ(kExtendedParamValue, + base::GetFieldTrialParamValueByFeature( + feature_engagement::kIPHWebUiHelpBubbleTestFeature, + kExtendedParamName)); +}
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.cc b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.cc index 2aecbf6..3a99870 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.cc +++ b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.cc
@@ -18,9 +18,9 @@ views::View& parent_view, media_preview_metrics::Context metrics_context) : metrics_context_(metrics_context) { - auto* video_stream_view = + video_stream_view_ = parent_view.AddChildView(std::make_unique<VideoStreamView>()); - video_stream_view_tracker_.SetView(video_stream_view); + scoped_observation_.Observe(video_stream_view_); } VideoStreamCoordinator::~VideoStreamCoordinator() { @@ -31,11 +31,18 @@ const media::VideoCaptureDeviceInfo& device_info, mojo::Remote<video_capture::mojom::VideoSource> video_source) { Stop(); - if (auto* view = GetVideoStreamView(); view) { + + if (video_stream_view_) { + // Wait till the preview is actually shown. + if (video_stream_view_->width() == 0) { + connect_to_device_params_.emplace(device_info, std::move(video_source)); + return; + } + // Using double the view width when choosing preferred format. This provides // more information to the interpolation algorithm, so scaled images appear // sharper. - int requested_format_width = 2 * view->width(); + int requested_format_width = 2 * video_stream_view_->width(); video_frame_handler_ = std::make_unique<capture_mode::CameraVideoFrameHandler>( content::GetContextFactory(), std::move(video_source), @@ -56,8 +63,8 @@ frame_received_callback_for_test_.Run(); } - if (auto* view = GetVideoStreamView(); view) { - view->ScheduleFramePaint(std::move(frame)); + if (video_stream_view_) { + video_stream_view_->ScheduleFramePaint(std::move(frame)); } if (!video_stream_start_time_) { @@ -71,8 +78,8 @@ // When called, `video_frame_handler_` is no longer valid. video_frame_handler_.reset(); video_stream_start_time_.reset(); - if (auto* view = GetVideoStreamView(); view) { - view->ClearFrame(); + if (video_stream_view_) { + video_stream_view_->ClearFrame(); } } @@ -90,12 +97,12 @@ mojo::Remote<video_capture::mojom::VideoSourceProvider> video_source_provider) { size_t rendered_frame_count = 0; - if (auto* view = GetVideoStreamView(); view) { - rendered_frame_count = view->GetRenderedFrameCount(); + if (video_stream_view_) { + rendered_frame_count = video_stream_view_->GetRenderedFrameCount(); // ClearFrame() should be called before CameraVideoFrameHandler::Close(). // This order is needed as to clear all frame references before resetting // the buffers which happens within Close(). - view->ClearFrame(); + video_stream_view_->ClearFrame(); } if (video_frame_handler_) { @@ -121,7 +128,7 @@ actual_fps); video_stream_start_time_.reset(); - if (rendered_frame_count > 0) { + if (GetVideoStreamView()) { float rendered_percent = static_cast<double>(rendered_frame_count) / video_stream_total_frames_; media_preview_metrics::RecordPreviewVideoFramesRenderedPercent( @@ -140,7 +147,17 @@ } } -VideoStreamView* VideoStreamCoordinator::GetVideoStreamView() { - auto* view = video_stream_view_tracker_.view(); - return view ? static_cast<VideoStreamView*>(view) : nullptr; +void VideoStreamCoordinator::OnViewIsDeleting(views::View* observed_view) { + CHECK(scoped_observation_.IsObservingSource(observed_view)); + scoped_observation_.Reset(); + video_stream_view_ = nullptr; +} + +void VideoStreamCoordinator::OnViewBoundsChanged(views::View* observed_view) { + CHECK(scoped_observation_.IsObservingSource(observed_view)); + if (observed_view->width() > 0 && connect_to_device_params_) { + ConnectToDevice(connect_to_device_params_->first, + std::move(connect_to_device_params_->second)); + connect_to_device_params_.reset(); + } }
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.h b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.h index 9c1e6c69..e45d9735 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.h +++ b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator.h
@@ -14,13 +14,14 @@ #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "chrome/browser/ui/views/media_preview/media_preview_metrics.h" #include "components/capture_mode/camera_video_frame_handler.h" #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/video_capture/public/mojom/video_source_provider.mojom.h" -#include "ui/views/view_tracker.h" +#include "ui/views/view_observer.h" class VideoStreamView; @@ -28,7 +29,8 @@ // The view controller layer would be very thin so it is combined with the // coordinator for the VideoStreamView. class VideoStreamCoordinator - : public capture_mode::CameraVideoFrameHandler::Delegate { + : public capture_mode::CameraVideoFrameHandler::Delegate, + views::ViewObserver { public: // VideoStreamView is added to `parent_view` children list. explicit VideoStreamCoordinator( @@ -60,13 +62,17 @@ frame_received_callback_for_test_ = std::move(callback); } - VideoStreamView* GetVideoStreamView(); + VideoStreamView* GetVideoStreamView() { return video_stream_view_; } + + // ViewObserver: + void OnViewIsDeleting(views::View* observed_view) override; + void OnViewBoundsChanged(views::View* observed_view) override; private: void StopInternal(mojo::Remote<video_capture::mojom::VideoSourceProvider> video_source_provider = {}); - views::ViewTracker video_stream_view_tracker_; + raw_ptr<VideoStreamView> video_stream_view_; std::unique_ptr<capture_mode::CameraVideoFrameHandler> video_frame_handler_; // Runs when a new frame is received. Used for testing. @@ -75,6 +81,12 @@ const media_preview_metrics::Context metrics_context_; size_t video_stream_total_frames_; std::optional<base::TimeTicks> video_stream_start_time_; + + std::optional<std::pair<media::VideoCaptureDeviceInfo, + mojo::Remote<video_capture::mojom::VideoSource>>> + connect_to_device_params_; + base::ScopedObservation<views::View, views::ViewObserver> scoped_observation_{ + this}; }; #endif // CHROME_BROWSER_UI_VIEWS_MEDIA_PREVIEW_CAMERA_PREVIEW_VIDEO_STREAM_COORDINATOR_H_
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc index 33cd5517..541d95c 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc +++ b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc
@@ -84,6 +84,10 @@ video_source_receiver_.Bind(video_source.BindNewPipeAndPassReceiver()); coordinator_->ConnectToDevice(GetVideoCaptureDeviceInfo(), std::move(video_source)); + + coordinator_->GetVideoStreamView()->SetPreferredSize(gfx::Size{250, 180}); + coordinator_->GetVideoStreamView()->SizeToPreferredSize(); + EXPECT_TRUE(fake_video_source_.WaitForCreatePushSubscription()); EXPECT_TRUE(fake_video_source_.WaitForPushSubscriptionActivated()); @@ -104,10 +108,10 @@ coordinator_->Stop(); EXPECT_TRUE(fake_video_source_.WaitForPushSubscriptionClosed()); - // The selected pixel height is 120, so it will be logged in the 1 bucket. + // The selected pixel height is 500, so it will be logged in the 406 bucket. histogram_tester_.ExpectUniqueSample( "MediaPreviews.UI.Permissions.Camera.PixelHeight", - /*bucket_min_value=*/1, 1); + /*bucket_min_value=*/406, 1); histogram_tester_.ExpectUniqueSample( "MediaPreviews.UI.Preview.Permissions.Video.ExpectedFPS", /*bucket_min_value=*/30, 1);
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/audio_stream_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/mic_preview/audio_stream_coordinator_unittest.cc index bb0d1e2..0d91bda 100644 --- a/chrome/browser/ui/views/media_preview/mic_preview/audio_stream_coordinator_unittest.cc +++ b/chrome/browser/ui/views/media_preview/mic_preview/audio_stream_coordinator_unittest.cc
@@ -62,7 +62,7 @@ MockStreamFactory fake_stream_factory_; }; -TEST_F(AudioStreamCoordinatorTest, ConnectToAudioCaptuerAndReceiveBuses) { +TEST_F(AudioStreamCoordinatorTest, ConnectToAudioCapturerAndReceiveBuses) { constexpr uint32_t kAudioBusesNumber = 9; // some arbitrary number base::MockCallback<base::RepeatingClosure> callback; EXPECT_CALL(callback, Run()).Times(kAudioBusesNumber); @@ -76,6 +76,7 @@ std::unique_ptr<::media::AudioBus> audio_bus = media::AudioBus::Create( {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::ChannelLayoutConfig::Mono(), kSampleRate, kSampleRate / 20}); + audio_bus->Zero(); for (uint32_t i = 0; i < kAudioBusesNumber; i++) { coordinator_->GetAudioCapturerForTest()->Capture(
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.cc index 37b654b..8a3e605 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.cc
@@ -159,6 +159,8 @@ } ReadAnythingCoordinator::~ReadAnythingCoordinator() { + local_side_panel_switch_delay_timer_.Stop(); + if (features::IsReadAnythingDocsIntegrationEnabled()) { RemoveGDocsHelperExtension(); } @@ -266,12 +268,17 @@ obs.Activate(true); } - // TODO(crbug.com/324143642): Handle the installation of a11y helper extension - // for local side panels. - if (features::IsReadAnythingDocsIntegrationEnabled() && - !features::IsReadAnythingLocalSidePanelEnabled()) { - InstallGDocsHelperExtension(); + if (!features::IsReadAnythingDocsIntegrationEnabled()) { + return; } + + if (!features::IsReadAnythingLocalSidePanelEnabled()) { + InstallGDocsHelperExtension(); + return; + } + + active_local_side_panel_count_++; + InstallGDocsHelperExtension(); } void ReadAnythingCoordinator::OnReadAnythingSidePanelEntryHidden() { @@ -279,12 +286,22 @@ obs.Activate(false); } - // TODO(crbug.com/324143642): Handle the uninstallation of a11y helper - // extension for local side panels. - if (features::IsReadAnythingDocsIntegrationEnabled() && - !features::IsReadAnythingLocalSidePanelEnabled()) { - RemoveGDocsHelperExtension(); + if (!features::IsReadAnythingDocsIntegrationEnabled()) { + return; } + + if (!features::IsReadAnythingLocalSidePanelEnabled()) { + RemoveGDocsHelperExtension(); + return; + } + + active_local_side_panel_count_--; + local_side_panel_switch_delay_timer_.Stop(); + local_side_panel_switch_delay_timer_.Start( + FROM_HERE, base::Seconds(30), + base::BindRepeating( + &ReadAnythingCoordinator::OnLocalSidePanelSwitchDelayTimeout, + weak_ptr_factory_.GetWeakPtr())); } std::unique_ptr<views::View> ReadAnythingCoordinator::CreateContainerView() { @@ -464,4 +481,12 @@ } } +void ReadAnythingCoordinator::OnLocalSidePanelSwitchDelayTimeout() { + if (active_local_side_panel_count_ > 0) { + return; + } + + RemoveGDocsHelperExtension(); +} + BROWSER_USER_DATA_KEY_IMPL(ReadAnythingCoordinator);
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h index 06c2307..1fdf49b 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h
@@ -113,6 +113,16 @@ void InstallGDocsHelperExtension(); void RemoveGDocsHelperExtension(); + // The number of active local side panel that is currently shown in the + // browser. If there is no active local side panel (count is 0) after a + // timeout, we can safely remove the gdocs helper extension. + int active_local_side_panel_count_ = 0; + // Start a timer when the user leaves a local side panel. If they switch to + // another local side panel before it expires, keep the extension installed; + // otherwise, uninstall it. This prevents frequent + // installations/uninstallations. + base::RepeatingTimer local_side_panel_switch_delay_timer_; + void OnLocalSidePanelSwitchDelayTimeout(); std::string default_language_code_; std::unique_ptr<ReadAnythingModel> model_; @@ -128,6 +138,8 @@ // BrowserListObserver: void OnBrowserSetLastActive(Browser* browser) override; + base::WeakPtrFactory<ReadAnythingCoordinator> weak_ptr_factory_{this}; + BROWSER_USER_DATA_KEY_DECL(); }; #endif // CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_READ_ANYTHING_READ_ANYTHING_COORDINATOR_H_
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator_unittest.cc index d7cd0d9..25dcc66 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator_unittest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator_unittest.cc
@@ -40,10 +40,21 @@ class ReadAnythingCoordinatorTest : public TestWithBrowserView { public: + ReadAnythingCoordinatorTest() + : TestWithBrowserView( + content::BrowserTaskEnvironment::TimeSource::MOCK_TIME) {} + + ReadAnythingCoordinatorTest(const ReadAnythingCoordinatorTest&) = delete; + ReadAnythingCoordinatorTest& operator=(const ReadAnythingCoordinatorTest&) = + delete; + void SetUp() override { base::test::ScopedFeatureList features; scoped_feature_list_.InitWithFeatures( - {features::kReadAnything, features::kReadAnythingDocsIntegration}, {}); + {features::kReadAnything, features::kReadAnythingDocsIntegration, + features::kReadAnythingLocalSidePanel, + features::kReadAnythingWebUIToolbar}, + {}); TestWithBrowserView::SetUp(); side_panel_coordinator_ = @@ -180,42 +191,51 @@ } #if !BUILDFLAG(IS_CHROMEOS_LACROS) -// TODO(b/324143642): enable this test when reading mode local side panels work -// with Docs. -TEST_F( - ReadAnythingCoordinatorTest, - DISABLED_SidePanelShowAndHide_NonLacros_CallEmbeddedA11yExtensionLoader) { +TEST_F(ReadAnythingCoordinatorTest, + SidePanelShowAndHide_NonLacros_CallEmbeddedA11yExtensionLoader) { SidePanelEntry* entry = contextual_registries_[0]->GetEntryForKey( SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)); EXPECT_FALSE(EmbeddedA11yExtensionLoader::GetInstance()->IsExtensionInstalled( extension_misc::kReadingModeGDocsHelperExtensionId)); + // If the local side panel entry is shown, install the helper extension. entry->OnEntryShown(); EXPECT_TRUE(EmbeddedA11yExtensionLoader::GetInstance()->IsExtensionInstalled( extension_misc::kReadingModeGDocsHelperExtensionId)); - // Called once when calling OnEntryHidden and once on destruction. + // If the local side panel entry is hidden, remove the helper extension after + // a timeout. entry->OnEntryHidden(); + // The helper extension is not removed immediately. + EXPECT_TRUE(EmbeddedA11yExtensionLoader::GetInstance()->IsExtensionInstalled( + extension_misc::kReadingModeGDocsHelperExtensionId)); + // The helper extension is removed after a timeout. + task_environment()->FastForwardBy(base::Seconds(30)); EXPECT_FALSE(EmbeddedA11yExtensionLoader::GetInstance()->IsExtensionInstalled( extension_misc::kReadingModeGDocsHelperExtensionId)); } #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) #if BUILDFLAG(IS_CHROMEOS_LACROS) -// TODO(b/324143642): enable this test when reading mode local side panels work -// with Docs. TEST_F( ReadAnythingCoordinatorTest, - DISABLED_SidePanelShowAndHide_Lacros_EmbeddedA11yManagerLacrosUpdateReadingModeState) { + SidePanelShowAndHide_Lacros_EmbeddedA11yManagerLacrosUpdateReadingModeState) { SidePanelEntry* entry = contextual_registries_[0]->GetEntryForKey( SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)); EXPECT_FALSE( EmbeddedA11yManagerLacros::GetInstance()->IsReadingModeEnabled()); + // If the local side panel entry is shown, set reading mode enabled to true. entry->OnEntryShown(); EXPECT_TRUE(EmbeddedA11yManagerLacros::GetInstance()->IsReadingModeEnabled()); + // If the local side panel entry is hidden, set reading mode enabled to false + // after a timeout. entry->OnEntryHidden(); + // The reading mode setting is not updated immediately. + EXPECT_TRUE(EmbeddedA11yManagerLacros::GetInstance()->IsReadingModeEnabled()); + // The reading mode setting is updated after a timeout. + task_environment()->FastForwardBy(base::Seconds(30)); EXPECT_FALSE( EmbeddedA11yManagerLacros::GetInstance()->IsReadingModeEnabled()); }
diff --git a/chrome/browser/ui/views/side_panel/side_panel.cc b/chrome/browser/ui/views/side_panel/side_panel.cc index 3ef1d7de..eda81ce 100644 --- a/chrome/browser/ui/views/side_panel/side_panel.cc +++ b/chrome/browser/ui/views/side_panel/side_panel.cc
@@ -447,7 +447,9 @@ std::optional<SidePanelEntry::Id> id = SidePanelUI::GetSidePanelUIForBrowser(browser_view_->browser()) ->GetCurrentEntryId(); - CHECK(id.has_value()); + if (!id.has_value()) { + return; + } int side_panel_contents_width = width() - GetBorderInsets().width(); int browser_window_width = browser_view_->width(); SidePanelUtil::RecordSidePanelResizeMetrics(
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc index 49e4dedc..7d3ca472 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -12,6 +12,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_forward.h" +#include "base/metrics/field_trial_params.h" #include "base/metrics/user_metrics.h" #include "base/strings/strcat.h" #include "base/time/time.h" @@ -1112,9 +1113,11 @@ pending_pin_promo_ = iph_feature; if (iph_feature && !browser_view_->CanShowFeaturePromo(*iph_feature) .is_blocked_this_instance()) { - // This is the standard "minimum successful impression" time. - constexpr base::TimeDelta kImpressionSuccessDuration = base::Seconds(6); - pin_promo_timer_.Start(FROM_HERE, kImpressionSuccessDuration, + // Default to ten second delay, but allow setting a different parameter via + // field trial. + const base::TimeDelta delay = base::GetFieldTrialParamByFeatureAsTimeDelta( + *iph_feature, "x_custom_iph_delay", base::Seconds(10)); + pin_promo_timer_.Start(FROM_HERE, delay, base::BindOnce(&SidePanelCoordinator::ShowPinPromo, base::Unretained(this))); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller.cc b/chrome/browser/ui/views/toolbar/toolbar_controller.cc index ab5b3427..cd14722 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller.cc
@@ -273,7 +273,6 @@ {kActionDevTools, "PinnedDeveloperToolsButton"}, {kActionNewIncognitoWindow, "PinnedNewIncognitoWindowButton"}, {kActionPrint, "PinnedPrintButton"}, - {kActionQrCodeGenerator, "PinnedQrCodeGeneratorButton"}, {kActionSendTabToSelf, "PinnedSendTabToSelfButton"}, {kActionSidePanelShowBookmarks, "PinnedShowBookmarkSidePanelButton"}, {kActionSidePanelShowReadAnything,
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc index e2e3430..6415ecc1 100644 --- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc +++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -42,6 +42,7 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/branded_strings.h" #include "chrome/grit/generated_resources.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/compose/core/browser/compose_features.h" #include "components/feature_engagement/public/feature_constants.h" #include "components/lens/lens_features.h" @@ -1343,6 +1344,8 @@ } } +// Note: If you add a badge here, be sure to add the name of the corresponding +// feature to tools/metrics/histograms/metadata/user_education/histograms.xml void MaybeRegisterChromeNewBadges(user_education::NewBadgeRegistry& registry) { if (registry.IsFeatureRegistered( user_education::features::kNewBadgeTestFeature)) { @@ -1370,6 +1373,14 @@ user_education::Metadata( 126, "emshack@chromium.org", "Shown in app menu when TabOrganizationAppMenuItem is enabled."))); + + registry.RegisterFeature(user_education::NewBadgeSpecification( + autofill::features::kAutofillForUnclassifiedFieldsAvailable, + user_education::Metadata( + 125, "vidhanj@google.com", + "Shown in the autofill section of the context menu for address and " + "credit card autofill entries when autofill for unclassified fields " + "is enabled."))); } std::unique_ptr<BrowserFeaturePromoController> CreateUserEducationResources(
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn index 9ca13c6e..fa7db3d 100644 --- a/chrome/browser/ui/webui/BUILD.gn +++ b/chrome/browser/ui/webui/BUILD.gn
@@ -3,6 +3,15 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//components/metrics/generate_allowlist_from_histograms_file.gni") + +generate_allowlist_from_histograms_file("webui_url_hashes") { + namespace = "webui_metrics" + input_xml_file = "//tools/metrics/histograms/enums.xml" + tag = "enum" + output_file = "webui_url_hashes.h" + allow_list_name = "WebUIUrlHashes" +} source_set("configs") { sources = [ @@ -48,6 +57,7 @@ "//ash/webui/firmware_update_ui", "//ash/webui/focus_mode", "//ash/webui/help_app_ui", + "//ash/webui/mall", "//ash/webui/os_feedback_ui", "//ash/webui/print_management", "//ash/webui/print_preview_cros", @@ -72,7 +82,11 @@ "webui_util.cc", "webui_util.h", ] + + sources += get_target_outputs(":webui_url_hashes") + deps = [ + ":webui_url_hashes", "//base", "//content/public/browser", "//content/public/common",
diff --git a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc index 362f4a2..737123d 100644 --- a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc +++ b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.h" +#include <memory> + #include "base/functional/callback.h" #include "build/chromeos_buildflags.h" #include "content/public/browser/webui_config_map.h" @@ -14,8 +16,10 @@ // Depending on //chrome/browser would cause a circular dependency because it // depends on //chrome/browser/ui which depends on this file's target. So we // suppress gn warnings. -#include "chrome/browser/app_mode/app_mode_utils.h" // nogncheck +// clang-format off +#include "chrome/browser/app_mode/app_mode_utils.h" // nogncheck #include "chrome/browser/feedback/feedback_dialog_utils.h" // nogncheck +// clang-format on #include "ash/webui/boca_ui/boca_ui.h" #include "ash/webui/camera_app_ui/camera_app_ui.h" @@ -28,6 +32,7 @@ #include "ash/webui/firmware_update_ui/firmware_update_app_ui.h" #include "ash/webui/focus_mode/focus_mode_ui.h" #include "ash/webui/help_app_ui/help_app_ui.h" +#include "ash/webui/mall/mall_ui.h" #include "ash/webui/media_app_ui/media_app_ui.h" #include "ash/webui/os_feedback_ui/os_feedback_ui.h" #include "ash/webui/personalization_app/personalization_app_ui.h" @@ -269,6 +274,7 @@ map.AddWebUIConfig(std::make_unique<LauncherInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<LockScreenNetworkUIConfig>()); map.AddWebUIConfig(std::make_unique<LockScreenStartReauthUIConfig>()); + map.AddWebUIConfig(std::make_unique<MallUIConfig>()); map.AddWebUIConfig(std::make_unique<ManageMirrorSyncUIConfig>()); map.AddWebUIConfig( MakeComponentConfigWithDelegate<MediaAppUIConfig, MediaAppUI,
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc index 498eeb4..d60dc89 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -983,8 +983,9 @@ SetupOrMoveDialogPage dialog_page) { // Allow no more than one upload dialog at a time. In the case of multiple // upload requests, they should either be handled simultaneously or queued. - if (SystemWebDialogDelegate::HasInstance( - GURL(chrome::kChromeUICloudUploadURL))) { + SystemWebDialogDelegate* existing_dialog = + SystemWebDialogDelegate::FindInstance(chrome::kChromeUICloudUploadURL); + if (existing_dialog) { LOG(WARNING) << "Another cloud upload dialog is already being shown"; if (dialog_page == SetupOrMoveDialogPage::kMoveConfirmationGoogleDrive || dialog_page == SetupOrMoveDialogPage::kMoveConfirmationOneDrive) { @@ -994,6 +995,8 @@ cloud_open_metrics_->LogTaskResult( OfficeTaskResult::kCannotShowSetupDialog); } + // Bring the existing dialog to the front to prompt the user to keep going. + existing_dialog->StackAtTop(); return false; }
diff --git a/chrome/browser/ui/webui/ash/settings/calculator/DIR_METADATA b/chrome/browser/ui/webui/ash/settings/calculator/DIR_METADATA new file mode 100644 index 0000000..e9400b87 --- /dev/null +++ b/chrome/browser/ui/webui/ash/settings/calculator/DIR_METADATA
@@ -0,0 +1 @@ +mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/ash/settings/calculator/OWNERS b/chrome/browser/ui/webui/ash/settings/calculator/OWNERS new file mode 100644 index 0000000..73220a8 --- /dev/null +++ b/chrome/browser/ui/webui/ash/settings/calculator/OWNERS
@@ -0,0 +1 @@ +file://ui/file_manager/OWNERS
diff --git a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.cc b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.cc index 453d6d1b..501fe17 100644 --- a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.cc +++ b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.cc
@@ -6,6 +6,7 @@ #include <cstdint> #include <numeric> +#include <type_traits> #include "ash/components/arc/session/arc_bridge_service.h" #include "ash/components/arc/session/arc_service_manager.h" @@ -40,49 +41,54 @@ #include "content/public/browser/storage_partition.h" namespace ash::settings { - namespace { -void GetTotalDiskSpaceBlocking(const base::FilePath& mount_path, - int64_t* total_bytes) { - int64_t size = base::SysInfo::AmountOfTotalDiskSpace(mount_path); - if (size >= 0) { - *total_bytes = size; - } -} - -void GetFreeDiskSpaceBlocking(const base::FilePath& mount_path, - int64_t* available_bytes) { - int64_t size = base::SysInfo::AmountOfFreeDiskSpace(mount_path); - if (size >= 0) { - *available_bytes = size; - } -} - // Computes the size of MyFiles and Play files. -int64_t ComputeLocalFilesSize(const base::FilePath& my_files_path, - const base::FilePath& android_files_path) { - int64_t size = 0; +int64_t ComputeLocalFilesSize(const base::FilePath& my_files, + const base::FilePath& play_files) { + // Compute size of MyFiles. + int64_t size = base::ComputeDirectorySize(my_files); - // Compute directory size of MyFiles. - size += base::ComputeDirectorySize(my_files_path); - - // Compute directory size of Play Files. - size += base::ComputeDirectorySize(android_files_path); - - // Remove size of Download. If Android is enabled, the size of the Download - // folder is counted in both MyFiles and Play files. If Android is disabled, - // the Download folder doesn't exist and the returned size is 0. - const base::FilePath download_files_path = - android_files_path.AppendASCII("Download"); - size -= base::ComputeDirectorySize(download_files_path); + // Compute size of Play Files. + if (int64_t play_size = base::ComputeDirectorySize(play_files); + play_size > 0) { + // Remove size of the Download folder, because it is already counted as part + // of MyFiles. + play_size -= base::ComputeDirectorySize(play_files.AppendASCII("Download")); + if (play_size > 0) { + size += play_size; + } + } return size; } } // namespace -SizeCalculator::SizeCalculator(const CalculationType& calculation_type) +std::ostream& operator<<(std::ostream& out, SizeCalculator::CalculationType t) { + switch (t) { +#define PRINT(s) \ + case SizeCalculator::CalculationType::k##s: \ + return out << #s; + PRINT(Total) + PRINT(Available) + PRINT(MyFiles) + PRINT(BrowsingData) + PRINT(AppsExtensions) + PRINT(DriveOfflineFiles) + PRINT(Crostini) + PRINT(OtherUsers) + PRINT(System) +#undef PRINT + } + + return out << "CalculationType(" + << static_cast< + std::underlying_type_t<SizeCalculator::CalculationType>>(t) + << ")"; +} + +SizeCalculator::SizeCalculator(CalculationType calculation_type) : calculation_type_(calculation_type) {} SizeCalculator::~SizeCalculator() {} @@ -95,18 +101,22 @@ PerformCalculation(); } -void SizeCalculator::AddObserver(SizeCalculator::Observer* observer) { +void SizeCalculator::AddObserver(Observer* observer) { observers_.AddObserver(observer); } -void SizeCalculator::RemoveObserver(SizeCalculator::Observer* observer) { +void SizeCalculator::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } -void SizeCalculator::NotifySizeCalculated(int64_t total_bytes) { +void SizeCalculator::NotifySizeCalculated(const int64_t size) { calculating_ = false; - for (SizeCalculator::Observer& observer : observers_) { - observer.OnSizeCalculated(calculation_type_, total_bytes); + + LOG_IF(ERROR, size < 0) << "Got negative size " << size + << " while calculating " << calculation_type_; + + for (Observer& observer : observers_) { + observer.OnSizeCalculated(calculation_type_, size); } } @@ -133,9 +143,6 @@ void TotalDiskSpaceCalculator::OnGetRootDeviceSize( std::optional<int64_t> reply) { if (reply.has_value()) { - if (reply.value() < 0) { - LOG(DFATAL) << "Negative root device size (" << reply.value() << ")"; - } NotifySizeCalculated(reply.value()); return; } @@ -143,28 +150,18 @@ // FakeSpacedClient does not have a proper implementation of // GetRootDeviceSize. If SpacedClient::GetRootDeviceSize does not return a // value, use GetTotalDiskSpace as a fallback. - VLOG(1) << "SpacedClient::OnGetRootDeviceSize: Empty reply. Using " - "GetTotalDiskSpace as fallback."; + VLOG(1) << "SpacedClient::OnGetRootDeviceSize gave an empty reply. " + "Using GetTotalDiskSpace as fallback."; GetTotalDiskSpace(); } void TotalDiskSpaceCalculator::GetTotalDiskSpace() { - const base::FilePath my_files_path = - file_manager::util::GetMyFilesFolderForProfile(profile_); - - int64_t* total_bytes = new int64_t(-1); - base::ThreadPool::PostTaskAndReply( + base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&GetTotalDiskSpaceBlocking, my_files_path, total_bytes), - base::BindOnce(&TotalDiskSpaceCalculator::OnGetTotalDiskSpace, - weak_ptr_factory_.GetWeakPtr(), base::Owned(total_bytes))); -} - -void TotalDiskSpaceCalculator::OnGetTotalDiskSpace(int64_t* total_bytes) { - if (*total_bytes < 0) { - LOG(DFATAL) << "Negative total disk space (" << *total_bytes << ")"; - } - NotifySizeCalculated(*total_bytes); + base::BindOnce(&base::SysInfo::AmountOfTotalDiskSpace, + file_manager::util::GetMyFilesFolderForProfile(profile_)), + base::BindOnce(&TotalDiskSpaceCalculator::NotifySizeCalculated, + weak_ptr_factory_.GetWeakPtr())); } FreeDiskSpaceCalculator::FreeDiskSpaceCalculator(Profile* profile) @@ -182,10 +179,8 @@ } void FreeDiskSpaceCalculator::GetUserFreeDiskSpace() { - const base::FilePath my_files_path = - file_manager::util::GetMyFilesFolderForProfile(profile_); SpacedClient::Get()->GetFreeDiskSpace( - my_files_path.value(), + file_manager::util::GetMyFilesFolderForProfile(profile_).value(), base::BindOnce(&FreeDiskSpaceCalculator::OnGetUserFreeDiskSpace, weak_ptr_factory_.GetWeakPtr())); } @@ -193,39 +188,25 @@ void FreeDiskSpaceCalculator::OnGetUserFreeDiskSpace( std::optional<int64_t> reply) { if (reply.has_value()) { - if (reply.value() < 0) { - LOG(DFATAL) << "Negative user free disk space (" << reply.value() << ")"; - } NotifySizeCalculated(reply.value()); return; } // FakeSpacedClient does not have a proper implementation of // GetFreeDiskSpace. If SpacedClient::GetFreeDiskSpace does not return a - // value, use GetFreeDiskSpaceBlocking as a fallback. - VLOG(1) << "SpacedClient::GetFreeDiskSpace: Empty reply. Using " - "GetFreeDiskSpaceBlocking as fallback."; + // value, use GetFreeDiskSpace as a fallback. + VLOG(1) << "SpacedClient::GetFreeDiskSpace gave an empty reply. " + "Using GetFreeDiskSpace as fallback."; GetFreeDiskSpace(); } void FreeDiskSpaceCalculator::GetFreeDiskSpace() { - const base::FilePath my_files_path = - file_manager::util::GetMyFilesFolderForProfile(profile_); - - int64_t* available_bytes = new int64_t(-1); - base::ThreadPool::PostTaskAndReply( + base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&GetFreeDiskSpaceBlocking, my_files_path, available_bytes), - base::BindOnce(&FreeDiskSpaceCalculator::OnGetFreeDiskSpace, - weak_ptr_factory_.GetWeakPtr(), - base::Owned(available_bytes))); -} - -void FreeDiskSpaceCalculator::OnGetFreeDiskSpace(int64_t* available_bytes) { - if (*available_bytes < 0) { - LOG(DFATAL) << "Negative free disk space (" << *available_bytes << ")"; - } - NotifySizeCalculated(*available_bytes); + base::BindOnce(&base::SysInfo::AmountOfFreeDiskSpace, + file_manager::util::GetMyFilesFolderForProfile(profile_)), + base::BindOnce(&FreeDiskSpaceCalculator::NotifySizeCalculated, + weak_ptr_factory_.GetWeakPtr())); } DriveOfflineSizeCalculator::DriveOfflineSizeCalculator(Profile* profile) @@ -245,37 +226,25 @@ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, base::BindOnce(&drive::util::ComputeDriveFsContentCacheSize, service->GetDriveFsContentCachePath()), - base::BindOnce(&DriveOfflineSizeCalculator::OnGetOfflineItemsSize, + base::BindOnce(&DriveOfflineSizeCalculator::NotifySizeCalculated, weak_ptr_factory_.GetWeakPtr())); } -void DriveOfflineSizeCalculator::OnGetOfflineItemsSize(int64_t offline_bytes) { - NotifySizeCalculated(offline_bytes > 0 ? offline_bytes : 0); -} - MyFilesSizeCalculator::MyFilesSizeCalculator(Profile* profile) : SizeCalculator(CalculationType::kMyFiles), profile_(profile) {} MyFilesSizeCalculator::~MyFilesSizeCalculator() = default; void MyFilesSizeCalculator::PerformCalculation() { - const base::FilePath my_files_path = - file_manager::util::GetMyFilesFolderForProfile(profile_); - - const base::FilePath android_files_path = - base::FilePath(file_manager::util::GetAndroidFilesPath()); - base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&ComputeLocalFilesSize, my_files_path, android_files_path), - base::BindOnce(&MyFilesSizeCalculator::OnGetMyFilesSize, + base::BindOnce(&ComputeLocalFilesSize, + file_manager::util::GetMyFilesFolderForProfile(profile_), + file_manager::util::GetAndroidFilesPath()), + base::BindOnce(&MyFilesSizeCalculator::NotifySizeCalculated, weak_ptr_factory_.GetWeakPtr())); } -void MyFilesSizeCalculator::OnGetMyFilesSize(int64_t total_bytes) { - NotifySizeCalculated(total_bytes); -} - BrowsingDataSizeCalculator::BrowsingDataSizeCalculator(Profile* profile) : SizeCalculator(CalculationType::kBrowsingData), profile_(profile) {} @@ -329,7 +298,7 @@ } else { browsing_data_size = -1; } - calculating_ = false; + NotifySizeCalculated(browsing_data_size); } } @@ -353,7 +322,7 @@ is_android_running_ = false; } -void AppsSizeCalculator::AddObserver(SizeCalculator::Observer* observer) { +void AppsSizeCalculator::AddObserver(Observer* observer) { // Start observing arc mojo connection when the first observer is added, to // allow the calculation of android apps. if (observers_.empty()) { @@ -362,11 +331,11 @@ ->storage_manager() ->AddObserver(this); } - observers_.AddObserver(observer); + SizeCalculator::AddObserver(observer); } -void AppsSizeCalculator::RemoveObserver(SizeCalculator::Observer* observer) { - observers_.RemoveObserver(observer); +void AppsSizeCalculator::RemoveObserver(Observer* observer) { + SizeCalculator::RemoveObserver(observer); // Stop observing arc connection if all observers have been removed. if (observers_.empty()) { arc::ArcServiceManager::Get() @@ -489,7 +458,6 @@ void AppsSizeCalculator::UpdateAppsAndExtensionsSize() { if (has_apps_extensions_size_ && has_android_apps_size_ && has_borealis_apps_size_) { - calculating_ = false; NotifySizeCalculated(apps_extensions_size_ + android_apps_size_ + borealis_apps_size_); } @@ -502,7 +470,7 @@ void CrostiniSizeCalculator::PerformCalculation() { if (!crostini::CrostiniFeatures::Get()->IsEnabled(profile_)) { - UpdateSize( + NotifySizeCalculated( profile_->GetPrefs()->GetInt64(crostini::prefs::kCrostiniLastDiskSize)); return; } @@ -521,17 +489,18 @@ std::optional<vm_tools::concierge::ListVmDisksResponse> response) { if (!response) { LOG(ERROR) << "Failed to get list of VM disks. Empty response."; - UpdateSize( + NotifySizeCalculated( profile_->GetPrefs()->GetInt64(crostini::prefs::kCrostiniLastDiskSize)); return; } if (!response->success()) { LOG(ERROR) << "Failed to list VM disks: " << response->failure_reason(); - UpdateSize( + NotifySizeCalculated( profile_->GetPrefs()->GetInt64(crostini::prefs::kCrostiniLastDiskSize)); return; } + int64_t vm_disk_usage = response->total_size(); // If Borealis is installed then we need to subtract its size from Crostini @@ -549,12 +518,7 @@ } profile_->GetPrefs()->SetInt64(crostini::prefs::kCrostiniLastDiskSize, vm_disk_usage); - UpdateSize(vm_disk_usage); -} - -void CrostiniSizeCalculator::UpdateSize(int64_t total_bytes) { - calculating_ = false; - NotifySizeCalculated(total_bytes); + NotifySizeCalculated(vm_disk_usage); } OtherUsersSizeCalculator::OtherUsersSizeCalculator() @@ -592,9 +556,9 @@ if (user_sizes_.size() != other_users_.size()) { return; } - int64_t other_users_total_bytes; + // If all the requests succeed, shows the total bytes in the UI. - other_users_total_bytes = + const int64_t other_users_total_bytes = base::Contains(user_sizes_, -1) ? -1 : std::accumulate(user_sizes_.begin(), user_sizes_.end(), 0LL);
diff --git a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.h b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.h index 01d3ae3..09aed5e5 100644 --- a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.h +++ b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.h
@@ -8,6 +8,7 @@ #include <array> #include <bitset> #include <memory> +#include <ostream> #include <vector> #include "ash/components/arc/mojom/storage_manager.mojom.h" @@ -57,7 +58,7 @@ static constexpr int kCalculationTypeCount = static_cast<int>(CalculationType::kLastCalculationItem) + 1; - explicit SizeCalculator(const CalculationType& calculation_type); + explicit SizeCalculator(CalculationType calculation_type); virtual ~SizeCalculator(); // Starts the size calculation of a given storage item. @@ -74,17 +75,20 @@ virtual void PerformCalculation() = 0; // Notify the StorageHandler about the calculated storage item size - void NotifySizeCalculated(int64_t total_bytes); + void NotifySizeCalculated(int64_t size); // Item id. const CalculationType calculation_type_; // Flag indicating that fetch operations for storage size are ongoing. bool calculating_ = false; + // Observers being notified about storage items size changes. - base::ObserverList<SizeCalculator::Observer> observers_; + base::ObserverList<Observer> observers_; }; +std::ostream& operator<<(std::ostream& out, SizeCalculator::CalculationType t); + // Class handling the calculation of the total disk space on the system. class TotalDiskSpaceCalculator : public SizeCalculator { public: @@ -107,8 +111,6 @@ void GetTotalDiskSpace(); - void OnGetTotalDiskSpace(int64_t* total_bytes); - raw_ptr<Profile> profile_; base::WeakPtrFactory<TotalDiskSpaceCalculator> weak_ptr_factory_{this}; }; @@ -135,8 +137,6 @@ void GetFreeDiskSpace(); - void OnGetFreeDiskSpace(int64_t* available_bytes); - raw_ptr<Profile> profile_; base::WeakPtrFactory<FreeDiskSpaceCalculator> weak_ptr_factory_{this}; }; @@ -156,8 +156,6 @@ void PerformCalculation() override; - void OnGetOfflineItemsSize(int64_t offline_bytes); - raw_ptr<Profile> profile_; base::WeakPtrFactory<DriveOfflineSizeCalculator> weak_ptr_factory_{this}; }; @@ -179,9 +177,6 @@ // SizeCalculator: void PerformCalculation() override; - // Updates the size of MyFiles and Play files. - void OnGetMyFilesSize(int64_t total_bytes); - raw_ptr<Profile> profile_; base::WeakPtrFactory<MyFilesSizeCalculator> weak_ptr_factory_{this}; }; @@ -327,9 +322,6 @@ void OnGetCrostiniSize( std::optional<vm_tools::concierge::ListVmDisksResponse>); - // Helper function to simplify updating the reported size of Crostini. - void UpdateSize(int64_t total_bytes); - raw_ptr<Profile> profile_; base::WeakPtrFactory<CrostiniSizeCalculator> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator_test_api.h b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator_test_api.h index ede3d15fb..f16d0a26 100644 --- a/chrome/browser/ui/webui/ash/settings/calculator/size_calculator_test_api.h +++ b/chrome/browser/ui/webui/ash/settings/calculator/size_calculator_test_api.h
@@ -26,8 +26,8 @@ total_disk_space_calculator_.OnGetRootDeviceSize(reply); } - void SimulateOnGetTotalDiskSpace(int64_t* total_bytes) { - total_disk_space_calculator_.OnGetTotalDiskSpace(total_bytes); + void SimulateOnGetTotalDiskSpace(int64_t total_bytes) { + total_disk_space_calculator_.NotifySizeCalculated(total_bytes); } private: @@ -47,8 +47,8 @@ free_disk_space_calculator_.OnGetUserFreeDiskSpace(reply); } - void SimulateOnGetFreeDiskSpace(int64_t* available_bytes) { - free_disk_space_calculator_.OnGetFreeDiskSpace(available_bytes); + void SimulateOnGetFreeDiskSpace(int64_t available_bytes) { + free_disk_space_calculator_.NotifySizeCalculated(available_bytes); } private: @@ -65,7 +65,7 @@ void StartCalculation() { drive_offline_size_calculator_.StartCalculation(); } void SimulateOnGetOfflineItemsSize(int64_t offline_bytes) { - drive_offline_size_calculator_.OnGetOfflineItemsSize(offline_bytes); + drive_offline_size_calculator_.NotifySizeCalculated(offline_bytes); } private:
diff --git a/chrome/browser/ui/webui/ash/settings/pages/storage/DIR_METADATA b/chrome/browser/ui/webui/ash/settings/pages/storage/DIR_METADATA new file mode 100644 index 0000000..e9400b87 --- /dev/null +++ b/chrome/browser/ui/webui/ash/settings/pages/storage/DIR_METADATA
@@ -0,0 +1 @@ +mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/ash/settings/pages/storage/OWNERS b/chrome/browser/ui/webui/ash/settings/pages/storage/OWNERS new file mode 100644 index 0000000..73220a8 --- /dev/null +++ b/chrome/browser/ui/webui/ash/settings/pages/storage/OWNERS
@@ -0,0 +1 @@ +file://ui/file_manager/OWNERS
diff --git a/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_handler_unittest.cc b/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_handler_unittest.cc index 93d18bc..34226de 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_handler_unittest.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_handler_unittest.cc
@@ -203,8 +203,8 @@ // space state determined by the UpdateOverallStatistics function, provided // that the spaced client is not available. int GetSpaceStateNoSpacedClient(int64_t total_size, int64_t available_size) { - total_disk_space_test_api_->SimulateOnGetTotalDiskSpace(&total_size); - free_disk_space_test_api_->SimulateOnGetFreeDiskSpace(&available_size); + total_disk_space_test_api_->SimulateOnGetTotalDiskSpace(total_size); + free_disk_space_test_api_->SimulateOnGetFreeDiskSpace(available_size); task_environment_.RunUntilIdle(); const base::Value* dictionary = GetWebUICallbackMessage("storage-size-stat-changed"); @@ -589,7 +589,7 @@ int64_t total_size = TB; int64_t available_size = 100 * GB; total_disk_space_test_api_->SimulateOnGetRootDeviceSize(total_size); - free_disk_space_test_api_->SimulateOnGetFreeDiskSpace(&available_size); + free_disk_space_test_api_->SimulateOnGetFreeDiskSpace(available_size); drive_offline_size_test_api_->SimulateOnGetOfflineItemsSize(50 * GB); const base::Value* callback = GetWebUICallbackMessage("storage-size-stat-changed");
diff --git a/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_util.cc b/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_util.cc index 33fda12..adcd1ed 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_util.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_util.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/webui/ash/settings/pages/storage/device_storage_util.h" +#include <bit> + namespace ash::settings { int64_t RoundByteSize(int64_t bytes) { @@ -15,20 +17,7 @@ return 0; } - // Subtract one to the original number of bytes. - bytes--; - // Set all the lower bits to 1. - bytes |= bytes >> 1; - bytes |= bytes >> 2; - bytes |= bytes >> 4; - bytes |= bytes >> 8; - bytes |= bytes >> 16; - bytes |= bytes >> 32; - // Add one. The one bit beyond the highest set bit is set to 1. All the lower - // bits are set to 0. - bytes++; - - return bytes; + return std::bit_ceil(static_cast<uint64_t>(bytes)); } } // namespace ash::settings
diff --git a/chrome/browser/ui/webui/ash/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/system_web_dialog_browsertest.cc index 1c49b41..23c439ea 100644 --- a/chrome/browser/ui/webui/ash/system_web_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/ash/system_web_dialog_browsertest.cc
@@ -148,4 +148,27 @@ << dialog_level; } +IN_PROC_BROWSER_TEST_F(SystemWebDialogTest, StackAtTop) { + const char* kDialogId1 = "dialog_id1"; + const char* kDialogId2 = "dialog_id2"; + auto* dialog1 = new MockSystemWebDialog(kDialogId1); + auto* dialog2 = new MockSystemWebDialog(kDialogId2); + dialog1->ShowSystemDialog(); + dialog2->ShowSystemDialog(); + auto* widget1 = + views::Widget::GetWidgetForNativeWindow(dialog1->dialog_window()); + auto* widget2 = + views::Widget::GetWidgetForNativeWindow(dialog2->dialog_window()); + + dialog1->StackAtTop(); + // Expect dialog1 brought to the top level. + EXPECT_TRUE(widget1->IsStackedAbove(widget2->GetNativeView())); + EXPECT_TRUE(widget1->is_top_level()); + + dialog2->StackAtTop(); + // Expect dialog2 brought to the top level. + EXPECT_TRUE(widget2->IsStackedAbove(widget1->GetNativeView())); + EXPECT_TRUE(widget2->is_top_level()); +} + } // namespace ash
diff --git a/chrome/browser/ui/webui/ash/system_web_dialog_delegate.cc b/chrome/browser/ui/webui/ash/system_web_dialog_delegate.cc index ba0732f5..e0e18a7f 100644 --- a/chrome/browser/ui/webui/ash/system_web_dialog_delegate.cc +++ b/chrome/browser/ui/webui/ash/system_web_dialog_delegate.cc
@@ -165,6 +165,10 @@ return GetDialogContentURL().spec(); } +void SystemWebDialogDelegate::StackAtTop() { + views::Widget::GetWidgetForNativeWindow(dialog_window())->StackAtTop(); +} + void SystemWebDialogDelegate::Focus() { // Focusing a modal dialog does not make it the topmost dialog and does not // enable interaction. It does however remove focus from the current dialog,
diff --git a/chrome/browser/ui/webui/ash/system_web_dialog_delegate.h b/chrome/browser/ui/webui/ash/system_web_dialog_delegate.h index 036b718..98c5d7d2 100644 --- a/chrome/browser/ui/webui/ash/system_web_dialog_delegate.h +++ b/chrome/browser/ui/webui/ash/system_web_dialog_delegate.h
@@ -63,6 +63,9 @@ // Adjust the init params for the widget. By default makes no change. virtual void AdjustWidgetInitParams(views::Widget::InitParams* params) {} + // Brings the dialog window to the front. + void StackAtTop(); + // Focuses the dialog window. Note: No-op for modal dialogs, see // implementation for details. void Focus(); @@ -97,6 +100,7 @@ protected: FRIEND_TEST_ALL_PREFIXES(SystemWebDialogLoginTest, NonModalTest); + FRIEND_TEST_ALL_PREFIXES(SystemWebDialogTest, StackAtTop); // Returns the dialog window (pointer to |aura::Window|). This will be a // |nullptr| if the dialog has not been created yet.
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 5ffe4b1..be71c6a 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -171,6 +171,7 @@ #include "ash/webui/file_manager/url_constants.h" #include "ash/webui/files_internals/url_constants.h" #include "ash/webui/help_app_ui/url_constants.h" +#include "ash/webui/mall/url_constants.h" #include "ash/webui/multidevice_debug/url_constants.h" #include "ash/webui/print_preview_cros/url_constants.h" #include "ash/webui/vc_background_ui/url_constants.h" @@ -1022,6 +1023,7 @@ GURL(ash::kChromeUICameraAppURL), GURL(ash::kChromeUIFilesInternalsURL), GURL(ash::kChromeUIHelpAppURL), + GURL(ash::kChromeUIMallUrl), GURL(ash::kChromeUIPrintPreviewCrosURL), GURL(ash::multidevice::kChromeUIProximityAuthURL), GURL(ash::vc_background_ui::kChromeUIVcBackgroundURL),
diff --git a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.cc b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.cc index 987d3d1..05e948d 100644 --- a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.cc +++ b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.cc
@@ -9,11 +9,11 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/bookmarks/bookmark_editor.h" #include "chrome/browser/ui/bookmarks/bookmark_utils.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/webui/commerce/shopping_insights_side_panel_ui.h" +#include "chrome/common/url_constants.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/commerce/core/commerce_feature_list.h" #include "components/commerce/core/price_tracking_utils.h" @@ -95,10 +95,31 @@ return; } - content::OpenURLParams params(url, content::Referrer(), - WindowOpenDisposition::NEW_FOREGROUND_TAB, - ui::PAGE_TRANSITION_LINK, false); - browser->OpenURL(params, /*navigation_handle_callback=*/{}); + NavigateToUrl(browser, url); +} + +void ShoppingUiHandlerDelegate::SwitchToOrOpenTab(const GURL& url) { + if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS()) { + return; + } + auto* browser = chrome::FindBrowserWithActiveWindow(); + if (!browser) { + browser = chrome::FindLastActive(); + } + if (!browser) { + return; + } + + auto* tab_strip_model = browser->tab_strip_model(); + for (int i = 0; i < tab_strip_model->count(); ++i) { + auto* web_contents = tab_strip_model->GetWebContentsAt(i); + if (web_contents->GetLastCommittedURL() == url) { + tab_strip_model->ActivateTabAt(i); + return; + } + } + + NavigateToUrl(browser, url); } void ShoppingUiHandlerDelegate::ShowFeedback() { @@ -148,4 +169,12 @@ return web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId(); } +void ShoppingUiHandlerDelegate::NavigateToUrl(Browser* browser, + const GURL& url) { + content::OpenURLParams params(url, content::Referrer(), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui::PAGE_TRANSITION_LINK, false); + browser->OpenURL(params, /*navigation_handle_callback=*/{}); +} + } // namespace commerce
diff --git a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h index 9349bbaf..389ff83 100644 --- a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h +++ b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_COMMERCE_SHOPPING_UI_HANDLER_DELEGATE_H_ #include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/browser.h" #include "components/commerce/core/webui/shopping_service_handler.h" #include "services/metrics/public/cpp/ukm_source_id.h" @@ -35,6 +36,8 @@ const bookmarks::BookmarkNode* GetOrAddBookmarkForCurrentUrl() override; + void SwitchToOrOpenTab(const GURL& url) override; + void OpenUrlInNewTab(const GURL& url) override; void ShowBookmarkEditorForCurrentUrl() override; @@ -45,6 +48,8 @@ ukm::SourceId GetCurrentTabUkmSourceId() override; private: + void NavigateToUrl(Browser* browser, const GURL& url); + // This delegate is owned by |insights_side_panel_ui_| so we expect // |insights_side_panel_ui_| to remain valid for the lifetime of |this|. raw_ptr<ShoppingInsightsSidePanelUI> insights_side_panel_ui_;
diff --git a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate_browsertest.cc b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate_browsertest.cc index d77f700..16a2532 100644 --- a/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate_browsertest.cc +++ b/chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate_browsertest.cc
@@ -2,16 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h" + #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/webui/commerce/shopping_ui_handler_delegate.h" #include "chrome/test/base/chrome_test_utils.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/bookmarks/browser/bookmark_model.h" #include "content/public/test/browser_test.h" +#include "content/public/test/test_navigation_observer.h" // Tests ShoppingUiHandlerDelegate. class ShoppingUiHandlerDelegateBrowserTest : public InProcessBrowserTest { @@ -27,16 +29,23 @@ return chrome_test_utils::GetActiveWebContents(this); } - void NavigateToURL( - const GURL& url, - WindowOpenDisposition disposition = WindowOpenDisposition::CURRENT_TAB) { + void NavigateToURL(const GURL& url) { ui_test_utils::NavigateToURLWithDisposition( - browser(), url, disposition, + browser(), url, WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); base::PlatformThread::Sleep(base::Seconds(2)); base::RunLoop().RunUntilIdle(); } + void OpenURLInNewTab(const GURL& url) { + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB | + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + base::PlatformThread::Sleep(base::Seconds(2)); + base::RunLoop().RunUntilIdle(); + } + raw_ptr<Profile, DanglingUntriaged> profile_; raw_ptr<bookmarks::BookmarkModel, DanglingUntriaged> bookmark_model_; }; @@ -84,3 +93,72 @@ DCHECK(node); ASSERT_EQ(bookmark_count + 1, other_node->children().size()); } + +IN_PROC_BROWSER_TEST_F(ShoppingUiHandlerDelegateBrowserTest, + TestSwitchToOrOpenTab_SwitchToExistingTab) { + auto delegate = + std::make_unique<commerce::ShoppingUiHandlerDelegate>(nullptr, profile_); + const GURL url_1 = GURL("https://www.example.com"); + NavigateToURL(url_1); + const auto* web_contents_1 = web_contents(); + const GURL url_2 = GURL("https://www.google.com"); + OpenURLInNewTab(url_2); + + ASSERT_EQ(2, browser()->tab_strip_model()->count()); + ASSERT_NE(web_contents(), web_contents_1); + ASSERT_EQ(url_2, web_contents()->GetLastCommittedURL()); + delegate->SwitchToOrOpenTab(url_1); + + EXPECT_EQ(2, browser()->tab_strip_model()->count()); + EXPECT_EQ(web_contents_1, web_contents()); + EXPECT_EQ(url_1, web_contents()->GetLastCommittedURL()); +} + +IN_PROC_BROWSER_TEST_F(ShoppingUiHandlerDelegateBrowserTest, + TestSwitchToOrOpenTab_OpenNewTab) { + auto delegate = + std::make_unique<commerce::ShoppingUiHandlerDelegate>(nullptr, profile_); + const GURL url = GURL("https://www.example.com"); + NavigateToURL(url); + const GURL url_2 = GURL("https://www.google.com"); + content::TestNavigationObserver observer(url_2); + observer.StartWatchingNewWebContents(); + + ASSERT_EQ(1, browser()->tab_strip_model()->count()); + ASSERT_EQ(url, web_contents()->GetLastCommittedURL()); + delegate->SwitchToOrOpenTab(url_2); + observer.WaitForNavigationFinished(); + + EXPECT_EQ(2, browser()->tab_strip_model()->count()); + EXPECT_EQ(url_2, web_contents()->GetLastCommittedURL()); +} + +IN_PROC_BROWSER_TEST_F(ShoppingUiHandlerDelegateBrowserTest, + TestSwitchToOrOpenTab_InvalidUrls) { + auto delegate = + std::make_unique<commerce::ShoppingUiHandlerDelegate>(nullptr, profile_); + const GURL invalid_url_1 = GURL("chrome://newtab"); + NavigateToURL(invalid_url_1); + const GURL invalid_url_2 = GURL("file://foo"); + OpenURLInNewTab(invalid_url_2); + const GURL valid_url = GURL("https://www.example.com"); + OpenURLInNewTab(valid_url); + const auto* valid_web_contents = web_contents(); + + ASSERT_EQ(3, browser()->tab_strip_model()->count()); + ASSERT_EQ(valid_web_contents, web_contents()); + ASSERT_EQ(valid_url, web_contents()->GetLastCommittedURL()); + delegate->SwitchToOrOpenTab(invalid_url_1); + + EXPECT_EQ(3, browser()->tab_strip_model()->count()); + // Ensure that the web contents remain the same, since `SwitchToOrOpenTab` + // shouldn't work for non-HTTP(S) urls. + EXPECT_EQ(valid_web_contents, web_contents()); + EXPECT_EQ(valid_url, web_contents()->GetLastCommittedURL()); + + delegate->SwitchToOrOpenTab(invalid_url_2); + + EXPECT_EQ(3, browser()->tab_strip_model()->count()); + EXPECT_EQ(valid_web_contents, web_contents()); + EXPECT_EQ(valid_url, web_contents()->GetLastCommittedURL()); +}
diff --git a/chrome/browser/ui/webui/cr_components/theme_color_picker/BUILD.gn b/chrome/browser/ui/webui/cr_components/theme_color_picker/BUILD.gn new file mode 100644 index 0000000..40ed7f86 --- /dev/null +++ b/chrome/browser/ui/webui/cr_components/theme_color_picker/BUILD.gn
@@ -0,0 +1,15 @@ +# 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. + +source_set("theme_color_picker") { + sources = [ + "customize_chrome_colors.cc", + "customize_chrome_colors.h", + ] + deps = [ + "//chrome/browser/new_tab_page/chrome_colors:generate_chrome_colors_info", + "//chrome/browser/new_tab_page/chrome_colors:generate_colors_info", + "//ui/base/mojom", + ] +}
diff --git a/chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.cc b/chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.cc index c246af6..b4cd8e90 100644 --- a/chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.cc +++ b/chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.cc
@@ -7,6 +7,7 @@ #include "base/ranges/algorithm.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_factory.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h" +#include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_util.h" #include "chrome/browser/new_tab_page/chrome_colors/generated_colors_info.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/theme_service.h" @@ -127,7 +128,7 @@ } else { DCHECK(theme_service_->UsingAutogeneratedTheme()); theme->is_forced = theme_service_->UsingPolicyTheme(); - int color_id = chrome_colors::ChromeColorsService::GetColorId( + int color_id = chrome_colors::GetChromeColorsInfo( theme->is_forced ? theme_service_->GetPolicyThemeColor() : theme_service_->GetAutogeneratedThemeColor()); if (color_id != chrome_colors::kOtherColorId) {
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc index cd1b493..90d50803 100644 --- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc +++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc
@@ -16,6 +16,7 @@ #include "base/logging.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/metrics/user_metrics.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" @@ -707,6 +708,11 @@ feature_engagement::TrackerFactory::GetForBrowserContext( browser->profile()); tracker->NotifyEvent("esb_download_promo_row_clicked"); + base::RecordAction( + base::UserMetricsAction("SafeBrowsing.EsbDownloadRowPromo.Click")); + base::UmaHistogramEnumeration( + "SafeBrowsing.EsbDownloadRowPromo.Outcome", + SafeBrowsingEsbDownloadRowPromoOutcome::kClicked); } void DownloadsDOMHandler::IsEligibleForEsbPromo( @@ -748,6 +754,8 @@ feature_engagement::TrackerFactory::GetForBrowserContext( manager->GetBrowserContext()); tracker->NotifyEvent("esb_download_promo_row_viewed"); + base::UmaHistogramEnumeration("SafeBrowsing.EsbDownloadRowPromo.Outcome", + SafeBrowsingEsbDownloadRowPromoOutcome::kShown); } // DownloadsDOMHandler, private: --------------------------------------------
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h index 952ade0..e4765cc3 100644 --- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h +++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h
@@ -31,6 +31,20 @@ class DownloadItem; } +// Represents the possible outcomes of showing a ESB download row promotion. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// +// LINT.IfChange(SafeBrowsingEsbDownloadRowPromoOutcome) +enum class SafeBrowsingEsbDownloadRowPromoOutcome { + // The kShown and kClicked values are not meant to be mutually exclusive, + // the same promo row can be shown AND clicked. + kShown = 0, + kClicked = 1, + kMaxValue = kClicked, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/safe_browsing/enums.xml:SafeBrowsingEsbDownloadRowPromoOutcome) + // The handler for Javascript messages related to the "downloads" view, // also observes changes to the download manager. // TODO(calamity): Remove WebUIMessageHandler.
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc index f18d1fd..a20633a 100644 --- a/chrome/browser/ui/webui/extensions/extensions_ui.cc +++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -334,6 +334,7 @@ {"noSitesAdded", IDS_EXTENSIONS_NO_SITES_ADDED}, {"editShortcutInputLabel", IDS_EXTENSIONS_EDIT_SHORTCUT_INPUT_LABEL}, {"editShortcutButtonLabel", IDS_EXTENSIONS_EDIT_SHORTCUT_BUTTON_LABEL}, + {"mv2DeprecationPanelTitle", IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_TITLE}, {"mv2DeprecationPanelDismissButton", IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISMISS_BUTTON}, {"mv2DeprecationPanelFindAlternativeButton", @@ -341,6 +342,10 @@ {"mv2DeprecationPanelKeepForNowButton", IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_KEEP_FOR_NOW_BUTTON}, {"mv2DeprecationPanelRemoveExtensionButton", IDS_EXTENSIONS_UNINSTALL}, + {"mv2DeprecationMessageWarningHeader", + IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_HEADER}, + {"mv2DeprecationMessageWarningSubtitle", + IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE}, {"shortcutNotSet", IDS_EXTENSIONS_SHORTCUT_NOT_SET}, {"shortcutScopeGlobal", IDS_EXTENSIONS_SHORTCUT_SCOPE_GLOBAL}, {"shortcutScopeLabel", IDS_EXTENSIONS_SHORTCUT_SCOPE_LABEL},
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc index e4c170c8d..ede52198 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
@@ -725,8 +725,10 @@ inner_contents[0]->GetPrimaryMainFrame()->GetLastCommittedOrigin())) { pdf_observer_ = std::make_unique<ReadAnythingWebContentsObserver>( weak_factory_.GetSafeRef(), inner_contents[0], kReadAnythingAXMode); - screen_ai::PdfOcrControllerFactory::GetForProfile(browser_->profile()) - ->Activate(); + if (features::IsPdfOcrEnabled()) { + screen_ai::PdfOcrControllerFactory::GetForProfile(browser_->profile()) + ->Activate(); + } } }
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h index 0cf60df3..330feeb1 100644 --- a/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h +++ b/chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h
@@ -187,8 +187,7 @@ supports_draggable_regions, T::GetWebUIName()), webui_url_(webui_url) { - static_assert( - views_metrics::IsValidWebUINameVariant("." + T::GetWebUIName())); + static_assert(views_metrics::IsValidWebUIName("." + T::GetWebUIName())); if (is_ready_to_show()) { CHECK(GetWebUIController()); GetWebUIController()->set_embedder(weak_ptr_factory_.GetWeakPtr());
diff --git a/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc b/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc new file mode 100644 index 0000000..f21725ec --- /dev/null +++ b/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc
@@ -0,0 +1,40 @@ +// 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 "base/hash/hash.h" +#include "base/metrics/histogram_base.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/ui/webui/webui_url_hashes.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/webui_config_map.h" +#include "content/public/test/browser_test.h" + +using WebUIUrlHashesBrowserTest = InProcessBrowserTest; + +// Tests that the URL hashes are listed in enum WebUIUrlHashes from +// //tools/metrics/histograms/enums.xml. Not finding a URL will cause a CHECK +// failure. enum WebUIUrlHashes is used to collect WebUI usage statistics. +// The URL hash is recorded in histogram "WebUI.CreatedForUrl" when a WebUI +// is opened. +IN_PROC_BROWSER_TEST_F(WebUIUrlHashesBrowserTest, UrlsInHistogram) { + content::WebUIConfigMap& map = content::WebUIConfigMap::GetInstance(); + std::vector<std::string> missing_entries; + for (const content::WebUIConfigInfo& config_info : + map.GetWebUIConfigList(nullptr)) { + std::string url = config_info.origin.Serialize() + "/"; + uint32_t hash = base::Hash(url); + std::string hash_string = + base::NumberToString(static_cast<base::HistogramBase::Sample>(hash)); + if (!webui_metrics::IsValidWebUIUrlHashes(hash_string)) { + missing_entries.push_back(base::StrCat( + {" <int value=\"", hash_string, "\" label=\"", url, "\"/>"})); + } + } + EXPECT_TRUE(missing_entries.empty()) + << "Please add this line to enum WebUIUrlHashes in " + "//tools/metrics/histograms/enums.xml:" + << std::endl + << base::JoinString(missing_entries, "\n"); +}
diff --git a/chrome/browser/webid/DEPS b/chrome/browser/webid/DEPS new file mode 100644 index 0000000..0d9c379 --- /dev/null +++ b/chrome/browser/webid/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+device/fido", +]
diff --git a/chrome/browser/webid/digital_identity_provider_desktop.cc b/chrome/browser/webid/digital_identity_provider_desktop.cc new file mode 100644 index 0000000..2211590 --- /dev/null +++ b/chrome/browser/webid/digital_identity_provider_desktop.cc
@@ -0,0 +1,101 @@ +// 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/webid/digital_identity_provider_desktop.h" + +#include <memory> + +#include "base/containers/span.h" +#include "chrome/grit/generated_resources.h" +#include "components/constrained_window/constrained_window_views.h" +#include "components/qr_code_generator/bitmap_generator.h" +#include "components/url_formatter/elide_url.h" +#include "content/public/browser/digital_identity_provider.h" +#include "crypto/random.h" +#include "device/fido/cable/v2_constants.h" +#include "device/fido/cable/v2_handshake.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/dialog_model.h" +#include "ui/views/bubble/bubble_dialog_model_host.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/widget/widget.h" + +namespace { + +// Smaller than DistanceMetric::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH. +const int kQrCodeSize = 240; + +using RequestStatusForMetrics = + content::DigitalIdentityProvider::RequestStatusForMetrics; + +std::unique_ptr<views::View> MakeQrCodeImageView(const std::string& qr_url) { + auto qr_code = qr_code_generator::GenerateImage( + base::as_byte_span(qr_url), qr_code_generator::ModuleStyle::kCircles, + qr_code_generator::LocatorStyle::kRounded, + qr_code_generator::CenterImage::kNoCenterImage, + qr_code_generator::QuietZone::kIncluded); + + // Success is guaranteed, because `qr_url`'s size is bounded and smaller + // than QR code limits. + CHECK(qr_code.has_value()); + auto image_view = std::make_unique<views::ImageView>( + ui::ImageModel::FromImageSkia(qr_code.value())); + image_view->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_WEB_DIGITAL_CREDENTIALS_QR_CODE_ALT_TEXT)); + image_view->SetImageSize(gfx::Size(kQrCodeSize, kQrCodeSize)); + return std::move(image_view); +} + +} // anonymous namespace + +DigitalIdentityProviderDesktop::DigitalIdentityProviderDesktop() = default; +DigitalIdentityProviderDesktop::~DigitalIdentityProviderDesktop() = default; + +void DigitalIdentityProviderDesktop::Request(content::WebContents* web_contents, + const url::Origin& rp_origin, + const std::string& request, + DigitalIdentityCallback callback) { + callback_ = std::move(callback); + + std::array<uint8_t, device::cablev2::kQRKeySize> qr_generator_key; + crypto::RandBytes(qr_generator_key); + std::string qr_url = device::cablev2::qr::Encode( + qr_generator_key, device::FidoRequestType::kGetAssertion); + ShowQrCodeDialog(web_contents, rp_origin, qr_url); +} + +void DigitalIdentityProviderDesktop::ShowQrCodeDialog( + content::WebContents* web_contents, + const url::Origin& rp_origin, + const std::string& qr_url) { + std::u16string formatted_rp_origin = l10n_util::GetStringFUTF16( + IDS_WEB_DIGITAL_CREDENTIALS_QR_BODY, + url_formatter::FormatOriginForSecurityDisplay( + rp_origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)); + auto dialog_model = + ui::DialogModel::Builder(std::make_unique<ui::DialogModelDelegate>()) + .AddCancelButton(base::BindOnce( + &DigitalIdentityProviderDesktop::OnQrCodeDialogCanceled, + weak_ptr_factory_.GetWeakPtr())) + .SetDialogDestroyingCallback(base::BindOnce( + &DigitalIdentityProviderDesktop::OnQrCodeDialogCanceled, + weak_ptr_factory_.GetWeakPtr())) + .SetTitle( + l10n_util::GetStringUTF16(IDS_WEB_DIGITAL_CREDENTIALS_QR_TITLE)) + .AddParagraph(ui::DialogModelLabel(formatted_rp_origin)) + .AddCustomField( + std::make_unique<views::BubbleDialogModelHost::CustomView>( + MakeQrCodeImageView(qr_url), + views::BubbleDialogModelHost::FieldType::kText)) + .Build(); + constrained_window::ShowWebModal(std::move(dialog_model), web_contents); +} + +void DigitalIdentityProviderDesktop::OnQrCodeDialogCanceled() { + if (callback_.is_null()) { + return; + } + + std::move(callback_).Run("", RequestStatusForMetrics::kErrorOther); +}
diff --git a/chrome/browser/webid/digital_identity_provider_desktop.h b/chrome/browser/webid/digital_identity_provider_desktop.h new file mode 100644 index 0000000..f62c9dbe --- /dev/null +++ b/chrome/browser/webid/digital_identity_provider_desktop.h
@@ -0,0 +1,41 @@ +// 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_WEBID_DIGITAL_IDENTITY_PROVIDER_DESKTOP_H_ +#define CHROME_BROWSER_WEBID_DIGITAL_IDENTITY_PROVIDER_DESKTOP_H_ + +#include "base/memory/weak_ptr.h" +#include "content/public/browser/digital_identity_provider.h" + +namespace content { +class WebContents; +} + +// Desktop-specific implementation of `DigitalIdentityProvider`. Uses FIDO +// hybrid flow to retrieve credentials stored on a mobile device. +class DigitalIdentityProviderDesktop : public content::DigitalIdentityProvider { + public: + DigitalIdentityProviderDesktop(); + ~DigitalIdentityProviderDesktop() override; + + void Request(content::WebContents* web_contents, + const url::Origin& rp_origin, + const std::string& request, + DigitalIdentityCallback callback) override; + + private: + // Shows dialog with QR code. + void ShowQrCodeDialog(content::WebContents* web_contents, + const url::Origin& rp_origin, + const std::string& qr_url); + + // Called when the QR code dialog is closed. + void OnQrCodeDialogCanceled(); + + DigitalIdentityCallback callback_; + + base::WeakPtrFactory<DigitalIdentityProviderDesktop> weak_ptr_factory_{this}; +}; + +#endif // CHROME_BROWSER_WEBID_DIGITAL_IDENTITY_PROVIDER_DESKTOP_H_
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 36de65c..9276d363 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1716342912-6c20a8da1ab5574a295e58baae778b2c2187405a-7f8cdd4ae657cb52ef1edfe726768f40297bde04.profdata +chrome-android64-main-1716400626-2b9f6aa81a461b5154e66b5b95a3c2c6ca4d06fc-08909446072ff97b4e3e5160ec492e669fa99fbe.profdata
diff --git a/chrome/build/lacros-arm64.pgo.txt b/chrome/build/lacros-arm64.pgo.txt index 8e7cc0f..54e1db6 100644 --- a/chrome/build/lacros-arm64.pgo.txt +++ b/chrome/build/lacros-arm64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-arm64-generic-main-1716379550-a19cb7e98d59b2e9671776e4d6c78e003191bbfc-0ab339800483e8dd806688cc201b1de7d7812e9d.profdata +chrome-chromeos-arm64-generic-main-1716422398-b9890d17cedc276bef6366182d3410dd8adf5ff7-733cf859ffcc1b41718638f8bf770fa68860c678.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt index 2d462f8..ad4b686 100644 --- a/chrome/build/lacros64.pgo.txt +++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-amd64-generic-main-1716379117-7ac95008ad1874908a2fee453514e50abf4450df-b9c5f7b8adaa3d1790edc1135d8db793ee62061a.profdata +chrome-chromeos-amd64-generic-main-1716422398-223ca7b3ef8df539c410074424fe09b534f064e4-733cf859ffcc1b41718638f8bf770fa68860c678.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 18ce5b9..aa96007 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1716379117-45912f1b47a395b65f7914621f4ad3f9dda191dc-b9c5f7b8adaa3d1790edc1135d8db793ee62061a.profdata +chrome-linux-main-1716443470-7b6cb0b13c1bd28665b4cccc7a87cff6b5eb3498-a62aa6f37c6a8a15d43fd327b8fbcd688d3fdf34.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index b87cec0..c3ee83b 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1716393394-da220abdf79101956394991c7e7cf778b80acedd-c5d620f70289ec2315d8cf748314cc9d50ce7596.profdata +chrome-mac-arm-main-1716443470-b482bcf7e612d5b7e58cc95dbaab92b63fddea22-a62aa6f37c6a8a15d43fd327b8fbcd688d3fdf34.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 8e353909..99950e92 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1716379117-2edf3255cd61b22dc9f362f1804f3a59f299e576-b9c5f7b8adaa3d1790edc1135d8db793ee62061a.profdata +chrome-win-arm64-main-1716443470-3fe318edfcee14fb294ebdb131a3f3ba9a1faacc-a62aa6f37c6a8a15d43fd327b8fbcd688d3fdf34.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 95e66ff..7797c2a 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1716389870-914bbcf711dac5d915d094891b9e1dd2d282aa70-2a060bf5d6d5ef8e7fb03458041e330549c968fc.profdata +chrome-win32-main-1716433120-c24f2430a667131eddae1cae404f57339ba71dfb-ef2a402c3112eb9024630d00dd0c735e85e67ae1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index b737947..f54a7b8 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1716367964-f310652993748df0a8f5b224c558ba8e46c421bf-f5636c890809c1d7e66826f95ba95d22b36e3fb2.profdata +chrome-win64-main-1716433120-675dfcdae9f7cdab7b292c05ff59e9a7818ac516-ef2a402c3112eb9024630d00dd0c735e85e67ae1.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 64d0d048..f096a46 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -245,6 +245,7 @@ "$root_gen_dir/ash/webui/ash_firmware_update_app_resources.pak", "$root_gen_dir/ash/webui/ash_focus_mode_resources.pak", "$root_gen_dir/ash/webui/ash_help_app_resources.pak", + "$root_gen_dir/ash/webui/ash_mall_cros_app_resources.pak", "$root_gen_dir/ash/webui/ash_media_app_resources.pak", "$root_gen_dir/ash/webui/ash_multidevice_debug_resources.pak", "$root_gen_dir/ash/webui/ash_os_feedback_resources.pak", @@ -330,6 +331,7 @@ "//ash/webui/file_manager/untrusted_resources:file_manager_untrusted_resources", "//ash/webui/firmware_update_ui/resources:resources", "//ash/webui/focus_mode/resources:resources", + "//ash/webui/mall/resources", "//ash/webui/os_feedback_ui/resources:resources", "//ash/webui/os_feedback_ui/untrusted_resources:resources", "//ash/webui/personalization_app/resources:resources",
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 2d7c5d71..ec13124 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -94,10 +94,7 @@ public_deps += [ "//components/version_info/android:channel_getter" ] } else if (is_chromeos_ash) { sources += [ "channel_info_chromeos.cc" ] - deps += [ - "//chromeos/crosapi/cpp", - "//chromeos/crosapi/cpp:crosapi_constants", - ] + deps += [ "//chromeos/ash/components/channel" ] } else if (is_chromeos_lacros) { sources += [ "channel_info_lacros.cc" ] } else if (is_posix) {
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index 848135d..05d89c0 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS
@@ -83,6 +83,9 @@ ] specific_include_rules = { + "channel_info_chromeos\.cc": [ + "+chromeos/ash/components/channel/channel_info.h", + ], "chrome_constants_ash_unittest\.cc": [ "+chromeos/ash/components/browser_context_helper/browser_context_types.h", ],
diff --git a/chrome/common/channel_info_chromeos.cc b/chrome/common/channel_info_chromeos.cc index 77596998..b179d15 100644 --- a/chrome/common/channel_info_chromeos.cc +++ b/chrome/common/channel_info_chromeos.cc
@@ -4,55 +4,17 @@ #include "chrome/common/channel_info.h" -#include "base/system/sys_info.h" -#include "build/branding_buildflags.h" -#include "chromeos/crosapi/cpp/crosapi_constants.h" +#include "chromeos/ash/components/channel/channel_info.h" #include "components/version_info/version_info.h" -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include "chromeos/crosapi/cpp/channel_to_enum.h" -#endif - namespace chrome { -namespace { - -version_info::Channel g_chromeos_channel = version_info::Channel::UNKNOWN; - -} // namespace std::string GetChannelName(WithExtendedStable with_extended_stable) { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - switch (GetChannel()) { - case version_info::Channel::STABLE: - return std::string(); - case version_info::Channel::BETA: - return "beta"; - case version_info::Channel::DEV: - return "dev"; - case version_info::Channel::CANARY: - return "canary"; - default: - return "unknown"; - } -#else - return std::string(); -#endif + return ash::GetChannelName(); } version_info::Channel GetChannel() { - static bool is_channel_set = false; - if (is_channel_set) - return g_chromeos_channel; - -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::string channel; - if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack, - &channel)) { - g_chromeos_channel = crosapi::ChannelToEnum(channel); - is_channel_set = true; - } -#endif - return g_chromeos_channel; + return ash::GetChannel(); } bool IsExtendedStableChannel() {
diff --git a/chrome/common/printing/printer_capabilities.cc b/chrome/common/printing/printer_capabilities.cc index 00bebb81..3d7f71ba 100644 --- a/chrome/common/printing/printer_capabilities.cc +++ b/chrome/common/printing/printer_capabilities.cc
@@ -129,6 +129,8 @@ #if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED) bool populate_paper_names = true; #if BUILDFLAG(IS_MAC) + // TODO(crbug.com/339188518): Is this needed on Linux? + // // Paper display name localization and vendor ID assignment is intended for // use with the CUPS IPP backend. If the CUPS IPP backend is not enabled, // localization will not properly occur.
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc index 5ffc8d9c..602c7fc 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller.cc +++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -545,6 +545,10 @@ model_.set_num_selections(0); } +void ReadAnythingAppController::OnRestartReadAloud() { + model_.ResetReadAloudState(); +} + void ReadAnythingAppController::OnAXTreeDestroyed(const ui::AXTreeID& tree_id) { // Cancel any running draw timers. post_user_entry_draw_timer_.Stop(); @@ -900,6 +904,8 @@ &ReadAnythingAppController::SendGetVoicePackInfoRequest) .SetMethod("sendInstallVoicePackRequest", &ReadAnythingAppController::SendInstallVoicePackRequest) + .SetMethod("onRestartReadAloud", + &ReadAnythingAppController::OnRestartReadAloud) .SetMethod("getNodeIdForCurrentSegmentIndex", &ReadAnythingAppController::GetNodeIdForCurrentSegmentIndex) .SetMethod("getNextWordHighlightLength",
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything_app_controller.h index ed9bbed..89d64a0 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller.h +++ b/chrome/renderer/accessibility/read_anything_app_controller.h
@@ -187,6 +187,7 @@ ui::AXNodeID focus_node_id, int focus_offset) const; void OnCollapseSelection() const; + void OnRestartReadAloud(); bool IsGoogleDocs() const; bool IsWebUIToolbarEnabled() const; bool IsReadAloudEnabled() const;
diff --git a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc index 36e141de..594557c 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc +++ b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
@@ -402,6 +402,8 @@ void OnCollapseSelection() { controller_->OnCollapseSelection(); } + void OnRestartReadAloud() { controller_->OnRestartReadAloud(); } + bool IsNodeIgnoredForReadAnything(ui::AXNodeID ax_node_id) { return controller_->model_.IsNodeIgnoredForReadAnything(ax_node_id); } @@ -2474,6 +2476,7 @@ // Confirm size is still 1. EXPECT_EQ((int)GetCurrentText().size(), 1); } + TEST_F(ReadAnythingAppControllerTest, GetCurrentText_ReturnsExpectedNodes) { // TODO(crbug.com/40927698): Investigate if we can improve in scenarios when // there's not a space between sentences. @@ -2529,6 +2532,55 @@ EXPECT_EQ((int)next_node_ids.size(), 0); } +TEST_F(ReadAnythingAppControllerTest, + GetCurrentText_AfterRestartReadAloud_StartsOver) { + std::u16string sentence1 = u"I've got the wind in my hair. "; + std::u16string sentence2 = u"And a gleam in my eyes. "; + std::u16string sentence3 = u"And an endless horizon. "; + ui::AXTreeUpdate update; + SetUpdateTreeID(&update); + ui::AXNodeData static_text1; + static_text1.id = 2; + static_text1.role = ax::mojom::Role::kStaticText; + static_text1.SetNameChecked(sentence1); + + ui::AXNodeData static_text2; + static_text2.id = 3; + static_text2.role = ax::mojom::Role::kStaticText; + static_text2.SetNameChecked(sentence2); + + ui::AXNodeData static_text3; + static_text3.id = 4; + static_text3.role = ax::mojom::Role::kStaticText; + static_text3.SetNameChecked(sentence3); + update.nodes = {static_text1, static_text2, static_text3}; + ProcessAccessibilityUpdatesAndEvents({update}); + OnAXTreeDistilled({static_text1.id, static_text2.id, static_text3.id}); + InitAXPosition(update.nodes[0].id); + + std::vector<ui::AXNodeID> next_node_ids = GetCurrentText(); + EXPECT_EQ((int)next_node_ids.size(), 1); + EXPECT_EQ(next_node_ids[0], static_text1.id); + + // Move to the next sentence. + next_node_ids = MoveToNextGranularityAndGetText(); + EXPECT_EQ((int)next_node_ids.size(), 1); + EXPECT_EQ(next_node_ids[0], static_text2.id); + + // If we init without restarting we should just go to the next sentence. + InitAXPosition(update.nodes[0].id); + next_node_ids = MoveToNextGranularityAndGetText(); + EXPECT_EQ((int)next_node_ids.size(), 1); + EXPECT_EQ(next_node_ids[0], static_text3.id); + + // After reset and then init, we should get the first sentence again. + OnRestartReadAloud(); + InitAXPosition(update.nodes[0].id); + std::vector<ui::AXNodeID> after_reset_ids = GetCurrentText(); + EXPECT_EQ((int)after_reset_ids.size(), 1); + EXPECT_EQ(after_reset_ids[0], static_text1.id); +} + TEST_F(ReadAnythingAppControllerTest, GetCurrentText_AfterAXTreeRefresh) { std::u16string sentence1 = u"This is a sentence. "; std::u16string sentence2 = u"This is another sentence. ";
diff --git a/chrome/renderer/accessibility/read_anything_app_model.h b/chrome/renderer/accessibility/read_anything_app_model.h index e5573012..2d11dbe 100644 --- a/chrome/renderer/accessibility/read_anything_app_model.h +++ b/chrome/renderer/accessibility/read_anything_app_model.h
@@ -400,6 +400,8 @@ // node isn't in the current segment. int GetCurrentTextEndIndex(const ui::AXNodeID& node_id); + void ResetReadAloudState(); + void IncrementMetric(const std::string& metric_name); // Log speech count events. @@ -441,8 +443,6 @@ // spoken by Read Aloud. ui::AXNode* GetNodeFromCurrentPosition() const; - void ResetReadAloudState(); - bool IsTextForReadAnything(const ui::AXNodeID& ax_node_id) const; bool ShouldSplitAtParagraph(
diff --git a/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc index c90e89c2..8d8fd8b 100644 --- a/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc +++ b/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc
@@ -261,6 +261,8 @@ model_->InitAXPositionWithNode(id); } + void ResetReadAloudState() { model_->ResetReadAloudState(); } + ui::AXNodePosition::AXPositionInstance GetNextNodePosition() { ReadAnythingAppModel::ReadAloudCurrentGranularity granularity = ReadAnythingAppModel::ReadAloudCurrentGranularity(); @@ -1937,6 +1939,62 @@ } TEST_F(ReadAnythingAppModelTest, + GetNextNodes_AfterResetReadAloudState_StartsOver) { + std::u16string sentence1 = u"Where the north wind meets the sea. "; + std::u16string sentence2 = u"There's a river full of memory. "; + std::u16string sentence3 = u"Sleep my darling safe and sound. "; + ui::AXTreeUpdate update; + SetUpdateTreeID(&update); + ui::AXNodeData static_text1; + static_text1.id = 2; + static_text1.role = ax::mojom::Role::kStaticText; + static_text1.SetNameChecked(sentence1); + + ui::AXNodeData static_text2; + static_text2.id = 3; + static_text2.role = ax::mojom::Role::kStaticText; + static_text2.SetNameChecked(sentence2); + + ui::AXNodeData static_text3; + static_text3.id = 4; + static_text3.role = ax::mojom::Role::kStaticText; + static_text3.SetNameChecked(sentence3); + update.nodes = {static_text1, static_text2, static_text3}; + ProcessAccessibilityUpdatesAndEvents({update}); + ProcessDisplayNodes({static_text1.id, static_text2.id, static_text3.id}); + InitAXPosition(update.nodes[0].id); + + // Get first and second granularity. + ReadAnythingAppModel::ReadAloudCurrentGranularity first_granularity = + GetNextNodes(); + EXPECT_EQ((int)first_granularity.node_ids.size(), 1); + EXPECT_TRUE(base::Contains(first_granularity.node_ids, static_text1.id)); + EXPECT_EQ(first_granularity.text, sentence1); + ReadAnythingAppModel::ReadAloudCurrentGranularity next_granularity = + GetNextNodes(); + EXPECT_EQ((int)next_granularity.node_ids.size(), 1); + EXPECT_TRUE(base::Contains(next_granularity.node_ids, static_text2.id)); + EXPECT_EQ(next_granularity.text, sentence2); + + // If we init without resetting we should just go to the next sentence + InitAXPosition(update.nodes[0].id); + ReadAnythingAppModel::ReadAloudCurrentGranularity last_granularity = + GetNextNodes(); + EXPECT_EQ((int)last_granularity.node_ids.size(), 1); + EXPECT_TRUE(base::Contains(last_granularity.node_ids, static_text3.id)); + EXPECT_EQ(last_granularity.text, sentence3); + + // After reset and then init, we should get the first sentence again. + ResetReadAloudState(); + InitAXPosition(update.nodes[0].id); + ReadAnythingAppModel::ReadAloudCurrentGranularity after_reset = + GetNextNodes(); + EXPECT_EQ((int)after_reset.node_ids.size(), 1); + EXPECT_TRUE(base::Contains(after_reset.node_ids, static_text1.id)); + EXPECT_EQ(first_granularity.text, sentence1); +} + +TEST_F(ReadAnythingAppModelTest, GetNodeIdForCurrentSegmentIndex_ReturnsCorrectNodes) { std::u16string sentence1 = u"Never feel heavy "; std::u16string sentence2 = u"or earthbound, ";
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc b/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc index ba04210..d6a916f 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc
@@ -4,7 +4,12 @@ #include "chrome/services/sharing/nearby/platform/wifi_direct_medium.h" +#include <netinet/in.h> + +#include "base/task/task_traits.h" #include "base/task/thread_pool.h" +#include "chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h" +#include "net/socket/socket_descriptor.h" namespace nearby::chrome { @@ -72,8 +77,36 @@ std::unique_ptr<api::WifiDirectServerSocket> WifiDirectMedium::ListenForService( int port) { - NOTIMPLEMENTED(); - return nullptr; + // Ensure that there is a valid WiFi Direct connection. + if (!connection_) { + return nullptr; + } + + // Create server socket. + auto fd = base::ScopedFD( + net::CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + if (fd.get() < 0) { + return nullptr; + } + mojo::PlatformHandle handle = mojo::PlatformHandle(std::move(fd)); + + // Wrap the async mojo call to make it sync. + bool did_associate; + { + base::WaitableEvent waitable_event; + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&WifiDirectMedium::AssociateSocket, + base::Unretained(this), &did_associate, + &waitable_event, handle.Clone())); + waitable_event.Wait(); + } + + if (!did_associate) { + // Socket not associated at the platform layer. + return nullptr; + } + + return std::make_unique<WifiDirectServerSocket>(std::move(handle)); } absl::optional<std::pair<std::int32_t, std::int32_t>> @@ -160,6 +193,24 @@ waitable_event->Signal(); } +void WifiDirectMedium::AssociateSocket(bool* did_associate, + base::WaitableEvent* waitable_event, + mojo::PlatformHandle socket_handle) { + CHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(connection_.is_bound()); + connection_->AssociateSocket( + std::move(socket_handle), + base::BindOnce(&WifiDirectMedium::OnSocketAssociated, + base::Unretained(this), did_associate, waitable_event)); +} + +void WifiDirectMedium::OnSocketAssociated(bool* did_associate, + base::WaitableEvent* waitable_event, + bool success) { + *did_associate = success; + waitable_event->Signal(); +} + void WifiDirectMedium::OnDisconnect() { // Reset the connection, since it has been disconnected at this point. connection_.reset();
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_medium.h b/chrome/services/sharing/nearby/platform/wifi_direct_medium.h index b5b282354..1cb92cc6 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_medium.h +++ b/chrome/services/sharing/nearby/platform/wifi_direct_medium.h
@@ -59,6 +59,13 @@ base::WaitableEvent* waitable_event, ash::wifi_direct::mojom::WifiDirectConnectionPropertiesPtr properties); + void AssociateSocket(bool* did_associate, + base::WaitableEvent* waitable_event, + mojo::PlatformHandle socket_descriptor); + void OnSocketAssociated(bool* did_associate, + base::WaitableEvent* waitable_event, + bool success); + void OnDisconnect(); scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc index 5e9cd740..57720853 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc
@@ -14,9 +14,16 @@ namespace { constexpr char kTestIPv4Address[] = "127.0.0.1"; +constexpr int kTestPort = 61234; class FakeWifiDirectConnection : public ash::wifi_direct::mojom::WifiDirectConnection { + public: + std::optional<::mojo::PlatformHandle> socket; + bool should_associate; + + private: + // ash::wifi_direct::mojom::WifiDirectConnection void GetProperties(GetPropertiesCallback callback) override { auto properties = ash::wifi_direct::mojom::WifiDirectConnectionProperties::New(); @@ -25,9 +32,11 @@ std::move(callback).Run(std::move(properties)); } - void AssociateSocket(::mojo::PlatformHandle socket, + // ash::wifi_direct::mojom::WifiDirectConnection + void AssociateSocket(::mojo::PlatformHandle handle, AssociateSocketCallback callback) override { - NOTIMPLEMENTED(); + socket = std::move(handle); + std::move(callback).Run(should_associate); } }; @@ -74,9 +83,10 @@ std::move(callback).Run(std::move(response)); } - void SetWifiDirectConnection( + FakeWifiDirectConnection* SetWifiDirectConnection( std::unique_ptr<FakeWifiDirectConnection> connection) { connection_ = std::move(connection); + return connection_.get(); } private: @@ -207,4 +217,73 @@ medium())); } +TEST_F(WifiDirectMediumTest, ListenForService_AssociatesSocket) { + auto* connection = manager()->SetWifiDirectConnection( + std::make_unique<FakeWifiDirectConnection>()); + connection->should_associate = true; + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + EXPECT_TRUE(medium->StartWifiDirect(&credentials)); + }, + medium())); + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + // TODO: Assert result once implementation is complete. + medium->ListenForService(kTestPort); + }, + medium())); + + EXPECT_TRUE(connection->socket); +} + +TEST_F(WifiDirectMediumTest, ListenForService_MissingConnection) { + manager()->SetWifiDirectConnection(nullptr); + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + EXPECT_FALSE(medium->StartWifiDirect(&credentials)); + }, + medium())); + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + // TODO: Assert result once implementation is complete. + medium->ListenForService(kTestPort); + }, + medium())); +} + +TEST_F(WifiDirectMediumTest, ListenForService_FailToAssociatesSocket) { + auto* connection = manager()->SetWifiDirectConnection( + std::make_unique<FakeWifiDirectConnection>()); + connection->should_associate = false; + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + EXPECT_TRUE(medium->StartWifiDirect(&credentials)); + }, + medium())); + + RunOnTaskRunner(base::BindOnce( + [](WifiDirectMedium* medium) { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + WifiDirectCredentials credentials; + // TODO: Assert result once implementation is complete. + medium->ListenForService(kTestPort); + }, + medium())); +} + } // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.cc b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.cc index d0319fe..3da85e9 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.cc
@@ -6,7 +6,9 @@ namespace nearby::chrome { -WifiDirectServerSocket::WifiDirectServerSocket() = default; +WifiDirectServerSocket::WifiDirectServerSocket(mojo::PlatformHandle handle) + : handle_(std::move(handle)) {} + WifiDirectServerSocket::~WifiDirectServerSocket() = default; // api::WifiDirectServerSocket
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h index 97d8c80b..1b7056d 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h +++ b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h
@@ -13,7 +13,7 @@ class WifiDirectServerSocket : public api::WifiDirectServerSocket { public: - WifiDirectServerSocket(); + explicit WifiDirectServerSocket(mojo::PlatformHandle handle); WifiDirectServerSocket(const WifiDirectServerSocket&) = delete; WifiDirectServerSocket& operator=(const WifiDirectServerSocket&) = delete; ~WifiDirectServerSocket() override; @@ -23,6 +23,9 @@ int GetPort() const override; std::unique_ptr<api::WifiDirectSocket> Accept() override; Exception Close() override; + + private: + mojo::PlatformHandle handle_; }; } // namespace nearby::chrome
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index e5bd122..5bbadd9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1738,7 +1738,6 @@ "//chrome/browser/devtools", "//chrome/browser/devtools:test_support", "//chrome/browser/dips:browser_tests", - "//chrome/browser/enterprise/identifiers:identifiers", "//chrome/browser/favicon", "//chrome/browser/first_party_sets", "//chrome/browser/headless:browser_tests", @@ -1783,6 +1782,7 @@ "//chrome/browser/ui/side_panel:side_panel_enums", "//chrome/browser/ui/tabs:tab_enums", "//chrome/browser/ui/web_applications:browser_tests", + "//chrome/browser/ui/webui", "//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings", "//chrome/browser/ui/webui/top_chrome", "//chrome/browser/web_applications:browser_tests", @@ -2375,6 +2375,7 @@ "../browser/file_system_access/file_system_access_picker_requires_user_gesture_browsertest.cc", "../browser/file_system_access/file_system_access_tab_helper_browsertest.cc", "../browser/file_system_access/file_system_file_handle_browsertest.cc", + "../browser/file_system_access/file_system_observer_storage_access_browsertest.cc", "../browser/first_party_sets/first_party_sets_policy_browsertest.cc", "../browser/first_run/first_run_browsertest.cc", "../browser/geolocation/geolocation_browsertest.cc", @@ -2838,6 +2839,7 @@ "../browser/ui/user_education/low_usage_help_controller_browsertest.cc", "../browser/ui/user_education/show_promo_in_page_browsertest.cc", "../browser/ui/user_education/start_tutorial_in_page_browsertest.cc", + "../browser/ui/user_education/user_education_configuration_provider_browsertest.cc", "../browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc", "../browser/ui/views/autofill/payments/offer_notification_icon_view_browsertest.cc", "../browser/ui/views/bluetooth_device_credentials_view_browsertest.cc", @@ -2926,6 +2928,7 @@ "../browser/ui/webui/tab_search/tab_search_ui_browsertest.cc", "../browser/ui/webui/top_chrome/webui_contents_preload_manager_browsertest.cc", "../browser/ui/webui/webui_load_timer_browsertest.cc", + "../browser/ui/webui/webui_url_hashes_browsertest.cc", "../browser/ui/zoom/zoom_controller_browsertest.cc", "../browser/ukm_worker_browsertest.cc", "../browser/unload_browsertest.cc", @@ -4845,7 +4848,7 @@ "../browser/ash/policy/skyvault/drive_upload_observer_browsertest.cc", "../browser/ash/policy/skyvault/file_location_utils_browsertest.cc", "../browser/ash/policy/skyvault/local_files_cleanup_browsertest.cc", - "../browser/ash/policy/skyvault/observer_browsertest.cc", + "../browser/ash/policy/skyvault/local_user_files_policy_observer_browsertest.cc", "../browser/ash/policy/skyvault/odfs_skyvault_uploader_browsertest.cc", "../browser/ash/policy/skyvault/policy_utils_browsertest.cc", "../browser/ash/policy/status_collector/child_status_collector_browsertest.cc", @@ -6846,7 +6849,6 @@ "//chrome/browser/crash_upload_list:unit_tests", "//chrome/browser/devtools", "//chrome/browser/dips:unit_tests", - "//chrome/browser/enterprise/identifiers", "//chrome/browser/favicon", "//chrome/browser/first_party_sets", "//chrome/browser/google:unit_tests", @@ -8431,6 +8433,7 @@ "//chrome/browser/media/router:test_support", "//chrome/browser/media/router/discovery:discovery", "//chrome/browser/media/router/discovery/access_code:access_code_sink_service", + "//chrome/browser/new_tab_page/chrome_colors", "//chrome/browser/new_tab_page/modules/feed:mojo_bindings", "//chrome/browser/new_tab_page/modules/history_clusters:mojo_bindings", "//chrome/browser/new_tab_page/modules/history_clusters/cart:mojo_bindings", @@ -8446,6 +8449,7 @@ "//chrome/browser/ui/color:color_headers", "//chrome/browser/ui/color:mixers", "//chrome/browser/ui/lens", + "//chrome/browser/ui/webui/cr_components/theme_color_picker", "//chrome/browser/ui/webui/discards:mojo_bindings", "//chrome/browser/ui/webui/downloads:mojo_bindings", "//chrome/browser/ui/webui/new_tab_page:mojo_bindings", @@ -8609,6 +8613,7 @@ sources += [ "../browser/accessibility/media_app/ax_media_app_untrusted_handler_unittest.cc", "../browser/browser_process_platform_part_ash_unittest.cc", + "../browser/chromeos/mahi/mahi_prefs_controller_ash_unittest.cc", "../browser/component_updater/cros_component_installer_chromeos_unittest.cc", "../browser/component_updater/metadata_table_chromeos_unittest.cc", "../browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AppMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AppMenuFacility.java index 408846f..3c0690f 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AppMenuFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AppMenuFacility.java
@@ -30,7 +30,6 @@ import org.chromium.base.test.transit.Station; import org.chromium.chrome.R; import org.chromium.chrome.browser.ui.appmenu.AppMenuItemProperties; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.ui.modelutil.MVCListAdapter; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; @@ -125,12 +124,8 @@ public static final @IdRes int SETTINGS_ID = R.id.preferences_id; public static final @IdRes int HELP_AND_FEEDBACK_ID = R.id.help_id; - protected final ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; - - protected AppMenuFacility( - HostStationT station, ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { + protected AppMenuFacility(HostStationT station) { super(station); - mChromeTabbedActivityTestRule = chromeTabbedActivityTestRule; } @CallSuper @@ -150,17 +145,12 @@ /** Default behavior for "Open new tab". */ protected NewTabPageStation createNewTabPageStation() { - return NewTabPageStation.newBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) - .withIsOpeningTabs(1) - .withIsSelectingTabs(1) - .build(); + return NewTabPageStation.newBuilder().withIsOpeningTabs(1).withIsSelectingTabs(1).build(); } /** Default behavior for "Open new Incognito tab". */ protected IncognitoNewTabPageStation createIncognitoNewTabPageStation() { return IncognitoNewTabPageStation.newBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIsOpeningTabs(1) .withIsSelectingTabs(1) .build();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java index 862e362e..f2faae8c 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java
@@ -53,10 +53,7 @@ } WebPageStation entryPageStation = - WebPageStation.newWebPageStationBuilder() - .withActivityTestRule(mActivityTestRule) - .withEntryPoint() - .build(); + WebPageStation.newWebPageStationBuilder().withEntryPoint().build(); // Wait for the Conditions to be met to return an active PageStation. return homeStation.travelToSync(entryPageStation, /* trigger= */ null);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ChromeTabbedActivityPublicTransitEntryPoints.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ChromeTabbedActivityPublicTransitEntryPoints.java index 96839574..c567694 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ChromeTabbedActivityPublicTransitEntryPoints.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ChromeTabbedActivityPublicTransitEntryPoints.java
@@ -32,10 +32,7 @@ sentinel.setAsEntryPoint(); WebPageStation entryPageStation = - WebPageStation.newWebPageStationBuilder() - .withActivityTestRule(mActivityTestRule) - .withEntryPoint() - .build(); + WebPageStation.newWebPageStationBuilder().withEntryPoint().build(); return sentinel.travelToSync( entryPageStation, mActivityTestRule::startMainActivityOnBlankPage); }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubBaseStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubBaseStation.java index 08a5cb0..4d0730b 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubBaseStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubBaseStation.java
@@ -36,7 +36,6 @@ import org.chromium.chrome.browser.hub.R; import org.chromium.chrome.browser.layouts.LayoutManager; import org.chromium.chrome.browser.layouts.LayoutType; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; /** The base station for Hub, with several panes and a toolbar. */ public abstract class HubBaseStation extends Station { @@ -63,17 +62,12 @@ withContentDescription( R.string.accessibility_tab_switcher_incognito_stack))); - protected final ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; protected ActivityElement<ChromeTabbedActivity> mActivityElement; protected TabModelSelectorCondition mTabModelSelectorCondition; - /** - * @param chromeTabbedActivityTestRule The {@link ChromeTabbedActivityTestRule} of the test. - */ - public HubBaseStation(ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { + public HubBaseStation() { super(); assert HubFieldTrial.isHubEnabled(); - mChromeTabbedActivityTestRule = chromeTabbedActivityTestRule; } /** Returns the station's {@link PaneId}. */ @@ -103,6 +97,14 @@ } /** + * @return the {@link ChromeTabbedActivity} for this station. + */ + protected ChromeTabbedActivity getActivity() { + assertSuppliersCanBeUsed(); + return mActivityElement.get(); + } + + /** * Returns to the previous tab via the back button. * * @return the {@link PageStation} that Hub returned to. @@ -113,7 +115,6 @@ // a solution that better handles the complexity. PageStation destination = PageStation.newPageStationBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIsOpeningTabs(0) .withIsSelectingTabs(1) .build(); @@ -133,8 +134,7 @@ return expectedDestination.cast(this); } - T destinationStation = expectedDestination.cast( - HubStationUtils.createHubStation(paneId, mChromeTabbedActivityTestRule)); + T destinationStation = expectedDestination.cast(HubStationUtils.createHubStation(paneId)); try { HUB_PANE_SWITCHER.onView().check(matches(isDisplayed()));
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubIncognitoTabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubIncognitoTabSwitcherStation.java index 5d00e036..102dec3 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubIncognitoTabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubIncognitoTabSwitcherStation.java
@@ -5,16 +5,12 @@ package org.chromium.chrome.test.transit; import org.chromium.chrome.browser.hub.PaneId; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; /** Incognito tab switcher pane station. */ public class HubIncognitoTabSwitcherStation extends HubTabSwitcherBaseStation { - /** - * @param chromeTabbedActivityTestRule The activity rule under test. - */ - public HubIncognitoTabSwitcherStation( - ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { - super(chromeTabbedActivityTestRule, /* isIncognito= */ true); + + public HubIncognitoTabSwitcherStation() { + super(/* isIncognito= */ true); } @Override
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubStationUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubStationUtils.java index fc6bd3f..ab6fea4 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubStationUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubStationUtils.java
@@ -8,7 +8,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.hub.PaneId; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import java.util.Map; @@ -37,16 +36,14 @@ /** * @param paneId The pane to create the station for. - * @param chromeTabbedActivityTestRule The test rule. * @return corresponding {@link HubBaseStation} subclass. */ - public static HubBaseStation createHubStation( - @PaneId int paneId, ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { + public static HubBaseStation createHubStation(@PaneId int paneId) { switch (paneId) { case PaneId.TAB_SWITCHER: - return new HubTabSwitcherStation(chromeTabbedActivityTestRule); + return new HubTabSwitcherStation(); case PaneId.INCOGNITO_TAB_SWITCHER: - return new HubIncognitoTabSwitcherStation(chromeTabbedActivityTestRule); + return new HubIncognitoTabSwitcherStation(); default: throw new IllegalArgumentException("No hub station is available for " + paneId); }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherAppMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherAppMenuFacility.java index 5cf5982..c328fa49 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherAppMenuFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherAppMenuFacility.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.test.transit; import org.chromium.chrome.R; +import org.chromium.content_public.browser.test.util.TestThreadUtils; /** The app menu shown when pressing ("...") in the Hub on a tab switcher pane. */ public class HubTabSwitcherAppMenuFacility extends AppMenuFacility<HubTabSwitcherBaseStation> { @@ -22,13 +23,13 @@ private Item<SettingsStation> mSettings; public HubTabSwitcherAppMenuFacility(HubTabSwitcherBaseStation station, boolean isIncognito) { - super(station, station.mChromeTabbedActivityTestRule); + super(station); mIsIncognito = isIncognito; } @Override protected void declareItems(ItemsBuilder items) { - boolean isTablet = mChromeTabbedActivityTestRule.getActivity().isTablet(); + boolean isTablet = mHostStation.getActivity().isTablet(); mNewTab = declareMenuItemToStation(items, NEW_TAB_ID, this::createNewTabPageStation); mNewIncognitoTab = @@ -36,8 +37,15 @@ items, NEW_INCOGNITO_TAB_ID, this::createIncognitoNewTabPageStation); if (!mIsIncognito) { // Regular Hub Tab Switcher - - if (mChromeTabbedActivityTestRule.tabsCount(/* regular= */ false) > 0) { + int tabCount = + TestThreadUtils.runOnUiThreadBlockingNoException( + () -> + mHostStation + .getActivity() + .getTabModelSelector() + .getModel(/* incognito= */ false) + .getCount()); + if (tabCount > 0) { mCloseAllTabs = declareStubMenuItem(items, CLOSE_ALL_TABS_ID); mSelectTabs = declareMenuItemToFacility( @@ -89,6 +97,6 @@ } private HubTabSwitcherListEditorFacility createListEditorFacility() { - return new HubTabSwitcherListEditorFacility(mHostStation, mChromeTabbedActivityTestRule); + return new HubTabSwitcherListEditorFacility(mHostStation); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherBaseStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherBaseStation.java index e323ccce..62208775 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherBaseStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherBaseStation.java
@@ -27,7 +27,6 @@ import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_management.TabGridView; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; /** The base station for Hub tab switcher stations. */ @@ -63,12 +62,9 @@ private final boolean mIsIncognito; - /** - * @param chromeTabbedActivityTestRule The activity rule under test. - */ - public HubTabSwitcherBaseStation( - ChromeTabbedActivityTestRule chromeTabbedActivityTestRule, boolean isIncognito) { - super(chromeTabbedActivityTestRule); + /** */ + public HubTabSwitcherBaseStation(boolean isIncognito) { + super(); mIsIncognito = isIncognito; } @@ -102,7 +98,6 @@ PageStation destination = PageStation.newPageStationBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIncognito(mIsIncognito) .withIsOpeningTabs(0) .withIsSelectingTabs(1) @@ -123,8 +118,7 @@ */ public <T extends HubTabSwitcherBaseStation> T closeTabAtIndex( int index, Class<T> expectedDestination) { - TabModelSelector tabModelSelector = - mChromeTabbedActivityTestRule.getActivity().getTabModelSelector(); + TabModelSelector tabModelSelector = mActivityElement.get().getTabModelSelector(); // By default stay in the same tab switcher state, unless closing the last incognito tab. boolean landInIncognitoSwitcher = false; @@ -142,8 +136,7 @@ HubStationUtils.createHubStation( landInIncognitoSwitcher ? PaneId.INCOGNITO_TAB_SWITCHER - : PaneId.TAB_SWITCHER, - mChromeTabbedActivityTestRule)); + : PaneId.TAB_SWITCHER)); return travelToSync( tabSwitcher, @@ -162,7 +155,6 @@ PageStation page = PageStation.newPageStationBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIncognito(mIsIncognito) .withIsOpeningTabs(1) .withIsSelectingTabs(1)
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherListEditorFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherListEditorFacility.java index 712c8980..e6bf0373 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherListEditorFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherListEditorFacility.java
@@ -16,7 +16,6 @@ import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.Facility; import org.chromium.base.test.transit.ViewElement; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; /** The 3-dot menu "Select Tabs" UI for the {@link HubTabSwitcherBase} panes. */ @@ -30,13 +29,8 @@ isDescendantOfA(withId(R.id.selectable_list)), withId(R.id.tab_list_recycler_view))); - private final ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; - - public HubTabSwitcherListEditorFacility( - HubTabSwitcherBaseStation station, - ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { + public HubTabSwitcherListEditorFacility(HubTabSwitcherBaseStation station) { super(station); - mChromeTabbedActivityTestRule = chromeTabbedActivityTestRule; } @Override
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherStation.java index 00bc559a..024da1c2 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/HubTabSwitcherStation.java
@@ -11,7 +11,6 @@ import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.ViewElement; import org.chromium.chrome.browser.hub.PaneId; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; /** Regular tab switcher pane station. */ @@ -19,11 +18,8 @@ public static final ViewElement EMPTY_STATE_TEXT = sharedViewElement(withText(R.string.tabswitcher_no_tabs_empty_state)); - /** - * @param chromeTabbedActivityTestRule The activity rule under test. - */ - public HubTabSwitcherStation(ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { - super(chromeTabbedActivityTestRule, /* isIncognito= */ false); + public HubTabSwitcherStation() { + super(/* isIncognito= */ false); } @Override
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/IncognitoTabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/IncognitoTabSwitcherStation.java index b86054c..93db8d51 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/IncognitoTabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/IncognitoTabSwitcherStation.java
@@ -7,13 +7,12 @@ import static androidx.test.espresso.action.ViewActions.click; import org.chromium.base.test.transit.Elements; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; /** The tab switcher screen showing incognito tabs. */ public class IncognitoTabSwitcherStation extends TabSwitcherStation { - public IncognitoTabSwitcherStation(ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { - super(chromeTabbedActivityTestRule, /* incognito= */ true); + public IncognitoTabSwitcherStation() { + super(/* incognito= */ true); } @Override @@ -26,8 +25,7 @@ } public RegularTabSwitcherStation selectRegularTabList() { - RegularTabSwitcherStation tabSwitcher = - new RegularTabSwitcherStation(mChromeTabbedActivityTestRule); + RegularTabSwitcherStation tabSwitcher = new RegularTabSwitcherStation(); return travelToSync(tabSwitcher, () -> REGULAR_TOGGLE_TAB_BUTTON.perform(click())); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/MessageFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/MessageFacility.java index ab1de80..c3ba0177 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/MessageFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/MessageFacility.java
@@ -79,7 +79,6 @@ MessageDispatcher messageDispatcher = MessageDispatcherProvider.from( mHostStation - .mChromeTabbedActivityTestRule .getActivity() .getWindowAndroid()); assert messageDispatcher != null;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/NewTabPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/NewTabPageStation.java index a0768ebc..b14c6a21 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/NewTabPageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/NewTabPageStation.java
@@ -12,6 +12,7 @@ import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.ViewElement; import org.chromium.chrome.R; +import org.chromium.ui.base.DeviceFormFactor; /** * The New Tab Page screen, with an omnibox, most visited tiles, and the Feed instead of the @@ -34,7 +35,7 @@ public void declareElements(Elements.Builder elements) { super.declareElements(elements); - boolean isTablet = mChromeTabbedActivityTestRule.getActivity().isTablet(); + boolean isTablet = DeviceFormFactor.isTablet(); // TODO(crbug.com/40267786): On generic_android32_foldable these elements do not appear or // appear unreliably when a keyboard is attached, which is the case for local development
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageAppMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageAppMenuFacility.java index 96cb892..cd20eb6 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageAppMenuFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageAppMenuFacility.java
@@ -30,7 +30,7 @@ protected Item<SettingsStation> mSettings; public PageAppMenuFacility(HostPageStationT station) { - super(station, station.mChromeTabbedActivityTestRule); + super(station); } @Override
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageStation.java index 03dbf26..2a1d3ee 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/PageStation.java
@@ -8,8 +8,6 @@ import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static org.junit.Assert.fail; - import static org.chromium.base.test.transit.ViewElement.unscopedViewElement; import org.chromium.base.ThreadUtils; @@ -29,7 +27,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelObserver; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.base.PageTransition; @@ -52,7 +49,6 @@ */ public static class Builder<T extends PageStation> { private final Function<Builder<T>, T> mFactoryMethod; - private ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; private boolean mIncognito; private boolean mIsEntryPoint; private Integer mNumTabsBeingOpened; @@ -65,11 +61,6 @@ mFactoryMethod = factoryMethod; } - public Builder<T> withActivityTestRule(ChromeTabbedActivityTestRule activityTestRule) { - mChromeTabbedActivityTestRule = activityTestRule; - return this; - } - public Builder<T> withIncognito(boolean incognito) { mIncognito = incognito; return this; @@ -112,7 +103,6 @@ } public Builder<T> initFrom(PageStation previousStation) { - mChromeTabbedActivityTestRule = previousStation.getTestRule(); mIncognito = previousStation.isIncognito(); return this; } @@ -122,7 +112,6 @@ } } - protected final ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; protected final boolean mIncognito; protected final boolean mIsEntryPoint; protected final int mNumTabsBeingOpened; @@ -146,9 +135,6 @@ /** Use {@link #newPageStationBuilder()} or the PageStation's subclass |newBuilder()|. */ protected <T extends PageStation> PageStation(Builder<T> builder) { - // activityTestRule is required - assert builder.mChromeTabbedActivityTestRule != null; - mChromeTabbedActivityTestRule = builder.mChromeTabbedActivityTestRule; // incognito is optional and defaults to false mIncognito = builder.mIncognito; @@ -191,7 +177,8 @@ elements.declareView(MENU_BUTTON); if (mNumTabsBeingOpened > 0) { - elements.declareEnterCondition(new TabAddedCondition(mNumTabsBeingOpened)); + elements.declareEnterCondition( + new TabAddedCondition(mNumTabsBeingOpened, mActivityElement)); } if (mIsEntryPoint) { @@ -204,7 +191,7 @@ // The last tab of N opened is the Tab that mSelectedTabSupplier will supply. mSelectedTabSupplier = elements.declareEnterCondition( - new TabSelectedCondition(mNumTabsBeingSelected)); + new TabSelectedCondition(mNumTabsBeingSelected, mActivityElement)); } else { // The Tab already created and provided to the constructor is the one that is // expected to be the activityTab. @@ -231,10 +218,6 @@ } } - public ChromeTabbedActivityTestRule getTestRule() { - return mChromeTabbedActivityTestRule; - } - public boolean isIncognito() { return mIncognito; } @@ -307,13 +290,9 @@ T destination; if (isIncognito()) { - destination = - expectedDestination.cast( - new IncognitoTabSwitcherStation(mChromeTabbedActivityTestRule)); + destination = expectedDestination.cast(new IncognitoTabSwitcherStation()); } else { - destination = - expectedDestination.cast( - new RegularTabSwitcherStation(mChromeTabbedActivityTestRule)); + destination = expectedDestination.cast(new RegularTabSwitcherStation()); } return travelToSync(destination, () -> TAB_SWITCHER_BUTTON.perform(click())); } @@ -325,8 +304,9 @@ T destination = expectedDestination.cast( HubStationUtils.createHubStation( - isIncognito() ? PaneId.INCOGNITO_TAB_SWITCHER : PaneId.TAB_SWITCHER, - getTestRule())); + isIncognito() + ? PaneId.INCOGNITO_TAB_SWITCHER + : PaneId.TAB_SWITCHER)); return travelToSync(destination, () -> TAB_SWITCHER_BUTTON.perform(click())); } @@ -372,21 +352,14 @@ return mPageLoadedCondition.get(); } - private void assertSuppliersCanBeUsed() { - int phase = getPhase(); - if (phase != Phase.ACTIVE && phase != Phase.TRANSITIONING_FROM) { - fail( - String.format( - "%s should have been ACTIVE or TRANSITIONING_FROM, but was %s", - this, phaseToString(phase))); - } - } - private class TabAddedCondition extends CallbackCondition implements TabModelObserver { private TabModel mTabModel; + private Supplier<ChromeTabbedActivity> mActivity; - protected TabAddedCondition(int numTabsBeingOpened) { + protected TabAddedCondition( + int numTabsBeingOpened, Supplier<ChromeTabbedActivity> activitySupplier) { super("didAddTab", numTabsBeingOpened); + mActivity = dependOnSupplier(activitySupplier, "ChromeTabbedActivity"); } @Override @@ -399,11 +372,7 @@ super.onStartMonitoring(); TestThreadUtils.runOnUiThreadBlocking( () -> { - mTabModel = - getTestRule() - .getActivity() - .getTabModelSelector() - .getModel(isIncognito()); + mTabModel = mActivity.get().getTabModelSelector().getModel(isIncognito()); mTabModel.addObserver(this); }); } @@ -421,9 +390,12 @@ implements TabModelObserver, Supplier<Tab> { private final List<Tab> mTabsSelected = new ArrayList<>(); private TabModel mTabModel; + private Supplier<ChromeTabbedActivity> mActivity; - private TabSelectedCondition(int numTabsBeingSelected) { + private TabSelectedCondition( + int numTabsBeingSelected, Supplier<ChromeTabbedActivity> activitySupplier) { super("didSelectTab", numTabsBeingSelected); + mActivity = dependOnSupplier(activitySupplier, "ChromeTabbedActivity"); } @Override @@ -442,11 +414,7 @@ super.onStartMonitoring(); TestThreadUtils.runOnUiThreadBlocking( () -> { - mTabModel = - getTestRule() - .getActivity() - .getTabModelSelector() - .getModel(isIncognito()); + mTabModel = mActivity.get().getTabModelSelector().getModel(isIncognito()); mTabModel.addObserver(this); }); }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/RegularTabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/RegularTabSwitcherStation.java index b247bea..f3f9235 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/RegularTabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/RegularTabSwitcherStation.java
@@ -12,7 +12,6 @@ import org.chromium.base.test.transit.Condition; import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.ViewElement; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; /** The tab switcher screen showing regular tabs. */ @@ -21,8 +20,8 @@ public static final ViewElement EMPTY_STATE_TEXT = scopedViewElement(withText(R.string.tabswitcher_no_tabs_empty_state)); - public RegularTabSwitcherStation(ChromeTabbedActivityTestRule chromeTabbedActivityTestRule) { - super(chromeTabbedActivityTestRule, /* incognito= */ false); + public RegularTabSwitcherStation() { + super(/* incognito= */ false); } @Override @@ -41,8 +40,7 @@ } public IncognitoTabSwitcherStation selectIncognitoTabList() { - IncognitoTabSwitcherStation tabSwitcher = - new IncognitoTabSwitcherStation(mChromeTabbedActivityTestRule); + IncognitoTabSwitcherStation tabSwitcher = new IncognitoTabSwitcherStation(); return travelToSync(tabSwitcher, () -> INCOGNITO_TOGGLE_TAB_BUTTON.perform(click())); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherActionMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherActionMenuFacility.java index 3707a4c7..27822ba 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherActionMenuFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherActionMenuFacility.java
@@ -64,19 +64,14 @@ // switcher if no normal tabs exist. if (tabModelSelector.getModel(false).getCount() == 0) { if (HubFieldTrial.isHubEnabled()) { - destination = - expectedDestination.cast( - new HubTabSwitcherStation(mHostStation.getTestRule())); + destination = expectedDestination.cast(new HubTabSwitcherStation()); } else { - destination = - expectedDestination.cast( - new RegularTabSwitcherStation(mHostStation.getTestRule())); + destination = expectedDestination.cast(new RegularTabSwitcherStation()); } } else { destination = expectedDestination.cast( PageStation.newPageStationBuilder() - .withActivityTestRule(mHostStation.getTestRule()) .withIncognito(false) .withIsOpeningTabs(0) .withIsSelectingTabs(1) @@ -85,13 +80,9 @@ } else { // No tabs left, so closing the last will take us to the tab switcher. if (HubFieldTrial.isHubEnabled()) { - destination = - expectedDestination.cast( - new HubTabSwitcherStation(mHostStation.getTestRule())); + destination = expectedDestination.cast(new HubTabSwitcherStation()); } else { - destination = - expectedDestination.cast( - new RegularTabSwitcherStation(mHostStation.getTestRule())); + destination = expectedDestination.cast(new RegularTabSwitcherStation()); } } } else { @@ -99,7 +90,6 @@ destination = expectedDestination.cast( PageStation.newPageStationBuilder() - .withActivityTestRule(mHostStation.getTestRule()) .withIncognito(tabModelSelector.isIncognitoSelected()) .withIsOpeningTabs(0) .withIsSelectingTabs(1) @@ -112,11 +102,7 @@ /** Select the "New tab" menu option to open a new Tab. */ public NewTabPageStation selectNewTab() { NewTabPageStation destination = - NewTabPageStation.newBuilder() - .withActivityTestRule(mHostStation.getTestRule()) - .withIsOpeningTabs(1) - .withIsSelectingTabs(1) - .build(); + NewTabPageStation.newBuilder().withIsOpeningTabs(1).withIsSelectingTabs(1).build(); return mHostStation.travelToSync(destination, () -> NEW_TAB_MENU_ITEM.perform(click())); } @@ -124,7 +110,6 @@ public IncognitoNewTabPageStation selectNewIncognitoTab() { IncognitoNewTabPageStation destination = IncognitoNewTabPageStation.newBuilder() - .withActivityTestRule(mHostStation.getTestRule()) .withIsOpeningTabs(1) .withIsSelectingTabs(1) .build();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherStation.java index e77da20d..16ca143 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/TabSwitcherStation.java
@@ -37,7 +37,6 @@ import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_management.TabGridView; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; import org.chromium.chrome.test.util.ToolbarTestUtils; @@ -94,18 +93,15 @@ withParent(instanceOf(TabGridView.class)))), isDisplayed()); - protected final ChromeTabbedActivityTestRule mChromeTabbedActivityTestRule; protected final boolean mIsIncognito; protected ActivityElement<ChromeTabbedActivity> mActivityElement; protected TabModelSelectorCondition mTabModelSelectorCondition; /** Instantiate one of the subclasses instead. */ - protected TabSwitcherStation( - ChromeTabbedActivityTestRule chromeTabbedActivityTestRule, boolean incognito) { + protected TabSwitcherStation(boolean incognito) { super(); assert !HubFieldTrial.isHubEnabled(); - mChromeTabbedActivityTestRule = chromeTabbedActivityTestRule; mIsIncognito = incognito; } @@ -131,7 +127,6 @@ PageStation page = PageStation.newPageStationBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIncognito(mIsIncognito) .withIsOpeningTabs(1) .withIsSelectingTabs(1) @@ -155,13 +150,9 @@ T tabSwitcher; if (landInIncognitoSwitcher) { - tabSwitcher = - expectedDestinationType.cast( - new IncognitoTabSwitcherStation(mChromeTabbedActivityTestRule)); + tabSwitcher = expectedDestinationType.cast(new IncognitoTabSwitcherStation()); } else { - tabSwitcher = - expectedDestinationType.cast( - new RegularTabSwitcherStation(mChromeTabbedActivityTestRule)); + tabSwitcher = expectedDestinationType.cast(new RegularTabSwitcherStation()); } return travelToSync( @@ -174,7 +165,6 @@ public PageStation selectTabAtIndex(int index) { PageStation page = PageStation.newPageStationBuilder() - .withActivityTestRule(mChromeTabbedActivityTestRule) .withIncognito(mIsIncognito) .withIsOpeningTabs(0) .withIsSelectingTabs(1)
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java index d7ef7d6..9411961e 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -38,7 +38,6 @@ import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.DropdownItemViewInfo; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdown; -import org.chromium.chrome.browser.omnibox.suggestions.SuggestionListProperties; import org.chromium.chrome.browser.omnibox.suggestions.base.ActionChipsProperties; import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderView; import org.chromium.chrome.browser.searchwidget.SearchActivity; @@ -51,6 +50,7 @@ import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; +import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -219,14 +219,6 @@ if (!mUrlBar.hasFocus()) mUrlBar.requestFocus(); Criteria.checkThat( "Omnibox is focused.", mUrlBar.hasFocus(), Matchers.is(true)); - // Wait for Suggestions list ready signal. - Criteria.checkThat( - "Focus change propagated", - mLocationBar - .getAutocompleteCoordinator() - .getSuggestionsDropdownModelForTest() - .get(SuggestionListProperties.OMNIBOX_SESSION_ACTIVE), - Matchers.is(true)); }); } @@ -449,7 +441,7 @@ () -> { mUrlBar.setText(userText); // Push this to the model as well. - mUrlBar.setAutocompleteText(userText, ""); + mUrlBar.setAutocompleteText(userText, "", Optional.empty()); }); checkText(Matchers.equalTo(userText), null); } @@ -479,15 +471,16 @@ * Specify the text to be offered as an inline autocompletion for the current user input. * * @param autocompleteText The suggested autocompletion for the text. + * @param additionalText The additional autocompletion for the text. */ - public void setAutocompleteText(String autocompleteText) { + public void setAutocompleteText(String autocompleteText, Optional<String> additionalText) { checkFocus(true); AtomicReference<String> userText = new AtomicReference<>(); TestThreadUtils.runOnUiThreadBlocking( () -> { userText.set(mUrlBar.getTextWithoutAutocomplete()); - mUrlBar.setAutocompleteText(userText.get(), autocompleteText); + mUrlBar.setAutocompleteText(userText.get(), autocompleteText, additionalText); }); checkText( Matchers.equalTo(userText.get()), @@ -503,7 +496,7 @@ public void checkText( @NonNull Matcher<String> textMatcher, @Nullable Matcher<String> autocompleteTextMatcher) { - checkText(textMatcher, autocompleteTextMatcher, null, null); + checkText(textMatcher, autocompleteTextMatcher, null); } /** @@ -511,17 +504,34 @@ * * @param textMatcher Matcher checking the content of the Omnibox. * @param autocompleteTextMatcher Optional Matcher for autocompletion. + * @param additionalTextMatcher Optional Matcher for additional text. + */ + public void checkText( + @NonNull Matcher<String> textMatcher, + @Nullable Matcher<String> autocompleteTextMatcher, + @Nullable Matcher<String> additionalTextMatcher) { + checkText(textMatcher, autocompleteTextMatcher, additionalTextMatcher, null, null); + } + + /** + * Verify the text content of the Omnibox. + * + * @param textMatcher Matcher checking the content of the Omnibox. + * @param autocompleteTextMatcher Optional Matcher for autocompletion. + * @param additionalTextMatcher Optional Matcher for additional text. * @param autocompleteSelectionStart Matcher for Autocomplete's start position. * @param autocompleteSelectionEnd Matcher for Autocomplete's end position. */ public void checkText( @NonNull Matcher<String> textMatcher, @Nullable Matcher<String> autocompleteTextMatcher, + @Nullable Matcher<String> additionalTextMatcher, int autocompleteSelectionStart, int autocompleteSelectionEnd) { checkText( textMatcher, autocompleteTextMatcher, + additionalTextMatcher, Matchers.is(autocompleteSelectionStart), Matchers.is(autocompleteSelectionEnd)); } @@ -531,12 +541,14 @@ * * @param textMatcher Matcher checking the content of the Omnibox. * @param autocompleteTextMatcher Optional Matcher for autocompletion. + * @param additionalTextMatcher Optional Matcher for additional text. * @param autocompleteSelectionStart Optional Matcher for Autocomplete's start position. * @param autocompleteSelectionEnd Optional Matcher for Autocomplete's end position. */ public void checkText( @NonNull Matcher<String> textMatcher, @Nullable Matcher<String> autocompleteTextMatcher, + @Nullable Matcher<String> additionalTextMatcher, @Nullable Matcher<Integer> autocompleteSelectionStart, @Nullable Matcher<Integer> autocompleteSelectionEnd) { waitAnimationsComplete(); @@ -561,6 +573,13 @@ autocompleteTextMatcher); } + if (additionalTextMatcher != null) { + Criteria.checkThat( + "Additional Text should match", + mUrlBar.getAdditionalText().orElse(""), + additionalTextMatcher); + } + if (autocompleteSelectionStart != null) { Criteria.checkThat( "Autocomplete Selection start",
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc index 3821e443..d4b56c73 100644 --- a/chrome/test/base/testing_profile_manager.cc +++ b/chrome/test/base/testing_profile_manager.cc
@@ -95,24 +95,7 @@ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) { DCHECK(called_set_up_); - // Create a path for the profile based on the name. - base::FilePath profile_path(profiles_path_); -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (ash::IsUserBrowserContextBaseName(base::FilePath(profile_name))) { - const std::string fake_email = - profile_name.find('@') == std::string::npos - ? base::ToLowerASCII(profile_name) + "@test" - : profile_name; - profile_path = - profile_path.Append(ash::ProfileHelper::Get()->GetUserProfileDir( - user_manager::FakeUserManager::GetFakeUsernameHash( - AccountId::FromUserEmail(fake_email)))); - } else { - profile_path = profile_path.AppendASCII(profile_name); - } -#else - profile_path = profile_path.AppendASCII(profile_name); -#endif + base::FilePath profile_path = GetProfilePath(profile_name); // Create the profile and register it. TestingProfile::Builder builder; @@ -294,6 +277,29 @@ #endif } +base::FilePath TestingProfileManager::GetProfilePath( + const std::string& profile_name) { + // Create a path for the profile based on the name. + base::FilePath profile_path(profiles_path_); +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (ash::IsUserBrowserContextBaseName(base::FilePath(profile_name))) { + const std::string fake_email = + profile_name.find('@') == std::string::npos + ? base::ToLowerASCII(profile_name) + "@test" + : profile_name; + profile_path = + profile_path.Append(ash::ProfileHelper::Get()->GetUserProfileDir( + user_manager::FakeUserManager::GetFakeUsernameHash( + AccountId::FromUserEmail(fake_email)))); + } else { + profile_path = profile_path.AppendASCII(profile_name); + } +#else + profile_path = profile_path.AppendASCII(profile_name); +#endif + return profile_path; +} + #if BUILDFLAG(IS_CHROMEOS_LACROS) void TestingProfileManager::SetAccountProfileMapper( std::unique_ptr<AccountProfileMapper> mapper) {
diff --git a/chrome/test/base/testing_profile_manager.h b/chrome/test/base/testing_profile_manager.h index ddab1d42..e2f4a2e6 100644 --- a/chrome/test/base/testing_profile_manager.h +++ b/chrome/test/base/testing_profile_manager.h
@@ -138,6 +138,9 @@ // Sets the last used profile; also sets the active time to now. void UpdateLastUser(Profile* last_active); + // Get the full profile path from the profile name. + base::FilePath GetProfilePath(const std::string& profile_name); + #if BUILDFLAG(IS_CHROMEOS_LACROS) void SetAccountProfileMapper(std::unique_ptr<AccountProfileMapper> mapper); #endif
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/tree_change_indirect.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/tree_change_indirect.js index d597ac8..6bfcb7a0 100644 --- a/chrome/test/data/extensions/api_test/automation/tests/tabs/tree_change_indirect.js +++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/tree_change_indirect.js
@@ -6,9 +6,9 @@ // tree are updated when the related content changes. // TODO(aleventhal) why isn't this working? -//function findById(id) { - //return rootNode.find({ htmlAttributes: { id }}); -//} +// function findById(id) { +// TODO(accessibility): Verify that the following line really works. +// return rootNode.find({ htmlId: id }); var allTests = [ function testUpdateRelatedNamesAndDescriptions() {
diff --git a/chrome/test/data/webui/about_sys/BUILD.gn b/chrome/test/data/webui/about_sys/BUILD.gn index 6c48a1d4..0a9a0bd6 100644 --- a/chrome/test/data/webui/about_sys/BUILD.gn +++ b/chrome/test/data/webui/about_sys/BUILD.gn
@@ -16,7 +16,6 @@ target_gen_dir) ] ts_deps = [ "//chrome/browser/resources/about_sys:build_ts", - "//third_party/polymer/v3_0:library", "//ui/webui/resources/js:build_ts", ] }
diff --git a/chrome/test/data/webui/about_sys/about_sys_test.ts b/chrome/test/data/webui/about_sys/about_sys_test.ts index efac7631..a03f70b 100644 --- a/chrome/test/data/webui/about_sys/about_sys_test.ts +++ b/chrome/test/data/webui/about_sys/about_sys_test.ts
@@ -5,7 +5,7 @@ import 'chrome://system/app.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import type {SystemAppElement} from 'chrome://system/app.js'; +import type {AppElement} from 'chrome://system/app.js'; import {BrowserProxyImpl} from 'chrome://system/browser_proxy.js'; import type {SystemLog} from 'chrome://system/browser_proxy.js'; import {assertEquals} from 'chrome://webui-test/chai_assert.js'; @@ -19,23 +19,23 @@ {statName: 'Related Website Sets', statValue: 'Disabled'}, ]; -async function createSystemAppElement(): Promise<SystemAppElement> { +async function createAppElement(): Promise<AppElement> { document.body.innerHTML = window.trustedTypes!.emptyHTML; - const app: SystemAppElement = document.createElement('system-app'); + const app = document.createElement('system-app'); document.body.appendChild(app); await eventToPromise('ready-for-testing', app); return app; } suite('AboutSystemTest', function() { - let app: SystemAppElement; + let app: AppElement; let browserProxy: TestAboutSysBrowserProxy; setup(async function() { browserProxy = new TestAboutSysBrowserProxy(); browserProxy.setSystemLogs(SYSTEM_LOGS); BrowserProxyImpl.setInstance(browserProxy); - app = await createSystemAppElement(); + app = await createAppElement(); }); test('RequestAboutSystemInfoTest', function() {
diff --git a/chrome/test/data/webui/chromeos/settings/os_about_page/os_about_page_test.ts b/chrome/test/data/webui/chromeos/settings/os_about_page/os_about_page_test.ts index 86e9fe6..82a50fc 100644 --- a/chrome/test/data/webui/chromeos/settings/os_about_page/os_about_page_test.ts +++ b/chrome/test/data/webui/chromeos/settings/os_about_page/os_about_page_test.ts
@@ -48,8 +48,6 @@ aboutBrowserProxy = new TestAboutPageBrowserProxy(); AboutPageBrowserProxyImpl.setInstanceForTesting(aboutBrowserProxy); - - Router.getInstance().navigateTo(routes.ABOUT); }); teardown(() => { @@ -82,7 +80,10 @@ clearBody(); page = document.createElement('os-about-page'); document.body.appendChild(page); + + Router.getInstance().navigateTo(routes.ABOUT); await flushTasks(); + await Promise.all([ aboutBrowserProxy.whenCalled('getChannelInfo'), aboutBrowserProxy.whenCalled('refreshUpdateStatus'),
diff --git a/chrome/test/data/webui/chromeos/settings/os_apps_page/app_parental_controls_page/app_parental_controls_subpage_test.ts b/chrome/test/data/webui/chromeos/settings/os_apps_page/app_parental_controls_page/app_parental_controls_subpage_test.ts index 57dd2aec..6437b40 100644 --- a/chrome/test/data/webui/chromeos/settings/os_apps_page/app_parental_controls_page/app_parental_controls_subpage_test.ts +++ b/chrome/test/data/webui/chromeos/settings/os_apps_page/app_parental_controls_page/app_parental_controls_subpage_test.ts
@@ -20,6 +20,8 @@ async function createPage(): Promise<void> { Router.getInstance().navigateTo(routes.APP_PARENTAL_CONTROLS); page = new SettingsAppParentalControlsSubpageElement(); + // Set verified to true to indicate pin was accepted on the apps page. + page.set('isVerified', true); document.body.appendChild(page); await flushTasks(); } @@ -133,4 +135,14 @@ assertTrue(appToggle.checked); assertFalse(app.isBlocked); }); + + test('Unverified page redirects to Apps', async () => { + Router.getInstance().navigateTo(routes.APP_PARENTAL_CONTROLS); + // Page is unverified by default and will redirect. + page = new SettingsAppParentalControlsSubpageElement(); + document.body.appendChild(page); + await flushTasks(); + + assertEquals(Router.getInstance().currentRoute, routes.APPS); + }); });
diff --git a/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc b/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc index ce01b34a..20372c4 100644 --- a/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc +++ b/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc
@@ -646,6 +646,13 @@ testing::Bool(), OSSettingsRevampMochaTestFasterSplitScreenDisabled::DescribeParams); +using OSSettingsRevampTestOsAboutPage = OSSettingsRevampMochaTest; + +INSTANTIATE_TEST_SUITE_P(RevampParameterized, + OSSettingsRevampTestOsAboutPage, + testing::Bool(), + OSSettingsRevampTestOsAboutPage::DescribeParams); + /* End Test Classes */ IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, AppLanguageSelectionDialog) { @@ -1325,15 +1332,13 @@ RunSettingsTest("os_a11y_page/tts_voice_subpage_test.js"); } -// TODO(crbug.com/336428443): Flaky for OsSettingsRevampWayfindingDisabled. -IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, - DISABLED_OsAboutPage_AllBuilds) { +IN_PROC_BROWSER_TEST_P(OSSettingsRevampTestOsAboutPage, AllBuilds) { RunSettingsTest("os_about_page/os_about_page_test.js", "runMochaSuite('<os-about-page> AllBuilds')"); } #if BUILDFLAG(GOOGLE_CHROME_BRANDING) -IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, OsAboutPage_OfficialBuild) { +IN_PROC_BROWSER_TEST_P(OSSettingsRevampTestOsAboutPage, OfficialBuild) { RunSettingsTest("os_about_page/os_about_page_test.js", "runMochaSuite('<os-about-page> OfficialBuild')"); }
diff --git a/chrome/test/data/webui/commerce/product_specifications/table_test.ts b/chrome/test/data/webui/commerce/product_specifications/table_test.ts index f3a6e634..377d494f 100644 --- a/chrome/test/data/webui/commerce/product_specifications/table_test.ts +++ b/chrome/test/data/webui/commerce/product_specifications/table_test.ts
@@ -145,7 +145,7 @@ assertEquals(0, event.detail.index); }); - test('opens new tab', async () => { + test('opens tab when `openTabButton` is clicked', async () => { // Arrange const testUrl = 'https://example.com'; tableElement.columns = [ @@ -172,8 +172,9 @@ openTabButton!.click(); // Assert. - assertEquals(1, shoppingServiceApi.getCallCount('openUrlInNewTab')); - assertEquals(testUrl, shoppingServiceApi.getArgs('openUrlInNewTab')[0].url); + assertEquals(1, shoppingServiceApi.getCallCount('switchToOrOpenTab')); + assertEquals( + testUrl, shoppingServiceApi.getArgs('switchToOrOpenTab')[0].url); }); test('shows open tab button when hovered', async () => {
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_password_input_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_password_input_test.js index 981b2e8..1ac8893 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/network_password_input_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/network_password_input_test.js
@@ -29,4 +29,12 @@ assertTrue(networkPassword.showPassword); assertEquals('text', passwordInput.type); }); + + test('Aria label', function() { + networkPassword.ariaLabel = 'test_aria_label'; + const passwordInput = networkPassword.$$('#input'); + assertTrue(!!passwordInput); + + assertEquals('test_aria_label', passwordInput.ariaLabel); + }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/sim_lock_dialogs_test.js b/chrome/test/data/webui/cr_components/chromeos/network/sim_lock_dialogs_test.js index c285188..58a5572 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/sim_lock_dialogs_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/sim_lock_dialogs_test.js
@@ -55,6 +55,10 @@ simLockStatus: {lockEnabled: false, lockType: '', retriesLeft: 3}, }; verifyDialogShown('enterPinDialog', deviceState); + const enterPin = simLockDialog.$$(`#enterPin`); + assertTrue(!!enterPin); + assertEquals( + enterPin.ariaLabel, simLockDialog.i18n('networkSimEnterPinTitle')); }); test('Show Change PIN dialog', async function() {
diff --git a/chrome/test/data/webui/extensions/detail_view_test.ts b/chrome/test/data/webui/extensions/detail_view_test.ts index 796a721..0b2ed200 100644 --- a/chrome/test/data/webui/extensions/detail_view_test.ts +++ b/chrome/test/data/webui/extensions/detail_view_test.ts
@@ -685,6 +685,25 @@ assertTrue(safetyWarningText!.textContent!.includes('Test Message')); }); + test('Mv2DeprecationMessageWarning_Disabled', function() { + // Warning is hidden if feature is disabled. + loadTimeData.overrideValues({MV2DeprecationPanelEnabled: false}); + testVisible(item, '#mv2DeprecationMessage', false); + }); + + test('Mv2DeprecationMessageWarning_Enabled', function() { + // Warning is hidden if feature is enabled but extension is not affected by + // the MV2 deprecation. + loadTimeData.overrideValues({MV2DeprecationPanelEnabled: true}); + testVisible(item, '#mv2DeprecationMessage', false); + + // Warning is visible if feature is enabled and extension is affected by the + // MV2 deprecation. + item.set('data.isAffectedByMV2Deprecation', true); + flush(); + testVisible(item, '#mv2DeprecationMessage', true); + }); + test('PinnedToToolbar', async function() { assertFalse( isVisible(item.shadowRoot!.querySelector<ExtensionsToggleRowElement>(
diff --git a/chrome/test/data/webui/extensions/extensions_browsertest.cc b/chrome/test/data/webui/extensions/extensions_browsertest.cc index 9987f58..b3f1a804 100644 --- a/chrome/test/data/webui/extensions/extensions_browsertest.cc +++ b/chrome/test/data/webui/extensions/extensions_browsertest.cc
@@ -291,6 +291,16 @@ RunTestCase("SafetyCheckWarning"); } +IN_PROC_BROWSER_TEST_F(CrExtensionsDetailViewTest, + Mv2DeprecationMessageWarning_Disabled) { + RunTestCase("Mv2DeprecationMessageWarning_Disabled"); +} + +IN_PROC_BROWSER_TEST_F(CrExtensionsDetailViewTest, + MvDeprecationMessageWarning_Enabled) { + RunTestCase("Mv2DeprecationMessageWarning_Enabled"); +} + IN_PROC_BROWSER_TEST_F(CrExtensionsDetailViewTest, PinnedToToolbar) { RunTestCase("PinnedToToolbar"); } @@ -352,6 +362,11 @@ RunTestCase("ManifestV2DeprecationPanel_Enabled"); } +IN_PROC_BROWSER_TEST_F(CrExtensionsItemListTest, + ManifestV2DeprecationPanel_TitleVisibility) { + RunTestCase("ManifestV2DeprecationPanel_TitleVisibility"); +} + //////////////////////////////////////////////////////////////////////////////// // Extension Load Error Tests
diff --git a/chrome/test/data/webui/extensions/item_list_test.ts b/chrome/test/data/webui/extensions/item_list_test.ts index d8dd4f38..6f31f9a 100644 --- a/chrome/test/data/webui/extensions/item_list_test.ts +++ b/chrome/test/data/webui/extensions/item_list_test.ts
@@ -32,7 +32,6 @@ createExt({ name: 'Alpha', id: 'a'.repeat(32), - safetyCheckText: {panelString: 'This extension contains malware.'}, }), createExt({name: 'Bravo', id: 'b'.repeat(32)}), createExt({name: 'Charlie', id: 'c'.repeat(29) + 'wxy'}), @@ -175,21 +174,85 @@ }); test('SafetyCheckPanel_EnabledSafetyCheck', function() { - // Panel is visible if safetyCheckShowReviewPanel is enabled. + // Panel is hidden if safetyCheckShowReviewPanel is enabled, there are no + // unsafe extensions and panel wasn't previously shown. loadTimeData.overrideValues( {safetyCheckShowReviewPanel: true, safetyHubShowReviewPanel: false}); setupElement(); flush(); + boundTestVisible('extensions-review-panel', false); + + // Panel is visible if safetyCheckShowReviewPanel is enabled, and there are + // unsafe extensions. + itemList.push( + 'extensions', createExtensionInfo({ + name: 'Unsafe extension', + id: 'd'.repeat(32), + safetyCheckText: {panelString: 'This extension contains malware.'}, + })); + flush(); boundTestVisible('extensions-review-panel', true); + const reviewPanel = + itemList.shadowRoot!.querySelector('extensions-review-panel'); + assertTrue(!!reviewPanel); + assertEquals(1, reviewPanel.extensions.length); + + // Panel is visible if safetyCheckShowReviewPanel is enabled, there are no + // unsafe extensions but the panel was previously shown. + // For this, we set the unsafe extension as acknowledged. + itemList.set( + 'extensions.3', createExtensionInfo({ + name: 'Unsafe extension', + id: 'd'.repeat(32), + safetyCheckText: {panelString: 'This extension contains malware.'}, + acknowledgeSafetyCheckWarning: true, + })); + flush(); + boundTestVisible('extensions-review-panel', true); + assertTrue(!!reviewPanel); + // There are no unsafe extensions in the panel. + assertEquals(0, reviewPanel.extensions.length); }); test('SafetyCheckPanel_EnabledSafetyHub', function() { - // Panel is visible if safetyHubShowReviewPanel is enabled. + // Panel is hidden if safetyHubShowReviewPanel is enabled, there are no + // unsafe extensions and panel wasn't previously shown. loadTimeData.overrideValues( {safetyCheckShowReviewPanel: false, safetyHubShowReviewPanel: true}); setupElement(); flush(); + boundTestVisible('extensions-review-panel', false); + + // Panel is visible if safetyHubShowReviewPanel is enabled, and there are + // unsafe extensions. + itemList.push( + 'extensions', createExtensionInfo({ + name: 'Unsafe extension', + id: 'd'.repeat(32), + safetyCheckText: {panelString: 'This extension contains malware.'}, + })); + flush(); boundTestVisible('extensions-review-panel', true); + const reviewPanel = + itemList.shadowRoot!.querySelector('extensions-review-panel'); + assertTrue(!!reviewPanel); + assertEquals(1, reviewPanel.extensions.length); + + // Panel is visible if safetyHubShowReviewPanel is enabled, there are no + // unsafe extensions but the panel was previously shown. + // For this, we set the unsafe extension as acknowledged. + itemList.set( + 'extensions.3', createExtensionInfo({ + name: 'Unsafe extension', + id: 'd'.repeat(32), + safetyCheckText: {panelString: 'This extension contains malware.'}, + acknowledgeSafetyCheckWarning: true, + })); + flush(); + boundTestVisible('extensions-review-panel', true); + assertTrue(!!reviewPanel); + // There are no unsafe extensions in the panel. + assertEquals(0, reviewPanel.extensions.length); }); test('ManifestV2DeprecationPanel_Disabled', async function() { @@ -250,4 +313,40 @@ flush(); boundTestVisible('extensions-mv2-deprecation-panel', false); }); + + test('ManifestV2DeprecationPanel_TitleVisibility', function() { + // Enable feature for both panels. Their visibility will be determined + // whether they have extensions to show. + loadTimeData.overrideValues({'MV2DeprecationPanelEnabled': true}); + loadTimeData.overrideValues({'safetyHubShowReviewPanel': true}); + + // Show the MV2 deprecation panel by adding an extension affected by the + // mv2 deprecation. + itemList.push('extensions', createExtensionInfo({ + name: 'MV2 extension', + id: 'd'.repeat(32), + isAffectedByMV2Deprecation: true, + })); + flush(); + boundTestVisible('extensions-mv2-deprecation-panel', true); + + // MV2 deprecation panel title is hidden when the review panel is hidden. + const mv2DeprecationPanel = itemList.shadowRoot!.querySelector<HTMLElement>( + 'extensions-mv2-deprecation-panel'); + assertTrue(!!mv2DeprecationPanel); + testVisible(mv2DeprecationPanel, '.panel-title', false); + + // Show the review panel by adding an extension with safety check text. + itemList.push( + 'extensions', createExtensionInfo({ + name: 'Unsafe extension', + id: 'e'.repeat(32), + safetyCheckText: {panelString: 'This extension contains malware.'}, + })); + flush(); + boundTestVisible('extensions-review-panel', true); + + // MV2 deprecation panel title is visible when the review panel is visible. + testVisible(mv2DeprecationPanel, '.panel-title', true); + }); });
diff --git a/chrome/test/data/webui/extensions/review_panel_test.ts b/chrome/test/data/webui/extensions/review_panel_test.ts index 4ef99b7..09390743 100644 --- a/chrome/test/data/webui/extensions/review_panel_test.ts +++ b/chrome/test/data/webui/extensions/review_panel_test.ts
@@ -35,8 +35,6 @@ id: 'a'.repeat(32), safetyCheckText: {panelString: 'This extension contains malware.'}, }), - createExtensionInfo({name: 'Bravo', id: 'b'.repeat(32)}), - createExtensionInfo({name: 'Charlie', id: 'c'.repeat(29)}), ]; element.extensions = extensionItems; document.body.appendChild(element); @@ -111,6 +109,18 @@ 'Alpha'); }); + test('CompletionStateShouldBeShownIfNoExtensions', async function() { + const completionTextContainer = + element.shadowRoot!.querySelector('.completion-container'); + assertTrue(!!completionTextContainer); + assertFalse(isVisible(completionTextContainer)); + + element.set('extensions', []); + await flushTasks(); + + assertTrue(isVisible(completionTextContainer)); + }); + test('CompletionStateShouldBeShownAfterDeletingItems', async function() { const completionTextContainer = element.shadowRoot!.querySelector('.completion-container'); @@ -185,17 +195,9 @@ element.shadowRoot!.querySelector('.completion-container'); class MockKeepItemDelegate extends MockItemDelegate { override setItemSafetyCheckWarningAcknowledged(): void { - const extensionItems = [ - createExtensionInfo({ - name: 'Alpha', - id: 'a'.repeat(32), - safetyCheckText: {panelString: 'This extension contains malware.'}, - acknowledgeSafetyCheckWarning: true, - }), - createExtensionInfo({name: 'Bravo', id: 'b'.repeat(32)}), - createExtensionInfo({name: 'Charlie', id: 'c'.repeat(29)}), - ]; - element.extensions = extensionItems; + // Update extensions to be an empty list since the only previous + // extension was marked as acknowledged. + element.set('extensions', []); } } element.delegate = new MockKeepItemDelegate(); @@ -215,7 +217,6 @@ // Click the Keep the Extension button. actionMenu.querySelector('button')!.click(); - await flushTasks(); await browserProxy.whenCalled('extensionKeptAction'); // The extension row should be removed and the completion state should be
diff --git a/chrome/test/data/webui/key_value_pair_viewer/BUILD.gn b/chrome/test/data/webui/key_value_pair_viewer/BUILD.gn index 5bd93d8..c1b1ea4 100644 --- a/chrome/test/data/webui/key_value_pair_viewer/BUILD.gn +++ b/chrome/test/data/webui/key_value_pair_viewer/BUILD.gn
@@ -12,7 +12,6 @@ target_gen_dir) ] ts_deps = [ "//chrome/browser/resources/key_value_pair_viewer_shared:build_ts", - "//third_party/polymer/v3_0:library", "//ui/webui/resources/js:build_ts", ] }
diff --git a/chrome/test/data/webui/key_value_pair_viewer/key_value_pair_viewer_test.ts b/chrome/test/data/webui/key_value_pair_viewer/key_value_pair_viewer_test.ts index 2a3ff9a..7a99825 100644 --- a/chrome/test/data/webui/key_value_pair_viewer/key_value_pair_viewer_test.ts +++ b/chrome/test/data/webui/key_value_pair_viewer/key_value_pair_viewer_test.ts
@@ -6,12 +6,11 @@ import 'chrome://system/strings.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {COLLAPSE_THRESHOLD} from 'chrome://system/shared/key_value_pair_viewer/key_value_pair_entry.js'; import type {KeyValuePairEntry, KeyValuePairEntryElement} from 'chrome://system/shared/key_value_pair_viewer/key_value_pair_entry.js'; import type {KeyValuePairViewerElement} from 'chrome://system/shared/key_value_pair_viewer/key_value_pair_viewer.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {isVisible} from 'chrome://webui-test/test_util.js'; +import {isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js'; import {getTrustedHtml} from 'chrome://webui-test/trusted_html.js'; export const ENTRIES: KeyValuePairEntry[] = [ @@ -50,20 +49,23 @@ }); } - setup(function() { + setup(async function() { document.body.innerHTML = getTrustedHtml(`<key-value-pair-viewer></key-value-pair-viewer>`); element = document.body.querySelector('key-value-pair-viewer')!; element.entries = ENTRIES; element.loading = false; - flush(); + await microtasksFinished(); collapsibleEntries = getCollapsibleEntries(); }); - test('SpinnerVisibilityTest', function() { + test('SpinnerVisibilityTest', async function() { element.loading = true; + await microtasksFinished(); assertTrue(isVisible(element.$.spinner)); + element.loading = false; + await microtasksFinished(); assertFalse(isVisible(element.$.spinner)); }); @@ -88,22 +90,25 @@ assertTrue(collapsibleEntries.length > 0); collapsibleEntries[0]!.collapsed = false; collapsibleEntries[collapsibleEntries.length - 1]!.collapsed = false; + return microtasksFinished(); } - test('ExpandAll button expands all collapsible cells', function() { - expandFirstAndLastCollapsibleLogEntries(); + test('ExpandAll button expands all collapsible cells', async function() { + await expandFirstAndLastCollapsibleLogEntries(); element.$.expandAll.click(); + await microtasksFinished(); for (const entry of collapsibleEntries) { assertFalse(entry.collapsed); } }); - test('CollapseAll button collapses all collapsible cells', function() { - expandFirstAndLastCollapsibleLogEntries(); + test('CollapseAll button collapses all collapsible cells', async function() { + await expandFirstAndLastCollapsibleLogEntries(); element.$.collapseAll.click(); + await microtasksFinished(); for (const entry of collapsibleEntries) { assertTrue(entry.collapsed);
diff --git a/chrome/test/data/webui/settings/settings_menu_test.ts b/chrome/test/data/webui/settings/settings_menu_test.ts index b3071ee..0a902a0 100644 --- a/chrome/test/data/webui/settings/settings_menu_test.ts +++ b/chrome/test/data/webui/settings/settings_menu_test.ts
@@ -48,31 +48,27 @@ Router.getInstance().navigateTo(routes.RESET); const selector = settingsMenu.$.menu; assertTrue(!!selector.selected); - const path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/reset', path); + assertEquals('/reset', selector.selected.toString()); }); test('navigateToAnotherSection', function() { Router.getInstance().navigateTo(routes.RESET); const selector = settingsMenu.$.menu; assertTrue(!!selector.selected); - let path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/reset', path); + assertEquals('/reset', selector.selected.toString()); Router.getInstance().navigateTo(routes.PEOPLE); flush(); assertTrue(!!selector.selected); - path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/people', path); + assertEquals('/people', selector.selected.toString()); }); test('navigateToBasic', function() { Router.getInstance().navigateTo(routes.RESET); const selector = settingsMenu.$.menu; assertTrue(!!selector.selected); - const path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/reset', path); + assertEquals('/reset', selector.selected.toString()); Router.getInstance().navigateTo(routes.BASIC); flush(); @@ -92,8 +88,7 @@ // GET_MOST_CHROME should select the 'About Chrome' entry. const selector = settingsMenu.$.menu; assertTrue(!!selector.selected); - const path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/help', path); + assertEquals('/help', selector.selected.toString()); }); // </if> @@ -121,8 +116,7 @@ const selector = settingsMenu.$.menu; assertTrue(!!selector.selected); - const path = new window.URL(selector.selected.toString()).pathname; - assertEquals('/ai', path); + assertEquals('/ai', selector.selected.toString()); }); test('pageVisibility', function() {
diff --git a/chrome/test/data/webui/settings/settings_performance_menu_test.ts b/chrome/test/data/webui/settings/settings_performance_menu_test.ts index 31af752..a374c574 100644 --- a/chrome/test/data/webui/settings/settings_performance_menu_test.ts +++ b/chrome/test/data/webui/settings/settings_performance_menu_test.ts
@@ -32,9 +32,8 @@ !!menu.selected, 'a menu item should be selected when directly navigating to the ' + 'performance route'); - const path = new window.URL(menu.selected.toString()).pathname; assertEquals( - '/performance', path, + '/performance', menu.selected.toString(), 'the selected menu item should be for the performance settings'); });
diff --git a/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts b/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts index 95c8a82..4da7ad8 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts
@@ -54,6 +54,7 @@ 'getUrlInfosForRecentlyViewedTabs', 'showInsightsSidePanelUi', 'openUrlInNewTab', + 'switchToOrOpenTab', 'showFeedback', 'isShoppingListEligible', 'getShoppingCollectionBookmarkFolderId', @@ -141,6 +142,10 @@ this.methodCalled('openUrlInNewTab'); } + switchToOrOpenTab() { + this.methodCalled('switchToOrOpenTab'); + } + showFeedback() { this.methodCalled('showFeedback'); }
diff --git a/chrome/test/data/webui/side_panel/read_anything/common.ts b/chrome/test/data/webui/side_panel/read_anything/common.ts index 2798c5c..f2ddeb16 100644 --- a/chrome/test/data/webui/side_panel/read_anything/common.ts +++ b/chrome/test/data/webui/side_panel/read_anything/common.ts
@@ -5,6 +5,7 @@ import type {CrLazyRenderElement} from '//resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; import {flush} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {ReadAnythingElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {playFromSelectionTimeout} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; export function emitEvent( app: ReadAnythingElement, name: string, options?: any): void { @@ -40,6 +41,10 @@ }; } +export async function waitForPlayFromSelection(): Promise<void> { + return new Promise(resolve => setTimeout(resolve, playFromSelectionTimeout)); +} + // Returns the list of items in the given dropdown menu export function getItemsInMenu( lazyMenu: CrLazyRenderElement<CrActionMenuElement>): HTMLButtonElement[] {
diff --git a/chrome/test/data/webui/side_panel/read_anything/language_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/language_menu_test.ts index 5985aeb..8a02e316 100644 --- a/chrome/test/data/webui/side_panel/read_anything/language_menu_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/language_menu_test.ts
@@ -39,7 +39,7 @@ // Bypass Typescript compiler to allow us to set a private readonly // property // @ts-ignore - languageMenu.voicePackInstallStatus = languagesToNotificationMap; + languageMenu.voicePackInstallStatus = {...languagesToNotificationMap}; flush(); }; @@ -324,10 +324,18 @@ assertLanguageNotification(getNotificationItems()[2]!, ''); }); - test('it shows downloading notification', async () => { + test('it shows and hides downloading notification', async () => { enabledLanguagesInPref = ['Italian', 'English (United States)']; setEnabledLanguages(); - languagesToNotificationMap['Italian'] = VoicePackStatus.INSTALLING; + languagesToNotificationMap['it'] = VoicePackStatus.INSTALLING; + setNotificationForLanguage(); + assertEquals(getNotificationItems().length, 3); + assertLanguageNotification(getNotificationItems()[0]!, ''); + assertLanguageNotification(getNotificationItems()[1]!, ''); + assertLanguageNotification( + getNotificationItems()[2]!, 'Downloading voices…'); + + languagesToNotificationMap['it'] = VoicePackStatus.INSTALLED; setNotificationForLanguage(); assertEquals(getNotificationItems().length, 3); assertLanguageNotification(getNotificationItems()[0]!, '');
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts index 50e1dea..ddc5d7f 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts
@@ -7,7 +7,7 @@ import {NEXT_GRANULARITY_EVENT, PREVIOUS_GRANULARITY_EVENT} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse} from 'chrome-untrusted://webui-test/chai_assert.js'; -import {emitEvent, suppressInnocuousErrors} from './common.js'; +import {emitEvent, suppressInnocuousErrors, waitForPlayFromSelection} from './common.js'; suite('ReadAloudHighlight', () => { let app: ReadAnythingElement; @@ -250,4 +250,68 @@ assertEquals(previousHighlights[1]!.textContent, sentence2); }); }); + + suite('on speaking from selection', () => { + let currentHighlight: HTMLElement|null; + let previousHighlights: NodeListOf<Element>; + + async function selectAndPlay( + anchorId: number, anchorOffset: number, focusId: number, + focusOffset: number): Promise<void> { + const selectedTree = Object.assign( + { + selection: { + anchor_object_id: anchorId, + focus_object_id: focusId, + anchor_offset: anchorOffset, + focus_offset: focusOffset, + is_backward: false, + }, + }, + axTree); + chrome.readingMode.setContentForTesting(selectedTree, leafIds); + app.updateSelection(); + app.playSpeech(); + return waitForPlayFromSelection(); + } + + setup(async () => { + await selectAndPlay(3, 1, 3, 5); + }); + + test('shows correct highlights', () => { + currentHighlight = + app.$.container.querySelector('.current-read-highlight'); + previousHighlights = + app.$.container.querySelectorAll('.previous-read-highlight'); + + assertEquals(currentHighlight!.textContent, sentence2); + assertEquals(previousHighlights!.length, 1); + assertEquals(previousHighlights![0]!.textContent, sentence1); + }); + + test('next granularity shows correct highlights', () => { + emitNextGranularity(); + + currentHighlight = + app.$.container.querySelector('.current-read-highlight'); + previousHighlights = + app.$.container.querySelectorAll('.previous-read-highlight'); + assertEquals(currentHighlight!.textContent, sentenceSegment1); + assertEquals(previousHighlights!.length, 2); + assertEquals(previousHighlights![0]!.textContent, sentence1); + assertEquals(previousHighlights![1]!.textContent, sentence2); + }); + + test('previous granularity shows correct highlights', () => { + emitPreviousGranularity(); + + currentHighlight = + app.$.container.querySelector('.current-read-highlight'); + previousHighlights = + app.$.container.querySelectorAll('.previous-read-highlight'); + assertEquals(currentHighlight!.textContent, sentence1); + assertEquals(previousHighlights!.length, 0); + }); + }); });
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection.ts b/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection.ts index f2985109..177a235 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection.ts
@@ -8,7 +8,7 @@ import {PauseActionSource} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; -import {suppressInnocuousErrors} from './common.js'; +import {suppressInnocuousErrors, waitForPlayFromSelection} from './common.js'; import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js'; suite('ReadAloud_UpdateContentSelection', () => { @@ -126,9 +126,11 @@ }); suite('While Read Aloud playing', () => { - setup(() => { + setup(async () => { app.playSpeech(); + await waitForPlayFromSelection(); }); + test('inner html of container matches expected html', () => { assertFalse(app.speechPlayingState.paused); assertTrue(app.speechPlayingState.speechStarted); @@ -144,12 +146,11 @@ assertEquals(innerHTML, expected); }); - test('selection in reading model panel cleared', () => { + test('selection in reading mode panel cleared', () => { const selection = document.getSelection()!; assertEquals(selection.toString(), ''); }); - test('container class correct', () => { assertEquals( app.$.container.className, @@ -178,20 +179,9 @@ assertEquals(innerHTML, expected); }); - test('selection in reading mode container correct', () => { - // Calling shadowRoot.getSelection directly is not supported in TS tests, - // so use a helper to get the selection from the app instead. + test('selection in reading mode panel cleared', () => { const selection = document.getSelection()!; - assertTrue(selection != null); - - // TODO(b/327519645): Playing Read Aloud slightly adjusts what's - // selected. This happened before disabling selection when Read Aloud - // was playing, but adding tests for disabled selection makes this bug - // more apparent. - assertEquals(selection.anchorNode!.textContent, 'World'); - assertEquals(selection.focusNode!.textContent, 'Friend!'); - assertEquals(selection.anchorOffset, 0); - assertEquals(selection.focusOffset, 0); + assertEquals(selection.toString(), ''); }); test('container class correct', () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection_pdf.ts b/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection_pdf.ts index 89b164f5..d14147ee 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection_pdf.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_aloud_update_content_selection_pdf.ts
@@ -8,7 +8,7 @@ import {PauseActionSource} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; -import {suppressInnocuousErrors} from './common.js'; +import {suppressInnocuousErrors, waitForPlayFromSelection} from './common.js'; import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js'; suite('ReadAloud_UpdateContentSelectionPDF', () => { @@ -129,9 +129,11 @@ }); suite('While Read Aloud playing', () => { - setup(() => { + setup(async () => { app.playSpeech(); + await waitForPlayFromSelection(); }); + test('inner html of container matches expected html', () => { assertFalse(app.speechPlayingState.paused); assertTrue(app.speechPlayingState.speechStarted); @@ -147,12 +149,11 @@ assertEquals(innerHTML, expected); }); - test('selection in reading model panel cleared', () => { + test('selection in reading mode panel cleared', () => { const selection = document.getSelection()!; assertEquals(selection.toString(), ''); }); - test('container class correct', () => { assertEquals( app.$.container.className, @@ -181,20 +182,9 @@ assertEquals(innerHTML, expected); }); - test('selection in reading mode container correct', () => { - // Calling shadowRoot.getSelection directly is not supported in TS tests, - // so use a helper to get the selection from the app instead. + test('selection in reading mode panel cleared', () => { const selection = document.getSelection()!; - assertTrue(selection != null); - - // TODO(b/327519645): Playing Read Aloud slightly adjusts what's - // selected. This happened before disabling selection when Read Aloud - // was playing, but adding tests for disabled selection makes this bug - // more apparent. - assertEquals(selection.anchorNode!.textContent, 'World'); - assertEquals(selection.focusNode!.textContent, 'Friend!'); - assertEquals(selection.anchorOffset, 0); - assertEquals(selection.focusOffset, 0); + assertEquals(selection.toString(), ''); }); test('container class correct', () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts index 1be011e4..d7968fd 100644 --- a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts
@@ -7,7 +7,7 @@ import {NEXT_GRANULARITY_EVENT, PauseActionSource, PREVIOUS_GRANULARITY_EVENT, RATE_EVENT, WordBoundaryMode} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertGT, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; -import {emitEvent, suppressInnocuousErrors} from './common.js'; +import {emitEvent, suppressInnocuousErrors, waitForPlayFromSelection} from './common.js'; import {FakeSpeechSynthesis} from './fake_speech_synthesis.js'; // TODO: b/323960128 - Add tests for word boundaries here or in a @@ -25,9 +25,11 @@ 'It\'s time to try defying gravity.', 'I think I\'ll try defying gravity.', 'Kiss me goodbye, I\'m defying gravity.', - 'And you won\'t bring me down', + 'And you won\'t bring me down.', ]; + const leafIds = [3, 5]; + const totalSentences = paragraph1.length + paragraph2.length; const axTree = { rootId: 1, nodes: [ @@ -62,6 +64,11 @@ ], }; + function getSpokenTexts(): string[] { + return speechSynthesis.spokenUtterances.map( + utterance => utterance.text.trim()); + } + setup(() => { suppressInnocuousErrors(); document.body.innerHTML = window.trustedTypes!.emptyHTML; @@ -94,11 +101,8 @@ }); test('speaks all text by sentences', () => { - assertEquals( - speechSynthesis.spokenUtterances.length, - paragraph1.length + paragraph2.length); - const utteranceTexts = speechSynthesis.spokenUtterances.map( - utterance => utterance.text.trim()); + assertEquals(speechSynthesis.spokenUtterances.length, totalSentences); + const utteranceTexts = getSpokenTexts(); assertTrue( paragraph1.every(sentence => utteranceTexts.includes(sentence))); assertTrue( @@ -165,6 +169,140 @@ }); }); + suite('with text selected', () => { + async function selectAndPlay( + baseTree: any, anchorId: number, anchorOffset: number, focusId: number, + focusOffset: number, isBackward: boolean = false): Promise<void> { + const selectedTree = Object.assign( + { + selection: { + anchor_object_id: anchorId, + focus_object_id: focusId, + anchor_offset: anchorOffset, + focus_offset: focusOffset, + is_backward: isBackward, + }, + }, + baseTree); + chrome.readingMode.setContentForTesting(selectedTree, leafIds); + app.updateSelection(); + app.playSpeech(); + return waitForPlayFromSelection(); + } + + test('first play starts from selected node', async () => { + await selectAndPlay(axTree, 5, 0, 5, 7); + + const utteranceTexts = getSpokenTexts(); + assertEquals(utteranceTexts.length, totalSentences - paragraph1.length); + assertTrue( + paragraph2.every(sentence => utteranceTexts.includes(sentence))); + }); + + test('selection is cleared after play', async () => { + await selectAndPlay(axTree, 5, 0, 5, 10); + assertEquals(app.getSelection().type, 'None'); + }); + + test( + 'when selection starts in middle of node, play from beginning of node', + async () => { + await selectAndPlay(axTree, 5, 10, 5, 20); + + const utteranceTexts = getSpokenTexts(); + assertEquals( + utteranceTexts.length, totalSentences - paragraph1.length); + assertTrue( + paragraph2.every(sentence => utteranceTexts.includes(sentence))); + }); + + test('when selection crosses nodes, play from earlier node', async () => { + await selectAndPlay(axTree, 3, 10, 5, 10); + + const utteranceTexts = getSpokenTexts(); + assertEquals(utteranceTexts.length, totalSentences); + assertTrue( + paragraph1.every(sentence => utteranceTexts.includes(sentence))); + assertTrue( + paragraph2.every(sentence => utteranceTexts.includes(sentence))); + }); + + test('when selection is backward, play from earlier node', async () => { + await selectAndPlay(axTree, 5, 10, 3, 10, /*isBackward=*/ true); + + const utteranceTexts = getSpokenTexts(); + assertEquals(utteranceTexts.length, totalSentences); + assertTrue( + paragraph1.every(sentence => utteranceTexts.includes(sentence))); + assertTrue( + paragraph2.every(sentence => utteranceTexts.includes(sentence))); + }); + + test( + 'after speech started, cancels speech and plays from selection', + async () => { + app.speechPlayingState.speechStarted = true; + + await selectAndPlay(axTree, 5, 0, 5, 10); + + assertTrue(speechSynthesis.canceled); + const utteranceTexts = getSpokenTexts(); + assertEquals( + utteranceTexts.length, totalSentences - paragraph1.length); + assertTrue( + paragraph2.every(sentence => utteranceTexts.includes(sentence))); + }); + + test('play from selection when node split across sentences', async () => { + const fragment1 = ' This is a sentence'; + const fragment2 = ' that ends in the next node. '; + const fragment3 = + 'And a following sentence in the same node to be selected.'; + const splitNodeTree = { + rootId: 1, + nodes: [ + { + id: 1, + role: 'rootWebArea', + htmlTag: '#document', + childIds: [2], + }, + { + id: 2, + role: 'paragraph', + htmlTag: 'p', + childIds: [3, 5], + }, + { + id: 3, + role: 'link', + htmlTag: 'a', + url: 'http://www.google.com', + childIds: [4], + }, + { + id: 4, + role: 'staticText', + name: fragment1, + }, + { + id: 5, + role: 'staticText', + name: fragment2 + fragment3, + }, + ], + }; + await selectAndPlay( + splitNodeTree, 5, fragment2.length + 1, 5, + fragment2.length + fragment3.length); + + const utteranceTexts = getSpokenTexts(); + // We shouldn't speak fragment2 even though it's in the same node + // because the selection only covers fragment 3. + assertEquals(utteranceTexts.length, 1); + assertTrue(utteranceTexts.includes(fragment3)); + }); + }); suite('on pause via pause button', () => { setup(() => { @@ -205,13 +343,12 @@ test('next granularity plays from there', () => { chrome.readingMode.initAxPositionWithNode(2); - const expectedNumSentences = paragraph1.length + paragraph2.length - 1; + const expectedNumSentences = totalSentences - 1; emitEvent(app, NEXT_GRANULARITY_EVENT); assertEquals(speechSynthesis.spokenUtterances.length, expectedNumSentences); - const utteranceTexts = speechSynthesis.spokenUtterances.map( - utterance => utterance.text.trim()); + const utteranceTexts = getSpokenTexts(); assertFalse(utteranceTexts.includes(paragraph1[0]!)); assertTrue(paragraph2.every(sentence => utteranceTexts.includes(sentence))); }); @@ -480,9 +617,7 @@ assertTrue(speechSynthesis.canceled); assertFalse(speechSynthesis.paused); - assertEquals( - speechSynthesis.spokenUtterances.length, - paragraph1.length + paragraph2.length); + assertEquals(speechSynthesis.spokenUtterances.length, totalSentences); }); }); });
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 5b6079b..8a5851ce 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -107,6 +107,7 @@ "installer.h", "ipc/update_service_internal_proxy.cc", "ipc/update_service_internal_proxy.h", + "lock.cc", "lock.h", "net/network.h", "persisted_data.cc", @@ -159,6 +160,7 @@ "//chrome/updater/protos:omaha_proto", "//components/crash/core/common", "//components/crx_file", + "//components/named_system_lock", "//components/policy/core/common:common_constants", "//components/policy/proto", "//components/prefs", @@ -195,7 +197,6 @@ "device_management/dm_storage_mac.mm", "installer_mac.cc", "ipc/ipc_security_mac.cc", - "lock_mac.mm", "mac/install_from_archive.h", "mac/install_from_archive.mm", "mac/setup/setup.mm", @@ -250,7 +251,6 @@ "device_management/dm_storage_win.cc", "ipc/update_service_internal_proxy_win.cc", "ipc/update_service_internal_proxy_win.h", - "lock_win.cc", "net/network_fetcher_win.cc", "policy/win/group_policy_manager.cc", "policy/win/group_policy_manager.h", @@ -366,7 +366,6 @@ "linux/setup/setup.cc", "linux/systemd_util.cc", "linux/systemd_util.h", - "lock_linux.cc", "net/network_fetcher_linux.cc", "setup_linux.cc", "update_service_internal_impl_qualifying_linux.cc", @@ -760,7 +759,6 @@ "external_constants_builder_unittest.cc", "external_constants_override_unittest.cc", "installer_unittest.cc", - "lock_unittest.cc", "net/network_unittest.cc", "persisted_data_unittest.cc", "policy/dm_policy_manager_unittest.cc", @@ -795,6 +793,7 @@ ":base", ":branding_header", ":constants_test", + ":public_sources", ":tagging", ":unit_test_util_sources", ":version_header",
diff --git a/chrome/updater/DEPS b/chrome/updater/DEPS index 4740dcea..04f8476 100644 --- a/chrome/updater/DEPS +++ b/chrome/updater/DEPS
@@ -4,6 +4,7 @@ "+components/crash/core/common", "+components/crx_file", "+components/named_mojo_ipc_server", + "+components/named_system_lock", "+components/policy", "+components/prefs", "+components/services/patch",
diff --git a/chrome/updater/app/app_install.cc b/chrome/updater/app/app_install.cc index e006d5d..eb670d4a 100644 --- a/chrome/updater/app/app_install.cc +++ b/chrome/updater/app/app_install.cc
@@ -22,6 +22,7 @@ #include "chrome/updater/activity.h" #include "chrome/updater/constants.h" #include "chrome/updater/external_constants.h" +#include "chrome/updater/lock.h" #include "chrome/updater/persisted_data.h" #include "chrome/updater/prefs.h" #include "chrome/updater/registration_data.h" @@ -104,7 +105,7 @@ int AppInstall::Initialize() { setup_lock_ = - ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); + CreateScopedLock(kSetupMutex, updater_scope(), kWaitForSetupLock); return kErrorOk; }
diff --git a/chrome/updater/app/app_uninstall.cc b/chrome/updater/app/app_uninstall.cc index 43fc9ae..7485521 100644 --- a/chrome/updater/app/app_uninstall.cc +++ b/chrome/updater/app/app_uninstall.cc
@@ -150,7 +150,7 @@ int AppUninstall::Initialize() { setup_lock_ = - ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); + CreateScopedLock(kSetupMutex, updater_scope(), kWaitForSetupLock); global_prefs_ = CreateGlobalPrefs(updater_scope()); if (global_prefs_) { config_ = base::MakeRefCounted<Configurator>(global_prefs_,
diff --git a/chrome/updater/app/app_uninstall_self.cc b/chrome/updater/app/app_uninstall_self.cc index 5386d728..5d0945ad 100644 --- a/chrome/updater/app/app_uninstall_self.cc +++ b/chrome/updater/app/app_uninstall_self.cc
@@ -41,7 +41,7 @@ int AppUninstallSelf::Initialize() { setup_lock_ = - ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); + CreateScopedLock(kSetupMutex, updater_scope(), kWaitForSetupLock); return kErrorOk; }
diff --git a/chrome/updater/app/app_update.cc b/chrome/updater/app/app_update.cc index cca6cbb..380a8a04 100644 --- a/chrome/updater/app/app_update.cc +++ b/chrome/updater/app/app_update.cc
@@ -29,7 +29,7 @@ int AppUpdate::Initialize() { setup_lock_ = - ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); + CreateScopedLock(kSetupMutex, updater_scope(), kWaitForSetupLock); return kErrorOk; }
diff --git a/chrome/updater/constants.cc b/chrome/updater/constants.cc index f049db0..8cceef3c 100644 --- a/chrome/updater/constants.cc +++ b/chrome/updater/constants.cc
@@ -134,4 +134,9 @@ const char kUserDefaultsSuiteName[] = MAC_BUNDLE_IDENTIFIER_STRING ".defaults"; #endif // BUILDFLAG(IS_MAC) +const char kInstallSourceTaggedMetainstaller[] = "taggedmi"; +const char kInstallSourceOffline[] = "offline"; +const char kInstallSourcePolicy[] = "policy"; +const char kInstallSourceOnDemand[] = "ondemand"; + } // namespace updater
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h index 3c76c43bc..d1d92e28e 100644 --- a/chrome/updater/constants.h +++ b/chrome/updater/constants.h
@@ -527,6 +527,12 @@ inline constexpr int GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT = 0x80040904; inline constexpr int GOOPDATEINSTALL_E_INSTALL_ALREADY_RUNNING = 0x80040907; +// Install Sources. +extern const char kInstallSourceTaggedMetainstaller[]; +extern const char kInstallSourceOffline[]; +extern const char kInstallSourcePolicy[]; +extern const char kInstallSourceOnDemand[]; + } // namespace updater #endif // CHROME_UPDATER_CONSTANTS_H_
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc index 99d6c9bd..1c540ed 100644 --- a/chrome/updater/installer.cc +++ b/chrome/updater/installer.cc
@@ -75,6 +75,7 @@ const std::string& app_id, const std::string& client_install_data, const std::string& install_data_index, + const std::string& install_source, const std::string& target_channel, const std::string& target_version_prefix, bool rollback_allowed, @@ -86,6 +87,7 @@ app_id_(app_id), client_install_data_(client_install_data), install_data_index_(install_data_index), + install_source_(install_source), rollback_allowed_(rollback_allowed), target_channel_(target_channel), target_version_prefix_(target_version_prefix), @@ -150,6 +152,7 @@ UpdateService::PolicySameVersionUpdate::kAllowed; component.target_version_prefix = target_version_prefix_; component.updates_enabled = !update_disabled_; + component.install_source = install_source_; std::move(callback).Run(component); }
diff --git a/chrome/updater/installer.h b/chrome/updater/installer.h index 6a86ab01..a6de3e9 100644 --- a/chrome/updater/installer.h +++ b/chrome/updater/installer.h
@@ -92,6 +92,7 @@ Installer(const std::string& app_id, const std::string& client_install_data, const std::string& install_data_index, + const std::string& install_source, const std::string& target_channel, const std::string& target_version_prefix, bool rollback_allowed, @@ -151,6 +152,7 @@ const std::string app_id_; const std::string client_install_data_; const std::string install_data_index_; + const std::string install_source_; const bool rollback_allowed_; const std::string target_channel_; const std::string target_version_prefix_;
diff --git a/chrome/updater/installer_unittest.cc b/chrome/updater/installer_unittest.cc index 225920c..9e812612 100644 --- a/chrome/updater/installer_unittest.cc +++ b/chrome/updater/installer_unittest.cc
@@ -41,8 +41,8 @@ base::RunLoop loop; base::MakeRefCounted<Installer>( - "id", "client_install_data", "install_data_index", "target_channel", - "target_version_prefix", /*rollback_allowed=*/true, + "id", "client_install_data", "install_data_index", "install_source", + "target_channel", "target_version_prefix", /*rollback_allowed=*/true, /*update_disabled=*/false, UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata, crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF) @@ -98,8 +98,8 @@ update_client::CrxComponent crx; base::RunLoop loop; base::MakeRefCounted<Installer>( - "id", "client_install_data", "install_data_index", "target_channel", - "target_version_prefix", /*rollback_allowed=*/true, + "id", "client_install_data", "install_data_index", "install_source", + "target_channel", "target_version_prefix", /*rollback_allowed=*/true, /*update_disabled=*/false, UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata, crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF) @@ -114,6 +114,7 @@ EXPECT_EQ(crx.version, base::Version("5.5.5.5")); EXPECT_EQ(crx.ap, "ap2"); EXPECT_EQ(crx.brand, "BTWO"); + EXPECT_EQ(crx.install_source, "install_source"); } #endif // BUILDFLAG(IS_MAC) @@ -140,8 +141,8 @@ base::RunLoop loop; base::MakeRefCounted<Installer>( - "id", "client_install_data", "install_data_index", "target_channel", - "target_version_prefix", /*rollback_allowed=*/true, + "id", "client_install_data", "install_data_index", "install_source", + "target_channel", "target_version_prefix", /*rollback_allowed=*/true, /*update_disabled=*/false, UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata, crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF) @@ -185,8 +186,8 @@ update_client::CrxComponent crx; base::RunLoop loop; base::MakeRefCounted<Installer>( - "id", "client_install_data", "install_data_index", "target_channel", - "target_version_prefix", /*rollback_allowed=*/true, + "id", "client_install_data", "install_data_index", "install_source", + "target_channel", "target_version_prefix", /*rollback_allowed=*/true, /*update_disabled=*/false, UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata, crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF)
diff --git a/chrome/updater/lock.cc b/chrome/updater/lock.cc new file mode 100644 index 0000000..6c5f2d9 --- /dev/null +++ b/chrome/updater/lock.cc
@@ -0,0 +1,52 @@ +// 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/updater/lock.h" + +#include <memory> + +#include "base/time/time.h" +#include "build/build_config.h" +#include "chrome/updater/updater_scope.h" +#include "components/named_system_lock/lock.h" + +#if BUILDFLAG(IS_POSIX) +#include <string> + +#include "base/strings/strcat.h" +#include "chrome/updater/updater_branding.h" +#elif BUILDFLAG(IS_WIN) +#include "base/strings/utf_string_conversions.h" +#include "chrome/updater/util/win_util.h" +#endif + +namespace updater { + +std::unique_ptr<ScopedLock> CreateScopedLock(const std::string& name, + UpdaterScope scope, + base::TimeDelta timeout) { +#if BUILDFLAG(IS_LINUX) + static constexpr char kSharedMemNamePrefix[] = "/" PRODUCT_FULLNAME_STRING; + static constexpr char kSharedMemNameSuffix[] = ".lock"; + return named_system_lock::ScopedLock::Create( + base::StrCat({kSharedMemNamePrefix, name, UpdaterScopeToString(scope), + kSharedMemNameSuffix}), + timeout); +#elif BUILDFLAG(IS_MAC) + static constexpr char kLockMachServiceNamePrefix[] = + MAC_BUNDLE_IDENTIFIER_STRING; + static constexpr char kLockMachServiceNameSuffix[] = ".lock"; + return named_system_lock::ScopedLock::Create( + base::StrCat({kLockMachServiceNamePrefix, name, + UpdaterScopeToString(scope), kLockMachServiceNameSuffix}), + timeout); +#elif BUILDFLAG(IS_WIN) + NamedObjectAttributes lock_attr = + GetNamedObjectAttributes(base::ASCIIToWide(name).c_str(), scope); + return named_system_lock::ScopedLock::Create(lock_attr.name, &lock_attr.sa, + timeout); +#endif +} + +} // namespace updater
diff --git a/chrome/updater/lock.h b/chrome/updater/lock.h index 9feb73b..4b56256 100644 --- a/chrome/updater/lock.h +++ b/chrome/updater/lock.h
@@ -10,32 +10,18 @@ #include "base/time/time.h" #include "chrome/updater/updater_scope.h" +#include "components/named_system_lock/lock.h" namespace updater { -enum class UpdaterScope; -class ScopedLockImpl; +using ScopedLock = ::named_system_lock::ScopedLock; -// ScopedLock represents a held lock. Destroying the ScopedLock releases the -// lock. ScopedLock is reentrant on windows, but not on mac or linux. -class ScopedLock { - public: - explicit ScopedLock(std::unique_ptr<ScopedLockImpl> impl); - ScopedLock(const ScopedLock&) = delete; - ScopedLock& operator=(const ScopedLock&) = delete; - ~ScopedLock(); - - // Returns a ScopedLock, or nullptr if the lock could not be acquired within - // the timeout. While the ScopedLock exists, no other process on the machine - // may acquire that lock. - static std::unique_ptr<ScopedLock> Create(const std::string& name, - UpdaterScope scope, - base::TimeDelta timeout); - - private: - std::unique_ptr<ScopedLockImpl> impl_; -}; - +// Returns a ScopedLock, or nullptr if the lock could not be acquired within +// the timeout. While the ScopedLock exists, no other process on the machine +// may acquire that lock. +std::unique_ptr<ScopedLock> CreateScopedLock(const std::string& name, + UpdaterScope scope, + base::TimeDelta timeout); } // namespace updater #endif // CHROME_UPDATER_LOCK_H_
diff --git a/chrome/updater/lock_unittest.cc b/chrome/updater/lock_unittest.cc deleted file mode 100644 index 4e5dac1d..0000000 --- a/chrome/updater/lock_unittest.cc +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2023 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/updater/lock.h" - -#include <memory> - -#include "base/run_loop.h" -#include "base/task/sequenced_task_runner.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" -#include "base/test/bind.h" -#include "base/test/task_environment.h" -#include "build/build_config.h" -#include "chrome/updater/test/test_scope.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if BUILDFLAG(IS_LINUX) -#include <fcntl.h> -#include <sys/mman.h> - -#include "base/files/file.h" -#include "base/strings/strcat.h" -#include "chrome/updater/updater_branding.h" -#include "chrome/updater/updater_scope.h" -#endif // BUILDFLAG(IS_LINUX) - -namespace updater { - -TEST(LockTest, LockThenLockSameThread) { - std::unique_ptr<ScopedLock> lock = ScopedLock::Create( - "foobar", GetUpdaterScopeForTesting(), base::Seconds(0)); - EXPECT_TRUE(lock); - - std::unique_ptr<ScopedLock> lock_again = ScopedLock::Create( - "foobar", GetUpdaterScopeForTesting(), base::Seconds(0)); - -#if BUILDFLAG(IS_WIN) - EXPECT_TRUE(lock_again); -#else // BUILDFLAG(IS_WIN) - EXPECT_FALSE(lock_again); -#endif // BUILDFLAG(IS_WIN) -} - -TEST(LockTest, LockThenTryLockInThreadFail) { - base::test::TaskEnvironment task_environment; - - std::unique_ptr<ScopedLock> lock = ScopedLock::Create( - "foobar", GetUpdaterScopeForTesting(), base::Seconds(0)); - EXPECT_TRUE(lock); - - base::RunLoop run_loop; - base::ThreadPool::PostTaskAndReply( - FROM_HERE, {base::MayBlock()}, base::BindOnce([] { - EXPECT_FALSE(ScopedLock::Create("foobar", GetUpdaterScopeForTesting(), - base::Seconds(0))); - }), - base::BindLambdaForTesting([&run_loop] { run_loop.Quit(); })); - run_loop.Run(); -} - -TEST(LockTest, TryLockInThreadSuccess) { - base::test::TaskEnvironment task_environment; - - base::RunLoop run_loop; - base::ThreadPool::PostTaskAndReply( - FROM_HERE, {base::MayBlock()}, base::BindOnce([] { - EXPECT_TRUE(ScopedLock::Create("foobar", GetUpdaterScopeForTesting(), - base::Seconds(0))); - }), - base::BindLambdaForTesting([&run_loop] { run_loop.Quit(); })); - run_loop.Run(); - - EXPECT_TRUE(ScopedLock::Create("foobar", GetUpdaterScopeForTesting(), - base::Seconds(0))); -} - -#if BUILDFLAG(IS_LINUX) -TEST(LockTest, SharedMemoryWrongPermissions) { - // Use a different lock name to avoid reusing a shared memory region leaked by - // other tests. - const std::string shared_mem_name = base::StrCat( - {"/", PRODUCT_FULLNAME_STRING, "permissions_test", - UpdaterScopeToString(GetUpdaterScopeForTesting()), ".lock"}); - - // Create a shared memory region with overpermissive perms. - int shm_fd = shm_open(shared_mem_name.c_str(), O_RDWR | O_CREAT | O_EXCL, - S_IRWXU | S_IRWXG | S_IRWXO); - ASSERT_GE(shm_fd, 0); - - EXPECT_FALSE(ScopedLock::Create( - "permissions_test", GetUpdaterScopeForTesting(), base::Seconds(0))); - - close(shm_fd); - shm_unlink(shared_mem_name.c_str()); -} -#endif // BUILDFLAG(IS_LINUX) - -} // namespace updater
diff --git a/chrome/updater/lock_win.cc b/chrome/updater/lock_win.cc deleted file mode 100644 index fdc0c16..0000000 --- a/chrome/updater/lock_win.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2023 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/updater/lock.h" - -#include <windows.h> - -#include <memory> - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "base/win/scoped_handle.h" -#include "chrome/updater/updater_scope.h" -#include "chrome/updater/util/win_util.h" -#include "chrome/updater/win/win_constants.h" - -namespace updater { - -class ScopedLockImpl { - public: - ScopedLockImpl() = default; - ScopedLockImpl(const ScopedLockImpl&) = delete; - ScopedLockImpl& operator=(const ScopedLockImpl&) = delete; - ~ScopedLockImpl(); - - private: - friend ScopedLock; - bool Initialize(const std::string& id, - UpdaterScope scope, - base::TimeDelta timeout); - - base::win::ScopedHandle mutex_; -}; - -ScopedLock::ScopedLock(std::unique_ptr<ScopedLockImpl> impl) - : impl_(std::move(impl)) {} - -ScopedLock::~ScopedLock() = default; - -// static -std::unique_ptr<ScopedLock> ScopedLock::Create(const std::string& name, - UpdaterScope scope, - base::TimeDelta timeout) { - auto lock = std::make_unique<ScopedLockImpl>(); - - VLOG(2) << "Trying to acquire the lock: " << name << ": " << scope; - if (!lock->Initialize(name, scope, timeout)) { - return nullptr; - } - VLOG(2) << "Lock acquired: " << name << ": " << scope; - - return std::make_unique<ScopedLock>(std::move(lock)); -} - -bool ScopedLockImpl::Initialize(const std::string& name, - UpdaterScope scope, - base::TimeDelta timeout) { - NamedObjectAttributes lock_attr = - GetNamedObjectAttributes(base::ASCIIToWide(name).c_str(), scope); - mutex_.Set(::CreateMutex(&lock_attr.sa, false, lock_attr.name.c_str())); - if (!mutex_.IsValid()) { - return false; - } - - DWORD ret = ::WaitForSingleObject(mutex_.Get(), timeout.InMilliseconds()); - return ret == WAIT_OBJECT_0 || ret == WAIT_ABANDONED; -} - -ScopedLockImpl::~ScopedLockImpl() { - if (mutex_.IsValid()) { - ::ReleaseMutex(mutex_.Get()); - VLOG(2) << "Lock released."; - } -} - -} // namespace updater
diff --git a/chrome/updater/prefs.cc b/chrome/updater/prefs.cc index e00a29f..5511e6f1 100644 --- a/chrome/updater/prefs.cc +++ b/chrome/updater/prefs.cc
@@ -20,6 +20,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "chrome/updater/constants.h" +#include "chrome/updater/lock.h" #include "chrome/updater/persisted_data.h" #include "chrome/updater/prefs_impl.h" #include "chrome/updater/updater_branding.h" @@ -148,7 +149,7 @@ const auto deadline(base::TimeTicks::Now() + kCreatePrefsWait); std::unique_ptr<ScopedLock> lock = - ScopedLock::Create(kPrefsAccessMutex, scope, kCreatePrefsWait); + CreateScopedLock(kPrefsAccessMutex, scope, kCreatePrefsWait); if (!lock) { LOG(ERROR) << "Failed to acquire GlobalPrefs"; return nullptr;
diff --git a/chrome/updater/test/request_matcher.cc b/chrome/updater/test/request_matcher.cc index 1014c23..4680e7d 100644 --- a/chrome/updater/test/request_matcher.cc +++ b/chrome/updater/test/request_matcher.cc
@@ -168,7 +168,9 @@ if (const auto* appid = dict->FindString("appid"); *appid == app_id) { if (const auto* install_source = dict->FindString("installsource")) { - return (*install_source == "ondemand") == + return (*install_source == "ondemand" || + *install_source == "taggedmi" || + *install_source == "policy") == (priority == UpdateService::Priority::kForeground); } }
diff --git a/chrome/updater/update_service_impl_impl.cc b/chrome/updater/update_service_impl_impl.cc index e511e2e..ee34e30 100644 --- a/chrome/updater/update_service_impl_impl.cc +++ b/chrome/updater/update_service_impl_impl.cc
@@ -108,6 +108,7 @@ scoped_refptr<PersistedData> persisted_data, const AppClientInstallData& app_client_install_data, const AppInstallDataIndex& app_install_data_index, + const std::string& install_source, UpdateService::Priority priority, bool update_blocked, UpdateService::PolicySameVersionUpdate policy_same_version_update, @@ -150,6 +151,7 @@ auto it = app_install_data_index.find(id); return it != app_install_data_index.end() ? it->second : ""; }(), + install_source, policy_service->GetTargetChannel(id).policy_or(std::string()), policy_service->GetTargetVersionPrefix(id).policy_or(std::string()), policy_service->IsRollbackToTargetVersionAllowed(id).policy_or(false), @@ -927,7 +929,7 @@ {std::make_pair(registration.app_id, client_install_data)}), AppInstallDataIndex( {std::make_pair(registration.app_id, install_data_index)}), - priority, + kInstallSourceTaggedMetainstaller, priority, /*update_blocked=*/false, PolicySameVersionUpdate::kAllowed), MakeUpdateClientCrxStateChangeCallback(config_, config_->GetUpdaterPersistedData(), @@ -1101,6 +1103,7 @@ install_data.app_id = app_id; install_data.brand = brand; install_data.requires_network_encryption = false; + install_data.install_source = kInstallSourceOffline; install_data.version = installer_version; update_client->SendPing( install_data, @@ -1197,6 +1200,9 @@ config_->GetCrxVerifierFormat(), config_->GetUpdaterPersistedData(), AppClientInstallData(), AppInstallDataIndex(), + priority == UpdateService::Priority::kForeground + ? kInstallSourceOnDemand + : "", priority, update_blocked, policy_same_version_update), MakeUpdateClientCrxStateChangeCallback( config_, config_->GetUpdaterPersistedData(), @@ -1223,6 +1229,9 @@ config_->GetCrxVerifierFormat(), config_->GetUpdaterPersistedData(), app_client_install_data, app_install_data_index, + priority == UpdateService::Priority::kForeground + ? kInstallSourceOnDemand + : "", priority, update_blocked, policy_same_version_update), MakeUpdateClientCrxStateChangeCallback( config_, config_->GetUpdaterPersistedData(), @@ -1257,12 +1266,13 @@ base::BindOnce( base::IgnoreResult(&update_client::UpdateClient::Install), update_client_, id, - base::BindOnce( - &internal::GetComponents, config_->GetPolicyService(), - config_->GetCrxVerifierFormat(), - config_->GetUpdaterPersistedData(), app_client_install_data, - app_install_data_index, Priority::kBackground, update_blocked, - policy_same_version_update), + base::BindOnce(&internal::GetComponents, + config_->GetPolicyService(), + config_->GetCrxVerifierFormat(), + config_->GetUpdaterPersistedData(), + app_client_install_data, app_install_data_index, + kInstallSourcePolicy, Priority::kBackground, + update_blocked, policy_same_version_update), MakeUpdateClientCrxStateChangeCallback( config_, config_->GetUpdaterPersistedData(), /*new_install=*/false, state_update),
diff --git a/chrome/updater/update_service_impl_impl.h b/chrome/updater/update_service_impl_impl.h index 2537649..788a306 100644 --- a/chrome/updater/update_service_impl_impl.h +++ b/chrome/updater/update_service_impl_impl.h
@@ -149,6 +149,7 @@ scoped_refptr<PersistedData> persisted_data, const AppClientInstallData& app_client_install_data, const AppInstallDataIndex& app_install_data_index, + const std::string& install_source, UpdateService::Priority priority, bool update_blocked, UpdateService::PolicySameVersionUpdate policy_same_version_update,
diff --git a/chrome/updater/update_service_impl_impl_unittest.cc b/chrome/updater/update_service_impl_impl_unittest.cc index a3ccc0f6..78871598 100644 --- a/chrome/updater/update_service_impl_impl_unittest.cc +++ b/chrome/updater/update_service_impl_impl_unittest.cc
@@ -85,7 +85,7 @@ base::RunLoop loop; internal::GetComponents( base::MakeRefCounted<PolicyService>(CreateExternalConstants()), - crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF, metadata, {}, {}, + crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF, metadata, {}, {}, {}, UpdateService::Priority::kForeground, false, UpdateService::PolicySameVersionUpdate::kNotAllowed, {"id1", "id2", "id3", "id4"},
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 7f51caf..72d6c39 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -15895.0.0 \ No newline at end of file +15896.0.0 \ No newline at end of file
diff --git a/chromeos/ash/components/BUILD.gn b/chromeos/ash/components/BUILD.gn index 7134726e..076825c 100644 --- a/chromeos/ash/components/BUILD.gn +++ b/chromeos/ash/components/BUILD.gn
@@ -15,6 +15,7 @@ "//chromeos/ash/components/audio:unit_tests", "//chromeos/ash/components/browser_context_helper:unit_tests", "//chromeos/ash/components/carrier_lock:unit_tests", + "//chromeos/ash/components/channel:unit_tests", "//chromeos/ash/components/cryptohome:unit_tests", "//chromeos/ash/components/data_migration:unit_tests", "//chromeos/ash/components/dbus:unit_tests",
diff --git a/chromeos/ash/components/channel/BUILD.gn b/chromeos/ash/components/channel/BUILD.gn new file mode 100644 index 0000000..c80dda44 --- /dev/null +++ b/chromeos/ash/components/channel/BUILD.gn
@@ -0,0 +1,40 @@ +# 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("//build/config/chromeos/ui_mode.gni") + +assert(is_chromeos_ash, + "Non-Chrome-OS builds must not depend on //chromeos/ash") + +component("channel") { + defines = [ "IS_CHROMEOS_ASH_COMPONENTS_CHANNEL_IMPL" ] + + sources = [ + "channel_info.cc", + "channel_info.h", + ] + + deps = [ + "//base", + "//build:branding_buildflags", + "//chromeos/crosapi/cpp", + "//chromeos/crosapi/cpp:crosapi_constants", + "//components/version_info", + ] +} + +source_set("unit_tests") { + testonly = true + + sources = [ "channel_info_unittest.cc" ] + + deps = [ + ":channel", + "//base", + "//base/test:test_support", + "//build:branding_buildflags", + "//components/version_info", + "//testing/gtest", + ] +}
diff --git a/chromeos/ash/components/channel/DEPS b/chromeos/ash/components/channel/DEPS new file mode 100644 index 0000000..1cebc83 --- /dev/null +++ b/chromeos/ash/components/channel/DEPS
@@ -0,0 +1,10 @@ +specific_include_rules = { + "channel_info\.cc": [ + "+chromeos/crosapi/cpp/channel_to_enum.h", + "+chromeos/crosapi/cpp/crosapi_constants.h", + "+components/version_info/version_info.h" + ], + "channel_info_unittest\.cc": [ + "+components/version_info/version_info.h" + ], +}
diff --git a/chromeos/ash/components/channel/channel_info.cc b/chromeos/ash/components/channel/channel_info.cc new file mode 100644 index 0000000..a588723 --- /dev/null +++ b/chromeos/ash/components/channel/channel_info.cc
@@ -0,0 +1,59 @@ +// 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 "chromeos/ash/components/channel/channel_info.h" + +#include "base/system/sys_info.h" +#include "build/branding_buildflags.h" +#include "chromeos/crosapi/cpp/crosapi_constants.h" +#include "components/version_info/version_info.h" + +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#include "chromeos/crosapi/cpp/channel_to_enum.h" +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + +namespace ash { +namespace { + +version_info::Channel g_chromeos_channel = version_info::Channel::UNKNOWN; + +} // namespace + +std::string GetChannelName() { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + switch (GetChannel()) { + case version_info::Channel::STABLE: + return std::string(); + case version_info::Channel::BETA: + return "beta"; + case version_info::Channel::DEV: + return "dev"; + case version_info::Channel::CANARY: + return "canary"; + default: + return "unknown"; + } +#else + return std::string(); +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +} + +version_info::Channel GetChannel() { + static bool is_channel_set = false; + if (is_channel_set) { + return g_chromeos_channel; + } + +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + std::string channel; + if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack, + &channel)) { + g_chromeos_channel = crosapi::ChannelToEnum(channel); + is_channel_set = true; + } +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + return g_chromeos_channel; +} + +} // namespace ash
diff --git a/chromeos/ash/components/channel/channel_info.h b/chromeos/ash/components/channel/channel_info.h new file mode 100644 index 0000000..77fb9d4 --- /dev/null +++ b/chromeos/ash/components/channel/channel_info.h
@@ -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. + +#ifndef CHROMEOS_ASH_COMPONENTS_CHANNEL_CHANNEL_INFO_H_ +#define CHROMEOS_ASH_COMPONENTS_CHANNEL_CHANNEL_INFO_H_ + +#include <string> + +#include "base/component_export.h" + +namespace version_info { +enum class Channel; +} // namespace version_info + +namespace ash { + +// Returns the name of the Ash's channel. For a branded build, this modifier is +// the channel ("cannary", "dev", or "beta", but "" for stable and "unknown" +// when we cannot determine the channel). For a non-branded build, always return +// "" as a name. +COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_CHANNEL) +std::string GetChannelName(); + +// Returns the Ash's channel. For a non-branded build or a branded build when +// the channel cannot be determined, it returns version_info::Channel::Unknown. +COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_CHANNEL) +version_info::Channel GetChannel(); + +} // namespace ash + +#endif // CHROMEOS_ASH_COMPONENTS_CHANNEL_CHANNEL_INFO_H_
diff --git a/chromeos/ash/components/channel/channel_info_unittest.cc b/chromeos/ash/components/channel/channel_info_unittest.cc new file mode 100644 index 0000000..1f5c49f --- /dev/null +++ b/chromeos/ash/components/channel/channel_info_unittest.cc
@@ -0,0 +1,42 @@ +// 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 "chromeos/ash/components/channel/channel_info.h" + +#include <string> + +#include "base/check_op.h" +#include "base/test/scoped_chromeos_version_info.h" +#include "base/time/time.h" +#include "build/branding_buildflags.h" +#include "components/version_info/version_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +using ChannelInfoTest = testing::Test; + +TEST_F(ChannelInfoTest, GetChannel) { + constexpr char kLsbRelease[] = "CHROMEOS_RELEASE_TRACK=canary-channel"; + base::test::ScopedChromeOSVersionInfo version(kLsbRelease, base::Time()); + +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + EXPECT_EQ(version_info::Channel::CANARY, GetChannel()); +#else + EXPECT_EQ(version_info::Channel::UNKNOWN, GetChannel()); +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +} + +TEST_F(ChannelInfoTest, GetChannelName) { + constexpr char kLsbRelease[] = "CHROMEOS_RELEASE_TRACK=dev-channel"; + base::test::ScopedChromeOSVersionInfo version(kLsbRelease, base::Time()); + +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + EXPECT_EQ("dev", GetChannelName()); +#else + EXPECT_EQ(std::string(), GetChannelName()); +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +} + +} // namespace ash
diff --git a/chromeos/ash/components/multidevice/logging/logging.cc b/chromeos/ash/components/multidevice/logging/logging.cc index 5af93d6..52a828d 100644 --- a/chromeos/ash/components/multidevice/logging/logging.cc +++ b/chromeos/ash/components/multidevice/logging/logging.cc
@@ -22,7 +22,7 @@ g_logging_enabled = true; } -ScopedLogMessage::ScopedLogMessage(const char* file, +ScopedLogMessage::ScopedLogMessage(const std::string_view file, int line, logging::LogSeverity severity) : file_(file), line_(line), severity_(severity) {} @@ -35,18 +35,18 @@ auto* log_buffer = LogBuffer::GetInstance(); CHECK(log_buffer); log_buffer->AddLogMessage(LogBuffer::LogMessage( - string_from_stream, base::Time::Now(), file_, line_, severity_)); + string_from_stream, base::Time::Now(), file_.data(), line_, severity_)); // Don't emit VERBOSE-level logging to the standard logging system unless // verbose logging is enabled for the source file. if (severity_ <= logging::LOGGING_VERBOSE && - logging::GetVlogLevelHelper(file_, strlen(file_) + 1) <= 0) { + logging::GetVlogLevelHelper(file_.data(), file_.size()) <= 0) { return; } // The destructor of |log_message| also creates a log for the standard logging // system. - logging::LogMessage log_message(file_, line_, severity_); + logging::LogMessage log_message(file_.data(), line_, severity_); log_message.stream() << string_from_stream; }
diff --git a/chromeos/ash/components/multidevice/logging/logging.h b/chromeos/ash/components/multidevice/logging/logging.h index a5e622e..0186d96 100644 --- a/chromeos/ash/components/multidevice/logging/logging.h +++ b/chromeos/ash/components/multidevice/logging/logging.h
@@ -6,6 +6,7 @@ #define CHROMEOS_ASH_COMPONENTS_MULTIDEVICE_LOGGING_LOGGING_H_ #include <sstream> +#include <string_view> #include "base/logging.h" @@ -20,9 +21,10 @@ // Examples: // PA_LOG(INFO) << "Waiting for " << x << " pending requests."; // PA_LOG(ERROR) << "Request failed: " << error_string; -#define PA_LOG(severity) \ - ash::multidevice::ScopedLogMessage(__FILE__, __LINE__, \ - logging::LOGGING_##severity) \ +#define PA_LOG(severity) \ + ash::multidevice::ScopedLogMessage( \ + std::string_view(__FILE__, std::size(__FILE__)), __LINE__, \ + logging::LOGGING_##severity) \ .stream() // Disables all logging while in scope. Intended to be called only from test @@ -40,7 +42,9 @@ // directly. class ScopedLogMessage { public: - ScopedLogMessage(const char* file, int line, logging::LogSeverity severity); + ScopedLogMessage(const std::string_view file, + int line, + logging::LogSeverity severity); ScopedLogMessage(const ScopedLogMessage&) = delete; ScopedLogMessage& operator=(const ScopedLogMessage&) = delete; @@ -50,7 +54,7 @@ std::ostream& stream() { return stream_; } private: - const char* file_; + const std::string_view file_; int line_; logging::LogSeverity severity_; std::ostringstream stream_;
diff --git a/chromeos/ash/components/quick_start/logging.cc b/chromeos/ash/components/quick_start/logging.cc index 918843e..9167551 100644 --- a/chromeos/ash/components/quick_start/logging.cc +++ b/chromeos/ash/components/quick_start/logging.cc
@@ -18,7 +18,7 @@ } // namespace -ScopedLogMessage::ScopedLogMessage(const char* file, +ScopedLogMessage::ScopedLogMessage(const std::string_view file, int line, logging::LogSeverity severity) : file_(file), line_(line), severity_(severity) {} @@ -26,7 +26,7 @@ ScopedLogMessage::~ScopedLogMessage() { if (ShouldEmitToStandardLog()) { // Create a log for the standard logging system. - logging::LogMessage log_message(file_, line_, severity_); + logging::LogMessage log_message(file_.data(), line_, severity_); log_message.stream() << stream_.str(); } } @@ -37,7 +37,7 @@ // - The Vlog Level for |file_| is at least 1 // - The --quick-start-verbose-logging switch is enabled return severity_ > logging::LOGGING_VERBOSE || - logging::GetVlogLevelHelper(file_, strlen(file_) + 1) > 0 || + logging::GetVlogLevelHelper(file_.data(), file_.size()) > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch( kQuickStartVerboseLoggingSwitch); }
diff --git a/chromeos/ash/components/quick_start/logging.h b/chromeos/ash/components/quick_start/logging.h index cfdcf34..d61eb62 100644 --- a/chromeos/ash/components/quick_start/logging.h +++ b/chromeos/ash/components/quick_start/logging.h
@@ -6,21 +6,26 @@ #define CHROMEOS_ASH_COMPONENTS_QUICK_START_LOGGING_H_ #include <sstream> +#include <string_view> #include "base/logging.h" namespace ash::quick_start { // Use the QS_LOG() macro for all logging related to Quick Start. -#define QS_LOG(severity) \ - ScopedLogMessage(__FILE__, __LINE__, logging::LOGGING_##severity).stream() +#define QS_LOG(severity) \ + ScopedLogMessage(std::string_view(__FILE__, std::size(__FILE__)), __LINE__, \ + logging::LOGGING_##severity) \ + .stream() // An intermediate object used by the QS_LOG macro, wrapping a // logging::LogMessage instance. When this object is destroyed, the message will // be logged with the standard logging system. class ScopedLogMessage { public: - ScopedLogMessage(const char* file, int line, logging::LogSeverity severity); + ScopedLogMessage(const std::string_view file, + int line, + logging::LogSeverity severity); ScopedLogMessage(const ScopedLogMessage&) = delete; ScopedLogMessage& operator=(const ScopedLogMessage&) = delete; ~ScopedLogMessage(); @@ -30,7 +35,7 @@ private: bool ShouldEmitToStandardLog() const; - const char* file_; + const std::string_view file_; int line_; logging::LogSeverity severity_; std::ostringstream stream_;
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.cc b/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.cc index e5629fe9..48cb67f 100644 --- a/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.cc +++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.cc
@@ -37,6 +37,18 @@ "Network.Ash.WiFiDirect.TagSocket.OperationResult"; // static +const char WifiP2PMetricsLogger::kWifiP2PConnectionDurationHistogram[] = + "Network.Ash.WiFiDirect.Connection.Duration"; + +// static +const char WifiP2PMetricsLogger::kGroupOwnerDisconnectReasonHistogram[] = + "Network.Ash.WiFiDirect.GroupOwner.DisconnectReason"; + +// static +const char WifiP2PMetricsLogger::kGroupClientDisconnectReasonHistogram[] = + "Network.Ash.WiFiDirect.GroupClient.DisconnectReason"; + +// static void WifiP2PMetricsLogger::RecordWifiP2PCapabilities( const WifiP2PCapabilities& capablities) { base::UmaHistogramEnumeration(kWifiP2PCapabilitiesHistogram, @@ -68,6 +80,20 @@ base::UmaHistogramBoolean(kTagSocketHistogram, success); } +void WifiP2PMetricsLogger::RecordWifiP2PConnectionDuration( + const base::TimeDelta& duration) { + base::UmaHistogramLongTimes(kWifiP2PConnectionDurationHistogram, duration); +} + +void WifiP2PMetricsLogger::RecordWifiP2PDisconnectReason( + DisconnectReason reason, + bool is_owner) { + base::UmaHistogramEnumeration(is_owner + ? kGroupOwnerDisconnectReasonHistogram + : kGroupClientDisconnectReasonHistogram, + reason); +} + // static WifiP2PMetricsLogger::WifiP2PMetricsCapabilities WifiP2PMetricsLogger::GetWifiP2PMetricsCapabilities(
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h b/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h index 5e1e4dc..3ad1124 100644 --- a/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h +++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h
@@ -7,6 +7,7 @@ #include "base/component_export.h" #include "base/gtest_prod_util.h" +#include "base/time/time.h" #include "chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h" namespace ash { @@ -15,6 +16,14 @@ // and emits UMA metrics to the related histogram. class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_WIFI_P2P) WifiP2PMetricsLogger { public: + // Represents the Wifi P2P disconnect reason. Entries should not be + // renumbered and numeric values should never be reused. + enum class DisconnectReason { + kClientInitiated = 0, + kInternalError = 1, + kMaxValue = kInternalError, + }; + // Emits whenever client queries the Wifi P2P capabilities. static void RecordWifiP2PCapabilities( const WifiP2PController::WifiP2PCapabilities& capablities); @@ -27,6 +36,13 @@ // Emits whenever a tag socket operation is attempted. static void RecordTagSocketOperationResult(bool success); + // Emits when the Wifi P2P connection is finished. + static void RecordWifiP2PConnectionDuration(const base::TimeDelta& duration); + + // Emit when the Wifi P2P connection disconnects. + static void RecordWifiP2PDisconnectReason(DisconnectReason reason, + bool is_owner); + WifiP2PMetricsLogger() = default; ~WifiP2PMetricsLogger() = default; WifiP2PMetricsLogger(const WifiP2PMetricsLogger&) = delete; @@ -72,6 +88,9 @@ static const char kDisconnectP2PGroupHistogram[]; static const char kDestroyP2PGroupHistogram[]; static const char kTagSocketHistogram[]; + static const char kWifiP2PConnectionDurationHistogram[]; + static const char kGroupOwnerDisconnectReasonHistogram[]; + static const char kGroupClientDisconnectReasonHistogram[]; static WifiP2PMetricsCapabilities GetWifiP2PMetricsCapabilities( const WifiP2PController::WifiP2PCapabilities& capablities);
diff --git a/chromeos/ash/resources/internal b/chromeos/ash/resources/internal index 70bca0e..2535bda 160000 --- a/chromeos/ash/resources/internal +++ b/chromeos/ash/resources/internal
@@ -1 +1 @@ -Subproject commit 70bca0e40f5fbbfc98120d9c45d3946b172415b0 +Subproject commit 2535bda7eaf460b4c563f8ca62908818463e9d12
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc b/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc index 70fdc9f..33e07f8 100644 --- a/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc +++ b/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc
@@ -4,6 +4,8 @@ #include "chromeos/ash/services/wifi_direct/wifi_direct_connection.h" +#include "chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h" + namespace ash::wifi_direct { namespace { @@ -41,7 +43,10 @@ CHECK(WifiP2PController::IsInitialized()); } -WifiDirectConnection::~WifiDirectConnection() = default; +WifiDirectConnection::~WifiDirectConnection() { + WifiP2PMetricsLogger::RecordWifiP2PConnectionDuration( + duration_timer_.Elapsed()); +} void WifiDirectConnection::GetProperties(GetPropertiesCallback callback) { std::move(callback).Run(GetMojoProperties(group_metadata_));
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_connection.h b/chromeos/ash/services/wifi_direct/wifi_direct_connection.h index 1e8fe5d4..5e29c3b 100644 --- a/chromeos/ash/services/wifi_direct/wifi_direct_connection.h +++ b/chromeos/ash/services/wifi_direct/wifi_direct_connection.h
@@ -7,6 +7,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/timer/elapsed_timer.h" #include "chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h" #include "chromeos/ash/components/wifi_p2p/wifi_p2p_group.h" #include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom.h" @@ -46,6 +47,7 @@ mojo::PendingRemote<mojom::WifiDirectConnection> CreateRemote( base::OnceClosure disconnect_handler); + base::ElapsedTimer duration_timer_; mojo::Receiver<mojom::WifiDirectConnection> receiver_{this}; WifiP2PGroup group_metadata_; };
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc b/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc index e824eccc..f2da51f 100644 --- a/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc +++ b/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc
@@ -5,6 +5,7 @@ #include "chromeos/ash/services/wifi_direct/wifi_direct_manager.h" #include "chromeos/ash/components/wifi_p2p/wifi_p2p_group.h" +#include "chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h" #include "chromeos/ash/services/wifi_direct/wifi_direct_connection.h" #include "components/device_event_log/device_event_log.h" @@ -110,6 +111,8 @@ return; } CHECK(shill_id_to_wifi_direct_connection_[shill_id]->IsOwner() == is_owner); + WifiP2PMetricsLogger::RecordWifiP2PDisconnectReason( + WifiP2PMetricsLogger::DisconnectReason::kInternalError, is_owner); shill_id_to_wifi_direct_connection_[shill_id].reset(); shill_id_to_wifi_direct_connection_.erase(it); @@ -169,7 +172,9 @@ << shill_id << " in map"; return; } - if (shill_id_to_wifi_direct_connection_[shill_id]->IsOwner()) { + const bool is_owner = + shill_id_to_wifi_direct_connection_[shill_id]->IsOwner(); + if (is_owner) { WifiP2PController::Get()->DestroyWifiP2PGroup( shill_id, base::BindOnce(&WifiDirectManager::OnDestroyOrDisconnectWifiDirectGroup, @@ -180,6 +185,8 @@ base::BindOnce(&WifiDirectManager::OnDestroyOrDisconnectWifiDirectGroup, weak_ptr_factory_.GetWeakPtr())); } + WifiP2PMetricsLogger::RecordWifiP2PDisconnectReason( + WifiP2PMetricsLogger::DisconnectReason::kClientInitiated, is_owner); shill_id_to_wifi_direct_connection_.erase(it); }
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc b/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc index 39de2ef..55659441 100644 --- a/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc +++ b/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc
@@ -7,6 +7,7 @@ #include "ash/constants/ash_features.h" #include "base/sync_socket.h" #include "base/test/bind.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/values.h" @@ -15,6 +16,7 @@ #include "chromeos/ash/components/dbus/shill/shill_clients.h" #include "chromeos/ash/components/dbus/shill/shill_manager_client.h" #include "chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h" +#include "chromeos/ash/components/wifi_p2p/wifi_p2p_metrics_logger.h" #include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom-test-utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/shill/dbus-constants.h" @@ -33,6 +35,13 @@ constexpr char kAssignedSSID[] = "DIRECT-1a"; constexpr char kAssignedPassphrase[] = "test_passphrase"; const int kTestShillId = 0; +const base::TimeDelta kDurationTime = base::Seconds(123); +constexpr char kWifiP2PConnectionDurationHistogram[] = + "Network.Ash.WiFiDirect.Connection.Duration"; +constexpr char kGroupOwnerDisconnectReasonHistogram[] = + "Network.Ash.WiFiDirect.GroupOwner.DisconnectReason"; +constexpr char kGroupClientDisconnectReasonHistogram[] = + "Network.Ash.WiFiDirect.GroupClient.DisconnectReason"; } // namespace @@ -120,11 +129,12 @@ wifi_direct_manager_->GetConnectionsCountForTesting()); } - private: + protected: base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::test::ScopedFeatureList feature_list_; std::unique_ptr<WifiDirectManager> wifi_direct_manager_; + base::HistogramTester histogram_tester_; }; TEST_F(WifiDirectManagerTest, CreateWifiDirectGroupWithCredentials_Success) { @@ -154,12 +164,21 @@ /*success=*/false); EXPECT_FALSE(AssociateSocket(wifi_direct_connection)); + task_environment_.FastForwardBy(kDurationTime); // Request disconnection from client side. wifi_direct_connection.reset(); ExpectConnectionsCount(0); EXPECT_EQ(kTestShillId, ShillManagerClient::Get() ->GetTestInterface() ->GetRecentlyDestroyedP2PGroupId()); + histogram_tester_.ExpectTotalCount(kGroupOwnerDisconnectReasonHistogram, 1); + histogram_tester_.ExpectBucketCount( + kGroupOwnerDisconnectReasonHistogram, + WifiP2PMetricsLogger::DisconnectReason::kClientInitiated, 1); + + histogram_tester_.ExpectTotalCount(kWifiP2PConnectionDurationHistogram, 1); + histogram_tester_.ExpectTimeBucketCount(kWifiP2PConnectionDurationHistogram, + kDurationTime, 1); } TEST_F(WifiDirectManagerTest, CreateWifiDirectGroupNoCredentials_Success) { @@ -180,9 +199,18 @@ EXPECT_EQ(kDefaultSSID, properties->credentials->ssid); EXPECT_EQ(kDefaultPassphrase, properties->credentials->passphrase); EXPECT_TRUE(AssociateSocket(wifi_direct_connection)); + + task_environment_.FastForwardBy(kDurationTime); // Request disconnection from client side. wifi_direct_connection.reset(); ExpectConnectionsCount(0); + histogram_tester_.ExpectTotalCount(kGroupOwnerDisconnectReasonHistogram, 1); + histogram_tester_.ExpectBucketCount( + kGroupOwnerDisconnectReasonHistogram, + WifiP2PMetricsLogger::DisconnectReason::kClientInitiated, 1); + histogram_tester_.ExpectTotalCount(kWifiP2PConnectionDurationHistogram, 1); + histogram_tester_.ExpectTimeBucketCount(kWifiP2PConnectionDurationHistogram, + kDurationTime, 1); } TEST_F(WifiDirectManagerTest, CreateWifiDirectGroupFailure_InvalidCredentials) { @@ -244,12 +272,20 @@ /*success=*/false); EXPECT_FALSE(AssociateSocket(wifi_direct_connection)); + task_environment_.FastForwardBy(kDurationTime); // Request disconnection from client side. wifi_direct_connection.reset(); ExpectConnectionsCount(0); EXPECT_EQ(kTestShillId, ShillManagerClient::Get() ->GetTestInterface() ->GetRecentlyDisconnectedP2PGroupId()); + histogram_tester_.ExpectTotalCount(kGroupClientDisconnectReasonHistogram, 1); + histogram_tester_.ExpectBucketCount( + kGroupClientDisconnectReasonHistogram, + WifiP2PMetricsLogger::DisconnectReason::kClientInitiated, 1); + histogram_tester_.ExpectTotalCount(kWifiP2PConnectionDurationHistogram, 1); + histogram_tester_.ExpectTimeBucketCount(kWifiP2PConnectionDurationHistogram, + kDurationTime, 1); } TEST_F(WifiDirectManagerTest, GroupClientEvents) { @@ -270,6 +306,7 @@ std::move(result_arguments.wifi_direct_connection)); ExpectConnectionsCount(1); + task_environment_.FastForwardBy(kDurationTime); auto p2pclient_dict = base::Value::Dict().Set(shill::kP2PClientInfoShillIDProperty, 0); p2pclient_dict.Set(shill::kP2PClientInfoStateProperty, @@ -282,6 +319,13 @@ shill::kP2PClientInfosProperty, base::Value(p2pclient_list.Clone())); ExpectConnectionsCount(0); + histogram_tester_.ExpectTotalCount(kGroupClientDisconnectReasonHistogram, 1); + histogram_tester_.ExpectBucketCount( + kGroupClientDisconnectReasonHistogram, + WifiP2PMetricsLogger::DisconnectReason::kInternalError, 1); + histogram_tester_.ExpectTotalCount(kWifiP2PConnectionDurationHistogram, 1); + histogram_tester_.ExpectTimeBucketCount(kWifiP2PConnectionDurationHistogram, + kDurationTime, 1); } TEST_F(WifiDirectManagerTest, ConnectToWifiDirectGroupFailure_InvalidResult) { @@ -314,6 +358,7 @@ std::move(result_arguments.wifi_direct_connection)); ExpectConnectionsCount(1); + task_environment_.FastForwardBy(kDurationTime); auto p2pgroup_dict = base::Value::Dict().Set(shill::kP2PGroupInfoShillIDProperty, 0); p2pgroup_dict.Set(shill::kP2PGroupInfoStateProperty, @@ -326,6 +371,13 @@ shill::kP2PGroupInfosProperty, base::Value(p2pgroup_list.Clone())); ExpectConnectionsCount(0); + histogram_tester_.ExpectTotalCount(kGroupOwnerDisconnectReasonHistogram, 1); + histogram_tester_.ExpectBucketCount( + kGroupOwnerDisconnectReasonHistogram, + WifiP2PMetricsLogger::DisconnectReason::kInternalError, 1); + histogram_tester_.ExpectTotalCount(kWifiP2PConnectionDurationHistogram, 1); + histogram_tester_.ExpectTimeBucketCount(kWifiP2PConnectionDurationHistogram, + kDurationTime, 1); } TEST_F(WifiDirectManagerTest, GetWifiP2PCapabilities) {
diff --git a/chromeos/components/magic_boost/OWNERS b/chromeos/components/magic_boost/OWNERS new file mode 100644 index 0000000..b5f20c3 --- /dev/null +++ b/chromeos/components/magic_boost/OWNERS
@@ -0,0 +1,3 @@ +amehfooz@chromium.org +leandre@chromium.org +yawano@google.com \ No newline at end of file
diff --git a/chromeos/components/magic_boost/public/cpp/BUILD.gn b/chromeos/components/magic_boost/public/cpp/BUILD.gn new file mode 100644 index 0000000..9454dbde --- /dev/null +++ b/chromeos/components/magic_boost/public/cpp/BUILD.gn
@@ -0,0 +1,20 @@ +# 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. + +import("//chrome/browser/buildflags.gni") + +assert(is_chromeos) + +component("cpp") { + output_name = "magic_boost" + + defines = [ "IS_MAGIC_BOOST_IMPL" ] + + sources = [ + "magic_boost_state.cc", + "magic_boost_state.h", + ] + + deps = [ "//base" ] +}
diff --git a/chromeos/components/magic_boost/public/cpp/magic_boost_state.cc b/chromeos/components/magic_boost/public/cpp/magic_boost_state.cc new file mode 100644 index 0000000..0987634 --- /dev/null +++ b/chromeos/components/magic_boost/public/cpp/magic_boost_state.cc
@@ -0,0 +1,39 @@ +// 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 "chromeos/components/magic_boost/public/cpp/magic_boost_state.h" + +#include "base/check.h" +#include "base/logging.h" + +namespace { +chromeos::MagicBoostState* g_magic_boost_state = nullptr; +} + +namespace chromeos { + +// static +MagicBoostState* MagicBoostState::Get() { + return g_magic_boost_state; +} + +MagicBoostState::MagicBoostState() { + CHECK(!g_magic_boost_state); + g_magic_boost_state = this; +} + +MagicBoostState::~MagicBoostState() { + CHECK_EQ(g_magic_boost_state, this); + g_magic_boost_state = nullptr; +} + +void MagicBoostState::AddObserver(MagicBoostState::Observer* observer) { + observers_.AddObserver(observer); +} + +void MagicBoostState::RemoveObserver(MagicBoostState::Observer* observer) { + observers_.RemoveObserver(observer); +} + +} // namespace chromeos
diff --git a/chromeos/components/magic_boost/public/cpp/magic_boost_state.h b/chromeos/components/magic_boost/public/cpp/magic_boost_state.h new file mode 100644 index 0000000..9834f40 --- /dev/null +++ b/chromeos/components/magic_boost/public/cpp/magic_boost_state.h
@@ -0,0 +1,57 @@ +// 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 CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_ +#define CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_ + +#include "base/component_export.h" +#include "base/observer_list.h" + +namespace chromeos { + +enum class HMRConsentStatus : int { + // User has agreed to consent by pressing "Yes/Agree" button to all dialogs + // from the consent window. + kApproved = 0, + // User has disagreed to consent by pressing "No/Disagree" button to any + // dialog from the consent window. + kDeclined = 1, + // No explicit consent to use the feature has been received yet. + kPending = 2, + // No request has been sent to users to collect their consent. + kUnset = 3, +}; + +// A class that holds MagicBoost related prefs and states. +class COMPONENT_EXPORT(MAGIC_BOOST) MagicBoostState { + public: + // A checked observer which receives MagicBoost state changes. + class Observer : public base::CheckedObserver { + public: + virtual void OnHMRConsentStatusUpdated(HMRConsentStatus status) = 0; + }; + + static MagicBoostState* Get(); + + MagicBoostState(); + + MagicBoostState(const MagicBoostState&) = delete; + MagicBoostState& operator=(const MagicBoostState&) = delete; + + virtual ~MagicBoostState(); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + HMRConsentStatus hmr_constent_status() const { return hmr_consent_status_; } + + private: + HMRConsentStatus hmr_consent_status_ = HMRConsentStatus::kUnset; + + base::ObserverList<Observer> observers_; +}; + +} // namespace chromeos + +#endif // CHROMEOS_COMPONENTS_MAGIC_BOOST_PUBLIC_CPP_MAGIC_BOOST_STATE_H_
diff --git a/chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h b/chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h index 677650a..c7ff00c8 100644 --- a/chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h +++ b/chromeos/components/mahi/public/cpp/mahi_media_app_content_manager.h
@@ -17,6 +17,10 @@ namespace ash { class MahiMediaAppClient; } + +namespace aura { +class Window; +} namespace chromeos { using GetMediaAppContentCallback = base::OnceCallback<void(crosapi::mojom::MahiPageContentPtr)>; @@ -51,9 +55,14 @@ // Client registration/removal. virtual void AddClient(base::UnguessableToken client_id, - raw_ptr<ash::MahiMediaAppClient> client) = 0; + ash::MahiMediaAppClient* client) = 0; virtual void RemoveClient(base::UnguessableToken client_id) = 0; + // Whether a Window* is observed by `MahiMediaAppContentManager`. Callers may + // suppress focus events of this window (i.e. not report to Mahi system) to + // avoid overriding the media app pdf focus events. + virtual bool ObservingWindow(const aura::Window* window) const = 0; + protected: MahiMediaAppContentManager();
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 69407c15..697f9b74 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -114,6 +114,10 @@ // with Finch. BASE_FEATURE(kCrosMall, "CrosMall", base::FEATURE_DISABLED_BY_DEFAULT); +// When enabled, the Mall app will be installed as an SWA. Only takes effect +// when CrosMall is enabled. This flag will be enabled with Finch. +BASE_FEATURE(kCrosMallSwa, "CrosMallSwa", base::FEATURE_DISABLED_BY_DEFAULT); + // Enables the behaviour difference between web apps and browser created // shortcut backed by the web app system on Chrome OS. BASE_FEATURE(kCrosShortstand, @@ -388,6 +392,11 @@ #endif } +bool IsCrosMallSwaEnabled() { + return chromeos::features::IsCrosMallEnabled() && + base::FeatureList::IsEnabled(chromeos::features::kCrosMallSwa); +} + bool IsCrosShortstandEnabled() { #if BUILDFLAG(IS_CHROMEOS_LACROS) return chromeos::BrowserParamsProxy::Get()->IsCrosShortstandEnabled();
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index ca1a7db..c7c6027 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -45,6 +45,7 @@ BASE_DECLARE_FEATURE(kCrosAppsBackgroundEventHandling); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kCrosComponents); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kCrosMall); +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kCrosMallSwa); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kCrosShortstand); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) @@ -126,6 +127,7 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosComponentsEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosWebAppInstallDialogEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosMallEnabled(); +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosMallSwaEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosWebAppShortcutUiUpdateEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsCrosShortstandEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
diff --git a/chromeos/dbus/power/fake_power_manager_client.cc b/chromeos/dbus/power/fake_power_manager_client.cc index cafa238..838934e 100644 --- a/chromeos/dbus/power/fake_power_manager_client.cc +++ b/chromeos/dbus/power/fake_power_manager_client.cc
@@ -236,7 +236,22 @@ void FakePowerManagerClient::SetKeyboardAmbientLightSensorEnabled( bool enabled) { + // If this is a no-op, don't emit a signal. + if (keyboard_ambient_light_sensor_enabled_ == enabled) { + return; + } keyboard_ambient_light_sensor_enabled_ = enabled; + + power_manager::AmbientLightSensorChange change; + change.set_sensor_enabled(keyboard_ambient_light_sensor_enabled_); + change.set_cause( + power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP); + + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce( + &FakePowerManagerClient::SendKeyboardAmbientLightSensorEnabledChanged, + weak_ptr_factory_.GetWeakPtr(), change)); } void FakePowerManagerClient::GetKeyboardAmbientLightSensorEnabled( @@ -594,6 +609,13 @@ } } +void FakePowerManagerClient::SendKeyboardAmbientLightSensorEnabledChanged( + const power_manager::AmbientLightSensorChange& proto) { + for (auto& observer : observers_) { + observer.KeyboardAmbientLightSensorEnabledChanged(proto); + } +} + void FakePowerManagerClient::SendKeyboardBrightnessChanged( const power_manager::BacklightBrightnessChange& change) { for (auto& observer : observers_)
diff --git a/chromeos/dbus/power/fake_power_manager_client.h b/chromeos/dbus/power/fake_power_manager_client.h index 8d56718..ebe0492 100644 --- a/chromeos/dbus/power/fake_power_manager_client.h +++ b/chromeos/dbus/power/fake_power_manager_client.h
@@ -215,6 +215,11 @@ void SendAmbientLightSensorEnabledChanged( const power_manager::AmbientLightSensorChange& proto); + // Notifies observers about changes to the Keyboard Ambient Light Sensor + // status. + void SendKeyboardAmbientLightSensorEnabledChanged( + const power_manager::AmbientLightSensorChange& proto); + // Notifies observers about the screen idle state changing. void SendScreenIdleStateChanged(const power_manager::ScreenIdleState& proto);
diff --git a/chromeos/dbus/power/fake_power_manager_client_unittest.cc b/chromeos/dbus/power/fake_power_manager_client_unittest.cc index 8284cabd..40f1266 100644 --- a/chromeos/dbus/power/fake_power_manager_client_unittest.cc +++ b/chromeos/dbus/power/fake_power_manager_client_unittest.cc
@@ -37,6 +37,10 @@ last_ambient_light_sensor_change() const { return last_ambient_light_sensor_change_; } + const power_manager::AmbientLightSensorChange& + last_keyboard_ambient_light_sensor_change() const { + return last_keyboard_ambient_light_sensor_change_; + } void ClearProps() { props_.Clear(); } @@ -56,11 +60,18 @@ last_ambient_light_sensor_change_ = change; } + void KeyboardAmbientLightSensorEnabledChanged( + const power_manager::AmbientLightSensorChange& change) override { + last_keyboard_ambient_light_sensor_change_ = change; + } + private: int num_power_changed_; power_manager::PowerSupplyProperties props_; power_manager::BatterySaverModeState battery_saver_state_; power_manager::AmbientLightSensorChange last_ambient_light_sensor_change_; + power_manager::AmbientLightSensorChange + last_keyboard_ambient_light_sensor_change_; }; void SetTestProperties(power_manager::PowerSupplyProperties* props) { @@ -352,6 +363,70 @@ power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP); } +// Test that observers are notified asynchronously when the Keyboard Ambient +// Light Sensor status changes. +TEST(FakePowerManagerClientTest, KeyboardAmbientLightSensorEnabled) { + base::test::SingleThreadTaskEnvironment task_environment( + base::test::SingleThreadTaskEnvironment::MainThreadType::UI); + FakePowerManagerClient client; + TestObserver test_observer; + + client.AddObserver(&test_observer); + + // The Keyboard Ambient Light Sensor is enabled by default. + EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_FALSE( + test_observer.last_keyboard_ambient_light_sensor_change().has_cause()); + + // Turn the Keyboard Ambient Light Sensor off, and check that observers are + // notified asynchronously. + client.SetKeyboardAmbientLightSensorEnabled(false); + + // The Keyboard Ambient Light Sensor should not be disabled synchronously, + // since the real client waits for a response from Power Manager. + EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_FALSE( + test_observer.last_keyboard_ambient_light_sensor_change().has_cause()); + base::RunLoop().RunUntilIdle(); + + // The Keyboard Ambient Light Sensor should be disabled now. + EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change() + .sensor_enabled()); + // The change cause should be USER_REQUEST_SETTINGS_APP because the change was + // triggered via the PowerManagerClient function. + EXPECT_TRUE( + test_observer.last_keyboard_ambient_light_sensor_change().has_cause()); + EXPECT_EQ( + test_observer.last_keyboard_ambient_light_sensor_change().cause(), + power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP); + + // Turn the Keyboard Ambient Light Sensor on, and check that observers are + // notified asynchronously. + client.SetKeyboardAmbientLightSensorEnabled(true); + + // The Keyboard Ambient Light Sensor should not be enabled synchronously, + // since the real client waits for a response from Power Manager. + EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change() + .sensor_enabled()); + base::RunLoop().RunUntilIdle(); + + // The Keyboard Ambient Light Sensor should be enabled now. + EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change() + .sensor_enabled()); + // The cause should be the same as before. + EXPECT_TRUE( + test_observer.last_keyboard_ambient_light_sensor_change().has_cause()); + EXPECT_EQ( + test_observer.last_keyboard_ambient_light_sensor_change().cause(), + power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP); +} + // Test that GetAmbientLightSensorEnabled works correctly. TEST(FakePowerManagerClientTest, GetAmbientLightSensorEnabled) { base::test::SingleThreadTaskEnvironment task_environment(
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc index 3f2b3c3..2c18a4f 100644 --- a/chromeos/dbus/power/power_manager_client.cc +++ b/chromeos/dbus/power/power_manager_client.cc
@@ -203,6 +203,9 @@ &PowerManagerClientImpl::ScreenBrightnessChangedReceived}, {power_manager::kAmbientLightSensorEnabledChangedSignal, &PowerManagerClientImpl::AmbientLightSensorEnabledChangedReceived}, + {power_manager::kKeyboardAmbientLightSensorEnabledChangedSignal, + &PowerManagerClientImpl:: + KeyboardAmbientLightSensorEnabledChangedReceived}, {power_manager::kAmbientColorTemperatureChangedSignal, &PowerManagerClientImpl::AmbientColorTemperatureChangedReceived}, {power_manager::kKeyboardBrightnessChangedSignal, @@ -855,6 +858,23 @@ } } + void KeyboardAmbientLightSensorEnabledChangedReceived(dbus::Signal* signal) { + dbus::MessageReader reader(signal); + power_manager::AmbientLightSensorChange proto; + if (!reader.PopArrayOfBytesAsProto(&proto)) { + POWER_LOG(ERROR) + << "Unable to decode protocol buffer from " + << power_manager::kKeyboardAmbientLightSensorEnabledChangedSignal + << " signal"; + return; + } + POWER_LOG(DEBUG) << "Keyboard ambient Light Sensor enabled changed to " + << proto.sensor_enabled() << ": cause " << proto.cause(); + for (auto& observer : observers_) { + observer.KeyboardAmbientLightSensorEnabledChanged(proto); + } + } + void AmbientColorTemperatureChangedReceived(dbus::Signal* signal) { dbus::MessageReader reader(signal); int32_t color_temperature = 0;
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h index 95b7ce1..a9b3ed4 100644 --- a/chromeos/dbus/power/power_manager_client.h +++ b/chromeos/dbus/power/power_manager_client.h
@@ -90,6 +90,10 @@ virtual void AmbientLightSensorEnabledChanged( const power_manager::AmbientLightSensorChange& change) {} + // Called when the keyboard ambient light sensor status changes. + virtual void KeyboardAmbientLightSensorEnabledChanged( + const power_manager::AmbientLightSensorChange& change) {} + // Called when the ambient light changed. virtual void AmbientColorChanged(const int32_t color_temperature) {}
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc index 0883106..3619d3cd 100644 --- a/chromeos/dbus/power/power_manager_client_unittest.cc +++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -185,7 +185,10 @@ last_ambient_light_sensor_change() const { return last_ambient_light_sensor_change_; } - + const power_manager::AmbientLightSensorChange& + last_keyboard_ambient_light_sensor_change() const { + return last_keyboard_ambient_light_sensor_change_; + } void set_should_block_suspend(bool take_callback) { should_block_suspend_ = take_callback; } @@ -238,6 +241,10 @@ const power_manager::AmbientLightSensorChange& change) override { last_ambient_light_sensor_change_ = change; } + void KeyboardAmbientLightSensorEnabledChanged( + const power_manager::AmbientLightSensorChange& change) override { + last_keyboard_ambient_light_sensor_change_ = change; + } private: raw_ptr<PowerManagerClient> client_; // Not owned. @@ -269,6 +276,10 @@ // Last-set ambient light sensor change. power_manager::AmbientLightSensorChange last_ambient_light_sensor_change_; + + // Last-set keyboard ambient light sensor change. + power_manager::AmbientLightSensorChange + last_keyboard_ambient_light_sensor_change_; }; // Stub implementation of PowerManagerClient::RenderProcessManagerDelegate. @@ -1053,6 +1064,73 @@ } } +// Tests that observers are notified about changes to the Keyboard ambient Light +// Sensor status. +TEST_F(PowerManagerClientTest, KeyboardAmbientLightSensorEnabledChanged) { + TestObserver observer(client_); + + EXPECT_FALSE(observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_FALSE( + observer.last_keyboard_ambient_light_sensor_change().has_cause()); + + { + // When PowerManagerClient receives a signal saying that the Keyboard + // Ambient Light Sensor is disabled, observers should be notified. + power_manager::AmbientLightSensorChange proto; + proto.set_sensor_enabled(false); + proto.set_cause( + power_manager::AmbientLightSensorChange_Cause_BRIGHTNESS_USER_REQUEST); + + dbus::Signal signal( + kInterface, + power_manager::kKeyboardAmbientLightSensorEnabledChangedSignal); + dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto); + EmitSignal(&signal); + + EXPECT_TRUE(observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_EQ( + proto.sensor_enabled(), + observer.last_keyboard_ambient_light_sensor_change().sensor_enabled()); + + // The change cause should be USER_REQUEST_SETTINGS_APP because the change + // was triggered via the PowerManagerClient function. + EXPECT_TRUE( + observer.last_keyboard_ambient_light_sensor_change().has_cause()); + EXPECT_EQ(proto.cause(), + observer.last_keyboard_ambient_light_sensor_change().cause()); + } + + { + // When PowerManagerClient receives a signal saying that the Ambient Light + // Sensor is enabled, observers should be notified. + power_manager::AmbientLightSensorChange proto; + proto.set_sensor_enabled(true); + proto.set_cause( + power_manager:: + AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP); + dbus::Signal signal( + kInterface, + power_manager::kKeyboardAmbientLightSensorEnabledChangedSignal); + dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto); + EmitSignal(&signal); + + EXPECT_TRUE(observer.last_keyboard_ambient_light_sensor_change() + .has_sensor_enabled()); + EXPECT_EQ( + proto.sensor_enabled(), + observer.last_keyboard_ambient_light_sensor_change().sensor_enabled()); + + // The change cause should be USER_REQUEST_SETTINGS_APP because the change + // was triggered via the PowerManagerClient function. + EXPECT_TRUE( + observer.last_keyboard_ambient_light_sensor_change().has_cause()); + EXPECT_EQ(proto.cause(), + observer.last_keyboard_ambient_light_sensor_change().cause()); + } +} + // Tests that |GetAmbientLightSensorEnabled| calls the DBus method with the // same name. TEST_F(PowerManagerClientTest, GetAmbientLightSensorEnabled) {
diff --git a/clank b/clank index 4cf2d33..052219a 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 4cf2d33f8d37edf5f5e1871ff6f930576f6686bb +Subproject commit 052219a0c9b8e1c4af50ef4be1a43d92e31d19b4
diff --git a/components/BUILD.gn b/components/BUILD.gn index 6c582b5..5e04dd03 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -248,6 +248,7 @@ "//components/metrics:unit_tests", "//components/metrics/demographics:unit_tests", "//components/named_mojo_ipc_server:unit_tests", + "//components/named_system_lock:unit_tests", "//components/navigation_metrics:unit_tests", "//components/net_log:unit_tests", "//components/network_session_configurator/browser:unit_tests",
diff --git a/components/aggregation_service/features.h b/components/aggregation_service/features.h index 2f42dff..79eacea 100644 --- a/components/aggregation_service/features.h +++ b/components/aggregation_service/features.h
@@ -13,6 +13,7 @@ namespace aggregation_service { +// This feature is no longer checked, and only the feature param is used. COMPONENT_EXPORT(AGGREGATION_SERVICE) BASE_DECLARE_FEATURE(kAggregationServiceMultipleCloudProviders);
diff --git a/components/attribution_reporting/trigger_registration.cc b/components/attribution_reporting/trigger_registration.cc index 1797015..8b43dcc6 100644 --- a/components/attribution_reporting/trigger_registration.cc +++ b/components/attribution_reporting/trigger_registration.cc
@@ -8,7 +8,6 @@ #include <utility> #include <vector> -#include "base/feature_list.h" #include "base/functional/function_ref.h" #include "base/json/json_reader.h" #include "base/metrics/histogram_functions.h" @@ -16,7 +15,6 @@ #include "base/types/expected.h" #include "base/types/expected_macros.h" #include "base/values.h" -#include "components/aggregation_service/features.h" #include "components/aggregation_service/parsing_utils.h" #include "components/attribution_reporting/aggregatable_dedup_key.h" #include "components/attribution_reporting/aggregatable_trigger_config.h" @@ -144,12 +142,9 @@ registration.aggregatable_values, AggregatableValues::FromJSON(dict.Find(kAggregatableValues))); - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { ASSIGN_OR_RETURN( registration.aggregation_coordinator_origin, ParseAggregationCoordinator(dict.Find(kAggregationCoordinatorOrigin))); - } registration.debug_key = ParseDebugKey(dict); registration.debug_reporting = ParseDebugReporting(dict); @@ -215,9 +210,7 @@ SerializeDebugReporting(dict, debug_reporting); - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders) && - aggregation_coordinator_origin.has_value()) { + if (aggregation_coordinator_origin.has_value()) { dict.Set(kAggregationCoordinatorOrigin, aggregation_coordinator_origin->Serialize()); }
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 180574d1..9f26e86c 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -567,15 +567,13 @@ } void AutofillAgent::ObserveCaret(WebElement element) { - if (auto control = element.DynamicTo<WebFormControlElement>(); - !element.IsContentEditable() && !form_util::IsTextAreaElement(control)) { - return; - } if (!base::FeatureList::IsEnabled(features::kAutofillCaretExtraction)) { return; } - if (!element.IsNull()) { + if (element && (element.IsContentEditable() || + form_util::IsTextAreaElement( + element.DynamicTo<WebFormControlElement>()))) { caret_state_.remove_listener = element.GetDocument().AddEventListener( WebNode::EventType::kSelectionchange, base::BindRepeating(&AutofillAgent::HandleCaretMovedInFormField, @@ -610,7 +608,7 @@ } } } - if (element.IsContentEditable()) { + if (element && element.IsContentEditable()) { if (std::optional<FormData> form = form_util::FindFormForContentEditable(element)) { CHECK_EQ(form->fields.size(), 1u); @@ -1502,10 +1500,16 @@ void AutofillAgent::DidReceiveLeftMouseDownOrGestureTapInNode( const WebNode& node) { DCHECK(node); + WebElement contenteditable; + const bool is_focused = + node.Focused() || ((contenteditable = node.RootEditableElement()) && + contenteditable.Focused() && + base::FeatureList::IsEnabled( + features::kAutofillContentEditableLeftClickFix)); #if defined(ANDROID) - HandleFocusChangeComplete(/*focused_node_was_last_clicked=*/node.Focused()); + HandleFocusChangeComplete(/*focused_node_was_last_clicked=*/is_focused); #else - last_left_mouse_down_or_gesture_tap_in_node_caused_focus_ = node.Focused(); + last_left_mouse_down_or_gesture_tap_in_node_caused_focus_ = is_focused; #endif }
diff --git a/components/autofill/content/renderer/autofill_agent_browsertest.cc b/components/autofill/content/renderer/autofill_agent_browsertest.cc index 3fa5cda..89084e2 100644 --- a/components/autofill/content/renderer/autofill_agent_browsertest.cc +++ b/components/autofill/content/renderer/autofill_agent_browsertest.cc
@@ -47,6 +47,7 @@ using ::testing::_; using ::testing::AllOf; +using ::testing::AtMost; using ::testing::DoAll; using ::testing::ElementsAre; using ::testing::ElementsAreArray; @@ -173,6 +174,27 @@ blink::WebString::FromUTF8(id))); } + void Focus(const char* id) { + ExecuteJavaScriptForTests(base::StringPrintf(R"( + document.getElementById('%s').focus(); + )", + id)); + task_environment_.FastForwardBy(base::Milliseconds(500)); + task_environment_.RunUntilIdle(); + } + + void Click(std::string_view target) { + SimulatePointClick( + GetWebElementById(target).BoundsInWidget().CenterPoint()); + task_environment_.RunUntilIdle(); + } + + void RightClick(std::string_view target) { + SimulatePointRightClick( + GetWebElementById(target).BoundsInWidget().CenterPoint()); + task_environment_.RunUntilIdle(); + } + void SimulateUserEditField(const blink::WebFormElement& form, const std::string& field_id, const std::string& value) { @@ -1305,14 +1327,6 @@ blink::WebElement GetElement() { return GetWebElementById("f"); } - void Focus() { - ExecuteJavaScriptForTests(R"( - document.getElementById('f').focus(); - )"); - task_environment_.FastForwardBy(base::Milliseconds(500)); - task_environment_.RunUntilIdle(); - } - void TriggerAskForValuesToFill() { switch (form_control_type()) { case FormControlType::kContentEditable: @@ -1367,7 +1381,7 @@ gfx::Rect caret_bounds; EXPECT_CALL(autofill_driver(), AskForValuesToFill) .WillOnce(DoAll(SaveArg<1>(&field), SaveArg<2>(&caret_bounds))); - Focus(); + Focus("f"); TriggerAskForValuesToFill(); EXPECT_FALSE(field.bounds().IsEmpty()); EXPECT_FALSE(caret_bounds.origin().IsOrigin()); @@ -1395,7 +1409,7 @@ EXPECT_CALL(checkpoint, Call("done")); } checkpoint.Call("focus"); - Focus(); + Focus("f"); checkpoint.Call("first move"); SetCaret(1, 1, /*pause_for=*/base::Seconds(1)); checkpoint.Call("second move"); @@ -1431,7 +1445,7 @@ EXPECT_CALL(checkpoint, Call("done")); } checkpoint.Call("focus"); - Focus(); + Focus("f"); checkpoint.Call("first move"); SetCaret(1, 1, /*pause_for=*/base::Milliseconds(1)); checkpoint.Call("second move is ignored"); @@ -1460,12 +1474,94 @@ EXPECT_CALL(checkpoint, Call("done")); } checkpoint.Call("focus"); - Focus(); + Focus("f"); checkpoint.Call("selection"); SetCaret(1, 4, /*pause_for=*/base::Seconds(1)); checkpoint.Call("done"); } +// Tests fixture for click handling. +class AutofillAgentTestClick + : public AutofillAgentTest, + public ::testing::WithParamInterface<const char*> { + public: + const char* field_html() const { return GetParam(); } + + void SetUp() override { + AutofillAgentTest::SetUp(); + // The DIV and SPAN dimensions are chosen so that + // - an empty DIV is clickable and + // - clicking on a non-empty DIV hits the node (a text node or SPAN) inside + // that DIV. + LoadHTML(base::StringPrintf(R"(<html> + <style> + div { width: 5em; height: 2ex; } + </style> + <body> + <div id=other></div> + %s)", + field_html())); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_{ + features::kAutofillContentEditableLeftClickFix}; +}; + +INSTANTIATE_TEST_SUITE_P( + AutofillAgentTest, + AutofillAgentTestClick, + ::testing::Values(R"(<input id=f>)", + R"(<textarea id=f></textarea>)", + R"(<div contenteditable id=f></div>)", + R"(<div contenteditable id=f>Hello world</div>)", + R"(<div contenteditable id=f><div></div></div>)")); + +// Tests that clicking on a field triggers AskForValuesToFillOnClick(). +// TODO(crbug.com/342126797): Fix Android's OnAskForValuesToFill() event. +#if !BUILDFLAG(IS_ANDROID) +#define MAYBE_AskForValuesToFillOnClick AskForValuesToFillOnClick +#else +#define MAYBE_AskForValuesToFillOnClick DISABLED_AskForValuesToFillOnClick +#endif +TEST_P(AutofillAgentTestClick, MAYBE_AskForValuesToFillOnClick) { + testing::MockFunction<void(std::string_view)> checkpoint; + { + testing::InSequence s; + FieldRendererId field = GetFieldRendererIdById("f"); + + EXPECT_CALL(checkpoint, Call("click on field")); + EXPECT_CALL(autofill_driver(), + AskForValuesToFill(_, HasFieldId(field), _, _)); + + EXPECT_CALL(checkpoint, Call("click on field")); + EXPECT_CALL(autofill_driver(), + AskForValuesToFill(_, HasFieldId(field), _, _)); + + EXPECT_CALL(checkpoint, Call("click outside of field")); + EXPECT_CALL(autofill_driver(), AskForValuesToFill).Times(0); + + EXPECT_CALL(checkpoint, Call("right click on field")); + EXPECT_CALL(autofill_driver(), AskForValuesToFill).Times(0); + EXPECT_CALL( + autofill_driver(), + AskForValuesToFill( + _, _, _, + AutofillSuggestionTriggerSource::kTextareaFocusedWithoutClick)) + .Times(AtMost(1)); + } + + WaitForFormsSeen(); + checkpoint.Call("click on field"); + Click("f"); + checkpoint.Call("click on field"); + Click("f"); + checkpoint.Call("click outside of field"); + Click("other"); + checkpoint.Call("right click on field"); + RightClick("f"); +} + } // namespace } // namespace autofill
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index 96cf5fa8..0faef59 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -2176,8 +2176,7 @@ if (content_editable.DynamicTo<WebFormElement>() || content_editable.DynamicTo<WebFormControlElement>() || !content_editable.IsContentEditable() || - (content_editable.ParentNode() && - content_editable.ParentNode().IsContentEditable())) { + content_editable != content_editable.RootEditableElement()) { return std::nullopt; }
diff --git a/components/autofill/content/renderer/form_tracker.cc b/components/autofill/content/renderer/form_tracker.cc index 2a8a4ca..bb4a35034 100644 --- a/components/autofill/content/renderer/form_tracker.cc +++ b/components/autofill/content/renderer/form_tracker.cc
@@ -98,8 +98,9 @@ ShouldReplaceElementsByRendererIds() ? form_util::GetContentEditableByRendererId(field_renderer_id_) : field_; - return content_editable.IsContentEditable() ? content_editable - : blink::WebElement(); + return content_editable && content_editable.IsContentEditable() + ? content_editable + : blink::WebElement(); } FieldRendererId FieldRef::GetId() const {
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index af9b6c9..bc71e50 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -176,6 +176,7 @@ "data_model/credit_card_benefit.h", "data_model/credit_card_cloud_token_data.cc", "data_model/credit_card_cloud_token_data.h", + "data_model/credit_card_network_identifiers.h", "data_model/data_model_utils.cc", "data_model/data_model_utils.h", "data_model/form_group.cc",
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 453f42a..9468a299 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1286,10 +1286,10 @@ BuildSuggestionsContext(form, field, trigger_source); GenerateSuggestionsAndMaybeShowUI( - form, field, trigger_source, std::move(context), + form, field, trigger_source, context, base::BindOnce(&BrowserAutofillManager::OnGenerateSuggestionsComplete, weak_ptr_factory_.GetWeakPtr(), form, field, - trigger_source)); + trigger_source, context)); } void BrowserAutofillManager::GenerateSuggestionsAndMaybeShowUI( @@ -1337,8 +1337,6 @@ return; } - LogSuggestionsCount(context, suggestions); - const bool form_element_was_clicked = trigger_source == AutofillSuggestionTriggerSource::kFormControlElementClicked; @@ -1490,8 +1488,10 @@ const FormData& form, const FormFieldData& field, AutofillSuggestionTriggerSource trigger_source, + const SuggestionsContext& context, bool show_suggestions, std::vector<Suggestion> suggestions) { + LogSuggestionsCount(context, suggestions); // When focusing on a field, log whether there is a suggestion for the user // and whether the suggestion is shown. FormStructure* form_structure = nullptr;
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h index 1033ca5..e2c8a87 100644 --- a/components/autofill/core/browser/browser_autofill_manager.h +++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -579,6 +579,7 @@ const FormData& form, const FormFieldData& field, AutofillSuggestionTriggerSource trigger_source, + const SuggestionsContext& context, bool show_suggestions, std::vector<Suggestion> suggestions);
diff --git a/components/autofill/core/browser/data_model/credit_card.h b/components/autofill/core/browser/data_model/credit_card.h index 294802f..b878c859 100644 --- a/components/autofill/core/browser/data_model/credit_card.h +++ b/components/autofill/core/browser/data_model/credit_card.h
@@ -17,6 +17,10 @@ #include "components/autofill/core/browser/ui/suggestion.h" #include "url/gurl.h" +// TODO(b/281812289): Remove this include when all dependencies switch to +// including this file directly instead of relying on credit_card.h. +#include "components/autofill/core/browser/data_model/credit_card_network_identifiers.h" + namespace autofill { // Unicode characters used in card number obfuscation: @@ -26,20 +30,6 @@ inline constexpr char16_t kMidlineEllipsisDot[] = u"\u2022\u2060\u2006\u2060"; inline constexpr char16_t kMidlineEllipsisPlainDot = u'\u2022'; -// The string identifiers for credit card icon resources. -inline constexpr char kAmericanExpressCard[] = "americanExpressCC"; -inline constexpr char kDinersCard[] = "dinersCC"; -inline constexpr char kDiscoverCard[] = "discoverCC"; -inline constexpr char kEloCard[] = "eloCC"; -inline constexpr char kGenericCard[] = "genericCC"; -inline constexpr char kJCBCard[] = "jcbCC"; -inline constexpr char kMasterCard[] = "masterCardCC"; -inline constexpr char kMirCard[] = "mirCC"; -inline constexpr char kTroyCard[] = "troyCC"; -inline constexpr char kUnionPay[] = "unionPayCC"; -inline constexpr char kVerveCard[] = "verveCC"; -inline constexpr char kVisaCard[] = "visaCC"; - struct AutofillMetadata; namespace internal {
diff --git a/components/autofill/core/browser/data_model/credit_card_network_identifiers.h b/components/autofill/core/browser/data_model/credit_card_network_identifiers.h new file mode 100644 index 0000000..7004fdc2 --- /dev/null +++ b/components/autofill/core/browser/data_model/credit_card_network_identifiers.h
@@ -0,0 +1,26 @@ +// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_NETWORK_IDENTIFIERS_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_NETWORK_IDENTIFIERS_H_ + +namespace autofill { + +// The string identifiers for credit card icon resources. +inline constexpr char kAmericanExpressCard[] = "americanExpressCC"; +inline constexpr char kDinersCard[] = "dinersCC"; +inline constexpr char kDiscoverCard[] = "discoverCC"; +inline constexpr char kEloCard[] = "eloCC"; +inline constexpr char kGenericCard[] = "genericCC"; +inline constexpr char kJCBCard[] = "jcbCC"; +inline constexpr char kMasterCard[] = "masterCardCC"; +inline constexpr char kMirCard[] = "mirCC"; +inline constexpr char kTroyCard[] = "troyCC"; +inline constexpr char kUnionPay[] = "unionPayCC"; +inline constexpr char kVerveCard[] = "verveCC"; +inline constexpr char kVisaCard[] = "visaCC"; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_NETWORK_IDENTIFIERS_H_
diff --git a/components/autofill/core/browser/payments_data_manager.cc b/components/autofill/core/browser/payments_data_manager.cc index daf96d6..7136c86 100644 --- a/components/autofill/core/browser/payments_data_manager.cc +++ b/components/autofill/core/browser/payments_data_manager.cc
@@ -711,7 +711,7 @@ } std::vector<BankAccount> PaymentsDataManager::GetMaskedBankAccounts() const { - if (!IsAutofillPaymentMethodsEnabled()) { + if (!HasMaskedBankAccounts()) { return {}; } std::vector<BankAccount> bank_accounts; @@ -1875,6 +1875,10 @@ credit_card_benefits_.push_back(std::move(benefit)); } +bool PaymentsDataManager::IsFacilitatedPaymentsPixUserPrefEnabled() const { + return prefs::IsFacilitatedPaymentsPixEnabled(pref_service_); +} + bool PaymentsDataManager::HasPendingPaymentQueries() const { return pending_creditcards_query_ != 0 || pending_server_creditcards_query_ != 0 ||
diff --git a/components/autofill/core/browser/payments_data_manager.h b/components/autofill/core/browser/payments_data_manager.h index af7de294..001c78f 100644 --- a/components/autofill/core/browser/payments_data_manager.h +++ b/components/autofill/core/browser/payments_data_manager.h
@@ -467,6 +467,9 @@ // not affect data in the real database. void AddCreditCardBenefitForTest(CreditCardBenefit benefit); + // Returns the value of the FacilitatedPaymentsPix user pref. + bool IsFacilitatedPaymentsPixUserPrefEnabled() const; + protected: friend class PaymentsDataManagerTestApi;
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index 89fcb4e..380e829 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -49,6 +49,14 @@ "AutofillCaretExtraction", base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, AutofillAgent's left-click handler tries to treat +// contenteditables appropriately. +// This is a kill switch. +// TODO(crbug.com/341695271): Remove when launched. +BASE_FEATURE(kAutofillContentEditableLeftClickFix, + "AutofillContentEditableLeftClickFix", + base::FEATURE_ENABLED_BY_DEFAULT); + // Same as `kAutofillAddressUserPerceptionSurvey` but for credit card forms. BASE_FEATURE(kAutofillCreditCardUserPerceptionSurvey, "AutofillCreditCardUserPerceptionSurvey",
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index d914819..69b6541 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -24,6 +24,8 @@ COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillCaretExtraction); COMPONENT_EXPORT(AUTOFILL) +BASE_DECLARE_FEATURE(kAutofillContentEditableLeftClickFix); +COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillCreditCardUserPerceptionSurvey); COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAssociateForms); COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/autofill/core/common/autofill_prefs.cc b/components/autofill/core/common/autofill_prefs.cc index 8b788bd..a5d5509 100644 --- a/components/autofill/core/common/autofill_prefs.cc +++ b/components/autofill/core/common/autofill_prefs.cc
@@ -299,5 +299,13 @@ prefs->SetDict(prefs::kAutofillSyncTransportOptIn, base::Value::Dict()); } +bool IsFacilitatedPaymentsPixEnabled(const PrefService* prefs) { +#if BUILDFLAG(IS_ANDROID) + return prefs->GetBoolean(kFacilitatedPaymentsPix); +#else + return false; +#endif // BUILDFLAG(IS_ANDROID) +} + } // namespace prefs } // namespace autofill
diff --git a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java index b821707..b5f2b2e 100644 --- a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java +++ b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java
@@ -13,6 +13,7 @@ import android.widget.TextView; import androidx.annotation.ColorRes; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.appcompat.content.res.AppCompatResources; import androidx.preference.PreferenceViewHolder; @@ -26,7 +27,7 @@ private View mView; /** The color resource ID for tinting of the view's background. */ - @ColorRes private Integer mBackgroundColorRes; + @ColorRes @Nullable private Integer mBackgroundColorRes; /** Indicates if the preference uses a custom layout. */ private final boolean mHasCustomLayout; @@ -127,6 +128,11 @@ updateBackground(); } + /** Returns the background color of the preference. */ + public @Nullable Integer getBackgroundColor() { + return mBackgroundColorRes; + } + /** * Sets the text to use when a11y announces the `summary` label. *
diff --git a/components/commerce/core/webui/shopping_service_handler.cc b/components/commerce/core/webui/shopping_service_handler.cc index 8f4f5d2..23b8383 100644 --- a/components/commerce/core/webui/shopping_service_handler.cc +++ b/components/commerce/core/webui/shopping_service_handler.cc
@@ -240,6 +240,12 @@ delegate_(std::move(delegate)) { scoped_subscriptions_observation_.Observe(shopping_service_); scoped_bookmark_model_observation_.Observe(bookmark_model_); + if (shopping_service_ && + shopping_service_->GetProductSpecificationsService()) { + scoped_product_spec_observer_.Observe( + shopping_service_->GetProductSpecificationsService()); + } + // It is safe to schedule updates and observe bookmarks. If the feature is // disabled, no new information will be fetched or provided to the frontend. shopping_service_->ScheduleSavedProductUpdate(); @@ -686,6 +692,12 @@ } } +void ShoppingServiceHandler::SwitchToOrOpenTab(const GURL& url) { + if (delegate_) { + delegate_->SwitchToOrOpenTab(url); + } +} + void ShoppingServiceHandler::ShowFeedback() { if (delegate_) { delegate_->ShowFeedback();
diff --git a/components/commerce/core/webui/shopping_service_handler.h b/components/commerce/core/webui/shopping_service_handler.h index 2e67ef56..3301099 100644 --- a/components/commerce/core/webui/shopping_service_handler.h +++ b/components/commerce/core/webui/shopping_service_handler.h
@@ -63,6 +63,8 @@ virtual void OpenUrlInNewTab(const GURL& url) = 0; + virtual void SwitchToOrOpenTab(const GURL& url) = 0; + virtual void ShowBookmarkEditorForCurrentUrl() = 0; virtual void ShowFeedback() = 0; @@ -109,6 +111,7 @@ void GetPriceTrackingStatusForCurrentUrl( GetPriceTrackingStatusForCurrentUrlCallback callback) override; void SetPriceTrackingStatusForCurrentUrl(bool track) override; + void SwitchToOrOpenTab(const GURL& url) override; void OpenUrlInNewTab(const GURL& url) override; void GetParentBookmarkFolderNameForCurrentUrl( GetParentBookmarkFolderNameForCurrentUrlCallback callback) override;
diff --git a/components/commerce/core/webui/shopping_service_handler_unittest.cc b/components/commerce/core/webui/shopping_service_handler_unittest.cc index 7759de4..2a5e9c8 100644 --- a/components/commerce/core/webui/shopping_service_handler_unittest.cc +++ b/components/commerce/core/webui/shopping_service_handler_unittest.cc
@@ -92,6 +92,7 @@ MOCK_METHOD(std::optional<GURL>, GetCurrentTabUrl, (), (override)); MOCK_METHOD(void, ShowInsightsSidePanelUI, (), (override)); MOCK_METHOD(void, OpenUrlInNewTab, (const GURL& url), (override)); + MOCK_METHOD(void, SwitchToOrOpenTab, (const GURL& url), (override)); MOCK_METHOD(void, ShowFeedback, (), (override)); MOCK_METHOD(const bookmarks::BookmarkNode*, GetOrAddBookmarkForCurrentUrl, @@ -662,6 +663,13 @@ handler_->OpenUrlInNewTab(url); } +TEST_F(ShoppingServiceHandlerTest, TestSwitchToOrOpenTab) { + const GURL url = GURL("http://example.com/"); + EXPECT_CALL(*delegate_, SwitchToOrOpenTab(url)).Times(1); + + handler_->SwitchToOrOpenTab(url); +} + TEST_F(ShoppingServiceHandlerTest, TestShowFeedback) { EXPECT_CALL(*delegate_, ShowFeedback).Times(1);
diff --git a/components/cross_device/logging/logging.cc b/components/cross_device/logging/logging.cc index f23d729b..45da4d16 100644 --- a/components/cross_device/logging/logging.cc +++ b/components/cross_device/logging/logging.cc
@@ -6,7 +6,7 @@ #include "base/command_line.h" CrossDeviceScopedLogMessage::CrossDeviceScopedLogMessage( - const char* file, + const std::string_view file, int line, logging::LogSeverity severity, Feature feature) @@ -16,17 +16,17 @@ const std::string string_from_stream = stream_.str(); CrossDeviceLogBuffer::GetInstance()->AddLogMessage( CrossDeviceLogBuffer::LogMessage(string_from_stream, feature_, - base::Time::Now(), file_, line_, + base::Time::Now(), file_.data(), line_, severity_)); // Don't emit VERBOSE-level logging to the standard logging system. if (severity_ <= logging::LOGGING_VERBOSE && - logging::GetVlogLevelHelper(file_, strlen(file_) + 1) <= 0) { + logging::GetVlogLevelHelper(file_.data(), file_.size()) <= 0) { return; } // The destructor of |log_message| also creates a log for the standard logging // system. - logging::LogMessage log_message(file_, line_, severity_); + logging::LogMessage log_message(file_.data(), line_, severity_); log_message.stream() << string_from_stream; }
diff --git a/components/cross_device/logging/logging.h b/components/cross_device/logging/logging.h index 59f2ab8..a6aab90 100644 --- a/components/cross_device/logging/logging.h +++ b/components/cross_device/logging/logging.h
@@ -6,6 +6,7 @@ #define COMPONENTS_CROSS_DEVICE_LOGGING_LOGGING_H_ #include <sstream> +#include <string_view> #include "base/logging.h" #include "components/cross_device/logging/log_buffer.h" @@ -14,8 +15,8 @@ // the debug page can reflect all logs related to this feature in the internal // debug WebUI (chrome://nearby-internals). #define CD_LOG(severity, feature) \ - CrossDeviceScopedLogMessage(__FILE__, __LINE__, logging::LOGGING_##severity, \ - feature) \ + CrossDeviceScopedLogMessage(std::string_view(__FILE__, std::size(__FILE__)), \ + __LINE__, logging::LOGGING_##severity, feature) \ .stream() // An intermediate object used by the CD_LOG macro, wrapping a @@ -24,7 +25,7 @@ // specific log buffer. class CrossDeviceScopedLogMessage { public: - CrossDeviceScopedLogMessage(const char* file, + CrossDeviceScopedLogMessage(const std::string_view file, int line, logging::LogSeverity severity, Feature feature); @@ -36,7 +37,7 @@ std::ostream& stream() { return stream_; } private: - const char* file_; + const std::string_view file_; Feature feature_; int line_; logging::LogSeverity severity_;
diff --git a/components/enterprise/browser/identifiers/profile_id_service.cc b/components/enterprise/browser/identifiers/profile_id_service.cc index 885c836..4c9f11b5 100644 --- a/components/enterprise/browser/identifiers/profile_id_service.cc +++ b/components/enterprise/browser/identifiers/profile_id_service.cc
@@ -64,6 +64,17 @@ if (device_id.empty()) return RecordError(Error::kGetDeviceIdFailure); + return GetProfileIdWithGuidAndDeviceId(profile_guid, device_id); +} + +std::optional<std::string> ProfileIdService::GetProfileIdWithGuidAndDeviceId( + const std::string profile_guid, + const std::string device_id) { + std::string profile_id = GetTestProfileIdFromStorage(); + if (!profile_id.empty()) { + return profile_id; + } + std::string encoded_string; base::Base64UrlEncode(base::SHA1HashString(profile_guid + device_id), base::Base64UrlEncodePolicy::OMIT_PADDING,
diff --git a/components/enterprise/browser/identifiers/profile_id_service.h b/components/enterprise/browser/identifiers/profile_id_service.h index 40b5eba..eef641c 100644 --- a/components/enterprise/browser/identifiers/profile_id_service.h +++ b/components/enterprise/browser/identifiers/profile_id_service.h
@@ -43,6 +43,10 @@ // Creates and returns the profile identifier for the current profile. std::optional<std::string> GetProfileId(); + std::optional<std::string> GetProfileIdWithGuidAndDeviceId( + const std::string profile_guid, + const std::string device_id); + private: std::unique_ptr<ProfileIdDelegate> delegate_; raw_ptr<PrefService> profile_prefs_;
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc index 6e20b1b..caa3ec8 100644 --- a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc +++ b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
@@ -140,19 +140,7 @@ base::FeatureList::IsEnabled(kEnablePixDetectionOnDomContentLoaded)) .Record(ukm::UkmRecorder::Get()); - // If a valid PIX code is found, and the user has Google wallet linked PIX - // accounts, verify that the payments API is available, and then show the PIX - // payment prompt. - // TODO(b/339477906): The check for bank accounts should move to - // OnPixCodeValidated. - auto* payments_data_manager = client_->GetPaymentsDataManager(); - if (!payments_data_manager) { - Reset(); - return; - } - if (result != mojom::PixCodeDetectionResult::kValidPixCodeFound || - !payments_data_manager->HasMaskedBankAccounts() || - !base::FeatureList::IsEnabled(kEnablePixPayments)) { + if (result != mojom::PixCodeDetectionResult::kValidPixCodeFound) { Reset(); return; } @@ -179,6 +167,18 @@ return; } + // If a valid PIX code is found, and the user has Google wallet linked PIX + // accounts, verify that the payments API is available, and then show the PIX + // payment prompt. + auto* payments_data_manager = client_->GetPaymentsDataManager(); + if (!payments_data_manager || + !payments_data_manager->IsFacilitatedPaymentsPixUserPrefEnabled() || + !payments_data_manager->HasMaskedBankAccounts() || + !base::FeatureList::IsEnabled(kEnablePixPayments)) { + Reset(); + return; + } + initiate_payment_request_details_->pix_code_ = std::move(pix_code); api_availability_check_start_time_ = base::TimeTicks::Now(); api_client_->IsAvailable(
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager.h b/components/facilitated_payments/core/browser/facilitated_payments_manager.h index ca00be80..092289c 100644 --- a/components/facilitated_payments/core/browser/facilitated_payments_manager.h +++ b/components/facilitated_payments/core/browser/facilitated_payments_manager.h
@@ -149,13 +149,13 @@ FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, InvalidPixCodeDetectionResultDoesNotTriggerApiClient); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - AbsenceOfPixAccountsDoesNotTriggerApiClient); + NoPixAccounts_NoApiClientTriggered); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - UnavailabilityOfPdmDoesNotTriggerApiClient); + NoPaymentsDataManager_NoApiClientTriggered); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, ValidPixDetectionResultToPixPaymentPromptShown); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - PixCodeValidated_ApiClientTriggered); + ApiClientTriggeredAfterPixCodeValidation); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, PaymentNotOfferedReason_CodeValidatorReturnsFalse); FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest,
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc b/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc index 4144c31e..ea12f61 100644 --- a/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc +++ b/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc
@@ -1114,10 +1114,11 @@ mojom::PixCodeDetectionResult::kInvalidPixCodeFound, std::string()); } -// If the PIX code has been validated, then the manager checks for API -// availability. +// The manager checks for API availability after validating the PIX code. TEST_F(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - PixCodeValidated_ApiClientTriggered) { + ApiClientTriggeredAfterPixCodeValidation) { + payments_data_manager_->AddMaskedBankAccountForTest(CreatePixBankAccount(1)); + EXPECT_CALL(*api_client_, IsAvailable(testing::_)); manager_->OnPixCodeValidated(/*pix_code=*/std::string(), @@ -1128,6 +1129,8 @@ // the manager does not check the API for availability. TEST_F(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, PixCodeValidationFailed_NoApiClientTriggered) { + payments_data_manager_->AddMaskedBankAccountForTest(CreatePixBankAccount(1)); + EXPECT_CALL(*api_client_, IsAvailable(testing::_)).Times(0); manager_->OnPixCodeValidated(/*pix_code=*/std::string(), @@ -1153,6 +1156,8 @@ // availability. TEST_F(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, PixCodeValidatorTerminatedUnexpectedly_NoApiClientTriggered) { + payments_data_manager_->AddMaskedBankAccountForTest(CreatePixBankAccount(1)); + EXPECT_CALL(*api_client_, IsAvailable(testing::_)).Times(0); manager_->OnPixCodeValidated( @@ -1181,25 +1186,25 @@ // If the user doesn't have any linked PIX accounts, the manager does not check // whether the facilitated payment API is available. TEST_F(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - AbsenceOfPixAccountsDoesNotTriggerApiClient) { + NoPixAccounts_NoApiClientTriggered) { EXPECT_CALL(*api_client_, IsAvailable(testing::_)).Times(0); - manager_->ProcessPixCodeDetectionResult( - mojom::PixCodeDetectionResult::kValidPixCodeFound, std::string()); + manager_->OnPixCodeValidated(/*pix_code=*/std::string(), + /*is_pix_code_valid=*/true); } // If payments data manager is unavailable, the manager does not check // whether the facilitated payment API is available. TEST_F(FacilitatedPaymentsManagerWithPixPaymentsEnabledTest, - UnavailabilityOfPdmDoesNotTriggerApiClient) { + NoPaymentsDataManager_NoApiClientTriggered) { payments_data_manager_->AddMaskedBankAccountForTest(CreatePixBankAccount(1)); ON_CALL(*client_, GetPaymentsDataManager) .WillByDefault(testing::Return(nullptr)); EXPECT_CALL(*api_client_, IsAvailable(testing::_)).Times(0); - manager_->ProcessPixCodeDetectionResult( - mojom::PixCodeDetectionResult::kValidPixCodeFound, std::string()); + manager_->OnPixCodeValidated(/*pix_code=*/std::string(), + /*is_pix_code_valid=*/true); } // If a valid PIX code is detected, and the user has PIX accounts, and API
diff --git a/components/history_embeddings/embedder.h b/components/history_embeddings/embedder.h index 627557f..e0c4c53 100644 --- a/components/history_embeddings/embedder.h +++ b/components/history_embeddings/embedder.h
@@ -79,6 +79,7 @@ ComputePassagesEmbeddingsCallback callback) = 0; // Set the callback to run when the embedder is ready to process requests. + // The callback is invoked immediately if the embedder is ready beforehand. virtual void SetOnEmbedderReady(OnEmbedderReadyCallback callback) = 0; protected:
diff --git a/components/history_embeddings/ml_embedder.cc b/components/history_embeddings/ml_embedder.cc index d0f59f1..31b26ad 100644 --- a/components/history_embeddings/ml_embedder.cc +++ b/components/history_embeddings/ml_embedder.cc
@@ -52,7 +52,11 @@ } void MlEmbedder::SetOnEmbedderReady(OnEmbedderReadyCallback callback) { - on_embedder_ready_ = std::move(callback); + if (service_controller_->EmbedderReady()) { + std::move(callback).Run(service_controller_->GetEmbedderMetadata()); + } else { + on_embedder_ready_ = std::move(callback); + } } } // namespace history_embeddings
diff --git a/components/history_embeddings/passage_embeddings_service_controller.cc b/components/history_embeddings/passage_embeddings_service_controller.cc index 1145d3b..d26bf89 100644 --- a/components/history_embeddings/passage_embeddings_service_controller.cc +++ b/components/history_embeddings/passage_embeddings_service_controller.cc
@@ -180,6 +180,10 @@ std::move(callback))); } +bool PassageEmbeddingsServiceController::EmbedderReady() { + return !sp_model_path_.empty() && !embeddings_model_path_.empty(); +} + void PassageEmbeddingsServiceController::ResetRemotes() { service_remote_.reset(); embedder_remote_.reset();
diff --git a/components/history_embeddings/passage_embeddings_service_controller.h b/components/history_embeddings/passage_embeddings_service_controller.h index 13f634f4..37abca48 100644 --- a/components/history_embeddings/passage_embeddings_service_controller.h +++ b/components/history_embeddings/passage_embeddings_service_controller.h
@@ -59,7 +59,11 @@ void GetEmbeddings(std::vector<std::string> passages, GetEmbeddingsCallback callback); - // Returns the embeddings model version; + // Returns true if this service controller is ready for embeddings generation. + bool EmbedderReady(); + + // Returns the metadata about the embeddings model. This is only valid when + // EmbedderReady() returns true. EmbedderMetadata GetEmbedderMetadata(); protected:
diff --git a/components/manta/BUILD.gn b/components/manta/BUILD.gn index d92628c..0ecca7c 100644 --- a/components/manta/BUILD.gn +++ b/components/manta/BUILD.gn
@@ -6,6 +6,8 @@ component("manta") { sources = [ + "anchovy_provider.cc", + "anchovy_provider.h", "base_provider.cc", "base_provider.h", "features.cc",
diff --git a/components/manta/anchovy_provider.cc b/components/manta/anchovy_provider.cc new file mode 100644 index 0000000..14a5f2c --- /dev/null +++ b/components/manta/anchovy_provider.cc
@@ -0,0 +1,50 @@ +// 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 "components/manta/anchovy_provider.h" + +#include <algorithm> +#include <vector> + +#include "base/check.h" +#include "base/memory/ptr_util.h" +#include "base/memory/scoped_refptr.h" +#include "components/endpoint_fetcher/endpoint_fetcher.h" +#include "components/manta/base_provider.h" +#include "components/manta/manta_service_callbacks.h" +#include "components/manta/proto/manta.pb.h" + +namespace manta { + +AnchovyProvider::AnchovyProvider( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + signin::IdentityManager* identity_manager, + bool is_otr_profile_, + const std::string& chrome_version, + const std::string& locale) + : BaseProvider(url_loader_factory, + identity_manager, + /*use_api_key=*/is_otr_profile_, + chrome_version, + locale) { + if (identity_manager) { + identity_manager_observation_.Observe(identity_manager); + } +} + +AnchovyProvider::~AnchovyProvider() = default; + +void AnchovyProvider::GetImageDescription(ImageDescriptionRequest& request, + MantaGenericCallback done_callback) { + // TODO (b/340320912): Implement. +} + +void AnchovyProvider::OnIdentityManagerShutdown( + signin::IdentityManager* identity_manager) { + if (identity_manager_observation_.IsObservingSource(identity_manager)) { + identity_manager_observation_.Reset(); + } +} + +} // namespace manta
diff --git a/components/manta/anchovy_provider.h b/components/manta/anchovy_provider.h new file mode 100644 index 0000000..737fecb --- /dev/null +++ b/components/manta/anchovy_provider.h
@@ -0,0 +1,57 @@ + +// 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 COMPONENTS_MANTA_ANCHOVY_PROVIDER_H_ +#define COMPONENTS_MANTA_ANCHOVY_PROVIDER_H_ + +#include <cstdint> +#include <vector> + +#include "base/component_export.h" +#include "components/manta/base_provider.h" +#include "components/manta/manta_service_callbacks.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +namespace manta { + +// The Anchovy provider for the Manta project. Provides a method for clients to +// call the relevant google API, handling OAuth and http fetching. +class COMPONENT_EXPORT(MANTA) AnchovyProvider : public BaseProvider { + public: + AnchovyProvider( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + signin::IdentityManager* identity_manager, + bool is_otr_profile_, + const std::string& chrome_version, + const std::string& locale); + AnchovyProvider(const AnchovyProvider&) = delete; + AnchovyProvider& operator=(const AnchovyProvider&) = delete; + ~AnchovyProvider() override; + + struct ImageDescriptionRequest { + ImageDescriptionRequest(std::string source_id, + std::string lang_tag, + const std::vector<uint8_t>& bytes) + : image_bytes(bytes), lang_tag(lang_tag), source_id(source_id) {} + ImageDescriptionRequest(ImageDescriptionRequest&& other) = default; + ImageDescriptionRequest(const ImageDescriptionRequest&) = delete; + ImageDescriptionRequest& operator=(const ImageDescriptionRequest&) = delete; + const raw_ref<const std::vector<uint8_t>> image_bytes; + const std::string lang_tag; + const std::string source_id; + }; + + virtual void GetImageDescription(ImageDescriptionRequest& request, + MantaGenericCallback callback); + // signin::IdentityManager::Observer: + void OnIdentityManagerShutdown( + signin::IdentityManager* identity_manager) override; + + private: + base::WeakPtrFactory<AnchovyProvider> weak_ptr_factory_{this}; +}; +} // namespace manta +#endif // COMPONENTS_MANTA_ANCHOVY_PROVIDER_H_
diff --git a/components/manta/base_provider.cc b/components/manta/base_provider.cc index e6e6217..ba6dcce5 100644 --- a/components/manta/base_provider.cc +++ b/components/manta/base_provider.cc
@@ -19,22 +19,21 @@ std::string GetProviderEndpoint(bool use_prod) { return use_prod ? kProdEndpointUrl : kAutopushEndpointUrl; } -// BaseProvider::BaseProvider() : is_demo_mode_(false), chrome_version_("") {} -BaseProvider::BaseProvider() : is_demo_mode_(false) {} + +BaseProvider::BaseProvider() : use_api_key_(false) {} BaseProvider::BaseProvider( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, signin::IdentityManager* identity_manager, - bool is_demo_mode, + bool use_api_key, const std::string& chrome_version, const std::string& locale) : url_loader_factory_(url_loader_factory), - is_demo_mode_(is_demo_mode), + use_api_key_(use_api_key), chrome_version_(chrome_version), locale_(locale) { - // Guest mode and demo mode also have valid identity_manager instance, so it's - // OK to CHECK here. - CHECK(identity_manager); - identity_manager_observation_.Observe(identity_manager); + if (identity_manager) { + identity_manager_observation_.Observe(identity_manager); + } } BaseProvider::~BaseProvider() = default; @@ -53,7 +52,7 @@ manta::proto::Request& request, const MantaMetricType metric_type, MantaProtoResponseCallback done_callback) { - if (!is_demo_mode_ && !identity_manager_observation_.IsObserving()) { + if (!use_api_key_ && !identity_manager_observation_.IsObserving()) { std::move(done_callback) .Run(nullptr, {MantaStatusCode::kNoIdentityManager}); return; @@ -77,7 +76,7 @@ base::Time start_time = base::Time::Now(); - if (is_demo_mode_) { + if (use_api_key_) { std::unique_ptr<EndpointFetcher> fetcher = CreateEndpointFetcherForDemoMode( url, annotation_tag, serialized_request); EndpointFetcher* const fetcher_ptr = fetcher.get();
diff --git a/components/manta/base_provider.h b/components/manta/base_provider.h index 2ed5f7b..d80b28e 100644 --- a/components/manta/base_provider.h +++ b/components/manta/base_provider.h
@@ -28,7 +28,7 @@ BaseProvider( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, signin::IdentityManager* identity_manager, - bool is_demo_mode, + bool use_api_key, const std::string& chrome_version = std::string(), const std::string& locale = std::string()); @@ -80,7 +80,7 @@ const std::string& post_data); // Useful client info for particular providers. - const bool is_demo_mode_; + const bool use_api_key_; const std::string chrome_version_; const std::string locale_; };
diff --git a/components/manta/manta_service.cc b/components/manta/manta_service.cc index 9d98250..2019582 100644 --- a/components/manta/manta_service.cc +++ b/components/manta/manta_service.cc
@@ -11,6 +11,7 @@ #include "base/memory/scoped_refptr.h" #include "build/chromeos_buildflags.h" #include "components/account_id/account_id.h" +#include "components/manta/anchovy_provider.h" #include "components/signin/public/identity_manager/account_capabilities.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/tribool.h" @@ -58,11 +59,13 @@ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, signin::IdentityManager* identity_manager, bool is_demo_mode, + bool is_otr_profile, const std::string& chrome_version, const std::string& locale) : shared_url_loader_factory_(shared_url_loader_factory), identity_manager_(identity_manager), is_demo_mode_(is_demo_mode), + is_otr_profile_(is_otr_profile), chrome_version_(chrome_version), locale_(locale) {} @@ -94,6 +97,18 @@ extended_account_info.capabilities.can_use_manta_service()); } +std::unique_ptr<AnchovyProvider> MantaService::CreateAnchovyProvider() { + if (!identity_manager_) { + // Anchovy Provider supports API Key Requests. + return std::make_unique<AnchovyProvider>(shared_url_loader_factory_, + nullptr, is_otr_profile_, + chrome_version_, locale_); + } + return std::make_unique<AnchovyProvider>(shared_url_loader_factory_, + identity_manager_, is_otr_profile_, + chrome_version_, locale_); +} + #if BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr<OrcaProvider> MantaService::CreateOrcaProvider() {
diff --git a/components/manta/manta_service.h b/components/manta/manta_service.h index e4585a371..f520e848 100644 --- a/components/manta/manta_service.h +++ b/components/manta/manta_service.h
@@ -29,6 +29,7 @@ kSupported = 1 }; +class AnchovyProvider; class MahiProvider; class OrcaProvider; class SnapperProvider; @@ -46,6 +47,7 @@ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, signin::IdentityManager* identity_manager, bool is_demo_mode, + bool is_otr_profile, const std::string& chrome_version, const std::string& locale); @@ -57,6 +59,8 @@ // Returns a unique pointer to an instance of the Providers for the // profile associated with the MantaService instance from which this method // is called. + std::unique_ptr<AnchovyProvider> CreateAnchovyProvider(); + #if BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr<MahiProvider> CreateMahiProvider(); std::unique_ptr<OrcaProvider> CreateOrcaProvider(); @@ -75,6 +79,7 @@ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; raw_ptr<signin::IdentityManager> identity_manager_; const bool is_demo_mode_; + const bool is_otr_profile_; const std::string chrome_version_; const std::string locale_; };
diff --git a/components/manta/manta_service_callbacks.cc b/components/manta/manta_service_callbacks.cc index aa5add99..78f565de6 100644 --- a/components/manta/manta_service_callbacks.cc +++ b/components/manta/manta_service_callbacks.cc
@@ -84,6 +84,10 @@ base::UmaHistogramTimes("Ash.MantaService.SparkyProvider.TimeCost", time_cost); break; + case MantaMetricType::kAnchovy: + base::UmaHistogramTimes("Ash.MantaService.AnchovyProvider.TimeCost", + time_cost); + break; } } } // namespace
diff --git a/components/manta/manta_service_callbacks.h b/components/manta/manta_service_callbacks.h index 2b7eb988..4fb1419 100644 --- a/components/manta/manta_service_callbacks.h +++ b/components/manta/manta_service_callbacks.h
@@ -22,6 +22,7 @@ // Enum that indicates the source of the call to manta server, used for logging // UMA metrics. enum class MantaMetricType { + kAnchovy, kOrca, kSnapper, kMahiSummary,
diff --git a/components/manta/proto/manta.proto b/components/manta/proto/manta.proto index 8e54787..46fb05d 100644 --- a/components/manta/proto/manta.proto +++ b/components/manta/proto/manta.proto
@@ -21,6 +21,8 @@ CHROMEOS_READER_Q_AND_A = 313; CHROMEOS_SPARKY = 314; reserved 304 to 311; + + ACCESSIBILITY_IMAGE_DESCRIPTION = 700; } message ClientInfo {
diff --git a/components/messages/android/BUILD.gn b/components/messages/android/BUILD.gn index 2b6231f..54f39b2 100644 --- a/components/messages/android/BUILD.gn +++ b/components/messages/android/BUILD.gn
@@ -23,7 +23,9 @@ resources_package = "org.chromium.components.messages" deps = [ + ":feature_flags_jni_headers_java", ":java_resources", + ":jni_headers_java", "//base:base_java", "//build/android:build_java", "//components/browser_ui/banners/android:java", @@ -36,10 +38,7 @@ "//ui/android:ui_java", ] - srcjar_deps = [ - ":jni_headers", - ":message_enums_java", - ] + srcjar_deps = [ ":message_enums_java" ] } android_library("unit_device_javatests") { @@ -72,11 +71,15 @@ generate_jni("jni_headers") { sources = [ "java/src/org/chromium/components/messages/MessageDispatcherBridge.java", - "java/src/org/chromium/components/messages/MessageFeatureMap.java", "java/src/org/chromium/components/messages/MessageWrapper.java", ] } +generate_jni("feature_flags_jni_headers") { + sources = + [ "java/src/org/chromium/components/messages/MessageFeatureMap.java" ] +} + static_library("android") { sources = [ "message_dispatcher_bridge.cc", @@ -157,7 +160,7 @@ ] deps = [ "//base", - "//components/messages/android:jni_headers", + "//components/messages/android:feature_flags_jni_headers", ] }
diff --git a/components/messages/android/messages_feature.cc b/components/messages/android/messages_feature.cc index 627ccf5..93d191e9 100644 --- a/components/messages/android/messages_feature.cc +++ b/components/messages/android/messages_feature.cc
@@ -8,7 +8,7 @@ #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" #include "base/no_destructor.h" -#include "components/messages/android/jni_headers/MessageFeatureMap_jni.h" +#include "components/messages/android/feature_flags_jni_headers/MessageFeatureMap_jni.h" namespace messages {
diff --git a/components/metrics/generate_allowlist_from_histograms_file.gni b/components/metrics/generate_allowlist_from_histograms_file.gni new file mode 100644 index 0000000..b07cdca --- /dev/null +++ b/components/metrics/generate_allowlist_from_histograms_file.gni
@@ -0,0 +1,43 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Generates a C++ header file that contains a list of values under a specific variant +# or enum. The list can be used for ensuring that values in C++ are in sync with the +# histogram file. The header file provides a function to check if a value in is the list. +# +# Parameters: +# input_xml_file: Input file that contains the allow list. This should be a +# .xml file under path //tools/metrics/histograms/ or its subfolders. +# +# namespace: +# C++ namespace in which the generated code should be scoped. +# +# tag: +# XML tag that contains the values. Should be either "variant" or "enum". +# +# allow_list_name: +# Name of the variant or enum list in the histogram file. +# +# output_file: +# Name of the generated file to be used for checking if a value exists in the list. +# +template("generate_allowlist_from_histograms_file") { + action(target_name) { + output_file = "$target_gen_dir/" + invoker.output_file + + script = + "//tools/metrics/histograms/generate_allowlist_from_histograms_file.py" + outputs = [ output_file ] + sources = [ invoker.input_xml_file ] + + args = [ + "--allow_list_name=" + invoker.allow_list_name, + "--namespace=" + invoker.namespace, + "--tag=" + invoker.tag, + "--output_dir=" + rebase_path(root_gen_dir, root_build_dir), + "--file=" + rebase_path(output_file, root_gen_dir), + "--input=" + rebase_path(invoker.input_xml_file, root_build_dir), + ] + } +}
diff --git a/components/metrics/generate_histograms_variants_allowlist.gni b/components/metrics/generate_histograms_variants_allowlist.gni deleted file mode 100644 index fc02215..0000000 --- a/components/metrics/generate_histograms_variants_allowlist.gni +++ /dev/null
@@ -1,39 +0,0 @@ -# Copyright 2023 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Generates an output file that contains all histograms which share the same -# variant name. This output file will act as an allow list. -# -# Parameters: -# input_xml_file: Input file that contains the allow list. This should be a -# .xml file with histogram descriptions and should be a path starting with -# //tools/metrics/histograms/ -# -# namespace: -# Namespace in which the generated code should be scoped. -# -# output_file: -# Name of the generated file to be used for compile time checking. -# -# allow_list_name: -# Name of the variants list that act as an allow list. -# -template("generate_histograms_variants_allowlist") { - action(target_name) { - output_file = "$target_gen_dir/" + invoker.output_file - - script = - "//tools/metrics/histograms/generate_histograms_variants_allowlist.py" - outputs = [ output_file ] - sources = [ invoker.input_xml_file ] - - args = [ - "-a" + invoker.allow_list_name, - "-n" + invoker.namespace, - "-o" + rebase_path(root_gen_dir, root_build_dir), - "-f" + rebase_path(output_file, root_gen_dir), - "-i" + rebase_path(invoker.input_xml_file, root_build_dir), - ] - } -}
diff --git a/components/metrics/structured/docs/sm_api.md b/components/metrics/structured/docs/sm_api.md index c11e96f..4e069f8 100644 --- a/components/metrics/structured/docs/sm_api.md +++ b/components/metrics/structured/docs/sm_api.md
@@ -126,7 +126,7 @@ ``` ## Local Verification -Structured Metrics has a debug page at `chrome://metrics-internal/structured` that can be used to verify recorded events and their contents. The page must be manually refreshed to see recently recorded events. +Structured Metrics has a debug page at `chrome://metrics-internals/structured` that can be used to verify recorded events and their contents. The page must be manually refreshed to see recently recorded events. <!-- TODO: Expand with image and additional functionality -->
diff --git a/components/metrics/structured/mojom/event.mojom b/components/metrics/structured/mojom/event.mojom index 86bd32a..aea626a 100644 --- a/components/metrics/structured/mojom/event.mojom +++ b/components/metrics/structured/mojom/event.mojom
@@ -22,7 +22,9 @@ // definitions in structured.xml. map<string, MetricValue> metrics@2; - // Time passed (in microseconds) since boot time. + // Time passed (in microseconds) since boot time. This is a timestamp + // that gets converted to system uptime before upload when the Event + // is passed from a WebUI Renderer process. [MinVersion=1] mojo_base.mojom.TimeDelta? system_uptime@3; // Whether this event is part of a sequence.
diff --git a/components/named_system_lock/BUILD.gn b/components/named_system_lock/BUILD.gn new file mode 100644 index 0000000..f66d83f --- /dev/null +++ b/components/named_system_lock/BUILD.gn
@@ -0,0 +1,33 @@ +# 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. + +static_library("named_system_lock") { + sources = [ "lock.h" ] + deps = [ "//base" ] + if (is_linux) { + sources += [ "lock_linux.cc" ] + } else if (is_mac) { + sources += [ "lock_mac.mm" ] + } else if (is_win) { + sources += [ "lock_win.cc" ] + } +} + +source_set("unit_tests") { + testonly = true + + sources = [] + + # Disable NamedSystemLockTest on unsupported platforms. + if (is_linux || is_win || is_mac) { + sources += [ "lock_unittest.cc" ] + } + + deps = [ + ":named_system_lock", + "//base", + "//base/test:test_support", + "//testing/gtest", + ] +}
diff --git a/components/named_system_lock/OWNERS b/components/named_system_lock/OWNERS new file mode 100644 index 0000000..0133be3e --- /dev/null +++ b/components/named_system_lock/OWNERS
@@ -0,0 +1 @@ +file://chrome/updater/OWNERS \ No newline at end of file
diff --git a/components/named_system_lock/README.md b/components/named_system_lock/README.md new file mode 100644 index 0000000..328ec59 --- /dev/null +++ b/components/named_system_lock/README.md
@@ -0,0 +1,41 @@ +This component provides a named system lock that allows for synchronization +across multiple processes without relying on lockfiles. Linux, MacOS, and +Windows are supported. + +## Example usage + +## Implementation + +The lock is implemented per platform: + +* Linux - As a pthread mutex. +* MacOS - Using `bootstrap_check_in()`, interpreting ownership of receive rights +on a Mach service name as ownership of a lock. +* Windows - As a kernel mutex. + +### Linux-specific notes + +The lock is implemented using a pthread mutex in shared memory. Contenders +attempt to open a POSIX shared memory object, creating the object if it does not +exist. The mutex is configured with the `PTHREAD_MUTEX_ROBUST` attribute to +ensure that it remains recoverable if the process holding the lock exits +abnormally. + +Due to the nature of the `shm_unlink` system call, it is impossible for any +contending process to determine if it is safe to destroy the shared memory +object. Consider the following sequence of processes A, B, and C: + +1. A: Shared memory foo does not exist. Create the shared memory object. +1. A: Creates and acquires the mutex lock in shared memory. +1. B: Shared memory foo exists. Open the existing shared memory object. +1. A: Release the mutex lock and shm_unlink “foo”. Note: Process B can still use +the shared memory until it closes it. Future attempts to open foo will fail with +ENOENT. foo can be recreated. +1. C: Shared memory foo does not exist. Create the shared memory object. +1. B: Acquire the mutex lock in shared memory. +1. C: Creates and acquires the mutex lock in shared memory. + +In the sequence above, unlinking the shared memory created a situation in which +processes B and C hold the lock simultaneously. Thus, by design, the lock uses a +leaky mutex in shared memory. The leak occurs once per named lock and is around +40 bytes. \ No newline at end of file
diff --git a/components/named_system_lock/lock.h b/components/named_system_lock/lock.h new file mode 100644 index 0000000..7e81b05 --- /dev/null +++ b/components/named_system_lock/lock.h
@@ -0,0 +1,56 @@ +// 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 COMPONENTS_NAMED_SYSTEM_LOCK_LOCK_H_ +#define COMPONENTS_NAMED_SYSTEM_LOCK_LOCK_H_ + +#include <memory> +#include <string> + +#include "build/build_config.h" + +#if BUILDFLAG(IS_WIN) +#include <windows.h> + +#include "base/win/atl.h" +#endif + +namespace base { +class TimeDelta; +} // namespace base + +namespace named_system_lock { + +class ScopedLockImpl; + +// ScopedLock represents a held lock. Destroying the ScopedLock releases the +// lock. ScopedLock is reentrant on Windows, but not on Mac or Linux. +class ScopedLock { + public: + explicit ScopedLock(std::unique_ptr<ScopedLockImpl> impl); + ScopedLock(const ScopedLock&) = delete; + ScopedLock& operator=(const ScopedLock&) = delete; + ~ScopedLock(); + + // Returns a ScopedLock, or nullptr if the lock could not be acquired within + // the timeout. While the ScopedLock exists, no other process on the machine + // may acquire that lock. The lock name has different meanings per platform: + // Linux: A shared memory object name starting with `/`. E.g. `/MyApp.lock`. + // Mac: A bootstrap service name (see `man bootstrap_check_in`). +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) + static std::unique_ptr<ScopedLock> Create(const std::string& name, + base::TimeDelta timeout); +#elif BUILDFLAG(IS_WIN) + static std::unique_ptr<ScopedLock> Create(const std::wstring& mutex_name, + CSecurityAttributes* sa, + base::TimeDelta timeout); +#endif + + private: + std::unique_ptr<ScopedLockImpl> impl_; +}; + +} // namespace named_system_lock + +#endif // COMPONENTS_NAMED_SYSTEM_LOCK_LOCK_H_
diff --git a/chrome/updater/lock_linux.cc b/components/named_system_lock/lock_linux.cc similarity index 73% rename from chrome/updater/lock_linux.cc rename to components/named_system_lock/lock_linux.cc index 3422b10..82e6976 100644 --- a/chrome/updater/lock_linux.cc +++ b/components/named_system_lock/lock_linux.cc
@@ -1,8 +1,8 @@ -// Copyright 2023 The Chromium Authors +// 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/updater/lock.h" +#include "components/named_system_lock/lock.h" #include <aio.h> #include <fcntl.h> @@ -18,32 +18,23 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr_exclusion.h" -#include "base/notreached.h" -#include "base/strings/strcat.h" #include "base/time/time.h" -#include "chrome/updater/updater_branding.h" -#include "chrome/updater/updater_scope.h" -namespace { -constexpr char kSharedMemNamePrefix[] = "/" PRODUCT_FULLNAME_STRING; -constexpr char kSharedMemNameSuffix[] = ".lock"; -} // namespace - -namespace updater { +namespace named_system_lock { // A global preferences lock for Linux implemented with pthread mutexes in // shared memory. Note that the shared memory region is leaked once per lock -// name for reasons described in `//docs/updater/design_doc.md`. The size of the -// leaked region is ~40 bytes. +// name for reasons described in the README.md. The size of the leaked region is +// ~40 bytes. class ScopedLockImpl { public: ScopedLockImpl(const ScopedLockImpl&) = delete; ScopedLockImpl& operator=(const ScopedLockImpl&) = delete; ~ScopedLockImpl(); - static std::unique_ptr<ScopedLockImpl> TryCreate(const std::string& id, - UpdaterScope scope, - base::TimeDelta timeout); + static std::unique_ptr<ScopedLockImpl> TryCreate( + const std::string& shared_mem_name, + base::TimeDelta timeout); private: ScopedLockImpl(pthread_mutex_t* mutex, int shm_fd) @@ -56,14 +47,9 @@ }; std::unique_ptr<ScopedLockImpl> ScopedLockImpl::TryCreate( - const std::string& id, - UpdaterScope scope, + const std::string& shared_mem_name, base::TimeDelta timeout) { bool should_init_mutex = false; - const std::string shared_mem_name( - base::StrCat({kSharedMemNamePrefix, id, UpdaterScopeToString(scope), - kSharedMemNameSuffix})); - int shm_fd = shm_open(shared_mem_name.c_str(), O_RDWR, S_IRUSR | S_IWUSR); if (shm_fd < 0 && errno == ENOENT) { shm_fd = @@ -77,13 +63,13 @@ base::stat_wrapper_t shm_stat; if (base::File::Fstat(shm_fd, &shm_stat) < 0) { - PLOG(ERROR) << "Cannot stat shared memory " << shared_mem_name; + VPLOG(1) << "Cannot stat shared memory " << shared_mem_name; return nullptr; } if (shm_stat.st_uid != getuid() || (shm_stat.st_mode & 0777) != (S_IRUSR | S_IWUSR)) { - LOG(ERROR) << "Refusing to use shared memory region " << shared_mem_name - << " with incorrect permissions"; + VLOG(1) << "Refusing to use shared memory region " << shared_mem_name + << " with incorrect permissions"; return nullptr; } @@ -115,27 +101,23 @@ const base::Time start = base::Time::NowFromSystemTime(); do { switch (pthread_mutex_trylock(mutex)) { - case EOWNERDEAD: { + case EOWNERDEAD: // A process holding the mutex died, try to recover it. if (pthread_mutex_consistent(mutex)) { return nullptr; } // The mutex is restored. It is in the locked state. [[fallthrough]]; - } - case 0: { + case 0: // The lock was acquired. return base::WrapUnique<ScopedLockImpl>( new ScopedLockImpl(mutex, shm_fd)); - } - case EBUSY: { + case EBUSY: // The mutex is held by another process. continue; - } - default: { + default: // An error occurred. return nullptr; - } } } while (base::Time::NowFromSystemTime() - start < timeout); @@ -157,11 +139,10 @@ // static std::unique_ptr<ScopedLock> ScopedLock::Create(const std::string& name, - UpdaterScope scope, base::TimeDelta timeout) { std::unique_ptr<ScopedLockImpl> impl = - ScopedLockImpl::TryCreate(name, scope, timeout); + ScopedLockImpl::TryCreate(name, timeout); return impl ? std::make_unique<ScopedLock>(std::move(impl)) : nullptr; } -} // namespace updater +} // namespace named_system_lock
diff --git a/chrome/updater/lock_mac.mm b/components/named_system_lock/lock_mac.mm similarity index 83% rename from chrome/updater/lock_mac.mm rename to components/named_system_lock/lock_mac.mm index f88fd7e..bbdb3aa 100644 --- a/chrome/updater/lock_mac.mm +++ b/components/named_system_lock/lock_mac.mm
@@ -1,8 +1,8 @@ -// Copyright 2023 The Chromium Authors +// 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/updater/lock.h" +#include "components/named_system_lock/lock.h" #include <mach/mach.h> #include <servers/bootstrap.h> @@ -16,21 +16,16 @@ #include "base/apple/mach_logging.h" #include "base/apple/scoped_mach_port.h" +#include "base/check.h" #include "base/logging.h" #include "base/strings/strcat.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "chrome/updater/updater_branding.h" -#include "chrome/updater/updater_scope.h" namespace { -// Mach service name prefix/suffix for the global lock. -constexpr char kLockMachServiceNamePrefix[] = MAC_BUNDLE_IDENTIFIER_STRING; -constexpr char kLockMachServiceNameSuffix[] = ".lock"; - // Interval to poll for lock availability if it is not immediately available. -// Final interval will be truncated to fit the available timeout. +// Final interval is truncated to fit the available timeout. constexpr base::TimeDelta kLockPollingInterval = base::Seconds(3); // @@ -73,14 +68,14 @@ } // anonymous namespace -namespace updater { +namespace named_system_lock { class ScopedLockImpl { public: // Constructs a ScopedLockImpl from a receive right. explicit ScopedLockImpl(base::apple::ScopedMachReceiveRight receive_right); - // Releases the receive right (and therefore releases the lock). + // Releases the receive right. ~ScopedLockImpl() = default; ScopedLockImpl(const ScopedLockImpl&) = delete; @@ -110,17 +105,12 @@ ScopedLock::~ScopedLock() = default; // static -std::unique_ptr<ScopedLock> ScopedLock::Create(const std::string& name, - UpdaterScope scope, +std::unique_ptr<ScopedLock> ScopedLock::Create(const std::string& service_name, base::TimeDelta timeout) { - const std::string service_name( - base::StrCat({kLockMachServiceNamePrefix, name, - UpdaterScopeToString(scope), kLockMachServiceNameSuffix})); - // Find the right namespace for the lock. Non-privileged processes cannot - // climb "up" out of their namespace, but the user updater runs with the right - // namespace (the interactive user session) anyway. The system updater needs - // the system namespace, which is the root of macOS' "tree" of Mach bootstrap + // climb "up" out of their namespace, but user processes run with the right + // namespace (the interactive user session) anyway. System processes need the + // system namespace, which is the root of macOS' "tree" of Mach bootstrap // namespaces. Daemons (including LaunchDaemons) and system services naturally // run under this namespace, but `sudo` -- a POSIX utility that is not aware // of the Mach portions of the macOS kernel -- runs targets without changing @@ -145,7 +135,7 @@ base::apple::ScopedMachSendRight::Receiver(next_right).get()); if (bootstrap_err != KERN_SUCCESS) { BOOTSTRAP_LOG(ERROR, bootstrap_err) - << "can't bootstrap_parent in ScopedLock::Create (for euid 0)"; + << "can't bootstrap_parent in ScopedLock::Create for euid 0"; break; // Use last known bootstrap_right. } CHECK(next_right.is_valid()) @@ -158,9 +148,8 @@ TryAcquireReceive(bootstrap_right, service_name.c_str())); base::TimeTicks deadline = base::TimeTicks::Now() + timeout; - constexpr base::TimeDelta kDeltaZero; for (base::TimeDelta remain = deadline - base::TimeTicks::Now(); - !receive_right.is_valid() && remain > kDeltaZero; + !receive_right.is_valid() && remain.is_positive(); remain = deadline - base::TimeTicks::Now()) { WaitToRetryLock(remain); receive_right = TryAcquireReceive(bootstrap_right, service_name); @@ -173,4 +162,4 @@ std::make_unique<ScopedLockImpl>(std::move(receive_right))); } -} // namespace updater +} // namespace named_system_lock
diff --git a/components/named_system_lock/lock_unittest.cc b/components/named_system_lock/lock_unittest.cc new file mode 100644 index 0000000..133142d --- /dev/null +++ b/components/named_system_lock/lock_unittest.cc
@@ -0,0 +1,112 @@ +// 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 "components/named_system_lock/lock.h" + +#include <memory> +#include <string> + +#include "base/run_loop.h" +#include "base/task/sequenced_task_runner.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "base/unguessable_token.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if BUILDFLAG(IS_LINUX) +#include <fcntl.h> +#include <sys/mman.h> + +#include "base/files/file.h" +#include "base/strings/strcat.h" +#elif BUILDFLAG(IS_MAC) +#include "base/strings/strcat.h" +#elif BUILDFLAG(IS_WIN) +#include <windows.h> + +#include "base/strings/utf_string_conversions.h" +#include "base/win/atl.h" +#endif + +namespace named_system_lock { + +class NamedSystemLockTest : public ::testing::Test { + public: + ~NamedSystemLockTest() override = default; + + protected: + // Use a different lock name for each test to avoid failures due to concurrent + // runs or leaks. + const std::string lock_name_ = base::UnguessableToken::Create().ToString(); + + std::unique_ptr<ScopedLock> CreateLock() { +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) + return ScopedLock::Create(lock_name_, base::Seconds(0)); +#else + CSecurityAttributes sa; + return ScopedLock::Create(base::ASCIIToWide(lock_name_), &sa, + base::Seconds(0)); +#endif + } +}; + +TEST_F(NamedSystemLockTest, LockThenLockSameThread) { + std::unique_ptr<ScopedLock> lock = CreateLock(); + EXPECT_TRUE(lock); + + std::unique_ptr<ScopedLock> lock_again = CreateLock(); + +#if BUILDFLAG(IS_WIN) + EXPECT_TRUE(lock_again); +#else // BUILDFLAG(IS_WIN) + EXPECT_FALSE(lock_again); +#endif // BUILDFLAG(IS_WIN) +} + +TEST_F(NamedSystemLockTest, LockThenTryLockInThreadFail) { + base::test::TaskEnvironment task_environment; + + std::unique_ptr<ScopedLock> lock = CreateLock(); + EXPECT_TRUE(lock); + + base::RunLoop run_loop; + base::ThreadPool::PostTaskAndReply( + FROM_HERE, {base::MayBlock()}, + base::BindLambdaForTesting([&] { EXPECT_FALSE(CreateLock()); }), + base::BindLambdaForTesting([&run_loop] { run_loop.Quit(); })); + run_loop.Run(); +} + +TEST_F(NamedSystemLockTest, TryLockInThreadSuccess) { + base::test::TaskEnvironment task_environment; + + base::RunLoop run_loop; + base::ThreadPool::PostTaskAndReply( + FROM_HERE, {base::MayBlock()}, + base::BindLambdaForTesting([&] { EXPECT_TRUE(CreateLock()); }), + base::BindLambdaForTesting([&run_loop] { run_loop.Quit(); })); + run_loop.Run(); + + EXPECT_TRUE(CreateLock()); +} + +#if BUILDFLAG(IS_LINUX) +TEST_F(NamedSystemLockTest, SharedMemoryWrongPermissions) { + // Create a shared memory region with overpermissive perms. + int shm_fd = shm_open(lock_name_.c_str(), O_RDWR | O_CREAT | O_EXCL, + S_IRWXU | S_IRWXG | S_IRWXO); + ASSERT_GE(shm_fd, 0); + + EXPECT_FALSE(CreateLock()); + + close(shm_fd); + shm_unlink(lock_name_.c_str()); +} +#endif // BUILDFLAG(IS_LINUX) + +} // namespace named_system_lock
diff --git a/components/named_system_lock/lock_win.cc b/components/named_system_lock/lock_win.cc new file mode 100644 index 0000000..a52257d5 --- /dev/null +++ b/components/named_system_lock/lock_win.cc
@@ -0,0 +1,75 @@ +// 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 "components/named_system_lock/lock.h" + +#include <windows.h> + +#include <memory> +#include <string> + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "base/win/atl.h" +#include "base/win/scoped_handle.h" + +namespace named_system_lock { + +class ScopedLockImpl { + public: + ScopedLockImpl() = default; + ScopedLockImpl(const ScopedLockImpl&) = delete; + ScopedLockImpl& operator=(const ScopedLockImpl&) = delete; + ~ScopedLockImpl(); + + private: + friend ScopedLock; + bool Initialize(const std::wstring& mutex_name, + CSecurityAttributes* sa, + base::TimeDelta timeout); + + base::win::ScopedHandle mutex_; +}; + +ScopedLock::ScopedLock(std::unique_ptr<ScopedLockImpl> impl) + : impl_(std::move(impl)) {} + +ScopedLock::~ScopedLock() = default; + +// static +std::unique_ptr<ScopedLock> ScopedLock::Create(const std::wstring& mutex_name, + CSecurityAttributes* sa, + base::TimeDelta timeout) { + auto lock = std::make_unique<ScopedLockImpl>(); + + VLOG(2) << "Trying to acquire the lock: " << mutex_name; + if (!lock->Initialize(mutex_name, sa, timeout)) { + return nullptr; + } + VLOG(2) << "Lock acquired: " << mutex_name; + + return std::make_unique<ScopedLock>(std::move(lock)); +} + +bool ScopedLockImpl::Initialize(const std::wstring& mutex_name, + CSecurityAttributes* sa, + base::TimeDelta timeout) { + mutex_.Set(::CreateMutex(sa, false, mutex_name.c_str())); + if (!mutex_.IsValid()) { + return false; + } + + DWORD ret = ::WaitForSingleObject(mutex_.Get(), timeout.InMilliseconds()); + return ret == WAIT_OBJECT_0 || ret == WAIT_ABANDONED; +} + +ScopedLockImpl::~ScopedLockImpl() { + if (mutex_.IsValid()) { + ::ReleaseMutex(mutex_.Get()); + VLOG(2) << "Lock released."; + } +} + +} // namespace named_system_lock
diff --git a/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java b/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java index 7ffc338d..5977b60 100644 --- a/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java +++ b/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java
@@ -4,8 +4,6 @@ package org.chromium.components.omnibox; -import android.content.Context; - import org.chromium.base.BaseSwitches; import org.chromium.base.CommandLine; import org.chromium.base.ResettersForTesting; @@ -41,9 +39,6 @@ public static final CachedFlag sOmniboxAnswerActions = newFlag(OmniboxFeatureList.OMNIBOX_ANSWER_ACTIONS, false); - public static final CachedFlag sOmniboxModernizeVisualUpdate = - newFlag(OmniboxFeatureList.OMNIBOX_MODERNIZE_VISUAL_UPDATE, true); - public static final CachedFlag sAnimateSuggestionsListAppearance = newFlag(OmniboxFeatureList.ANIMATE_SUGGESTIONS_LIST_APPEARANCE, false); @@ -143,14 +138,6 @@ return sCachedParams; } - /** - * @param context The activity context. - * @return Whether the new modernize visual UI update should be shown. - */ - public static boolean shouldShowModernizeVisualUpdate(Context context) { - return sOmniboxModernizeVisualUpdate.isEnabled(); - } - /** Returns whether the toolbar and status bar color should be matched. */ public static boolean shouldMatchToolbarAndStatusBarColor() { return sOmniboxMatchToolbarAndStatusBarColor.isEnabled();
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 12a4246..fbe93ae 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -389,11 +389,6 @@ "OmniboxSteadyStateTextColor", base::FEATURE_DISABLED_BY_DEFAULT); -// Enable new Omnibox & Suggestions visual style. -BASE_FEATURE(kOmniboxModernizeVisualUpdate, - "OmniboxModernizeVisualUpdate", - base::FEATURE_ENABLED_BY_DEFAULT); - // Android only flag that controls whether the new security indicator should be // used, on non-Android platforms this is controlled through the // ChromeRefresh2023 flag. @@ -551,7 +546,6 @@ static base::NoDestructor<base::android::FeatureMap> kFeatureMap( std::vector<const base::Feature*>{{ &kOmniboxAnswerActions, - &kOmniboxModernizeVisualUpdate, &kQueryTilesInZPSOnNTP, &kAnimateSuggestionsListAppearance, &kGroupingFrameworkForNonZPS,
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index 1d5acbd..7e0b2d31 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -109,10 +109,6 @@ BASE_DECLARE_FEATURE(kOmniboxSteadyStateTextColor); -// Omnibox & Suggestions UI - these affect both the omnibox and the suggestions -// popup. -BASE_DECLARE_FEATURE(kOmniboxModernizeVisualUpdate); - // Android only flag that controls whether the new security indicator should be // used, on non-Android platforms this is controlled through the // ChromeRefresh2023 flag.
diff --git a/components/optimization_guide/core/model_execution/on_device_model_component.cc b/components/optimization_guide/core/model_execution/on_device_model_component.cc index f1ea499..a95d5352 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_component.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_component.cc
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "base/types/cxx23_to_underlying.h" #include "components/optimization_guide/core/model_execution/model_execution_util.h" +#include "components/optimization_guide/core/model_util.h" #include "components/optimization_guide/core/optimization_guide_constants.h" #include "components/optimization_guide/core/optimization_guide_enums.h" #include "components/optimization_guide/core/optimization_guide_features.h" @@ -180,6 +181,13 @@ } void OnDeviceModelComponentStateManager::OnStartup() { + if (auto model_path_override_switch = + switches::GetOnDeviceModelExecutionOverride()) { + SetReady(base::Version("override"), + *StringToFilePath(*model_path_override_switch), + base::Value::Dict()); + return; + } BeginUpdateRegistration(); }
diff --git a/components/optimization_guide/core/model_execution/on_device_model_metadata.cc b/components/optimization_guide/core/model_execution/on_device_model_metadata.cc index b0946bc..6a5cc5a 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_metadata.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_metadata.cc
@@ -15,7 +15,6 @@ #include "base/task/thread_pool.h" #include "components/optimization_guide/core/model_execution/model_execution_util.h" #include "components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h" -#include "components/optimization_guide/core/model_util.h" #include "components/optimization_guide/core/optimization_guide_constants.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/optimization_guide/core/optimization_guide_switches.h" @@ -69,13 +68,6 @@ background_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), background_task_priority}); - auto model_path_override_switch = - switches::GetOnDeviceModelExecutionOverride(); - if (model_path_override_switch) { - Load(*StringToFilePath(*model_path_override_switch), "override"); - return; - } - if (on_device_component_state_manager) { on_device_component_state_manager_ = std::move(on_device_component_state_manager);
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc index 32d26d73..0e0cfa3b 100644 --- a/components/optimization_guide/core/optimization_guide_features.cc +++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -705,6 +705,9 @@ if (perf_classes_string.empty()) { perf_classes_string = "3,4,5,6"; } + if (perf_classes_string == "*") { + return true; + } std::vector<std::string_view> perf_classes_list = base::SplitStringPiece( perf_classes_string, ",", base::WhitespaceHandling::TRIM_WHITESPACE, base::SplitResult::SPLIT_WANT_NONEMPTY);
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 3f6d903..aead1bc 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 3f6d9031ecaca37232dc4d1dfbf1d901dee9edb4 +Subproject commit aead1bc58636071403043aedcb96f127d4c6474d
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc index 9a334f2..0fd38e1 100644 --- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc +++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
@@ -26,6 +26,7 @@ #include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_util.h" #include "content/public/browser/navigation_handle.h" +#include "content/public/browser/preloading_data.h" #include "content/public/common/process_type.h" #include "net/http/http_response_headers.h" #include "services/network/public/cpp/request_destination.h" @@ -136,7 +137,9 @@ const char kHistogramLargestContentfulPaintCrossSiteSubFrame[] = "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2." "CrossSiteSubFrame"; - +const char kHistogramLargestContentfulPaintSetSpeculationRulesPrerender[] = + "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2." + "SetSpeculationRulesPrerender"; const char kHistogramNumInteractions[] = "PageLoad.InteractiveTiming.NumInteractions"; const char kHistogramUserInteractionLatencyHighPercentile2MaxEventDuration[] = @@ -911,30 +914,41 @@ .GetLargestContentfulPaintHandler() .MergeMainFrameAndSubframes(); if (all_frames_largest_contentful_paint.ContainsValidTime()) { + const base::TimeDelta lcp_time = + all_frames_largest_contentful_paint.Time().value(); if (WasStartedInForegroundOptionalEventInForeground( all_frames_largest_contentful_paint.Time(), GetDelegate())) { - EmitLCPTraceEvent(all_frames_largest_contentful_paint.Time().value()); - PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint, - all_frames_largest_contentful_paint.Time().value()); + EmitLCPTraceEvent(lcp_time); + PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint, lcp_time); + + if (content::WebContents* web_contents = GetDelegate().GetWebContents()) { + if (content::PreloadingData* preloading_data = + content::PreloadingData::GetForWebContents(web_contents)) { + if (preloading_data->HasSpeculationRulesPrerender()) { + PAGE_LOAD_HISTOGRAM( + internal:: + kHistogramLargestContentfulPaintSetSpeculationRulesPrerender, + lcp_time); + } + } + } // The pseudo metric of |kHistogramLargestContentfulPaint|. Only used to // assess field trial data quality. PAGE_LOAD_HISTOGRAM( "UMA.Pseudo.PageLoad.PaintTiming.NavigationToLargestContentfulPaint2", - metrics::GetPseudoMetricsSample( - all_frames_largest_contentful_paint.Time().value())); + metrics::GetPseudoMetricsSample(lcp_time)); UMA_HISTOGRAM_ENUMERATION( internal::kHistogramLargestContentfulPaintContentType, all_frames_largest_contentful_paint.TextOrImage()); TRACE_EVENT_MARK_WITH_TIMESTAMP1( "loading", "NavStartToLargestContentfulPaint::AllFrames::UMA", - GetDelegate().GetNavigationStart() + - all_frames_largest_contentful_paint.Time().value(), - "data", all_frames_largest_contentful_paint.DataAsTraceValue()); + GetDelegate().GetNavigationStart() + lcp_time, "data", + all_frames_largest_contentful_paint.DataAsTraceValue()); } else { PAGE_LOAD_HISTOGRAM( internal:: kBackgroundHttpsOrDataOrFileSchemeHistogramLargestContentfulPaint, - all_frames_largest_contentful_paint.Time().value()); + lcp_time); } }
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h index ef82c73..705603d 100644 --- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h +++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
@@ -45,6 +45,8 @@ extern const char kHistogramLargestContentfulPaintMainFrame[]; extern const char kHistogramLargestContentfulPaintMainFrameContentType[]; extern const char kHistogramLargestContentfulPaintCrossSiteSubFrame[]; +extern const char + kHistogramLargestContentfulPaintSetSpeculationRulesPrerender[]; extern const char kHistogramParseBlockedOnScriptLoad[]; extern const char kHistogramParseBlockedOnScriptExecution[];
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc index 9e7d535c..4dcff20 100644 --- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc +++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
@@ -22,6 +22,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/test/navigation_simulator.h" +#include "content/public/test/preloading_test_util.h" #include "content/public/test/test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/common/input/web_mouse_event.h" @@ -156,6 +157,14 @@ .empty()); } + void TestHistogram(const char* name, + std::vector<base::Bucket> buckets, + const base::Location& location = FROM_HERE) { + EXPECT_THAT(tester()->histogram_tester().GetAllSamples(name), + base::BucketsAreArray(buckets)) + << location.ToString(); + } + const base::HistogramTester& histogram_tester() { return tester()->histogram_tester(); } @@ -1709,3 +1718,31 @@ std::vector<std::string>{ base::NumberToString(navigation_id)})); } + +TEST_P(UmaPageLoadMetricsObserverTest, LCPSpeculationRulesPrerender) { + const int kExpected = 4780; + const char* kHistogram = + internal::kHistogramLargestContentfulPaintSetSpeculationRulesPrerender; + + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromSecondsSinceUnixEpoch(1); + timing.paint_timing->largest_contentful_paint->largest_text_paint = + base::Milliseconds(kExpected); + timing.paint_timing->largest_contentful_paint->largest_text_paint_size = 120u; + PopulateRequiredTimingFields(&timing); + + NavigateAndCommit(GURL("https://a.test")); + content::test::SetHasSpeculationRulesPrerender( + content::PreloadingData::GetOrCreateForWebContents(web_contents())); + tester()->SimulateTimingUpdate(timing); + // Navigate again to force histogram recording. + NavigateAndCommit(GURL("https://b.test")); + TestHistogram(kHistogram, {{kExpected, 1}}); + + content::PreloadingData::GetOrCreateForWebContents(web_contents()); + tester()->SimulateTimingUpdate(timing); + // Navigate again to force histogram recording without setting the flag. + NavigateAndCommit(GURL("https://c.test")); + TestHistogram(kHistogram, {{kExpected, 1}}); +}
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml index aeb6406..fa04630 100644 --- a/components/policy/resources/templates/policies.yaml +++ b/components/policy/resources/templates/policies.yaml
@@ -1259,6 +1259,7 @@ 1258: KeyboardFocusableScrollersEnabled 1259: ExtensibleEnterpriseSSOEnabled 1260: CSSCustomStateDeprecatedSyntaxEnabled + 1261: MemorySaverModeSavings atomic_groups: 1: Homepage 2: RemoteAccess
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/MemorySaverModeSavings.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/MemorySaverModeSavings.yaml new file mode 100644 index 0000000..7eac97a --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/MemorySaverModeSavings.yaml
@@ -0,0 +1,42 @@ +caption: Change Memory Saver Mode Savings +default: null +desc: |- + This policy changes the savings level of Memory Saver. + + This only takes effect when Memory Saver is enabled through settings or through the <ph name="HIGH_EFFICIENCY_MODE_ENABLED_POLICY_NAME">HighEfficiencyModeEnabled</ph> policy, and will effect how heuristics are used to determine when to discard tabs. For example, reducing the lifetime of an inactive tab before discarding it can save memory, but it also means that tabs will be reloaded more frequently which can lead to bad user experience and cost more network traffic. + + Setting the policy to 0 - Memory Saver will get moderate memory savings. Tabs become inactive after a longer period of time + + Setting the policy to 1 - Memory Saver will get balanced memory savings. Tabs become inactive after an optimal period of time. + + Setting the policy to 2 - Memory Saver will get maximum memory savings. Tabs become inactive after a shorter period of time. + + If this policy is unset, the end user can control this setting in chrome://settings/performance. +example_value: 0 +features: + dynamic_refresh: true + per_profile: false +items: +- caption: Moderate memory savings. + name: Moderate + value: 0 +- caption: Balanced memory savings. + name: Balanced + value: 1 +- caption: Maximum memory savings. + name: Maximum + value: 2 +owners: +- charlesmeng@chromium.org +- file://chrome/browser/ui/performance_controls/OWNERS +schema: + type: integer + enum: + - 0 + - 1 + - 2 +supported_on: +- chrome.*:126- +- chrome_os:126- +tags: [] +type: int-enum
diff --git a/components/policy/test/data/pref_mapping/MemorySaverModeSavings.json b/components/policy/test/data/pref_mapping/MemorySaverModeSavings.json new file mode 100644 index 0000000..03bbe3c --- /dev/null +++ b/components/policy/test/data/pref_mapping/MemorySaverModeSavings.json
@@ -0,0 +1,20 @@ +[ + { + "os": [ + "win", + "linux", + "mac", + "chromeos_ash" + ], + "simple_policy_pref_mapping_test": { + "pref_name": "performance_tuning.high_efficiency_mode.aggressiveness", + "pref_location": "local_state", + "default_value": 1, + "values_to_test": [ + 0, + 1, + 2 + ] + } + } +]
diff --git a/components/printing/test/print_render_frame_helper_browsertest.cc b/components/printing/test/print_render_frame_helper_browsertest.cc index 7805e781..cd376f71 100644 --- a/components/printing/test/print_render_frame_helper_browsertest.cc +++ b/components/printing/test/print_render_frame_helper_browsertest.cc
@@ -648,12 +648,10 @@ }; PixelCount CheckPixels(const Image& image, uint32_t target_color, - int width, - int top, - int bottom) { + const gfx::Rect& rect) { PixelCount count; - for (int y = top; y < bottom; y++) { - for (int x = 0; x < width; x++) { + for (int y = rect.y(); y < rect.bottom(); y++) { + for (int x = rect.x(); x < rect.right(); x++) { uint32_t pixel = image.pixel_at(x, y); if (pixel == target_color) { count.with_target_color++; @@ -1071,13 +1069,14 @@ ASSERT_EQ(image->size(), gfx::Size(kPageWidth, kPageHeight)); // Look for the blue square in the header area. - PixelCount pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 24); + PixelCount pixel_count = + CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 24, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 24, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); @@ -1088,14 +1087,14 @@ ASSERT_EQ(image->size(), gfx::Size(kPageWidth, kPageHeight)); // Look for the blue square in the header area. - pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 24); + pixel_count = CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. It will be missing, because // the margin isn't large enough. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 21, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 21, kPageWidth, 21)); EXPECT_EQ(pixel_count.with_target_color, 0u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); @@ -1107,13 +1106,13 @@ // Look for the blue square in the header area. It will be missing, because // the margin isn't large enough. - pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 21); + pixel_count = CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 21)); EXPECT_EQ(pixel_count.with_target_color, 0u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 24, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 24, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); } @@ -1181,13 +1180,14 @@ ASSERT_EQ(image->size(), gfx::Size(kPageWidth, kPageHeight)); // Look for the blue square in the header area. - PixelCount pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 24); + PixelCount pixel_count = + CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 24, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 24, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); @@ -1201,14 +1201,14 @@ // particular page is extral large, so there should be room for the header, // even if the margins have been scaled down along with the rest of the page // box. - pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 24); + pixel_count = CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. It shouldn't be there, since // there isn't enough room for it. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 24, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 24, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 0u); // Due to the margin downscaling, the red body background will intersect with // this area. @@ -1223,15 +1223,15 @@ // Look for the blue square in the header area. Even if the specified margins // on this particular page are 0, the page is small and centered on the page, // leaving plenty of space for headers and footers. - pixel_count = CheckPixels(*image, 0x0000ffU, kPageWidth, 0, 24); + pixel_count = CheckPixels(*image, 0x0000ffU, gfx::Rect(0, 0, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); // Look for the yellow square in the footer area. Even if the specified // margins on this particular page are 0, the page is small and centered on // the page, leaving plenty of space for headers and footers. - pixel_count = - CheckPixels(*image, 0xffff00U, kPageWidth, kPageHeight - 24, kPageHeight); + pixel_count = CheckPixels(*image, 0xffff00U, + gfx::Rect(0, kPageHeight - 24, kPageWidth, 24)); EXPECT_EQ(pixel_count.with_target_color, 81u); EXPECT_EQ(pixel_count.unknown_nonwhite, 0u); }
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc index 21d74565..c8cb4b4 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc +++ b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc
@@ -57,8 +57,7 @@ } // namespace // TODO (crbug.com/1408187): Add coverage for all state / input / output keys. -// TODO (crbug.com/340589498): Parameterize tests in this file. -class PrivacySandboxTestUtilTest : public testing::Test { +class PrivacySandboxTestUtilTest { public: PrivacySandboxTestUtilTest() : browser_task_environment_( @@ -78,11 +77,11 @@ /*tpcd_metadata_manager=*/nullptr, "chrome-extension"); } - ~PrivacySandboxTestUtilTest() override { + ~PrivacySandboxTestUtilTest() { host_content_settings_map()->ShutdownOnUIThread(); } - void SetUp() override { + void SetUpPrivacySandboxTest() { auto user_provider = std::make_unique<content_settings::MockProvider>(); user_provider_ = user_provider.get(); auto managed_provider = std::make_unique<content_settings::MockProvider>(); @@ -159,84 +158,177 @@ privacy_sandbox::ScopedPrivacySandboxAttestations scoped_attestations_; }; -TEST_F(PrivacySandboxTestUtilTest, StateKey_M1TopicsEnabledUserPrefValue) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kM1TopicsEnabledUserPrefValue, state); - EXPECT_EQ( - state, - prefs()->GetUserPref(prefs::kPrivacySandboxM1TopicsEnabled)->GetBool()); - } +class PrivacySandboxTestUtilBoolTest : public PrivacySandboxTestUtilTest, + public testing::TestWithParam<bool> { + public: + ~PrivacySandboxTestUtilBoolTest() override = default; + void SetUp() override { SetUpPrivacySandboxTest(); } +}; + +INSTANTIATE_TEST_SUITE_P(PrivacySandboxTestUtilBoolTestInstantiation, + PrivacySandboxTestUtilBoolTest, + testing::ValuesIn<bool>({false, true})); + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyM1TopicsEnabledStateKeySetsPref) { + bool state = GetParam(); + ApplyTestState(StateKey::kM1TopicsEnabledUserPrefValue, state); + EXPECT_EQ( + prefs()->GetUserPref(prefs::kPrivacySandboxM1TopicsEnabled)->GetBool(), + state); } -TEST_F(PrivacySandboxTestUtilTest, StateKey_CookieControlsModeUserPrefValue) { - std::vector<content_settings::CookieControlsMode> states = { - content_settings::CookieControlsMode::kBlockThirdParty, - content_settings::CookieControlsMode::kIncognitoOnly, - content_settings::CookieControlsMode::kOff}; - - for (auto state : states) { - ApplyTestState(StateKey::kCookieControlsModeUserPrefValue, state); - EXPECT_EQ(state, - static_cast<content_settings::CookieControlsMode>( - prefs()->GetUserPref(prefs::kCookieControlsMode)->GetInt())); - } +TEST_P(PrivacySandboxTestUtilBoolTest, + VerifykBlockAll3pcToggleEnabledStateKeySetsPref) { + bool state = GetParam(); + ApplyTestState(StateKey::kBlockAll3pcToggleEnabledUserPrefValue, state); + EXPECT_EQ(prefs()->GetUserPref(prefs::kBlockAll3pcToggleEnabled)->GetBool(), + state); } -TEST_F(PrivacySandboxTestUtilTest, - StateKey_VerifykBlockAll3pcToggleEnabledUserPrefValueSetsPref) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kBlockAll3pcToggleEnabledUserPrefValue, state); - EXPECT_EQ( - state, - prefs()->GetUserPref(prefs::kBlockAll3pcToggleEnabled)->GetBool()); - } +TEST_P(PrivacySandboxTestUtilBoolTest, + VerifykTrackingProtection3pcdEnabledStateKeySetsPref) { + bool state = GetParam(); + ApplyTestState(StateKey::kTrackingProtection3pcdEnabledUserPrefValue, state); + EXPECT_EQ( + prefs()->GetUserPref(prefs::kTrackingProtection3pcdEnabled)->GetBool(), + state); } -TEST_F(PrivacySandboxTestUtilTest, - StateKey_VerifykTrackingProtection3pcdEnabledUserPrefValueSetsPref) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kTrackingProtection3pcdEnabledUserPrefValue, - state); - EXPECT_EQ( - state, - prefs()->GetUserPref(prefs::kTrackingProtection3pcdEnabled)->GetBool()); - } +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyM1FledgeEnabledStateKeySetsPref) { + bool state = GetParam(); + ApplyTestState(StateKey::kM1FledgeEnabledUserPrefValue, state); + EXPECT_EQ( + prefs()->GetUserPref(prefs::kPrivacySandboxM1FledgeEnabled)->GetBool(), + state); } -TEST_F(PrivacySandboxTestUtilTest, StateKey_SiteDataUserDefault) { - std::vector<ContentSetting> states = {CONTENT_SETTING_ALLOW, - CONTENT_SETTING_BLOCK, - CONTENT_SETTING_SESSION_ONLY}; - - for (auto state : states) { - ApplyTestState(StateKey::kSiteDataUserDefault, state); - - // The state should have ended up in the user provider we gave to the util. - auto user_rule_iterator = user_provider()->GetRuleIterator( - ContentSettingsType::COOKIES, - /*incognito=*/false, - content_settings::PartitionKey::GetDefaultForTesting()); - - EXPECT_TRUE(user_rule_iterator->HasNext()); - auto rule = user_rule_iterator->Next(); - EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern); - EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern); - EXPECT_EQ(base::Value(state), rule->value); - - // Nothing should have ended up in the managed provider, which will present - // as a null iterator. - auto managed_rule_iterator = managed_provider()->GetRuleIterator( - ContentSettingsType::COOKIES, - /*incognito=*/false, - content_settings::PartitionKey::GetDefaultForTesting()); - EXPECT_EQ(nullptr, managed_rule_iterator); - } +TEST_P(PrivacySandboxTestUtilBoolTest, + VerifyM1AdMeasurementEnabledStateKeySetsPref) { + bool state = GetParam(); + ApplyTestState(StateKey::kM1AdMeasurementEnabledUserPrefValue, state); + EXPECT_EQ(prefs() + ->GetUserPref(prefs::kPrivacySandboxM1AdMeasurementEnabled) + ->GetBool(), + state); } -TEST_F(PrivacySandboxTestUtilTest, StateKey_SiteDataUserExceptions) { +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyIsIncognitoStateKey) { + bool state = GetParam(); + ApplyTestState(StateKey::kIsIncognito, state); + EXPECT_EQ(mock_delegate()->IsIncognitoProfile(), state); +} + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyIsRestrictedAccountStateKey) { + bool state = GetParam(); + ApplyTestState(StateKey::kIsRestrictedAccount, state); + EXPECT_EQ(mock_delegate()->IsPrivacySandboxRestricted(), state); +} + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyHasCurrentTopicsStateKey) { + bool state = GetParam(); + ApplyTestState(StateKey::kHasCurrentTopics, state); + EXPECT_EQ( + mock_browsing_topics_service()->GetTopTopicsForDisplay().size() > 0u, + state); +} + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyHasBlockedTopicsStateKey) { + bool state = GetParam(); + testing::Mock::VerifyAndClearExpectations(mock_privacy_sandbox_service()); + EXPECT_CALL(*mock_privacy_sandbox_service(), + SetTopicAllowed(testing::_, false)) + .Times(state ? 1 : 0); + ApplyTestState(StateKey::kHasBlockedTopics, state); +} + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyActiveTopicsConsentStateKey) { + bool state = GetParam(); + ApplyTestState(StateKey::kActiveTopicsConsent, state); + EXPECT_EQ( + prefs()->GetUserPref(prefs::kPrivacySandboxTopicsConsentGiven)->GetBool(), + state); +} + +TEST_P(PrivacySandboxTestUtilBoolTest, VerifyTopicsToggleNewValueInputKey) { + bool state = GetParam(); + testing::Mock::VerifyAndClearExpectations(mock_privacy_sandbox_service()); + EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsToggleChanged(state)); + ProvideInput(InputKey::kTopicsToggleNewValue, state); +} + +class PrivacySandboxTestUtilCookieControlsModeTest + : public PrivacySandboxTestUtilTest, + public testing::TestWithParam<content_settings::CookieControlsMode> { + public: + ~PrivacySandboxTestUtilCookieControlsModeTest() override = default; + void SetUp() override { SetUpPrivacySandboxTest(); } +}; + +INSTANTIATE_TEST_SUITE_P( + PrivacySandboxTestUtilCookieControlsModeTestInstantiation, + PrivacySandboxTestUtilCookieControlsModeTest, + testing::ValuesIn<content_settings::CookieControlsMode>( + {content_settings::CookieControlsMode::kBlockThirdParty, + content_settings::CookieControlsMode::kIncognitoOnly, + content_settings::CookieControlsMode::kOff})); + +TEST_P(PrivacySandboxTestUtilCookieControlsModeTest, + VerifyCookieControlsModeStateKeySetsPref) { + content_settings::CookieControlsMode state = GetParam(); + ApplyTestState(StateKey::kCookieControlsModeUserPrefValue, state); + EXPECT_EQ(static_cast<content_settings::CookieControlsMode>( + prefs()->GetUserPref(prefs::kCookieControlsMode)->GetInt()), + state); +} + +class PrivacySandboxTestUtilContentSettingTest + : public PrivacySandboxTestUtilTest, + public testing::TestWithParam<ContentSetting> { + public: + ~PrivacySandboxTestUtilContentSettingTest() override = default; + void SetUp() override { SetUpPrivacySandboxTest(); } +}; + +INSTANTIATE_TEST_SUITE_P(PrivacySandboxTestUtilContentSettingTestInstantiation, + PrivacySandboxTestUtilContentSettingTest, + testing::ValuesIn<ContentSetting>( + {CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK, + CONTENT_SETTING_SESSION_ONLY})); + +TEST_P(PrivacySandboxTestUtilContentSettingTest, + VerifySiteDataUserDefaultStateKey) { + ContentSetting state = GetParam(); + ApplyTestState(StateKey::kSiteDataUserDefault, state); + + // The state should have ended up in the user provider we gave to the util. + auto user_rule_iterator = user_provider()->GetRuleIterator( + ContentSettingsType::COOKIES, + /*incognito=*/false, + content_settings::PartitionKey::GetDefaultForTesting()); + + EXPECT_TRUE(user_rule_iterator->HasNext()); + auto rule = user_rule_iterator->Next(); + EXPECT_EQ(rule->primary_pattern, ContentSettingsPattern::Wildcard()); + EXPECT_EQ(rule->secondary_pattern, ContentSettingsPattern::Wildcard()); + EXPECT_EQ(rule->value, base::Value(state)); + + // Nothing should have ended up in the managed provider, which will present + // as a null iterator. + auto managed_rule_iterator = managed_provider()->GetRuleIterator( + ContentSettingsType::COOKIES, + /*incognito=*/false, + content_settings::PartitionKey::GetDefaultForTesting()); + EXPECT_EQ(managed_rule_iterator, nullptr); +} + +class PrivacySandboxBaseTestUtilTest : public PrivacySandboxTestUtilTest, + public testing::Test { + public: + ~PrivacySandboxBaseTestUtilTest() override = default; + void SetUp() override { SetUpPrivacySandboxTest(); } +}; + +TEST_F(PrivacySandboxBaseTestUtilTest, VerifySiteDataUserExceptionStateKey) { const std::string kException = "https://embedded.com"; ApplyTestState(StateKey::kSiteDataUserExceptions, SiteDataExceptions{{kException, CONTENT_SETTING_BLOCK}}); @@ -249,9 +341,9 @@ EXPECT_TRUE(user_rule_iterator->HasNext()); auto rule = user_rule_iterator->Next(); - EXPECT_EQ(kException, rule->primary_pattern.ToString()); - EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern); - EXPECT_EQ(base::Value(CONTENT_SETTING_BLOCK), rule->value); + EXPECT_EQ(rule->primary_pattern.ToString(), kException); + EXPECT_EQ(rule->secondary_pattern, ContentSettingsPattern::Wildcard()); + EXPECT_EQ(rule->value, base::Value(CONTENT_SETTING_BLOCK)); // Nothing should have ended up in the managed provider, which will present // as a null iterator. @@ -259,93 +351,16 @@ ContentSettingsType::COOKIES, /*incognito=*/false, content_settings::PartitionKey::GetDefaultForTesting()); - EXPECT_EQ(nullptr, managed_rule_iterator); + EXPECT_EQ(managed_rule_iterator, nullptr); } -TEST_F(PrivacySandboxTestUtilTest, StateKey_M1FledgeEnabledUserPrefValue) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kM1FledgeEnabledUserPrefValue, state); - EXPECT_EQ( - state, - prefs()->GetUserPref(prefs::kPrivacySandboxM1FledgeEnabled)->GetBool()); - } -} - -TEST_F(PrivacySandboxTestUtilTest, - StateKey_M1AdMeasurementEnabledUserPrefValue) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kM1AdMeasurementEnabledUserPrefValue, state); - EXPECT_EQ(state, - prefs() - ->GetUserPref(prefs::kPrivacySandboxM1AdMeasurementEnabled) - ->GetBool()); - } -} - -TEST_F(PrivacySandboxTestUtilTest, StateKey_IsIncognito) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kIsIncognito, state); - EXPECT_EQ(state, mock_delegate()->IsIncognitoProfile()); - } -} - -TEST_F(PrivacySandboxTestUtilTest, StateKey_IsRestrictedAccount) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kIsRestrictedAccount, state); - EXPECT_EQ(state, mock_delegate()->IsPrivacySandboxRestricted()); - } -} - -TEST_F(PrivacySandboxTestUtilTest, StateKey_HasCurrentTopics) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - ApplyTestState(StateKey::kHasCurrentTopics, state); - EXPECT_GT(mock_browsing_topics_service()->GetTopTopicsForDisplay().size(), - 0u); - } -} - -TEST_F(PrivacySandboxTestUtilTest, StateKey_HasBlockedTopics) { - std::vector<bool> states = {true, false}; - for (auto state : states) { - testing::Mock::VerifyAndClearExpectations(mock_privacy_sandbox_service()); - EXPECT_CALL(*mock_privacy_sandbox_service(), - SetTopicAllowed(testing::_, false)) - .Times(state ? 1 : 0); - ApplyTestState(StateKey::kHasBlockedTopics, state); - } -} - -TEST_F(PrivacySandboxTestUtilTest, StateKey_AdvanceClockBy) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyAdvanceClockByStateKey) { base::Time start_time = base::Time::Now(); ApplyTestState(StateKey::kAdvanceClockBy, base::Hours(1)); EXPECT_EQ(start_time + base::Hours(1), base::Time::Now()); } -TEST_F(PrivacySandboxTestUtilTest, StateKey_ActiveTopicsConsent) { - std::vector<bool> states = {true, false}; - for (bool state : states) { - ApplyTestState(StateKey::kActiveTopicsConsent, state); - EXPECT_EQ(state, prefs() - ->GetUserPref(prefs::kPrivacySandboxTopicsConsentGiven) - ->GetBool()); - } -} - -TEST_F(PrivacySandboxTestUtilTest, InputKey_TopicsToggleNewValue) { - std::vector<bool> states = {true, false}; - for (bool state : states) { - testing::Mock::VerifyAndClearExpectations(mock_privacy_sandbox_service()); - EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsToggleChanged(state)); - ProvideInput(InputKey::kTopicsToggleNewValue, state); - } -} - -TEST_F(PrivacySandboxTestUtilTest, InputKey_PromptActionOccurred) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyPromptActionOccurredInputKey) { constexpr int kArbitraryValue = 7; testing::Mock::VerifyAndClearExpectations(mock_privacy_sandbox_service()); EXPECT_CALL(*mock_privacy_sandbox_service(), @@ -353,7 +368,8 @@ ProvideInput(InputKey::kPromptAction, kArbitraryValue); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsTopicsAllowedForContext) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsTopicsAllowedForContextOutputKey) { GURL kTopicsURL = GURL("https://topics.com"); EXPECT_CALL(*mock_privacy_sandbox_settings(), @@ -365,13 +381,13 @@ {OutputKey::kIsTopicsAllowedForContext, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsTopicsAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyIsTopicsAllowedOutputKey) { EXPECT_CALL(*mock_privacy_sandbox_settings(), IsTopicsAllowed()) .WillOnce(testing::Return(true)); CheckOutput({}, {OutputKey::kIsTopicsAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsFledgeAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyIsFledgeAllowedOutputKey) { url::Origin kFledgeAuctionPartyOrigin = url::Origin::Create(GURL("https://fledge.com")); @@ -386,7 +402,8 @@ {OutputKey::kIsFledgeJoinAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsAttributionReportingAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsAttributionReportingAllowedOutputKey) { url::Origin kAdMeasurementReportingOrigin = url::Origin::Create(GURL("https://measurement.com")); @@ -401,7 +418,8 @@ {OutputKey::kIsAttributionReportingAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_MaySendAttributionReport) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyMaySendAttributionReportOutputKey) { url::Origin kAdMeasurementSourceOrigin = url::Origin::Create(GURL("https://source.com")); url::Origin kAdMeasurementDestinationOrigin = @@ -423,7 +441,7 @@ {OutputKey::kMaySendAttributionReport, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsSharedStorageAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyIsSharedStorageAllowedOutputKey) { EXPECT_CALL( *mock_privacy_sandbox_settings(), IsSharedStorageAllowed(TopFrameOrigin(), AccessingOrigin(), @@ -437,7 +455,8 @@ {OutputKey::kIsSharedStorageAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsSharedStorageSelectURLAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsSharedStorageSelectURLAllowedOutputKey) { EXPECT_CALL(*mock_privacy_sandbox_settings(), IsSharedStorageSelectURLAllowed( TopFrameOrigin(), AccessingOrigin(), @@ -450,7 +469,8 @@ {OutputKey::kIsSharedStorageSelectURLAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_IsPrivateAggregationAllowed) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsPrivateAggregationAllowedOutputKey) { url::Origin kAdMeasurementReportingOrigin = url::Origin::Create(GURL("https://reporting.com")); @@ -466,13 +486,14 @@ {OutputKey::kIsPrivateAggregationAllowed, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_TopicsConsentGiven) { +TEST_F(PrivacySandboxBaseTestUtilTest, VerifyTopicsConsentGivenOutputKey) { EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsHasActiveConsent()) .WillOnce(testing::Return(true)); CheckOutput({}, {OutputKey::kTopicsConsentGiven, true}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_TopicsConsentLastUpdateReason) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyTopicsConsentLastUpdateReasonOutputKey) { EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsConsentLastUpdateSource()) .WillOnce(testing::Return( privacy_sandbox::TopicsConsentUpdateSource::kSettings)); @@ -480,14 +501,16 @@ privacy_sandbox::TopicsConsentUpdateSource::kSettings}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_TopicsConsentLastUpdateTime) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyTopicsConsentLastUpdateTimeOutputKey) { auto consent_time = base::Time::Now() - base::Hours(1); EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsConsentLastUpdateTime()) .WillOnce(testing::Return(consent_time)); CheckOutput({}, {OutputKey::kTopicsConsentLastUpdateTime, consent_time}); } -TEST_F(PrivacySandboxTestUtilTest, OutputKey_TopicsConsentStringIdentifiers) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyTopicsConsentStringIdentifiersOutputKey) { auto identifier = IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_CANONICAL; EXPECT_CALL(*mock_privacy_sandbox_service(), TopicsConsentLastUpdateText()) @@ -497,8 +520,8 @@ std::vector<int>{identifier}}); } -TEST_F(PrivacySandboxTestUtilTest, - OutputKey_IsSharedStorageAllowedDebugMessage) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsSharedStorageAllowedDebugMessageOutputKey) { std::string actual_out_debug_message; EXPECT_CALL( *mock_privacy_sandbox_settings(), @@ -519,8 +542,8 @@ &expected_out_debug_message}); } -TEST_F(PrivacySandboxTestUtilTest, - OutputKey_IsSharedStorageSelectURLAllowedDebugMessage) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsSharedStorageSelectURLAllowedDebugMessageOutputKey) { std::string actual_out_debug_message; EXPECT_CALL(*mock_privacy_sandbox_settings(), IsSharedStorageSelectURLAllowed( @@ -540,8 +563,8 @@ &expected_out_debug_message}); } -TEST_F(PrivacySandboxTestUtilTest, - OutputKey_IsSharedStorageBlockSiteSettingSpecific) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsSharedStorageBlockSiteSettingSpecificOutputKey) { bool actual_out_block_is_site_setting_specific = true; EXPECT_CALL( *mock_privacy_sandbox_settings(), @@ -564,8 +587,8 @@ &expected_out_block_is_site_setting_specific}); } -TEST_F(PrivacySandboxTestUtilTest, - OutputKey_IsSharedStorageSelectURLBlockSiteSettingSpecific) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsSharedStorageSelectURLBlockSiteSettingSpecificOutputKey) { bool actual_out_block_is_site_setting_specific = true; EXPECT_CALL(*mock_privacy_sandbox_settings(), IsSharedStorageSelectURLAllowed( @@ -587,8 +610,8 @@ &expected_out_block_is_site_setting_specific}); } -TEST_F(PrivacySandboxTestUtilTest, - OutputKey_IsPrivateAggregationBlockSiteSettingSpecific) { +TEST_F(PrivacySandboxBaseTestUtilTest, + VerifyIsPrivateAggregationBlockSiteSettingSpecificOutputKey) { bool actual_out_block_is_site_setting_specific = true; EXPECT_CALL( *mock_privacy_sandbox_settings(),
diff --git a/components/reporting/client/report_queue_impl.cc b/components/reporting/client/report_queue_impl.cc index 898278c..f7be577 100644 --- a/components/reporting/client/report_queue_impl.cc +++ b/components/reporting/client/report_queue_impl.cc
@@ -35,6 +35,7 @@ #include "components/reporting/proto/synced/record.pb.h" #include "components/reporting/proto/synced/record_constants.pb.h" #include "components/reporting/storage/storage_module_interface.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/reporting/util/statusor.h" @@ -318,6 +319,10 @@ if (!self) { std::move(callback).Run( Status(error::UNAVAILABLE, "Queue has been destructed")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::REPORT_QUEUE_DESTRUCTED, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); @@ -404,6 +409,10 @@ if (!self) { std::move(callback).Run( Status(error::UNAVAILABLE, "Queue has been destructed")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::REPORT_QUEUE_DESTRUCTED, + UnavailableErrorReason::MAX_VALUE); return; } std::move(callback).Run(status);
diff --git a/components/reporting/client/report_queue_provider.cc b/components/reporting/client/report_queue_provider.cc index 246a878..cbb721b4 100644 --- a/components/reporting/client/report_queue_provider.cc +++ b/components/reporting/client/report_queue_provider.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" +#include "base/metrics/histogram_functions.h" #include "base/sequence_checker.h" #include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" @@ -26,6 +27,7 @@ #include "components/reporting/client/report_queue_impl.h" #include "components/reporting/proto/synced/record_constants.pb.h" #include "components/reporting/storage/storage_module_interface.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/reporting/util/status_macros.h" #include "components/reporting/util/statusor.h" @@ -151,6 +153,10 @@ if (!provider) { std::move(cb).Run(base::unexpected( Status(error::UNAVAILABLE, "Provider has been shut down"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::REPORT_QUEUE_PROVIDER_DESTRUCTED, + UnavailableErrorReason::MAX_VALUE); return; } // Configure report queue config with an appropriate DM token and @@ -278,6 +284,10 @@ std::move(report_queue_request->release_create_cb()) .Run(base::unexpected( Status(error::UNAVAILABLE, "Unable to build a ReportQueue"))); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::UNABLE_TO_BUILD_REPORT_QUEUE, + UnavailableErrorReason::MAX_VALUE); create_request_queue_.pop(); } return;
diff --git a/components/reporting/storage/storage_queue.cc b/components/reporting/storage/storage_queue.cc index 2aa472f..be54092 100644 --- a/components/reporting/storage/storage_queue.cc +++ b/components/reporting/storage/storage_queue.cc
@@ -54,6 +54,7 @@ #include "components/reporting/storage/storage_uploader_interface.h" #include "components/reporting/util/file.h" #include "components/reporting/util/refcounted_closure_list.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" #include "components/reporting/util/status_macros.h" #include "components/reporting/util/statusor.h" @@ -235,6 +236,10 @@ // Make sure the assigned directory exists. base::File::Error error; if (!base::CreateDirectoryAndGetError(options_.directory(), &error)) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FAILED_TO_CREATE_STORAGE_QUEUE_DIRECTORY, + UnavailableErrorReason::MAX_VALUE); return Status( error::UNAVAILABLE, base::StrCat( @@ -932,6 +937,10 @@ void OnStart() override { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -948,6 +957,10 @@ void PrepareDataFiles() { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1015,6 +1028,10 @@ void BeginUploading() { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1040,6 +1057,10 @@ void StartUploading() { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1107,6 +1128,10 @@ if (!storage_queue_) { std::move(completion_cb_) .Run(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); files_.clear(); current_file_ = files_.end(); return; @@ -1128,6 +1153,10 @@ void CallCurrentRecord(std::string_view blob) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1163,6 +1192,10 @@ ScopedReservation scoped_reservation) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1188,6 +1221,10 @@ void CallGapUpload(uint64_t count) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1215,6 +1252,10 @@ void NextRecord(bool more_records) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1242,6 +1283,10 @@ // not match), returns error. StatusOr<std::string_view> EnsureBlob(int64_t sequencing_id) { if (!storage_queue_) { + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return base::unexpected( Status(error::UNAVAILABLE, "StorageQueue shut down")); } @@ -1328,6 +1373,10 @@ void CallRecordOrGap(int64_t sequencing_id) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1363,6 +1412,10 @@ void InstantiateUploader(base::OnceCallback<void()> continuation) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -1393,6 +1446,10 @@ StatusOr<std::unique_ptr<UploaderInterface>> uploader_result) { if (!storage_queue_) { Response(Status(error::UNAVAILABLE, "StorageQueue shut down")); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::STORAGE_QUEUE_SHUTDOWN, + UnavailableErrorReason::MAX_VALUE); return; } DCHECK_CALLED_ON_VALID_SEQUENCE( @@ -2295,6 +2352,9 @@ bool expect_readonly) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!handle_) { + base::UmaHistogramEnumeration(reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_NOT_OPEN, + UnavailableErrorReason::MAX_VALUE); return base::unexpected( Status(error::UNAVAILABLE, base::StrCat({"File not open ", name()}))); } @@ -2382,6 +2442,9 @@ StatusOr<uint32_t> StorageQueue::SingleFile::Append(std::string_view data) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!handle_) { + base::UmaHistogramEnumeration(reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::FILE_NOT_OPEN, + UnavailableErrorReason::MAX_VALUE); return base::unexpected( Status(error::UNAVAILABLE, base::StrCat({"File not open ", name()}))); }
diff --git a/components/reporting/util/BUILD.gn b/components/reporting/util/BUILD.gn index c68a9f22..6c898f6 100644 --- a/components/reporting/util/BUILD.gn +++ b/components/reporting/util/BUILD.gn
@@ -29,6 +29,7 @@ static_library("status") { sources = [ + "reporting_errors.h", "status.cc", "status.h", "statusor.cc",
diff --git a/components/reporting/util/disconnectable_client.cc b/components/reporting/util/disconnectable_client.cc index 948c5d7..257dd1e 100644 --- a/components/reporting/util/disconnectable_client.cc +++ b/components/reporting/util/disconnectable_client.cc
@@ -12,8 +12,10 @@ #include "base/logging.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" +#include "components/reporting/util/reporting_errors.h" #include "components/reporting/util/status.h" namespace reporting { @@ -33,6 +35,10 @@ if (!is_available_) { delegate->Respond(Status(error::UNAVAILABLE, disconnectable_client::kErrorServiceUnavailable)); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::CLIENT_NOT_CONNECTED_TO_MISSIVE, + UnavailableErrorReason::MAX_VALUE); return; } // Add the delegate to the map. @@ -71,6 +77,10 @@ // Respond through the |delegate|. delegate->Respond(Status( error::UNAVAILABLE, disconnectable_client::kErrorServiceUnavailable)); + base::UmaHistogramEnumeration( + reporting::kUmaUnavailableErrorReason, + UnavailableErrorReason::CLIENT_NOT_CONNECTED_TO_MISSIVE, + UnavailableErrorReason::MAX_VALUE); } } }
diff --git a/components/reporting/util/reporting_errors.h b/components/reporting/util/reporting_errors.h new file mode 100644 index 0000000..2567d60a --- /dev/null +++ b/components/reporting/util/reporting_errors.h
@@ -0,0 +1,44 @@ +// 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 COMPONENTS_REPORTING_UTIL_REPORTING_ERRORS_H_ +#define COMPONENTS_REPORTING_UTIL_REPORTING_ERRORS_H_ + +namespace reporting { + +inline constexpr char kUmaUnavailableErrorReason[] = + "Browser.ERP.UnavailableErrorReason"; + +// These enum values represent the different error messages associated with +// usages of `error::UNAVAILABLE` in Chrome. Anytime `error::UNAVAILABLE` is +// used, it should be UMA logged using this enum and +// kUmaUnavailableErrorReason. +// +// Update `UnavailableErrorReasonBrowser` in +// tools/metrics/histograms/metadata/browser/enums.xml when adding new values +// to this enum. +// +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class UnavailableErrorReason { + CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_BROWSER = 0, + CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_PROFILE = 1, + CLIENT_NOT_CONNECTED_TO_MISSIVE = 2, + DEVICE_DM_TOKEN_NOT_SET = 3, + FAILED_TO_CREATE_STORAGE_QUEUE_DIRECTORY = 4, + FILE_NOT_OPEN = 5, + FILE_UPLOAD_DELEGATE_IS_NULL = 6, + FILE_UPLOAD_JOB_DELEGATE_IS_NULL = 7, + REPORTING_CLIENT_IS_NULL = 8, + REPORT_QUEUE_DESTRUCTED = 9, + REPORT_QUEUE_IS_NULL = 10, + REPORT_QUEUE_PROVIDER_DESTRUCTED = 11, + STORAGE_QUEUE_SHUTDOWN = 12, + UNABLE_TO_BUILD_REPORT_QUEUE = 13, + UPLOAD_PROVIDER_IS_NULL = 14, + MAX_VALUE +}; +} // namespace reporting + +#endif // COMPONENTS_REPORTING_UTIL_REPORTING_ERRORS_H_
diff --git a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafeBrowsingApiBridge.java b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafeBrowsingApiBridge.java index 596aa211..2f68b73 100644 --- a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafeBrowsingApiBridge.java +++ b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafeBrowsingApiBridge.java
@@ -214,6 +214,13 @@ callbackId, resultStatus, metadata, checkDelta); } } + + @Override + public void onVerifyAppsEnabledDone(long callbackId, int result) { + synchronized (sSafetyNetApiHandlerLock) { + SafeBrowsingApiBridgeJni.get().onVerifyAppsEnabledDone(callbackId, result); + } + } } private static class SafeBrowsingApiLookupDoneObserver @@ -321,6 +328,34 @@ } } + /** + * Check if app verification is enabled through the SafetyNet API. + * + * <p>Must only be called if {@link #ensureSafetyNetApiInitialized()} returns true. + */ + @CalledByNative + public static void isVerifyAppsEnabled(long callbackId) { + synchronized (sSafetyNetApiHandlerLock) { + assert sSafetyNetApiHandlerInitCalled; + assert sSafetyNetApiHandler != null; + sSafetyNetApiHandler.isVerifyAppsEnabled(callbackId); + } + } + + /** + * Prompt the user to enable app verification through the SafetyNet API. + * + * <p>Must only be called if {@link #ensureSafetyNetApiInitialized()} returns true. + */ + @CalledByNative + public static void enableVerifyApps(long callbackId) { + synchronized (sSafetyNetApiHandlerLock) { + assert sSafetyNetApiHandlerInitCalled; + assert sSafetyNetApiHandler != null; + sSafetyNetApiHandler.enableVerifyApps(callbackId); + } + } + @NativeMethods interface Natives { void onUrlCheckDoneBySafetyNetApi( @@ -333,5 +368,7 @@ int[] threatAttributes, int responseStatus, long checkDelta); + + void onVerifyAppsEnabledDone(long callbackId, int result); } }
diff --git a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java index 7dbab4a..c56cde9 100644 --- a/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java +++ b/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java
@@ -23,9 +23,7 @@ String metadata, long checkDelta); - // TODO(crbug.com/341790041): Remove the default implementation - // here since it's not suitable for production use. - default void onVerifyAppsEnabledDone(long callbackId, @VerifyAppsResult int result) {} + void onVerifyAppsEnabledDone(long callbackId, @VerifyAppsResult int result); } // Possible values for resultStatus. Native side has the same definitions.
diff --git a/components/safe_browsing/android/native_java_unittests/src/org/chromium/components/safe_browsing/SafeBrowsingApiHandlerBridgeNativeUnitTestHelper.java b/components/safe_browsing/android/native_java_unittests/src/org/chromium/components/safe_browsing/SafeBrowsingApiHandlerBridgeNativeUnitTestHelper.java index 953cc9c..a9bec2e3a 100644 --- a/components/safe_browsing/android/native_java_unittests/src/org/chromium/components/safe_browsing/SafeBrowsingApiHandlerBridgeNativeUnitTestHelper.java +++ b/components/safe_browsing/android/native_java_unittests/src/org/chromium/components/safe_browsing/SafeBrowsingApiHandlerBridgeNativeUnitTestHelper.java
@@ -31,6 +31,9 @@ private static final long DEFAULT_CHECK_DELTA_MS = 10; // See safe_browsing_handler_util.h --> JavaThreatTypes private static final int THREAT_TYPE_CSD_ALLOWLIST = 16; + // The result that will be returned in {@link #isVerifyAppsEnabled(long)} or {@link + // #enableVerifyApps(long)}. + private static int sVerifyAppsResult = VerifyAppsResult.FAILED; // Maps to store preset values, keyed by uri. private static final Map<String, Boolean> sCsdAllowlistMap = new HashMap<>(); @@ -67,6 +70,16 @@ return Boolean.TRUE.equals(sCsdAllowlistMap.get(uri)); } + @Override + public void isVerifyAppsEnabled(final long callbackId) { + mObserver.onVerifyAppsEnabledDone(callbackId, sVerifyAppsResult); + } + + @Override + public void enableVerifyApps(final long callbackId) { + mObserver.onVerifyAppsEnabledDone(callbackId, sVerifyAppsResult); + } + public static void tearDown() { sThreatsOfInterestMap.clear(); sMetadataMap.clear(); @@ -89,6 +102,10 @@ public static void setResult(int result) { sResult = result; } + + public static void setVerifyAppsResult(int result) { + sVerifyAppsResult = result; + } } /** @@ -266,4 +283,9 @@ static long getSafeBrowsingApiUrlCheckTimeObserverResult() { return sSafeBrowsingApiUrlCheckTimeObserver.getCapturedUrlCheckTimeDeltaMicros(); } + + @CalledByNative + static void setVerifyAppsResult(int result) { + MockSafetyNetApiHandler.setVerifyAppsResult(result); + } }
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc b/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc index 9f083e09..8aa9b8b 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc +++ b/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
@@ -422,6 +422,19 @@ return *pending_safe_browsing_callbacks; } +using PendingVerifyAppsCallbacksMap = std::unordered_map< + jlong, + SafeBrowsingApiHandlerBridge::VerifyAppsResponseCallback>; +PendingVerifyAppsCallbacksMap& GetPendingVerifyAppsCallbacks() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // Holds the list of callback objects that we are currently waiting to hear + // the result of from GmsCore. + // The key is a unique count-up integer. + static base::NoDestructor<PendingVerifyAppsCallbacksMap> pending_callbacks; + return *pending_callbacks; +} + bool StartAllowlistCheck(const GURL& url, const SBThreatType& sb_threat_type) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); @@ -614,6 +627,30 @@ response_status, check_delta_microseconds)); } +void OnVerifyAppsEnabledDone(jlong callback_id, jint j_result) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + PendingVerifyAppsCallbacksMap& pending_callbacks = + GetPendingVerifyAppsCallbacks(); + bool found = base::Contains(pending_callbacks, callback_id); + DCHECK(found) << "Not found in pending_verify_apps_callbacks: " + << callback_id; + if (!found) { + return; + } + + SafeBrowsingApiHandlerBridge::VerifyAppsResponseCallback callback = + std::move(pending_callbacks[callback_id]); + std::move(callback).Run(static_cast<VerifyAppsEnabledResult>(j_result)); +} + +void JNI_SafeBrowsingApiBridge_OnVerifyAppsEnabledDone(JNIEnv* env, + jlong callback_id, + jint j_result) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&OnVerifyAppsEnabledDone, callback_id, j_result)); +} + // // SafeBrowsingApiHandlerBridge // @@ -731,6 +768,31 @@ url, safe_browsing::SBThreatType::SB_THREAT_TYPE_CSD_ALLOWLIST); } +void SafeBrowsingApiHandlerBridge::StartIsVerifyAppsEnabled( + VerifyAppsResponseCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + JNIEnv* env = AttachCurrentThread(); + if (!Java_SafeBrowsingApiBridge_ensureSafetyNetApiInitialized(env)) { + std::move(callback).Run(VerifyAppsEnabledResult::FAILED); + } + + jlong callback_id = next_verify_apps_callback_id_++; + GetPendingVerifyAppsCallbacks().insert({callback_id, std::move(callback)}); + Java_SafeBrowsingApiBridge_isVerifyAppsEnabled(env, callback_id); +} +void SafeBrowsingApiHandlerBridge::StartEnableVerifyApps( + VerifyAppsResponseCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + JNIEnv* env = AttachCurrentThread(); + if (!Java_SafeBrowsingApiBridge_ensureSafetyNetApiInitialized(env)) { + std::move(callback).Run(VerifyAppsEnabledResult::FAILED); + } + + jlong callback_id = next_verify_apps_callback_id_++; + GetPendingVerifyAppsCallbacks().insert({callback_id, std::move(callback)}); + Java_SafeBrowsingApiBridge_enableVerifyApps(env, callback_id); +} + void SafeBrowsingApiHandlerBridge::OnSafeBrowsingApiNonRecoverableFailure() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_bridge.h b/components/safe_browsing/android/safe_browsing_api_handler_bridge.h index 67d061f..28a2c54 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler_bridge.h +++ b/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
@@ -26,6 +26,8 @@ public: using ResponseCallback = base::OnceCallback<void(SBThreatType, const ThreatMetadata&)>; + using VerifyAppsResponseCallback = + base::OnceCallback<void(VerifyAppsEnabledResult)>; SafeBrowsingApiHandlerBridge() = default; @@ -51,6 +53,14 @@ bool StartCSDAllowlistCheck(const GURL& url); + // Query whether app verification is enabled. Will run `callback` with + // the result of the query. + void StartIsVerifyAppsEnabled(VerifyAppsResponseCallback callback); + + // Prompt the user to enable app verification. Will run `callback` + // with the result of the query. + void StartEnableVerifyApps(VerifyAppsResponseCallback callback); + // Called when a non-recoverable failure is encountered from SafeBrowsing API. void OnSafeBrowsingApiNonRecoverableFailure(); @@ -83,6 +93,10 @@ // reputation from GmsCore SafeBrowsing API. jlong next_safe_browsing_callback_id_ = 0; + // Used as a key to identify unique requests sent to Java related to + // SafetyNet app verification. + jlong next_verify_apps_callback_id_ = 0; + // Whether SafeBrowsing API is available. Set to false if previous call to // SafeBrowsing API has encountered a non-recoverable failure. If set to // false, future calls to SafeBrowsing API will fall back to SafetyNet API.
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_bridge_unittest.cc b/components/safe_browsing/android/safe_browsing_api_handler_bridge_unittest.cc index 2519a07..d674889 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler_bridge_unittest.cc +++ b/components/safe_browsing/android/safe_browsing_api_handler_bridge_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" #include "components/safe_browsing/android/native_j_unittests_jni_headers/SafeBrowsingApiHandlerBridgeNativeUnitTestHelper_jni.h" #include "components/safe_browsing/android/safe_browsing_api_handler_util.h" #include "components/safe_browsing/core/browser/db/util.h" @@ -136,6 +137,11 @@ static_cast<int>(returned_response_status)); } + void SetVerifyAppsResult(VerifyAppsEnabledResult result) { + Java_SafeBrowsingApiHandlerBridgeNativeUnitTestHelper_setVerifyAppsResult( + env_, static_cast<int>(result)); + } + void RunHashDatabaseUrlCheck( const GURL& url, const SBThreatTypeSet& threat_types, @@ -817,6 +823,22 @@ /*expected_threat_type=*/SB_THREAT_TYPE_SAFE); } +TEST_F(SafeBrowsingApiHandlerBridgeTest, IsVerifyAppsEnabled) { + SetVerifyAppsResult(VerifyAppsEnabledResult::SUCCESS_ENABLED); + base::test::TestFuture<VerifyAppsEnabledResult> result_future; + SafeBrowsingApiHandlerBridge::GetInstance().StartIsVerifyAppsEnabled( + result_future.GetCallback()); + EXPECT_EQ(result_future.Get(), VerifyAppsEnabledResult::SUCCESS_ENABLED); +} + +TEST_F(SafeBrowsingApiHandlerBridgeTest, EnableVerifyApps) { + SetVerifyAppsResult(VerifyAppsEnabledResult::TIMEOUT); + base::test::TestFuture<VerifyAppsEnabledResult> result_future; + SafeBrowsingApiHandlerBridge::GetInstance().StartEnableVerifyApps( + result_future.GetCallback()); + EXPECT_EQ(result_future.Get(), VerifyAppsEnabledResult::TIMEOUT); +} + class SafeBrowsingApiHandlerBridgeNewGmsApiDisabledTest : public SafeBrowsingApiHandlerBridgeTest { public:
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_util.h b/components/safe_browsing/android/safe_browsing_api_handler_util.h index 92e49860..4e4b7d5 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler_util.h +++ b/components/safe_browsing/android/safe_browsing_api_handler_util.h
@@ -125,6 +125,17 @@ MAX_VALUE }; +// LINT.IfChange +// The result of either SafetyNet.isVerifyAppsEnabled or +// SafetyNet.enableVerifyApps. +enum class VerifyAppsEnabledResult { + SUCCESS_ENABLED = 0, + SUCCESS_NOT_ENABLED = 1, + TIMEOUT = 2, + FAILED = 3, +}; +// LINT.ThenChange(/components/safe_browsing/android/java/src/org/chromium/components/safe_browsing/SafetyNetApiHandler.java) + // This parses the JSON from the GMSCore API and then: // 1) Picks the most severe threat type // 2) Parses that threat's key/value pairs into the metadata struct.
diff --git a/components/safe_browsing/content/browser/client_side_detection_host.cc b/components/safe_browsing/content/browser/client_side_detection_host.cc index a1ee0c3..ccff81a26 100644 --- a/components/safe_browsing/content/browser/client_side_detection_host.cc +++ b/components/safe_browsing/content/browser/client_side_detection_host.cc
@@ -73,7 +73,12 @@ const char kCsdDebugFeatureDirectoryFlag[] = "csd-debug-feature-directory"; const char kSkipCSDAllowlistOnPreclassification[] = "safe-browsing-skip-csd-allowlist"; -const float kProbabilityForSendingSampleRequest = 0.0001; + +// Probability value used to sample pings on CSD allowlist match. For other safe +// browsing countermeasures, we sample at 1 in 100 rate, but in this, we hit the +// allowlist 1000 times more than the rate at which we send a ping due to local +// model verdict. Therefore, we sample at 1 in 100,000 rate instead. +const float kProbabilityForSendingSampleRequest = 0.00001; void WriteFeaturesToDisk(const ClientPhishingRequest& features, const base::FilePath& base_path) {
diff --git a/components/sync/protocol/nigori_specifics.proto b/components/sync/protocol/nigori_specifics.proto index 673762a..86cf2ba5 100644 --- a/components/sync/protocol/nigori_specifics.proto +++ b/components/sync/protocol/nigori_specifics.proto
@@ -77,6 +77,9 @@ // Evaluation group for the first eligibility criteria (Android device // with LSKF, Gaia PWD public key & between 5 and 50 passwords). ANDROID_LSKF_GAIA_PASSWORD_5_50_PASSWORDS_EVALUATION = 2; + // Cohort of users used to validate metrics analysis strategy by comparing + // metrics posted by users within CONTROL and VALIDATION groups. + CONTROL_AND_VALIDATION_MARKING_EXERCISE = 3; } // ID of cohort account belongs to. Only use IDs defined within enum |Cohort|.
diff --git a/components/variations/variations_layers.cc b/components/variations/variations_layers.cc index 4bc828390..8864428 100644 --- a/components/variations/variations_layers.cc +++ b/components/variations/variations_layers.cc
@@ -6,9 +6,11 @@ #include <stddef.h> #include <stdint.h> + #include <cstdint> #include <memory> #include <optional> +#include <set> #include <type_traits> #include "base/check_op.h" @@ -145,6 +147,17 @@ } } +bool AreLayerMemberIDsUnique(const Layer& layer_proto) { + std::set<uint32_t> member_ids; + for (const auto& member : layer_proto.members()) { + if (member_ids.contains(member.id())) { + return false; + } + member_ids.insert(member.id()); + } + return true; +} + } // namespace VariationsLayers::VariationsLayers(const VariationsSeed& seed, @@ -352,6 +365,11 @@ return; } + if (!AreLayerMemberIDsUnique(layer_proto)) { + LogInvalidLayerReason(InvalidLayerReason::kDuplicatedLayerMemberID); + return; + } + if (!AreSlotBoundsValid(layer_proto)) { LogInvalidLayerReason(InvalidLayerReason::kInvalidSlotBounds); return;
diff --git a/components/variations/variations_layers.h b/components/variations/variations_layers.h index 596130e..793704b 100644 --- a/components/variations/variations_layers.h +++ b/components/variations/variations_layers.h
@@ -29,7 +29,8 @@ kUnknownFields = 6, LayerIDNotUnique = 7, kLimitedLayerDropped = 8, - kMaxValue = kLimitedLayerDropped, + kDuplicatedLayerMemberID = 9, + kMaxValue = kDuplicatedLayerMemberID, }; // A view over the layers defined within a variations seed.
diff --git a/components/variations/variations_layers_unittest.cc b/components/variations/variations_layers_unittest.cc index 90e57aa..916341fb 100644 --- a/components/variations/variations_layers_unittest.cc +++ b/components/variations/variations_layers_unittest.cc
@@ -329,6 +329,42 @@ EXPECT_FALSE(VariationsLayers::AreSlotBoundsValid(layer)); } +TEST_F(VariationsLayersTest, UniqueLayerMemberIDs) { + const auto layer = + CreateLayer({.id = 1u, + .num_slots = 10u, + .entropy_mode = Layer::DEFAULT, + .layer_members = {{.id = 1u, .start = 0u, .end = 4u}, + {.id = 2u, .start = 5u, .end = 9u}}}); + auto seed = CreateSeed({.layers = {layer}, .studies = {}}); + + VariationsLayers layers(seed, entropy_providers_); + + // One of the two layer members must be active since together they are + // covering all slots. + EXPECT_TRUE(layers.IsLayerMemberActive(1u, 1u) || + layers.IsLayerMemberActive(1u, 2u)); + histogram_tester_.ExpectTotalCount("Variations.InvalidLayerReason", 0); +} + +TEST_F(VariationsLayersTest, DuplicatedLayerMemberIDs) { + // There are two layer members with ID=1 in this layer. + const auto layer = + CreateLayer({.id = 1u, + .num_slots = 10u, + .entropy_mode = Layer::DEFAULT, + .layer_members = {{.id = 1u, .start = 0u, .end = 4u}, + {.id = 1u, .start = 5u, .end = 9u}}}); + auto seed = CreateSeed({.layers = {layer}, .studies = {}}); + + VariationsLayers layers(seed, entropy_providers_); + + EXPECT_FALSE(layers.IsLayerMemberActive(1u, 1u)); + const int expected_bucket = 9; // kDuplicatedLayerMemberID + histogram_tester_.ExpectUniqueSample("Variations.InvalidLayerReason", + expected_bucket, 1); +} + TEST_F(VariationsLayersTest, LowEntropyStudy) { Study study = CreateTwoArmStudy(Study_Consistency_PERMANENT); AddGoogleExperimentIds(&study);
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index 91f0435..8403204 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -2103,12 +2103,12 @@ cc::PaintFlags green_flags; green_flags.setColor(SkColors::kGreen); - auto blue_recording = cc::FakeRecordingSource::Create(quad_rect_.size()); - blue_recording->add_draw_rect_with_flags(outer_rect, black_flags); - blue_recording->add_draw_rect_with_flags(inner_rect, blue_flags); - blue_recording->Rerecord(); + cc::FakeRecordingSource blue_recording(quad_rect_.size()); + blue_recording.add_draw_rect_with_flags(outer_rect, black_flags); + blue_recording.add_draw_rect_with_flags(inner_rect, blue_flags); + blue_recording.Rerecord(); scoped_refptr<cc::RasterSource> blue_raster_source = - blue_recording->CreateRasterSource(); + blue_recording.CreateRasterSource(); auto* blue_quad = this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); @@ -2118,12 +2118,12 @@ this->quad_rect_.size(), false, this->quad_rect_, 1.f, {}, blue_raster_source->GetDisplayItemList()); - auto green_recording = cc::FakeRecordingSource::Create(quad_rect_.size()); - green_recording->add_draw_rect_with_flags(outer_rect, green_flags); - green_recording->add_draw_rect_with_flags(inner_rect, black_flags); - green_recording->Rerecord(); + cc::FakeRecordingSource green_recording(quad_rect_.size()); + green_recording.add_draw_rect_with_flags(outer_rect, green_flags); + green_recording.add_draw_rect_with_flags(inner_rect, black_flags); + green_recording.Rerecord(); scoped_refptr<cc::RasterSource> green_raster_source = - green_recording->CreateRasterSource(); + green_recording.CreateRasterSource(); auto* green_quad = this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); @@ -4333,17 +4333,17 @@ gfx::Rect blue_rect(gfx::Size(100, 100)); gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50)); - auto blue_recording = cc::FakeRecordingSource::Create(blue_rect.size()); + cc::FakeRecordingSource blue_recording(blue_rect.size()); cc::PaintFlags red_flags; red_flags.setColor(SkColors::kRed); - blue_recording->add_draw_rect_with_flags(blue_rect, red_flags); + blue_recording.add_draw_rect_with_flags(blue_rect, red_flags); cc::PaintFlags blue_flags; blue_flags.setColor(SkColors::kBlue); - blue_recording->add_draw_rect_with_flags(blue_clip_rect, blue_flags); - blue_recording->Rerecord(); + blue_recording.add_draw_rect_with_flags(blue_clip_rect, blue_flags); + blue_recording.Rerecord(); scoped_refptr<cc::RasterSource> blue_raster_source = - blue_recording->CreateRasterSource(); + blue_recording.CreateRasterSource(); gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right()); bool needs_blending = true; @@ -4364,13 +4364,13 @@ blue_raster_source->GetDisplayItemList()); // One viewport-filling green quad. - auto green_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource green_recording(viewport.size()); cc::PaintFlags green_flags; green_flags.setColor(SkColors::kGreen); - green_recording->add_draw_rect_with_flags(viewport, green_flags); - green_recording->Rerecord(); + green_recording.add_draw_rect_with_flags(viewport, green_flags); + green_recording.Rerecord(); scoped_refptr<cc::RasterSource> green_raster_source = - green_recording->CreateRasterSource(); + green_recording.CreateRasterSource(); gfx::Transform green_quad_to_target_transform; SharedQuadState* green_shared_state = CreateTestSharedQuadState( @@ -4402,13 +4402,13 @@ auto pass = CreateTestRenderPass(id, viewport, transform_to_root); // One viewport-filling 0.5-opacity green quad. - auto green_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource green_recording(viewport.size()); cc::PaintFlags green_flags; green_flags.setColor(SkColors::kGreen); - green_recording->add_draw_rect_with_flags(viewport, green_flags); - green_recording->Rerecord(); + green_recording.add_draw_rect_with_flags(viewport, green_flags); + green_recording.Rerecord(); scoped_refptr<cc::RasterSource> green_raster_source = - green_recording->CreateRasterSource(); + green_recording.CreateRasterSource(); gfx::Transform green_quad_to_target_transform; SharedQuadState* green_shared_state = CreateTestSharedQuadState( @@ -4422,13 +4422,13 @@ green_raster_source->GetDisplayItemList()); // One viewport-filling white quad. - auto white_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource white_recording(viewport.size()); cc::PaintFlags white_flags; white_flags.setColor(SkColors::kWhite); - white_recording->add_draw_rect_with_flags(viewport, white_flags); - white_recording->Rerecord(); + white_recording.add_draw_rect_with_flags(viewport, white_flags); + white_recording.Rerecord(); scoped_refptr<cc::RasterSource> white_raster_source = - white_recording->CreateRasterSource(); + white_recording.CreateRasterSource(); gfx::Transform white_quad_to_target_transform; SharedQuadState* white_shared_state = CreateTestSharedQuadState( @@ -4458,13 +4458,13 @@ auto pass = CreateTestRenderPass(id, viewport, transform_to_root); // One viewport-filling 0.5-opacity transparent quad. - auto transparent_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource transparent_recording(viewport.size()); cc::PaintFlags transparent_flags; transparent_flags.setColor(SkColors::kTransparent); - transparent_recording->add_draw_rect_with_flags(viewport, transparent_flags); - transparent_recording->Rerecord(); + transparent_recording.add_draw_rect_with_flags(viewport, transparent_flags); + transparent_recording.Rerecord(); scoped_refptr<cc::RasterSource> transparent_raster_source = - transparent_recording->CreateRasterSource(); + transparent_recording.CreateRasterSource(); gfx::Transform transparent_quad_to_target_transform; SharedQuadState* transparent_shared_state = CreateTestSharedQuadState( @@ -4478,13 +4478,13 @@ transparent_raster_source->GetDisplayItemList()); // One viewport-filling white quad. - auto white_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource white_recording(viewport.size()); cc::PaintFlags white_flags; white_flags.setColor(SkColors::kWhite); - white_recording->add_draw_rect_with_flags(viewport, white_flags); - white_recording->Rerecord(); + white_recording.add_draw_rect_with_flags(viewport, white_flags); + white_recording.Rerecord(); scoped_refptr<cc::RasterSource> white_raster_source = - white_recording->CreateRasterSource(); + white_recording.CreateRasterSource(); gfx::Transform white_quad_to_target_transform; SharedQuadState* white_shared_state = CreateTestSharedQuadState( @@ -4533,13 +4533,13 @@ draw_point_color(canvas, 1, 0, SkColors::kBlue); draw_point_color(canvas, 1, 1, SkColors::kGreen); - auto recording = cc::FakeRecordingSource::Create(viewport.size()); - recording->add_draw_image_with_flags( + cc::FakeRecordingSource recording(viewport.size()); + recording.add_draw_image_with_flags( surface->makeImageSnapshot(), gfx::Point(), SkSamplingOptions(SkFilterMode::kLinear), cc::PaintFlags()); - recording->Rerecord(); + recording.Rerecord(); scoped_refptr<cc::RasterSource> raster_source = - recording->CreateRasterSource(); + recording.CreateRasterSource(); gfx::Transform quad_to_target_transform; SharedQuadState* shared_state = @@ -4582,13 +4582,13 @@ draw_point_color(canvas, 1, 0, SkColors::kBlue); draw_point_color(canvas, 1, 1, SkColors::kGreen); - auto recording = cc::FakeRecordingSource::Create(viewport.size()); - recording->add_draw_image_with_flags( + cc::FakeRecordingSource recording(viewport.size()); + recording.add_draw_image_with_flags( surface->makeImageSnapshot(), gfx::Point(), SkSamplingOptions(SkFilterMode::kLinear), cc::PaintFlags()); - recording->Rerecord(); + recording.Rerecord(); scoped_refptr<cc::RasterSource> raster_source = - recording->CreateRasterSource(); + recording.CreateRasterSource(); gfx::Transform quad_to_target_transform; SharedQuadState* shared_state = @@ -4797,18 +4797,18 @@ gfx::Rect green_rect1(gfx::Point(80, 0), gfx::Size(20, 100)); gfx::Rect green_rect2(gfx::Point(0, 80), gfx::Size(100, 20)); - auto green_recording = cc::FakeRecordingSource::Create(viewport.size()); + cc::FakeRecordingSource green_recording(viewport.size()); cc::PaintFlags red_flags; red_flags.setColor(SkColors::kRed); - green_recording->add_draw_rect_with_flags(viewport, red_flags); + green_recording.add_draw_rect_with_flags(viewport, red_flags); cc::PaintFlags green_flags; green_flags.setColor(SkColors::kGreen); - green_recording->add_draw_rect_with_flags(green_rect1, green_flags); - green_recording->add_draw_rect_with_flags(green_rect2, green_flags); - green_recording->Rerecord(); + green_recording.add_draw_rect_with_flags(green_rect1, green_flags); + green_recording.add_draw_rect_with_flags(green_rect2, green_flags); + green_recording.Rerecord(); scoped_refptr<cc::RasterSource> green_raster_source = - green_recording->CreateRasterSource(); + green_recording.CreateRasterSource(); SharedQuadState* top_right_green_shared_quad_state = CreateTestSharedQuadState(green_quad_to_target_transform, viewport, @@ -4858,21 +4858,21 @@ blue_layer_rect1.Inset(inset); blue_layer_rect2.Inset(inset); - auto recording = cc::FakeRecordingSource::Create(layer_rect.size()); + cc::FakeRecordingSource recording(layer_rect.size()); cc::Region outside(layer_rect); outside.Subtract(gfx::ToEnclosingRect(union_layer_rect)); for (gfx::Rect rect : outside) { - recording->add_draw_rect_with_flags(rect, red_flags); + recording.add_draw_rect_with_flags(rect, red_flags); } cc::PaintFlags blue_flags; blue_flags.setColor(SkColors::kBlue); - recording->add_draw_rectf_with_flags(blue_layer_rect1, blue_flags); - recording->add_draw_rectf_with_flags(blue_layer_rect2, blue_flags); - recording->Rerecord(); + recording.add_draw_rectf_with_flags(blue_layer_rect1, blue_flags); + recording.add_draw_rectf_with_flags(blue_layer_rect2, blue_flags); + recording.Rerecord(); scoped_refptr<cc::RasterSource> raster_source = - recording->CreateRasterSource(); + recording.CreateRasterSource(); gfx::Rect content_union_rect( gfx::ToEnclosingRect(gfx::ScaleRect(union_layer_rect, contents_scale)));
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index a620a527..27cb4a63 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/allocator/partition_alloc_support.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/functional/bind.h" @@ -1403,6 +1404,8 @@ UpdateGPUInfoGL(); } } + + base::allocator::PartitionAllocSupport::Get()->OnBackgrounded(); } void GpuServiceImpl::OnForegrounded() { @@ -1426,6 +1429,7 @@ } } gpu_channel_manager_->OnApplicationForegounded(); + base::allocator::PartitionAllocSupport::Get()->OnForegrounded(); } #if !BUILDFLAG(IS_ANDROID)
diff --git a/components/viz/service/surfaces/surface_saved_frame.cc b/components/viz/service/surfaces/surface_saved_frame.cc index 272991b..6d7d4f7 100644 --- a/components/viz/service/surfaces/surface_saved_frame.cc +++ b/components/viz/service/surfaces/surface_saved_frame.cc
@@ -119,15 +119,16 @@ if (copy_request_count_ == 0) { InitFrameResult(); - - // Dispatch the callback asynchronously from the ctor; otherwise CompositorFrameSinkSupport - // tries to access the SurfaceAnimationManager before it's initialized. - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, - base::BindOnce(std::move(directive_finished_callback_), directive_)); + DispatchCopyDoneCallback(); } } +void SurfaceSavedFrame::DispatchCopyDoneCallback() { + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(std::move(directive_finished_callback_), directive_)); +} + std::unique_ptr<CopyOutputRequest> SurfaceSavedFrame::CreateCopyRequestIfNeeded( const CompositorRenderPass& render_pass, const CompositorRenderPassList& render_pass_list, @@ -183,9 +184,10 @@ size_t SurfaceSavedFrame::ExpectedResultCount() const { base::flat_set<CompositorRenderPassId> ids; - for (auto& shared_element : directive_.shared_elements()) + for (auto& shared_element : directive_.shared_elements()) { if (!shared_element.render_pass_id.is_null()) ids.insert(shared_element.render_pass_id); + } return ids.size(); } @@ -198,7 +200,7 @@ // Even if we early out, we update the count since we are no longer waiting // for this result. if (--copy_request_count_ == 0) { - std::move(directive_finished_callback_).Run(directive_); + DispatchCopyDoneCallback(); } // Return if the result is empty.
diff --git a/components/viz/service/surfaces/surface_saved_frame.h b/components/viz/service/surfaces/surface_saved_frame.h index 17da339..cb386e6 100644 --- a/components/viz/service/surfaces/surface_saved_frame.h +++ b/components/viz/service/surfaces/surface_saved_frame.h
@@ -118,6 +118,10 @@ bool is_software, std::unique_ptr<CopyOutputResult> result); + // The `directive_finished_callback_` is dispatched asynchronously since the + // callback can access *and* delete this object. + void DispatchCopyDoneCallback(); + size_t ExpectedResultCount() const; void InitFrameResult();
diff --git a/components/viz/service/transitions/surface_animation_manager.cc b/components/viz/service/transitions/surface_animation_manager.cc index af3097f..dc3ee1d 100644 --- a/components/viz/service/transitions/surface_animation_manager.cc +++ b/components/viz/service/transitions/surface_animation_manager.cc
@@ -177,6 +177,18 @@ const CompositorFrameTransitionDirective& directive) { CHECK_EQ(stage_, Stage::kPendingCopy); stage_ = Stage::kWaitingForAnimate; + + // Importing textures must be deferred until the SurfaceAnimationManager is + // bound to a frame sink. This is because ref-counting for textures + // referenced in a Surface's frame is managed by the frame sink associated + // with that Surface. So if this transition is potentially cross frame sink, + // we need to defer importing textures until the animate directive. The + // frame sink for the transition is finalized to the frame sink using the + // animate directive. + if (!directive.maybe_cross_frame_sink()) { + ImportTextures(); + } + std::move(callback).Run(directive); } @@ -186,12 +198,20 @@ } stage_ = Stage::kAnimating; + if (!saved_textures_) { + ImportTextures(); + } - DCHECK(!saved_textures_); + return true; +} + +void SurfaceAnimationManager::ImportTextures() { + CHECK(!saved_textures_); + if (!saved_frame_ || !saved_frame_->IsValid()) { LOG(ERROR) << "Failure in caching shared element snapshots"; saved_frame_.reset(); - return true; + return; } // Import the saved frame, which converts it to a ResourceFrame -- a @@ -199,7 +219,6 @@ saved_textures_.emplace( transferable_resource_tracker_.ImportResources(std::move(saved_frame_))); empty_resource_ids_.clear(); - return true; } void SurfaceAnimationManager::ReceiveFromChild(
diff --git a/components/viz/service/transitions/surface_animation_manager.h b/components/viz/service/transitions/surface_animation_manager.h index c0dae628..a53af15 100644 --- a/components/viz/service/transitions/surface_animation_manager.h +++ b/components/viz/service/transitions/surface_animation_manager.h
@@ -100,6 +100,11 @@ SaveDirectiveCompleteCallback callback, const CompositorFrameTransitionDirective& directive); + // Maps the textures cached by the save directive to transferable resources. + // Shared element resource IDs can only be replaced with cached textures after + // this step. + void ImportTextures(); + enum class Stage { kPendingCopy, kWaitingForAnimate, kAnimating }; Stage stage_ = Stage::kPendingCopy;
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn index 61421a3..464e72b 100644 --- a/content/app/BUILD.gn +++ b/content/app/BUILD.gn
@@ -37,7 +37,7 @@ content_app_deps += [ "//content/browser", "//content/child", - "//content/public/android:jni", + "//content/public/android:content_app_jni", "//device/bluetooth", "//device/gamepad", "//gpu",
diff --git a/content/app/android/content_child_process_service_delegate.cc b/content/app/android/content_child_process_service_delegate.cc index 3af9ef4..7289c50a 100644 --- a/content/app/android/content_child_process_service_delegate.cc +++ b/content/app/android/content_child_process_service_delegate.cc
@@ -15,7 +15,7 @@ #include "content/child/child_thread_impl.h" #include "content/common/android/surface_wrapper.h" #include "content/common/shared_file_util.h" -#include "content/public/android/content_main_dex_jni/ContentChildProcessServiceDelegate_jni.h" +#include "content/public/android/content_app_jni/ContentChildProcessServiceDelegate_jni.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_switches.h" #include "gpu/command_buffer/service/texture_owner.h"
diff --git a/content/app/android/content_main_android.cc b/content/app/android/content_main_android.cc index 9a5cd40e..febc805 100644 --- a/content/app/android/content_main_android.cc +++ b/content/app/android/content_main_android.cc
@@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "content/app/android/content_main_android.h" + #include <memory> #include "base/lazy_instance.h" #include "base/no_destructor.h" #include "base/trace_event/trace_event.h" -#include "content/app/android/content_main_android.h" -#include "content/public/android/content_main_dex_jni/ContentMain_jni.h" +#include "content/public/android/content_app_jni/ContentMain_jni.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_delegate.h" #include "content/public/app/content_main_runner.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 62618587..e56a1d7 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1903,8 +1903,6 @@ "renderer_host/transient_allow_popup.h", "renderer_host/transient_focus_source_user_activation.cc", "renderer_host/transient_focus_source_user_activation.h", - "renderer_host/ui_events_helper.cc", - "renderer_host/ui_events_helper.h", "renderer_host/view_transition_commit_deferring_condition.cc", "renderer_host/view_transition_commit_deferring_condition.h", "renderer_host/view_transition_opt_in_state.cc",
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc index c139385..549b2c8 100644 --- a/content/browser/accessibility/browser_accessibility_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -8,6 +8,7 @@ #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_enums.mojom-shared.h" #include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/platform/test_ax_platform_tree_manager_delegate.h" @@ -751,7 +752,7 @@ ui::AXNodeData root; root.id = 1; root.role = ax::mojom::Role::kRootWebArea; - root.html_attributes.push_back(std::make_pair("id", "my_html_id")); + root.AddStringAttribute(ax::mojom::StringAttribute::kHtmlId, "my_html_id"); std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager( BrowserAccessibilityManager::Create(
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc index 71097c1..65eb636 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -666,42 +666,29 @@ return nullptr; } -bool DumpAccessibilityTestBase::HasHtmlAttribute( - BrowserAccessibility& node, - const char* attr, - const std::string& value) const { - std::string result; - if (node.GetHtmlAttribute(attr, &result)) - return result == value; - - if (base::EqualsCaseInsensitiveASCII(attr, "class")) - return node.GetStringAttribute(ax::mojom::StringAttribute::kClassName) == - value; - - return false; -} - -BrowserAccessibility* DumpAccessibilityTestBase::FindNodeByHTMLAttribute( - const char* attr, +BrowserAccessibility* DumpAccessibilityTestBase::FindNodeByStringAttribute( + const ax::mojom::StringAttribute attr, const std::string& value) const { BrowserAccessibility* root = GetManager()->GetBrowserAccessibilityRoot(); CHECK(root); - return FindNodeByHTMLAttributeInSubtree(*root, attr, value); + return FindNodeByStringAttributeInSubtree(*root, attr, value); } BrowserAccessibility* -DumpAccessibilityTestBase::FindNodeByHTMLAttributeInSubtree( +DumpAccessibilityTestBase::FindNodeByStringAttributeInSubtree( BrowserAccessibility& node, - const char* attr, + const ax::mojom::StringAttribute attr, const std::string& value) const { - if (HasHtmlAttribute(node, attr, value)) + if (node.GetStringAttribute(attr) == value) { return &node; + } for (unsigned int i = 0; i < node.PlatformChildCount(); ++i) { - if (BrowserAccessibility* result = FindNodeByHTMLAttributeInSubtree( - *node.PlatformGetChild(i), attr, value)) + if (BrowserAccessibility* result = FindNodeByStringAttributeInSubtree( + *node.PlatformGetChild(i), attr, value)) { return result; + } } return nullptr; }
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.h b/content/browser/accessibility/dump_accessibility_browsertest_base.h index e84b07b..2586fc7 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.h +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -187,12 +187,9 @@ base::test::ScopedFeatureList scoped_feature_list_; - bool HasHtmlAttribute(BrowserAccessibility& node, - const char* attr, - const std::string& value) const; - - BrowserAccessibility* FindNodeByHTMLAttribute(const char* attr, - const std::string& value) const; + BrowserAccessibility* FindNodeByStringAttribute( + const ax::mojom::StringAttribute attr, + const std::string& value) const; protected: ui::AXInspectTestHelper test_helper_; @@ -233,9 +230,9 @@ BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node, const std::string& name) const; - BrowserAccessibility* FindNodeByHTMLAttributeInSubtree( + BrowserAccessibility* FindNodeByStringAttributeInSubtree( BrowserAccessibility& node, - const char* attr, + const ax::mojom::StringAttribute attr, const std::string& value) const; // The entries in skip_urls will be omitted from the result. This is used,
diff --git a/content/browser/accessibility/dump_accessibility_node_browsertest.cc b/content/browser/accessibility/dump_accessibility_node_browsertest.cc index 63c93cd..dd1f293 100644 --- a/content/browser/accessibility/dump_accessibility_node_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
@@ -51,9 +51,11 @@ formatter->SetPropertyFilters(scenario_.property_filters, AXTreeFormatter::kFiltersDefaultSet); - BrowserAccessibility* test_node = FindNodeByHTMLAttribute("id", "test"); + BrowserAccessibility* test_node = + FindNodeByStringAttribute(ax::mojom::StringAttribute::kHtmlId, "test"); if (!test_node) - test_node = FindNodeByHTMLAttribute("class", "test"); + test_node = FindNodeByStringAttribute( + ax::mojom::StringAttribute::kClassName, "test"); std::string contents = test_node ? formatter->FormatNode(test_node) : "Test node not found.";
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc index db891fe..b22510e 100644 --- a/content/browser/accessibility/web_contents_accessibility_android.cc +++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -858,7 +858,8 @@ node->GetStateDescription())); std::u16string element_id; - if (node->GetHtmlAttribute("id", &element_id)) { + if (node->GetString16Attribute(ax::mojom::StringAttribute::kHtmlId, + &element_id)) { Java_AccessibilityNodeInfoBuilder_setAccessibilityNodeInfoViewIdResourceName( env, obj, info, base::android::ConvertUTF16ToJavaString(env, element_id));
diff --git a/content/browser/aggregation_service/aggregatable_report.cc b/content/browser/aggregation_service/aggregatable_report.cc index a5c18ec6..a8a4abf 100644 --- a/content/browser/aggregation_service/aggregatable_report.cc +++ b/content/browser/aggregation_service/aggregatable_report.cc
@@ -36,7 +36,6 @@ #include "base/uuid.h" #include "base/values.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "components/aggregation_service/parsing_utils.h" #include "components/cbor/values.h" #include "components/cbor/writer.h" @@ -70,22 +69,16 @@ const std::optional<url::Origin>& aggregation_coordinator_origin) { switch (aggregation_mode) { case blink::mojom::AggregationServiceMode::kTeeBased: - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - if (!aggregation_coordinator_origin.has_value()) { - return {GetAggregationServiceProcessingUrl( - ::aggregation_service::GetDefaultAggregationCoordinatorOrigin())}; - } - if (!::aggregation_service::IsAggregationCoordinatorOriginAllowed( - *aggregation_coordinator_origin)) { - return {}; - } + if (!aggregation_coordinator_origin.has_value()) { return {GetAggregationServiceProcessingUrl( - *aggregation_coordinator_origin)}; - } else { - return {GURL( - kPrivacySandboxAggregationServiceTrustedServerUrlAwsParam.Get())}; + ::aggregation_service::GetDefaultAggregationCoordinatorOrigin())}; } + if (!::aggregation_service::IsAggregationCoordinatorOriginAllowed( + *aggregation_coordinator_origin)) { + return {}; + } + return { + GetAggregationServiceProcessingUrl(*aggregation_coordinator_origin)}; case blink::mojom::AggregationServiceMode::kExperimentalPoplar: // TODO(crbug.com/40214439): Update default processing urls. return {GURL("https://server1.example"), GURL("https://server2.example")}; @@ -474,9 +467,7 @@ break; } - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders) && - payload_contents.aggregation_coordinator_origin.has_value()) { + if (payload_contents.aggregation_coordinator_origin.has_value()) { out->set_aggregation_coordinator_origin( payload_contents.aggregation_coordinator_origin->Serialize()); } @@ -1032,15 +1023,12 @@ value.Set("debug_key", base::NumberToString(debug_key_.value())); } - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { value.Set( "aggregation_coordinator_origin", aggregation_coordinator_origin_ .value_or( ::aggregation_service::GetDefaultAggregationCoordinatorOrigin()) .Serialize()); - } for (const auto& item : additional_fields_) { CHECK(!value.contains(item.first))
diff --git a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc index e71b48c..8b8f0cf4 100644 --- a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc +++ b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
@@ -22,11 +22,9 @@ #include "base/strings/string_number_conversions.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/time/time.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/aggregation_service/aggregation_service.h" #include "content/browser/aggregation_service/aggregation_service_storage.h" @@ -1365,76 +1363,6 @@ } TEST_F(AggregationServiceStorageSqlTest, - AggregationCoordinatorFeatureModifiedBetweenStorageAndLoading_Success) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - OpenDatabase(); - - AggregatableReportRequest example_request = - aggregation_service::CreateExampleRequest(); - - storage_->StoreRequest( - aggregation_service::CloneReportRequest(example_request)); - EXPECT_EQ(GetRequestsReportingOnOrBefore(base::Time::Max()).size(), 1u); - - // Turning the feature on should not affect the report loading. - scoped_feature_list.Reset(); - scoped_feature_list.InitAndEnableFeature( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - ::aggregation_service::ScopedAggregationCoordinatorAllowlistForTesting - scoped_coordinator_allowlist( - {url::Origin::Create(GURL("https://a.test"))}); - - ASSERT_EQ(GetRequestsReportingOnOrBefore(base::Time::Max()).size(), 1u); - EXPECT_FALSE(GetRequestsReportingOnOrBefore(base::Time::Max())[0] - .request.payload_contents() - .aggregation_coordinator_origin.has_value()); - - storage_->ClearDataBetween(base::Time(), base::Time(), base::NullCallback()); - - AggregationServicePayloadContents payload_contents = - example_request.payload_contents(); - payload_contents.aggregation_coordinator_origin = - url::Origin::Create(GURL("https://a.test")); - - storage_->StoreRequest( - AggregatableReportRequest::Create(payload_contents, - example_request.shared_info().Clone()) - .value()); - ASSERT_EQ(GetRequestsReportingOnOrBefore(base::Time::Max()).size(), 1u); - EXPECT_EQ(GetRequestsReportingOnOrBefore(base::Time::Max())[0] - .request.payload_contents() - .aggregation_coordinator_origin.value() - .GetURL() - .spec(), - "https://a.test/"); - - // Turning the feature off should also not affect the report loading. - scoped_feature_list.Reset(); - scoped_feature_list.InitAndDisableFeature( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - - ASSERT_EQ(storage_ - ->GetRequestsReportingOnOrBefore(base::Time::Max(), - /*limit=*/std::nullopt) - .size(), - 1u); - EXPECT_EQ(storage_ - ->GetRequestsReportingOnOrBefore(base::Time::Max(), - /*limit=*/std::nullopt)[0] - .request.payload_contents() - .aggregation_coordinator_origin.value() - .GetURL() - .spec(), - "https://a.test/"); - histograms_.ExpectTotalCount( - "PrivacySandbox.AggregationService.Storage.Sql." - "RequestDelayFromUpdatedReportTime2", - 0); -} - -TEST_F(AggregationServiceStorageSqlTest, AggregationCoordinatorAllowlistChanges_ReportDeleted) { std::optional< ::aggregation_service::ScopedAggregationCoordinatorAllowlistForTesting>
diff --git a/content/browser/attribution_reporting/attribution_resolver_unittest.cc b/content/browser/attribution_reporting/attribution_resolver_unittest.cc index f1648ac0..7b9bb25 100644 --- a/content/browser/attribution_reporting/attribution_resolver_unittest.cc +++ b/content/browser/attribution_reporting/attribution_resolver_unittest.cc
@@ -23,10 +23,8 @@ #include "base/memory/raw_ptr.h" #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" -#include "components/aggregation_service/features.h" #include "components/attribution_reporting/aggregatable_dedup_key.h" #include "components/attribution_reporting/aggregatable_trigger_config.h" #include "components/attribution_reporting/aggregatable_trigger_data.h" @@ -3754,9 +3752,6 @@ } TEST_F(AttributionResolverTest, AggregationCoordinator_RoundTrip) { - base::test::ScopedFeatureList scoped_feature_list( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - auto coordinator_origin = SuitableOrigin::Deserialize("https://a.test"); storage()->StoreSource(TestAggregatableSourceProvider().GetBuilder().Build());
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc index efeed791..2ceab40 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
@@ -33,7 +33,6 @@ #include "base/test/task_environment.h" #include "base/time/time.h" #include "base/uuid.h" -#include "components/aggregation_service/features.h" #include "components/attribution_reporting/constants.h" #include "components/attribution_reporting/destination_set.h" #include "components/attribution_reporting/event_level_epsilon.h" @@ -388,7 +387,6 @@ } protected: - base::test::ScopedFeatureList scoped_feature_list_; base::test::SingleThreadTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::ScopedTempDir temp_directory_; @@ -2159,9 +2157,6 @@ }, }; - base::test::ScopedFeatureList scoped_feature_list( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - for (auto test_case : kTestCases) { OpenDatabase(); storage()->StoreSource(SourceBuilder() @@ -2271,9 +2266,6 @@ }, }; - base::test::ScopedFeatureList scoped_feature_list( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - for (auto test_case : kTestCases) { OpenDatabase(); // Create the tables.
diff --git a/content/browser/attribution_reporting/sql_utils.cc b/content/browser/attribution_reporting/sql_utils.cc index 9443a45c1..4c337db 100644 --- a/content/browser/attribution_reporting/sql_utils.cc +++ b/content/browser/attribution_reporting/sql_utils.cc
@@ -16,10 +16,8 @@ #include "base/check_op.h" #include "base/containers/flat_map.h" #include "base/containers/span.h" -#include "base/feature_list.h" #include "base/numerics/safe_conversions.h" #include "base/time/time.h" -#include "components/aggregation_service/features.h" #include "components/attribution_reporting/aggregatable_trigger_config.h" #include "components/attribution_reporting/aggregation_keys.h" #include "components/attribution_reporting/constants.h" @@ -56,9 +54,7 @@ void SerializeCommonAggregatableData( const AttributionReport::CommonAggregatableData& data, proto::AttributionCommonAggregatableMetadata& msg) { - if (base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders) && - data.aggregation_coordinator_origin.has_value()) { + if (data.aggregation_coordinator_origin.has_value()) { msg.set_coordinator_origin( data.aggregation_coordinator_origin->Serialize()); } @@ -93,9 +89,7 @@ return false; } - if (base::FeatureList::IsEnabled( - ::aggregation_service::kAggregationServiceMultipleCloudProviders) && - msg.has_coordinator_origin()) { + if (msg.has_coordinator_origin()) { auto aggregation_coordinator_origin = attribution_reporting::SuitableOrigin::Deserialize( msg.coordinator_origin());
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc index fd327c2..24f86e6 100644 --- a/content/browser/child_process_launcher_helper_mac.cc +++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -155,11 +155,17 @@ can_cache_policy ? sandbox::SandboxCompiler::Target::kCompiled : sandbox::SandboxCompiler::Target::kSource); compiler.SetProfile(sandbox::policy::GetSandboxProfile(sandbox_type)); - SetupSandboxParameters(sandbox_type, *command_line_.get(), + const bool sandbox_ok = + SetupSandboxParameters(sandbox_type, *command_line_.get(), #if BUILDFLAG(ENABLE_PPAPI) - plugins_, + plugins_, #endif - &compiler); + &compiler); + + if (!sandbox_ok) { + LOG(ERROR) << "Sandbox setup failed."; + return false; + } std::string error; if (!compiler.CompilePolicyToProto(policy_, error)) {
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc index 6e1845c..c3e874d 100644 --- a/content/browser/devtools/devtools_instrumentation.cc +++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -544,33 +544,6 @@ return issue; } -std::unique_ptr<protocol::Audits::InspectorIssue> -BuildCookieDeprecationMetadataIssue( - const blink::mojom::CookieDeprecationMetadataIssueDetailsPtr& - issue_details) { - auto metadata_issue_details = - protocol::Audits::CookieDeprecationMetadataIssueDetails::Create() - .SetAllowedSites(std::make_unique<protocol::Array<protocol::String>>( - issue_details->allowed_sites)) - .SetOptOutPercentage(issue_details->opt_out_percentage) - .SetIsOptOutTopLevel(issue_details->is_opt_out_top_level) - .Build(); - - auto protocol_issue_details = - protocol::Audits::InspectorIssueDetails::Create() - .SetCookieDeprecationMetadataIssueDetails( - std::move(metadata_issue_details)) - .Build(); - - auto issue = protocol::Audits::InspectorIssue::Create() - .SetCode(protocol::Audits::InspectorIssueCodeEnum:: - CookieDeprecationMetadataIssue) - .SetDetails(std::move(protocol_issue_details)) - .Build(); - - return issue; -} - void UpdateChildFrameTrees(FrameTreeNode* ftn, bool update_target_info) { if (auto* agent_host = WebContentsDevToolsAgentHost::GetFor( WebContentsImpl::FromFrameTreeNode(ftn))) { @@ -1818,6 +1791,34 @@ } } +std::unique_ptr<protocol::Audits::InspectorIssue> +BuildCookieDeprecationMetadataIssue( + const blink::mojom::CookieDeprecationMetadataIssueDetailsPtr& + issue_details) { + auto metadata_issue_details = + protocol::Audits::CookieDeprecationMetadataIssueDetails::Create() + .SetAllowedSites(std::make_unique<protocol::Array<protocol::String>>( + issue_details->allowed_sites)) + .SetOptOutPercentage(issue_details->opt_out_percentage) + .SetIsOptOutTopLevel(issue_details->is_opt_out_top_level) + .SetOperation(BuildCookieOperation(issue_details->operation)) + .Build(); + + auto protocol_issue_details = + protocol::Audits::InspectorIssueDetails::Create() + .SetCookieDeprecationMetadataIssueDetails( + std::move(metadata_issue_details)) + .Build(); + + auto issue = protocol::Audits::InspectorIssue::Create() + .SetCode(protocol::Audits::InspectorIssueCodeEnum:: + CookieDeprecationMetadataIssue) + .SetDetails(std::move(protocol_issue_details)) + .Build(); + + return issue; +} + } // namespace void ReportCookieIssue(
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index f371c95..0d953c09 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -611,42 +611,62 @@ return nullptr; const base::TimeTicks kNullTicks; - return Network::ResourceTiming::Create() - .SetRequestTime((load_timing.request_start - kNullTicks).InSecondsF()) - .SetProxyStart( - timeDelta(load_timing.proxy_resolve_start, load_timing.request_start)) - .SetProxyEnd( - timeDelta(load_timing.proxy_resolve_end, load_timing.request_start)) - .SetDnsStart(timeDelta(load_timing.connect_timing.domain_lookup_start, - load_timing.request_start)) - .SetDnsEnd(timeDelta(load_timing.connect_timing.domain_lookup_end, - load_timing.request_start)) - .SetConnectStart(timeDelta(load_timing.connect_timing.connect_start, + auto timing = + Network::ResourceTiming::Create() + .SetRequestTime((load_timing.request_start - kNullTicks).InSecondsF()) + .SetProxyStart(timeDelta(load_timing.proxy_resolve_start, + load_timing.request_start)) + .SetProxyEnd(timeDelta(load_timing.proxy_resolve_end, load_timing.request_start)) - .SetConnectEnd(timeDelta(load_timing.connect_timing.connect_end, + .SetDnsStart(timeDelta(load_timing.connect_timing.domain_lookup_start, + load_timing.request_start)) + .SetDnsEnd(timeDelta(load_timing.connect_timing.domain_lookup_end, load_timing.request_start)) - .SetSslStart(timeDelta(load_timing.connect_timing.ssl_start, - load_timing.request_start)) - .SetSslEnd(timeDelta(load_timing.connect_timing.ssl_end, - load_timing.request_start)) - .SetWorkerStart(-1) - .SetWorkerReady(-1) - .SetWorkerFetchStart(timeDelta(load_timing.service_worker_fetch_start, + .SetConnectStart(timeDelta(load_timing.connect_timing.connect_start, load_timing.request_start)) - .SetWorkerRespondWithSettled( - timeDelta(load_timing.service_worker_respond_with_settled, - load_timing.request_start)) - .SetSendStart( - timeDelta(load_timing.send_start, load_timing.request_start)) - .SetSendEnd(timeDelta(load_timing.send_end, load_timing.request_start)) - .SetPushStart( - timeDelta(load_timing.push_start, load_timing.request_start, 0)) - .SetPushEnd(timeDelta(load_timing.push_end, load_timing.request_start, 0)) - .SetReceiveHeadersStart(timeDelta(load_timing.receive_headers_start, - load_timing.request_start)) - .SetReceiveHeadersEnd( - timeDelta(load_timing.receive_headers_end, load_timing.request_start)) - .Build(); + .SetConnectEnd(timeDelta(load_timing.connect_timing.connect_end, + load_timing.request_start)) + .SetSslStart(timeDelta(load_timing.connect_timing.ssl_start, + load_timing.request_start)) + .SetSslEnd(timeDelta(load_timing.connect_timing.ssl_end, + load_timing.request_start)) + .SetWorkerStart(-1) + .SetWorkerReady(-1) + .SetWorkerFetchStart(timeDelta(load_timing.service_worker_fetch_start, + load_timing.request_start)) + .SetWorkerRespondWithSettled( + timeDelta(load_timing.service_worker_respond_with_settled, + load_timing.request_start)) + .SetSendStart( + timeDelta(load_timing.send_start, load_timing.request_start)) + .SetSendEnd( + timeDelta(load_timing.send_end, load_timing.request_start)) + .SetPushStart( + timeDelta(load_timing.push_start, load_timing.request_start, 0)) + .SetPushEnd( + timeDelta(load_timing.push_end, load_timing.request_start, 0)) + .SetReceiveHeadersStart(timeDelta(load_timing.receive_headers_start, + load_timing.request_start)) + .SetReceiveHeadersEnd(timeDelta(load_timing.receive_headers_end, + load_timing.request_start)) + .Build(); + + if (base::FeatureList::IsEnabled( + blink::features::kServiceWorkerStaticRouterTimingInfo)) { + if (!load_timing.service_worker_router_evaluation_start.is_null()) { + timing->SetWorkerRouterEvaluationStart( + timeDelta(load_timing.service_worker_router_evaluation_start, + load_timing.request_start)); + } + + if (!load_timing.service_worker_cache_lookup_start.is_null()) { + timing->SetWorkerCacheLookupStart( + timeDelta(load_timing.service_worker_cache_lookup_start, + load_timing.request_start)); + } + } + + return timing; } std::unique_ptr<Network::ConnectTiming> GetConnectTiming( @@ -2115,6 +2135,12 @@ *info.service_worker_router_info->matched_source_type)); } + if (info.service_worker_router_info->actual_source_type) { + service_worker_router_info->SetActualSourceType( + BuildServiceWorkerRouterSourceType( + *info.service_worker_router_info->actual_source_type)); + } + response->SetServiceWorkerRouterInfo(std::move(service_worker_router_info)); }
diff --git a/content/browser/fenced_frame/fenced_frame.cc b/content/browser/fenced_frame/fenced_frame.cc index ccccd2c..dab5c85 100644 --- a/content/browser/fenced_frame/fenced_frame.cc +++ b/content/browser/fenced_frame/fenced_frame.cc
@@ -210,6 +210,14 @@ web_contents_->SetFocusedFrame(node, source); } +FrameTree* FencedFrame::GetOwnedPictureInPictureFrameTree() { + return nullptr; +} + +FrameTree* FencedFrame::GetPictureInPictureOpenerFrameTree() { + return nullptr; +} + RenderFrameProxyHost* FencedFrame::InitInnerFrameTreeAndReturnProxyToOuterFrameTree( blink::mojom::RemoteFrameInterfacesFromRendererPtr remote_frame_interfaces,
diff --git a/content/browser/fenced_frame/fenced_frame.h b/content/browser/fenced_frame/fenced_frame.h index 8ea2f59..6d8eb3f 100644 --- a/content/browser/fenced_frame/fenced_frame.h +++ b/content/browser/fenced_frame/fenced_frame.h
@@ -68,6 +68,8 @@ RenderFrameHostImpl* GetProspectiveOuterDocument() override; FrameTree* LoadingTree() override; void SetFocusedFrame(FrameTreeNode* node, SiteInstanceGroup* source) override; + FrameTree* GetOwnedPictureInPictureFrameTree() override; + FrameTree* GetPictureInPictureOpenerFrameTree() override; // Returns the devtools frame token of the fenced frame's inner FrameTree's // main frame.
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc index 7f42ef0..00ca4b9 100644 --- a/content/browser/interest_group/ad_auction_service_impl.cc +++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -27,7 +27,6 @@ #include "base/types/expected.h" #include "base/uuid.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "content/browser/attribution_reporting/attribution_manager.h" #include "content/browser/devtools/devtools_instrumentation.h" #include "content/browser/fenced_frame/fenced_frame_reporter.h" @@ -202,13 +201,6 @@ updated_group.expiry = max_expiry; } - if (!base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - // Override with the default if a non-default coordinator is specified when - // the feature is disabled. - updated_group.aggregation_coordinator_origin = std::nullopt; - } - if (updated_group.aggregation_coordinator_origin && !aggregation_service::IsAggregationCoordinatorOriginAllowed( updated_group.aggregation_coordinator_origin.value())) {
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc index 8ff1f30..bb78d1f 100644 --- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc +++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -40,7 +40,6 @@ #include "build/build_config.h" #include "build/buildflag.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "components/cbor/diagnostic_writer.h" #include "components/cbor/reader.h" #include "components/services/storage/shared_storage/shared_storage_manager.h" @@ -783,7 +782,6 @@ blink::features::kAdInterestGroupAPI, blink::features::kFledge, blink::features::kFledgeClearOriginJoinedAdInterestGroups, blink::features::kFledgeNegativeTargeting, - aggregation_service::kAggregationServiceMultipleCloudProviders, features::kEnableUpdatingUserBiddingSignals, features::kEnableUpdatingExecutionModeToFrozenContext}, /*disabled_features=*/{}); @@ -10388,20 +10386,8 @@ InvokeCallbackForURN(*auction_result); } -class AdAuctionServiceImplPrivateAggregationMultiCloudTest - : public AdAuctionServiceImplPrivateAggregationEnabledTest { - public: - AdAuctionServiceImplPrivateAggregationMultiCloudTest() { - feature_list_.InitAndEnableFeature( - aggregation_service::kAggregationServiceMultipleCloudProviders); - } - - protected: - base::test::ScopedFeatureList feature_list_; -}; - -TEST_F(AdAuctionServiceImplPrivateAggregationMultiCloudTest, - PrivateAggregationReportsForwarded) { +TEST_F(AdAuctionServiceImplPrivateAggregationEnabledTest, + PrivateAggregationReportsForwardedWithCoordinator) { // Add a mock to intercept calls to the PrivateAggregationHost. class MockPrivateAggregationHost : public PrivateAggregationHost { public:
diff --git a/content/browser/interest_group/ad_auction_service_mojolpm_fuzzer.cc b/content/browser/interest_group/ad_auction_service_mojolpm_fuzzer.cc index e18595b..6c7afef 100644 --- a/content/browser/interest_group/ad_auction_service_mojolpm_fuzzer.cc +++ b/content/browser/interest_group/ad_auction_service_mojolpm_fuzzer.cc
@@ -25,7 +25,6 @@ #include "base/task/sequenced_task_runner.h" #include "base/test/scoped_feature_list.h" #include "base/thread_annotations.h" -#include "components/aggregation_service/features.h" #include "content/browser/interest_group/ad_auction_service_impl.h" #include "content/browser/interest_group/ad_auction_service_mojolpm_fuzzer.pb.h" #include "content/browser/interest_group/ad_auction_service_mojolpm_fuzzer_stringifiers.h" @@ -294,7 +293,6 @@ blink::features::kAdInterestGroupAPI, blink::features::kFledge, blink::features::kFledgeClearOriginJoinedAdInterestGroups, blink::features::kFledgeNegativeTargeting, - aggregation_service::kAggregationServiceMultipleCloudProviders, features::kEnableUpdatingUserBiddingSignals, features::kEnableUpdatingExecutionModeToFrozenContext}, /*disabled_features=*/{});
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index 2fe2537..4edfa0ae 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -53,7 +53,6 @@ #include "base/values.h" #include "build/build_config.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "components/network_session_configurator/common/network_switches.h" #include "components/web_package/web_bundle_builder.h" #include "content/browser/aggregation_service/aggregatable_report.h" @@ -5115,21 +5114,7 @@ } } -class InterestGroupAggregationCoordinatorBrowserTest - : public InterestGroupBrowserTest { - public: - InterestGroupAggregationCoordinatorBrowserTest() { - feature_list_.InitAndEnableFeature( - aggregation_service::kAggregationServiceMultipleCloudProviders); - } - - ~InterestGroupAggregationCoordinatorBrowserTest() override = default; - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(InterestGroupAggregationCoordinatorBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, JoinInterestGroupInvalidAggregationCoordinatorOrigin) { const char kScriptTemplate[] = R"( (async function() { @@ -5160,7 +5145,7 @@ EvalJs(shell(), JsReplace(kScriptTemplate, origin_string.c_str()))); } -IN_PROC_BROWSER_TEST_F(InterestGroupAggregationCoordinatorBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, JoinInterestGroupValidAggregationCoordinatorOrigin) { const char kScriptTemplate[] = R"( (async function() { @@ -5192,7 +5177,7 @@ aggregation_service::kDefaultAggregationCoordinatorAwsCloud))); } -IN_PROC_BROWSER_TEST_F(InterestGroupAggregationCoordinatorBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, JoinInterestGroupNonHTTPSAggregationCoordinatorOrigin) { const char kScriptTemplate[] = R"( (async function() { @@ -5224,7 +5209,7 @@ } IN_PROC_BROWSER_TEST_F( - InterestGroupAggregationCoordinatorBrowserTest, + InterestGroupBrowserTest, JoinInterestGroupUnsupportedAggregationCoordinatorOrigin) { const char kScriptTemplate[] = R"( (async function() {
diff --git a/content/browser/interest_group/interest_group_pa_report_util.cc b/content/browser/interest_group/interest_group_pa_report_util.cc index 18fd9209..5ec39850 100644 --- a/content/browser/interest_group/interest_group_pa_report_util.cc +++ b/content/browser/interest_group/interest_group_pa_report_util.cc
@@ -21,7 +21,6 @@ #include "base/notreached.h" #include "base/numerics/clamped_math.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "content/browser/private_aggregation/private_aggregation_host.h" #include "content/browser/private_aggregation/private_aggregation_manager.h" #include "content/common/content_export.h" @@ -363,13 +362,6 @@ std::move(request->contribution->get_histogram_contribution())); } - if (!base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - // Override with the default if a non-default coordinator is specified when - // the feature is disabled. - aggregation_coordinator_origin = std::nullopt; - } - if (aggregation_coordinator_origin && !aggregation_service::IsAggregationCoordinatorOriginAllowed( aggregation_coordinator_origin.value())) {
diff --git a/content/browser/interest_group/interest_group_update_manager.cc b/content/browser/interest_group/interest_group_update_manager.cc index b2fc28c..26b5844 100644 --- a/content/browser/interest_group/interest_group_update_manager.cc +++ b/content/browser/interest_group/interest_group_update_manager.cc
@@ -28,7 +28,6 @@ #include "base/time/time.h" #include "base/values.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "content/browser/interest_group/interest_group_features.h" #include "content/browser/interest_group/interest_group_manager_impl.h" #include "content/browser/interest_group/interest_group_storage.h" @@ -577,13 +576,6 @@ [[nodiscard]] bool TryToCopyPrivateAggregationConfig( const base::Value::Dict& dict, InterestGroupUpdate& interest_group_update) { - if (!base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - // Ignore the specified aggregation coordinator unless the feature is - // enabled. - return true; - } - const base::Value::Dict* maybe_config = dict.FindDict("privateAggregationConfig"); if (!maybe_config) {
diff --git a/content/browser/network/shared_dictionary_browsertest.cc b/content/browser/network/shared_dictionary_browsertest.cc index cb44331..d2db348 100644 --- a/content/browser/network/shared_dictionary_browsertest.cc +++ b/content/browser/network/shared_dictionary_browsertest.cc
@@ -65,44 +65,44 @@ // Generated by: // tools/origin_trials/generate_token.py --version 3 --expire-days 3650 \ -// https://shared-dictionary.test CompressionDictionaryTransportV2 +// https://shared-dictionary.test CompressionDictionaryTransportForTest // Token details: // Version: 3 // Origin: https://shared-dictionary.test:443 // Is Subdomain: None // Is Third Party: None // Usage Restriction: None -// Feature: CompressionDictionaryTransportV2 -// Expiry: 2022646497 (2034-02-04 06:14:57 UTC) +// Feature: CompressionDictionaryTransportForTest +// Expiry: 2021587921 (2034-01-23 00:12:01 UTC) // Signature (Base64): -// iSWtWCojh+4RRpPFD/sN2iIldcgTAqoVymCrvnJ70GR55Xz454uH4GDxFNHkREXsFwDG0ZPx -// llzEtFSCK0uoBQ== +// Jwep7Wi24cUGZGE97g4mInnJqjlL1vtgc5wzkmA7rgPmVOXvNjijuMCjr/m44anH6sHiDpkG +// i3Z4ymlj5OFmAw== constexpr std::string_view kOriginTrialToken = - "A4klrVgqI4fuEUaTxQ/7DdoiJXXIEwKqFcpgq75ye9BkeeV8+OeLh+Bg8RTR5ERF7BcAxtGT8Z" - "ZcxLRUgitLqAUAAAB1eyJvcmlnaW4iOiAiaHR0cHM6Ly9zaGFyZWQtZGljdGlvbmFyeS50ZXN0" - "OjQ0MyIsICJmZWF0dXJlIjogIkNvbXByZXNzaW9uRGljdGlvbmFyeVRyYW5zcG9ydFYyIiwgIm" - "V4cGlyeSI6IDIwMjI2NDY0OTd9"; + "AycHqe1otuHFBmRhPe4OJiJ5yao5S9b7YHOcM5JgO64D5lTl7zY4o7jAo6/5uOGpx+rB4g6ZBo" + "t2eMppY+ThZgMAAAB6eyJvcmlnaW4iOiAiaHR0cHM6Ly9zaGFyZWQtZGljdGlvbmFyeS50ZXN0" + "OjQ0MyIsICJmZWF0dXJlIjogIkNvbXByZXNzaW9uRGljdGlvbmFyeVRyYW5zcG9ydEZvclRlc3" + "QiLCAiZXhwaXJ5IjogMjAyMTU4NzkyMX0="; // Generated by: // tools/origin_trials/generate_token.py --version 3 --expire-days 3650 \ // --is-third-party \ -// https://shared-dictionary.test CompressionDictionaryTransportV2 +// https://shared-dictionary.test CompressionDictionaryTransportForTest // Token details: // Version: 3 // Origin: https://shared-dictionary.test:443 // Is Subdomain: None // Is Third Party: True // Usage Restriction: None -// Feature: CompressionDictionaryTransportV2 -// Expiry: 2022647128 (2034-02-04 06:25:28 UTC) +// Feature: CompressionDictionaryTransportForTest +// Expiry: 2021587536 (2034-01-23 00:05:36 UTC) // Signature (Base64): -// O4XHAT50NH7/v3OTMgrJHRt1UqWEU09IXNRJNmhFfd+S/Q0ysYTX/kjPc+TbH/TnZrb0aXoO -// JhpWj/rqE8a6Dw== +// N4A/mWnaU02PTXa0Sd2TyX1hGhjhJGe/KoH9O0RxJI2OCEIlmZVM8e+AJLpp3D/qNWIfS3oX +// dg0sEPDyr/nICQ== constexpr std::string_view kThirdPartyOriginTrialToken = - "AzuFxwE+dDR+/79zkzIKyR0bdVKlhFNPSFzUSTZoRX3fkv0NMrGE1/5Iz3Pk2x/052a29Gl6Di" - "YaVo/66hPGug8AAACLeyJvcmlnaW4iOiAiaHR0cHM6Ly9zaGFyZWQtZGljdGlvbmFyeS50ZXN0" - "OjQ0MyIsICJmZWF0dXJlIjogIkNvbXByZXNzaW9uRGljdGlvbmFyeVRyYW5zcG9ydFYyIiwgIm" - "V4cGlyeSI6IDIwMjI2NDcxMjgsICJpc1RoaXJkUGFydHkiOiB0cnVlfQ=="; + "AzeAP5lp2lNNj012tEndk8l9YRoY4SRnvyqB/TtEcSSNjghCJZmVTPHvgCS6adw/6jViH0t6F3" + "YNLBDw8q/5yAkAAACQeyJvcmlnaW4iOiAiaHR0cHM6Ly9zaGFyZWQtZGljdGlvbmFyeS50ZXN0" + "OjQ0MyIsICJmZWF0dXJlIjogIkNvbXByZXNzaW9uRGljdGlvbmFyeVRyYW5zcG9ydEZvclRlc3" + "QiLCAiZXhwaXJ5IjogMjAyMTU4NzUzNiwgImlzVGhpcmRQYXJ0eSI6IHRydWV9"; // The Structured Field sf-binary hash of sha256 of dictionary. // (content/test/data/shared_dictionary/test.dict and test_dict.html). @@ -118,7 +118,7 @@ constexpr std::string_view kErrorInvalidHashString = "test(\"Invalid dictionary hash.\");"; constexpr std::string_view kErrorNoSharedDictionaryAcceptEncodingString = - "test(\"sbr or zstd-d is not set in accept-encoding header.\");"; + "test(\"dcb or dcz is not set in accept-encoding header.\");"; constexpr std::string_view kCompressedDataOriginalString = "test(\"This is compressed test data using a test dictionary\");"; @@ -127,9 +127,14 @@ // $ echo "This is a test dictionary." > /tmp/dict // $ echo -n "test(\"This is compressed test data using a test dictionary\");" \ // > /tmp/data -// $ brotli -o /tmp/out.sbr -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.sbr +// $ echo -en '\xffDCB' > /tmp/out.dcb +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb +// $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb +// $ xxd -i /tmp/out.dcb constexpr uint8_t kBrotliCompressedData[] = { + 0xff, 0x44, 0x43, 0x42, 0x53, 0x96, 0x9b, 0xcf, 0x5e, 0x96, 0x0e, 0x0e, + 0xdb, 0xf0, 0xa4, 0xbd, 0xde, 0x6b, 0x0b, 0x3e, 0x93, 0x81, 0xe1, 0x56, + 0xde, 0x7f, 0x5b, 0x91, 0xce, 0x83, 0x91, 0x62, 0x42, 0x70, 0xf4, 0x16, 0xa1, 0xe0, 0x01, 0x00, 0x64, 0x9c, 0xa4, 0xaa, 0xd7, 0x47, 0xe0, 0x26, 0x4b, 0x95, 0x91, 0xb4, 0x46, 0x36, 0x09, 0xc9, 0xc7, 0x0e, 0x38, 0xe4, 0x44, 0xe8, 0x72, 0x0d, 0x3c, 0x6e, 0xab, 0x35, 0x9b, 0x0f, 0x4b, 0xd1, @@ -142,13 +147,19 @@ // $ echo "This is a test dictionary." > /tmp/dict // $ echo -n "test(\"This is compressed test data using a test dictionary\");" \ // > /tmp/data -// $ zstd -o /tmp/out.szst -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.szst +// $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz +// $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data +// $ cat /tmp/tmp.zstd >> /tmp/out.dcz +// $ xxd -i /tmp/out.dcz constexpr uint8_t kZstdCompressedData[] = { - 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3d, 0x35, 0x01, 0x00, 0xe0, 0x74, - 0x65, 0x73, 0x74, 0x28, 0x22, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x73, 0x69, - 0x6e, 0x67, 0x22, 0x29, 0x3b, 0x03, 0x10, 0x05, 0xdf, 0x9f, 0x96, + 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00, 0x53, 0x96, 0x9b, 0xcf, + 0x5e, 0x96, 0x0e, 0x0e, 0xdb, 0xf0, 0xa4, 0xbd, 0xde, 0x6b, 0x0b, 0x3e, + 0x93, 0x81, 0xe1, 0x56, 0xde, 0x7f, 0x5b, 0x91, 0xce, 0x83, 0x91, 0x62, + 0x42, 0x70, 0xf4, 0x16, 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3d, 0x35, 0x01, + 0x00, 0xe0, 0x74, 0x65, 0x73, 0x74, 0x28, 0x22, 0x63, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x61, 0x74, 0x61, 0x20, 0x75, 0x73, + 0x69, 0x6e, 0x67, 0x22, 0x29, 0x3b, 0x03, 0x10, 0x05, 0xdf, 0x9f, 0x96, 0x11, 0x21, 0x8a, 0x48, 0x20, 0xef, 0xeb}; const std::string kZstdCompressedDataString = std::string(reinterpret_cast<const char*>(kZstdCompressedData), @@ -406,10 +417,9 @@ return false; } if (base::FeatureList::IsEnabled(network::features::kSharedZstd)) { - return it->second == "br-d, zstd-d" || - base::EndsWith(it->second, ", br-d, zstd-d"); + return it->second == "dcb, dcz" || base::EndsWith(it->second, ", dcb, dcz"); } else { - return it->second == "br-d" || base::EndsWith(it->second, ", br-d"); + return it->second == "dcb" || base::EndsWith(it->second, ", dcb"); } } @@ -749,8 +759,6 @@ if (dict_hash) { if (*dict_hash == kExpectedDictionaryHashBase64) { if (HasSharedDictionaryAcceptEncoding(request.headers)) { - response->AddCustomHeader("content-dictionary", - kExpectedDictionaryHashBase64); if (base::FeatureList::IsEnabled(network::features::kSharedZstd)) { response->AddCustomHeader( "content-encoding", @@ -1397,9 +1405,7 @@ if (dict_hash) { if (*dict_hash == kExpectedDictionaryHashBase64) { if (HasSharedDictionaryAcceptEncoding(request.headers)) { - response->AddCustomHeader("content-encoding", "br-d"); - response->AddCustomHeader("content-dictionary", - kExpectedDictionaryHashBase64); + response->AddCustomHeader("content-encoding", "dcb"); response->set_content(kBrotliCompressedDataString); } else { response->set_content(kErrorNoSharedDictionaryAcceptEncodingString);
diff --git a/content/browser/picture_in_picture/document_picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/document_picture_in_picture_window_controller_impl.cc index f23dabe79..69ab72d 100644 --- a/content/browser/picture_in_picture/document_picture_in_picture_window_controller_impl.cc +++ b/content/browser/picture_in_picture/document_picture_in_picture_window_controller_impl.cc
@@ -39,10 +39,6 @@ // This is a no-op if the controller already exists. CreateForWebContents(web_contents); auto* controller = FromWebContents(web_contents); - // The controller must not have pre-existing web content. It's supposed - // to have been destroyed by NotifyClosedAndStopObserving() if it's being - // reused. - DCHECK(!controller->GetChildWebContents()); return controller; }
diff --git a/content/browser/preloading/preloading_data_impl.cc b/content/browser/preloading/preloading_data_impl.cc index fe369d3..f17903c 100644 --- a/content/browser/preloading/preloading_data_impl.cc +++ b/content/browser/preloading/preloading_data_impl.cc
@@ -99,6 +99,11 @@ } // static +PreloadingData* PreloadingData::GetForWebContents(WebContents* web_contents) { + return PreloadingDataImpl::FromWebContents(web_contents); +} + +// static PreloadingDataImpl* PreloadingDataImpl::GetOrCreateForWebContents( WebContents* web_contents) { auto* preloading_impl = PreloadingDataImpl::FromWebContents(web_contents); @@ -373,6 +378,13 @@ } } +void PreloadingDataImpl::SetHasSpeculationRulesPrerender() { + has_speculation_rules_prerender_ = true; +} +bool PreloadingDataImpl::HasSpeculationRulesPrerender() { + return has_speculation_rules_prerender_; +} + void PreloadingDataImpl::RecordMetricsForPreloadingAttempts( ukm::SourceId navigated_page_source_id) { for (auto& attempt : preloading_attempts_) {
diff --git a/content/browser/preloading/preloading_data_impl.h b/content/browser/preloading/preloading_data_impl.h index 48aa0de..265ff3c7 100644 --- a/content/browser/preloading/preloading_data_impl.h +++ b/content/browser/preloading/preloading_data_impl.h
@@ -86,6 +86,8 @@ PreloadingPredictor predictor) { return is_navigation_in_predictor_domain_callbacks_.count(predictor); } + void SetHasSpeculationRulesPrerender(); + bool HasSpeculationRulesPrerender() override; void AddPreloadingPrediction(const PreloadingPredictor& predictor, PreloadingConfidence confidence, @@ -179,6 +181,10 @@ // navigation until the navigation takes place. std::vector<PreloadingPrediction> preloading_predictions_; + // This flag will be true if there's been at least 1 attempt to do a + // speculation-rules based prerender. + bool has_speculation_rules_prerender_ = false; + // The random seed used to determine if a preloading attempt should be sampled // in UKM logs. We use a different random seed for each session and then hash // that seed with the UKM source ID so that all attempts for a given source ID
diff --git a/content/browser/preloading/prerender/prerender_host.cc b/content/browser/preloading/prerender/prerender_host.cc index ae2768b..4ed0bfa2 100644 --- a/content/browser/preloading/prerender/prerender_host.cc +++ b/content/browser/preloading/prerender/prerender_host.cc
@@ -325,6 +325,14 @@ NOTREACHED_NORETURN(); } +FrameTree* PrerenderHost::GetOwnedPictureInPictureFrameTree() { + return nullptr; +} + +FrameTree* PrerenderHost::GetPictureInPictureOpenerFrameTree() { + return nullptr; +} + int PrerenderHost::GetOuterDelegateFrameTreeNodeId() { // A prerendered FrameTree is not "inner to" or "nested inside" another // FrameTree; it exists in parallel to the primary FrameTree of the current
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h index 22ab2346..2c23a4f 100644 --- a/content/browser/preloading/prerender/prerender_host.h +++ b/content/browser/preloading/prerender/prerender_host.h
@@ -149,6 +149,8 @@ int GetOuterDelegateFrameTreeNodeId() override; RenderFrameHostImpl* GetProspectiveOuterDocument() override; void SetFocusedFrame(FrameTreeNode* node, SiteInstanceGroup* source) override; + FrameTree* GetOwnedPictureInPictureFrameTree() override; + FrameTree* GetPictureInPictureOpenerFrameTree() override; // NavigationControllerDelegate void NotifyNavigationStateChangedFromController(
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc index bc97401..b188dfda 100644 --- a/content/browser/preloading/prerenderer_impl.cc +++ b/content/browser/preloading/prerenderer_impl.cc
@@ -241,6 +241,10 @@ GetContentClient()->browser()->LogWebFeatureForCurrentPage( &rfhi, blink::mojom::WebFeature::kSpeculationRulesPrerender); + auto* preloading_data = static_cast<PreloadingDataImpl*>( + PreloadingData::GetOrCreateForWebContents(web_contents)); + preloading_data->SetHasSpeculationRulesPrerender(); + IncrementReceivedPrerendersCountForMetrics( PreloadingTriggerTypeFromSpeculationInjectionType( candidate->injection_type),
diff --git a/content/browser/private_aggregation/private_aggregation_host.cc b/content/browser/private_aggregation/private_aggregation_host.cc index 844f4fde..101e5d5 100644 --- a/content/browser/private_aggregation/private_aggregation_host.cc +++ b/content/browser/private_aggregation/private_aggregation_host.cc
@@ -33,7 +33,6 @@ #include "base/uuid.h" #include "base/values.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/aggregation_service/aggregation_service_features.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" @@ -186,13 +185,6 @@ return false; } - if (!base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - // Override with the default if a non-default coordinator is specified when - // the feature is disabled. - aggregation_coordinator_origin = std::nullopt; - } - if (aggregation_coordinator_origin.has_value() && !aggregation_service::IsAggregationCoordinatorOriginAllowed( aggregation_coordinator_origin.value())) {
diff --git a/content/browser/private_aggregation/private_aggregation_host.h b/content/browser/private_aggregation/private_aggregation_host.h index f4bd2ea..bcb3a99 100644 --- a/content/browser/private_aggregation/private_aggregation_host.h +++ b/content/browser/private_aggregation/private_aggregation_host.h
@@ -121,10 +121,7 @@ // timeout, regardless of when the disconnection actually happens. `timeout` // must be positive if set. If `timeout` is set, `context_id` must be set too. // If `aggregation_coordinator_origin` is set, the origin must be on the - // allowlist. But if the `kAggregationServiceMultipleCloudProviders` - // feature is disabled, this function will act as if - // `aggregation_coordinator_origin` was not set. `filtering_id_max_bytes` must - // be positive and no greater than + // allowlist. `filtering_id_max_bytes` must be positive and no greater than // `AggregationServicePayloadContents::kMaximumFilteringIdMaxBytes`. The // return value indicates whether the receiver was accepted. Virtual for // testing.
diff --git a/content/browser/private_aggregation/private_aggregation_host_unittest.cc b/content/browser/private_aggregation/private_aggregation_host_unittest.cc index 50197ea..b92e9e4 100644 --- a/content/browser/private_aggregation/private_aggregation_host_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_host_unittest.cc
@@ -1015,69 +1015,6 @@ } } -TEST_F(PrivateAggregationHostTest, - AggregationCoordinatorOriginIgnoredIfFeatureDisabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - ::aggregation_service::kAggregationServiceMultipleCloudProviders); - ::aggregation_service::ScopedAggregationCoordinatorAllowlistForTesting - scoped_coordinator_allowlist( - {url::Origin::Create(GURL("https://a.test"))}); - - const url::Origin kExampleOrigin = - url::Origin::Create(GURL("https://example.com")); - const url::Origin kMainFrameOrigin = - url::Origin::Create(GURL("https://main_frame.com")); - - const url::Origin kValidCoordinatorOrigin = - url::Origin::Create(GURL("https://a.test")); - const url::Origin kInvalidCoordinatorOrigin = - url::Origin::Create(GURL("https://b.test")); - - const std::optional<url::Origin> kTestCases[] = { - std::nullopt, - kValidCoordinatorOrigin, - kInvalidCoordinatorOrigin, - }; - - for (const auto& test_case : kTestCases) { - base::HistogramTester histogram; - - mojo::Remote<blink::mojom::PrivateAggregationHost> remote; - bool bind_result = host_->BindNewReceiver( - kExampleOrigin, kMainFrameOrigin, - PrivateAggregationBudgetKey::Api::kProtectedAudience, - /*context_id=*/std::nullopt, /*timeout=*/std::nullopt, test_case, - PrivateAggregationHost::kDefaultFilteringIdMaxBytes, - remote.BindNewPipeAndPassReceiver()); - - // The provided origin should be ignored. - EXPECT_TRUE(bind_result); - - std::optional<AggregatableReportRequest> validated_request; - EXPECT_CALL(mock_callback_, Run) - .WillOnce(GenerateAndSaveReportRequest(&validated_request)); - - std::vector<blink::mojom::AggregatableReportHistogramContributionPtr> - contributions; - contributions.push_back( - blink::mojom::AggregatableReportHistogramContribution::New( - /*bucket=*/123, /*value=*/456, /*filtering_id=*/std::nullopt)); - remote->ContributeToHistogram(std::move(contributions)); - - remote.reset(); - host_->FlushReceiverSetForTesting(); - - histogram.ExpectUniqueSample( - kPipeResultHistogram, - PrivateAggregationHost::PipeResult::kReportSuccess, 1); - - ASSERT_TRUE(validated_request); - EXPECT_FALSE(validated_request->payload_contents() - .aggregation_coordinator_origin.has_value()); - } -} - TEST_F(PrivateAggregationHostTest, FilteringIdMaxBytesValidated) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitWithFeatures(
diff --git a/content/browser/renderer_host/back_forward_cache_metrics_browsertest.cc b/content/browser/renderer_host/back_forward_cache_metrics_browsertest.cc index 6308ff4..7afa915 100644 --- a/content/browser/renderer_host/back_forward_cache_metrics_browsertest.cc +++ b/content/browser/renderer_host/back_forward_cache_metrics_browsertest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "content/browser/renderer_host/back_forward_cache_metrics.h" + #include "base/functional/bind.h" #include "base/run_loop.h" #include "base/task/single_thread_task_runner.h" @@ -11,7 +13,6 @@ #include "build/build_config.h" #include "components/ukm/test_ukm_recorder.h" #include "content/browser/renderer_host/back_forward_cache_impl.h" -#include "content/browser/renderer_host/back_forward_cache_metrics.h" #include "content/browser/renderer_host/navigation_controller_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/content_navigation_policy.h" @@ -29,12 +30,14 @@ #include "content/public/test/test_navigation_observer.h" #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" +#include "mojo/public/cpp/test_support/test_utils.h" #include "net/dns/mock_host_resolver.h" #include "services/device/public/cpp/test/scoped_geolocation_overrider.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" +#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-test-utils.h" using base::Bucket; using testing::ElementsAre; @@ -106,17 +109,54 @@ void NavigateAndWaitForDisablingFeature( const GURL& url, blink::scheduler::WebSchedulerTrackedFeature feature) { - base::RunLoop run_loop; - current_frame_host() - ->SetBackForwardCacheDisablingFeaturesCallbackForTesting( - base::BindLambdaForTesting( - [&run_loop, feature]( - blink::scheduler::WebSchedulerTrackedFeatures features) { - if (features.Has(feature) && run_loop.running()) - run_loop.Quit(); - })); - EXPECT_TRUE(NavigateToURL(shell(), url)); - run_loop.Run(); + class BfcacheDisabledByFeatureWaiter + : public blink::mojom:: + BackForwardCacheControllerHostInterceptorForTesting { + public: + explicit BfcacheDisabledByFeatureWaiter( + RenderFrameHostImpl* render_frame_host, + blink::scheduler::WebSchedulerTrackedFeature expected_feature) + : render_frame_host_(render_frame_host), + swapped_impl_( + render_frame_host + ->back_forward_cache_controller_host_receiver_for_testing(), + this), + expected_feature_(expected_feature) {} + + void Wait() { run_loop_.Run(); } + + // BackForwardCacheControllerHostInterceptorForTesting overrides: + blink::mojom::BackForwardCacheControllerHost* GetForwardingInterface() + override { + return swapped_impl_.old_impl(); + } + + // BackForwardCacheControllerHost overrides: + void DidChangeBackForwardCacheDisablingFeatures( + RenderFrameHostImpl::BackForwardCacheBlockingDetails details) + override { + GetForwardingInterface()->DidChangeBackForwardCacheDisablingFeatures( + std::move(details)); + if (render_frame_host_->GetBackForwardCacheDisablingFeatures().Has( + expected_feature_)) { + run_loop_.Quit(); + } + } + + private: + base::RunLoop run_loop_; + const raw_ptr<RenderFrameHostImpl> render_frame_host_; + mojo::test::ScopedSwapImplForTesting< + blink::mojom::BackForwardCacheControllerHost> + swapped_impl_; + const blink::scheduler::WebSchedulerTrackedFeature expected_feature_; + }; + + { + BfcacheDisabledByFeatureWaiter waiter(current_frame_host(), feature); + EXPECT_TRUE(NavigateToURL(shell(), url)); + waiter.Wait(); + } EXPECT_EQ(base::Difference( current_frame_host()->GetBackForwardCacheDisablingFeatures(),
diff --git a/content/browser/renderer_host/compositor_dependencies_android.cc b/content/browser/renderer_host/compositor_dependencies_android.cc index 0e585cc7..9b49233 100644 --- a/content/browser/renderer_host/compositor_dependencies_android.cc +++ b/content/browser/renderer_host/compositor_dependencies_android.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/allocator/partition_alloc_support.h" #include "base/features.h" #include "base/functional/bind.h" #include "base/no_destructor.h" @@ -43,6 +44,9 @@ content::GpuProcessHost::CallOnUI( FROM_HERE, content::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, base::BindOnce([](content::GpuProcessHost* host) { + // This is not necessarily the most logical place to notify the + // allocator, but it matches the call made on the GPU process side. + base::allocator::PartitionAllocSupport::Get()->OnBackgrounded(); if (host) { host->gpu_service()->OnBackgrounded(); } @@ -53,6 +57,7 @@ content::GpuProcessHost::CallOnUI( FROM_HERE, content::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, base::BindOnce([](content::GpuProcessHost* host) { + base::allocator::PartitionAllocSupport::Get()->OnForegrounded(); if (host) { host->gpu_service()->OnForegrounded(); }
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h index 554df12..99d5e50 100644 --- a/content/browser/renderer_host/frame_tree.h +++ b/content/browser/renderer_host/frame_tree.h
@@ -193,6 +193,13 @@ // changing the focused frame tree in the case of inner/outer FrameTrees. virtual void SetFocusedFrame(FrameTreeNode* node, SiteInstanceGroup* source) = 0; + + // Returns this FrameTree's picture-in-picture FrameTree if it has one. + virtual FrameTree* GetOwnedPictureInPictureFrameTree() = 0; + + // Returns this FrameTree's opener if this FrameTree represents a + // picture-in-picture window. + virtual FrameTree* GetPictureInPictureOpenerFrameTree() = 0; }; // Type of FrameTree instance.
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index a634f066..1769f5e 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -754,6 +754,20 @@ rfh->ActivateUserActivation(notification_type, sticky_only); } + // If we're in a picture-in-picture frame tree, then also activate the opener + // frame of the picture-in-picture root. + FrameTree* pip_opener = + frame_tree().delegate()->GetPictureInPictureOpenerFrameTree(); + if (base::FeatureList::IsEnabled( + blink::features::kDocumentPictureInPictureUserActivation) && + pip_opener) { + RenderFrameHostImpl* opener_frame_host = + pip_opener->root()->current_frame_host(); + + opener_frame_host->DidReceiveUserActivation(); + opener_frame_host->ActivateUserActivation(notification_type, sticky_only); + } + current_frame_host()->browsing_context_state()->set_has_active_user_gesture( true); @@ -770,6 +784,24 @@ sticky_only); } } + + if (base::FeatureList::IsEnabled( + blink::features::kDocumentPictureInPictureUserActivation)) { + // If we own a picture-in-picture window, then also activate same-origin + // frames within the picture-in-picture window. + FrameTree* picture_in_picture_frame_tree = + frame_tree().delegate()->GetOwnedPictureInPictureFrameTree(); + if (picture_in_picture_frame_tree) { + for (FrameTreeNode* node : picture_in_picture_frame_tree->Nodes()) { + if (node->current_frame_host() + ->GetLastCommittedOrigin() + .IsSameOriginWith(current_origin)) { + node->current_frame_host()->ActivateUserActivation( + notification_type, sticky_only); + } + } + } + } } navigator().controller().NotifyUserActivation(); @@ -783,12 +815,39 @@ for (FrameTreeNode* node : frame_tree().Nodes()) { node->current_frame_host()->ConsumeTransientUserActivation(); } + + if (base::FeatureList::IsEnabled( + blink::features::kDocumentPictureInPictureUserActivation)) { + // If we're consuming user activation in a picture-in-picture window, ensure + // that its opener's frames also consume activation. + FrameTree* pip_opener = + frame_tree().delegate()->GetPictureInPictureOpenerFrameTree(); + if (pip_opener) { + for (FrameTreeNode* node : pip_opener->Nodes()) { + node->current_frame_host()->ConsumeTransientUserActivation(); + } + } + + // If we own a picture-in-picture window, ensure that its frames also + // consume activation. + FrameTree* picture_in_picture_frame_tree = + frame_tree().delegate()->GetOwnedPictureInPictureFrameTree(); + if (picture_in_picture_frame_tree) { + for (FrameTreeNode* node : picture_in_picture_frame_tree->Nodes()) { + node->current_frame_host()->ConsumeTransientUserActivation(); + } + } + } + current_frame_host()->browsing_context_state()->set_has_active_user_gesture( false); return was_active; } bool FrameTreeNode::ClearUserActivation() { + // Note that we don't need to clear user activation for the picture-in-picture + // subtree here since this is only called for a navigation, which closes the + // picture-in-picture window. for (FrameTreeNode* node : frame_tree().SubtreeNodes(this)) node->current_frame_host()->ClearUserActivation(); current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index aedbc1f..c9c7140 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -44,7 +44,7 @@ #include "ui/events/keycodes/keyboard_codes.h" #if defined(USE_AURA) -#include "content/browser/renderer_host/ui_events_helper.h" +#include "content/common/input/events_helper.h" #include "ui/events/event.h" #endif
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc index 535eb86..da8f452 100644 --- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc +++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -11,7 +11,6 @@ #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_aura.h" -#include "content/browser/renderer_host/ui_events_helper.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/compositor.h" @@ -41,6 +40,91 @@ return 0; } +enum class TouchEventCoordinateSystem { SCREEN_COORDINATES, LOCAL_COORDINATES }; + +ui::EventType WebTouchPointStateToEventType(blink::WebTouchPoint::State state) { + switch (state) { + case blink::WebTouchPoint::State::kStateReleased: + return ui::ET_TOUCH_RELEASED; + + case blink::WebTouchPoint::State::kStatePressed: + return ui::ET_TOUCH_PRESSED; + + case blink::WebTouchPoint::State::kStateMoved: + return ui::ET_TOUCH_MOVED; + + case blink::WebTouchPoint::State::kStateCancelled: + return ui::ET_TOUCH_CANCELLED; + + case blink::WebTouchPoint::State::kStateStationary: + case blink::WebTouchPoint::State::kStateUndefined: + return ui::ET_UNKNOWN; + } +} + +// Creates a list of ui::TouchEvents out of a single WebTouchEvent. +// A WebTouchEvent can contain information about a number of WebTouchPoints, +// whereas a ui::TouchEvent contains information about a single touch-point. So +// it is possible to create more than one ui::TouchEvents out of a single +// WebTouchEvent. All the ui::TouchEvent in the list will carry the same +// LatencyInfo the WebTouchEvent carries. +// |coordinate_system| specifies which fields to use for the co-ordinates, +// WebTouchPoint.position or WebTouchPoint.screenPosition. Is's up to the +// caller to do any co-ordinate system mapping (typically to get them into +// the Aura EventDispatcher co-ordinate system). +bool MakeUITouchEventsFromWebTouchEvents( + const TouchEventWithLatencyInfo& touch_with_latency, + std::vector<std::unique_ptr<ui::TouchEvent>>* list, + TouchEventCoordinateSystem coordinate_system) { + const blink::WebTouchEvent& touch = touch_with_latency.event; + ui::EventType type = ui::ET_UNKNOWN; + switch (touch.GetType()) { + case blink::WebInputEvent::Type::kTouchStart: + type = ui::ET_TOUCH_PRESSED; + break; + case blink::WebInputEvent::Type::kTouchEnd: + type = ui::ET_TOUCH_RELEASED; + break; + case blink::WebInputEvent::Type::kTouchMove: + type = ui::ET_TOUCH_MOVED; + break; + case blink::WebInputEvent::Type::kTouchCancel: + type = ui::ET_TOUCH_CANCELLED; + break; + default: + NOTREACHED_IN_MIGRATION(); + return false; + } + + int flags = ui::WebEventModifiersToEventFlags(touch.GetModifiers()); + base::TimeTicks timestamp = touch.TimeStamp(); + for (unsigned i = 0; i < touch.touches_length; ++i) { + const blink::WebTouchPoint& point = touch.touches[i]; + if (WebTouchPointStateToEventType(point.state) != type) { + continue; + } + // ui events start in the co-ordinate space of the EventDispatcher. + gfx::PointF location; + if (coordinate_system == TouchEventCoordinateSystem::LOCAL_COORDINATES) { + location = point.PositionInWidget(); + } else { + location = point.PositionInScreen(); + } + auto uievent = std::make_unique<ui::TouchEvent>( + type, gfx::Point(), timestamp, + ui::PointerDetails(ui::EventPointerType::kTouch, point.id, + point.radius_x, point.radius_y, point.force, + point.rotation_angle, point.tilt_x, point.tilt_y, + point.tangential_pressure), + flags); + uievent->set_location_f(location); + uievent->set_root_location_f(location); + uievent->set_latency(touch_with_latency.latency); + list->push_back(std::move(uievent)); + } + return true; +} + } // namespace SyntheticGestureTargetAura::SyntheticGestureTargetAura( @@ -71,7 +155,8 @@ } std::vector<std::unique_ptr<ui::TouchEvent>> events; bool conversion_success = MakeUITouchEventsFromWebTouchEvents( - touch_with_latency, &events, LOCAL_COORDINATES); + touch_with_latency, &events, + TouchEventCoordinateSystem::LOCAL_COORDINATES); DCHECK(conversion_success); aura::Window* window = GetWindow();
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc index 952f422..24ef474 100644 --- a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc +++ b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
@@ -7,7 +7,7 @@ #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" -#include "content/browser/renderer_host/ui_events_helper.h" +#include "content/common/input/events_helper.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "ui/events/blink/web_input_event_traits.h" #include "ui/events/event.h"
diff --git a/content/browser/renderer_host/input/touch_emulator.cc b/content/browser/renderer_host/input/touch_emulator.cc index ee0e9a2e..ea3b7a1 100644 --- a/content/browser/renderer_host/input/touch_emulator.cc +++ b/content/browser/renderer_host/input/touch_emulator.cc
@@ -11,7 +11,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "content/browser/renderer_host/input/motion_event_web.h" -#include "content/browser/renderer_host/ui_events_helper.h" +#include "content/common/input/events_helper.h" #include "content/common/input/render_widget_host_view_input.h" #include "content/common/input/web_touch_event_traits.h" #include "content/grit/content_resources.h"
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 74c760f..06136f3a 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4943,11 +4943,6 @@ renderer_reported_bfcache_blocking_details_ = std::move(details); MaybeEvictFromBackForwardCache(); - - if (back_forward_cache_disabling_features_callback_for_testing_) { - back_forward_cache_disabling_features_callback_for_testing_.Run( - GetBackForwardCacheDisablingFeatures()); - } } using BackForwardCacheDisablingFeatureHandle =
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 50b98ae..36ca129 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -1687,25 +1687,24 @@ mojo::PendingAssociatedReceiver<mojom::DomAutomationControllerHost> receiver); - // Exposed so that tests can swap the implementation and intercept calls. + // Expose Mojo receivers to tests for use with + // `mojo::test::ScopedSwapImplForTesting`. + mojo::AssociatedReceiver<blink::mojom::BackForwardCacheControllerHost>& + back_forward_cache_controller_host_receiver_for_testing() { + return back_forward_cache_controller_host_associated_receiver_; + } mojo::AssociatedReceiver<mojom::FrameHost>& frame_host_receiver_for_testing() { return frame_host_associated_receiver_; } - - // Exposed so that tests can swap the implementation and intercept calls. mojo::AssociatedReceiver<blink::mojom::LocalFrameHost>& local_frame_host_receiver_for_testing() { return local_frame_host_receiver_; } - - // Exposed so that tests can swap the implementation and intercept calls. mojo::AssociatedReceiver<blink::mojom::LocalMainFrameHost>& local_main_frame_host_receiver_for_testing() { return local_main_frame_host_receiver_; } - - // Exposed so that tests can swap the implementation and intercept calls. mojo::Receiver<blink::mojom::BrowserInterfaceBroker>& browser_interface_broker_receiver_for_testing() { return broker_receiver_; @@ -1883,12 +1882,6 @@ // information than `GetBackForwardCacheDisablingFeatures()`, which returns // only a list of features used. BackForwardCacheBlockingDetails GetBackForwardCacheBlockingDetails() const; - using BackForwardCacheDisablingFeaturesCallback = - base::RepeatingCallback<void(BackForwardCacheDisablingFeatures)>; - void SetBackForwardCacheDisablingFeaturesCallbackForTesting( - BackForwardCacheDisablingFeaturesCallback callback) { - back_forward_cache_disabling_features_callback_for_testing_ = callback; - } // Returns a PrefetchedSignedExchangeCache which is attached to |this|. scoped_refptr<PrefetchedSignedExchangeCache> @@ -5053,9 +5046,6 @@ // nested within a fenced frame. const FencedFrameStatus fenced_frame_status_; - BackForwardCacheDisablingFeaturesCallback - back_forward_cache_disabling_features_callback_for_testing_; - // Manages a transient affordance for this frame or subframes to open a popup. TransientAllowPopup transient_allow_popup_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 07a00a4..94d26d1 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -5247,6 +5247,8 @@ DCHECK(child_process_launcher_.get()); DCHECK(!child_process_launcher_->IsStarting()); #if BUILDFLAG(IS_ANDROID) + // TODO(339097516): Remove the following CHECK when the issue is fixed. + CHECK(child_process_launcher_->GetProcess().IsValid()); child_process_launcher_->SetRenderProcessPriority(priority_); #elif BUILDFLAG(IS_MAC) if (base::FeatureList::IsEnabled(
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 1a9bf18..bb11201a 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -97,7 +97,7 @@ #if defined(USE_AURA) #include "content/browser/renderer_host/render_widget_host_view_aura.h" -#include "content/browser/renderer_host/ui_events_helper.h" +#include "content/common/input/events_helper.h" #include "ui/aura/test/test_screen.h" #include "ui/events/event.h" #endif
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 67ed5f4db..8f5da124 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -54,11 +54,11 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" -#include "content/browser/renderer_host/ui_events_helper.h" #include "content/browser/renderer_host/visible_time_request_trigger.h" #include "content/browser/screen_orientation/screen_orientation_provider.h" #include "content/common/content_switches_internal.h" #include "content/common/features.h" +#include "content/common/input/events_helper.h" #include "content/common/input/input_router.h" #include "content/common/input/web_input_event_builders_android.h" #include "content/public/android/content_jni_headers/RenderWidgetHostViewImpl_jni.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 9989a02..fbad07b 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -49,8 +49,8 @@ #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_event_handler.h" -#include "content/browser/renderer_host/ui_events_helper.h" #include "content/browser/renderer_host/visible_time_request_trigger.h" +#include "content/common/input/events_helper.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/device_service.h" #include "content/public/browser/render_view_host.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_ios.mm b/content/browser/renderer_host/render_widget_host_view_ios.mm index 0479923..e39e6ad 100644 --- a/content/browser/renderer_host/render_widget_host_view_ios.mm +++ b/content/browser/renderer_host/render_widget_host_view_ios.mm
@@ -20,8 +20,8 @@ #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_ios_uiview.h" #include "content/browser/renderer_host/text_input_manager.h" -#include "content/browser/renderer_host/ui_events_helper.h" #include "content/common/content_switches_internal.h" +#include "content/common/input/events_helper.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/common/content_switches.h" #include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 171b2396..ca703d1 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -42,8 +42,8 @@ #include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #import "content/browser/renderer_host/text_input_client_mac.h" -#import "content/browser/renderer_host/ui_events_helper.h" #include "content/browser/renderer_host/visible_time_request_trigger.h" +#import "content/common/input/events_helper.h" #include "content/common/input/web_input_event_builders_mac.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_plugin_guest_manager.h"
diff --git a/content/browser/renderer_host/ui_events_helper.cc b/content/browser/renderer_host/ui_events_helper.cc deleted file mode 100644 index 0fc26a9..0000000 --- a/content/browser/renderer_host/ui_events_helper.cc +++ /dev/null
@@ -1,107 +0,0 @@ -// Copyright 2012 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/renderer_host/ui_events_helper.h" - -#include <stdint.h> - -#include "content/common/input/web_touch_event_traits.h" -#include "third_party/blink/public/common/features.h" -#include "third_party/blink/public/common/input/web_input_event.h" -#include "ui/events/base_event_utils.h" -#include "ui/events/blink/blink_event_util.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/events/types/event_type.h" - -namespace { - -ui::EventType WebTouchPointStateToEventType( - blink::WebTouchPoint::State state) { - switch (state) { - case blink::WebTouchPoint::State::kStateReleased: - return ui::ET_TOUCH_RELEASED; - - case blink::WebTouchPoint::State::kStatePressed: - return ui::ET_TOUCH_PRESSED; - - case blink::WebTouchPoint::State::kStateMoved: - return ui::ET_TOUCH_MOVED; - - case blink::WebTouchPoint::State::kStateCancelled: - return ui::ET_TOUCH_CANCELLED; - - default: - return ui::ET_UNKNOWN; - } -} - -} // namespace - -namespace content { - -bool MakeUITouchEventsFromWebTouchEvents( - const TouchEventWithLatencyInfo& touch_with_latency, - std::vector<std::unique_ptr<ui::TouchEvent>>* list, - TouchEventCoordinateSystem coordinate_system) { - const blink::WebTouchEvent& touch = touch_with_latency.event; - ui::EventType type = ui::ET_UNKNOWN; - switch (touch.GetType()) { - case blink::WebInputEvent::Type::kTouchStart: - type = ui::ET_TOUCH_PRESSED; - break; - case blink::WebInputEvent::Type::kTouchEnd: - type = ui::ET_TOUCH_RELEASED; - break; - case blink::WebInputEvent::Type::kTouchMove: - type = ui::ET_TOUCH_MOVED; - break; - case blink::WebInputEvent::Type::kTouchCancel: - type = ui::ET_TOUCH_CANCELLED; - break; - default: - NOTREACHED_IN_MIGRATION(); - return false; - } - - int flags = ui::WebEventModifiersToEventFlags(touch.GetModifiers()); - base::TimeTicks timestamp = touch.TimeStamp(); - for (unsigned i = 0; i < touch.touches_length; ++i) { - const blink::WebTouchPoint& point = touch.touches[i]; - if (WebTouchPointStateToEventType(point.state) != type) - continue; - // ui events start in the co-ordinate space of the EventDispatcher. - gfx::PointF location; - if (coordinate_system == LOCAL_COORDINATES) - location = point.PositionInWidget(); - else - location = point.PositionInScreen(); - auto uievent = std::make_unique<ui::TouchEvent>( - type, gfx::Point(), timestamp, - ui::PointerDetails(ui::EventPointerType::kTouch, point.id, - point.radius_x, point.radius_y, point.force, - point.rotation_angle, point.tilt_x, point.tilt_y, - point.tangential_pressure), - flags); - uievent->set_location_f(location); - uievent->set_root_location_f(location); - uievent->set_latency(touch_with_latency.latency); - list->push_back(std::move(uievent)); - } - return true; -} - -bool InputEventResultStateIsSetBlocking( - blink::mojom::InputEventResultState ack_state) { - // Default input events are marked as kNotConsumed and should not - // be marked as blocking. - switch (ack_state) { - case blink::mojom::InputEventResultState::kConsumed: - return true; - default: - return false; - } -} - -} // namespace content
diff --git a/content/browser/renderer_host/ui_events_helper.h b/content/browser/renderer_host/ui_events_helper.h deleted file mode 100644 index af4f47e..0000000 --- a/content/browser/renderer_host/ui_events_helper.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2012 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_UI_EVENTS_HELPER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_UI_EVENTS_HELPER_H_ - -#include <memory> -#include <vector> - -#include "content/common/input/event_with_latency_info.h" -#include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" - -namespace ui { -class TouchEvent; -} - -namespace content { - -enum TouchEventCoordinateSystem { - SCREEN_COORDINATES, - LOCAL_COORDINATES -}; - -// Creates a list of ui::TouchEvents out of a single WebTouchEvent. -// A WebTouchEvent can contain information about a number of WebTouchPoints, -// whereas a ui::TouchEvent contains information about a single touch-point. So -// it is possible to create more than one ui::TouchEvents out of a single -// WebTouchEvent. All the ui::TouchEvent in the list will carry the same -// LatencyInfo the WebTouchEvent carries. -// |coordinate_system| specifies which fields to use for the co-ordinates, -// WebTouchPoint.position or WebTouchPoint.screenPosition. Is's up to the -// caller to do any co-ordinate system mapping (typically to get them into -// the Aura EventDispatcher co-ordinate system). -bool MakeUITouchEventsFromWebTouchEvents( - const TouchEventWithLatencyInfo& touch, - std::vector<std::unique_ptr<ui::TouchEvent>>* list, - TouchEventCoordinateSystem coordinate_system); - -// Utility to map the event ack state from the renderer, returns true if the -// event could be handled blocking. -bool InputEventResultStateIsSetBlocking(blink::mojom::InputEventResultState); - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_UI_EVENTS_HELPER_H_
diff --git a/content/browser/sandbox_parameters_mac.h b/content/browser/sandbox_parameters_mac.h index cc023802..963e820c 100644 --- a/content/browser/sandbox_parameters_mac.h +++ b/content/browser/sandbox_parameters_mac.h
@@ -30,7 +30,7 @@ // This populates the sandbox parameters in the client for the given // |sandbox_type|. Some parameters may be extracted from the |command_line|. -CONTENT_EXPORT void SetupSandboxParameters( +CONTENT_EXPORT bool SetupSandboxParameters( sandbox::mojom::Sandbox sandbox_type, const base::CommandLine& command_line, #if BUILDFLAG(ENABLE_PPAPI)
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm index 1539c80..9b5a275 100644 --- a/content/browser/sandbox_parameters_mac.mm +++ b/content/browser/sandbox_parameters_mac.mm
@@ -203,7 +203,7 @@ } #endif -void SetupGpuSandboxParameters(sandbox::SandboxCompiler* compiler, +bool SetupGpuSandboxParameters(sandbox::SandboxCompiler* compiler, const base::CommandLine& command_line) { SetupCommonSandboxParameters(compiler, command_line); AddDarwinDirs(compiler); @@ -221,18 +221,22 @@ @autoreleasepool { NSBundle* helper_bundle = [NSBundle bundleWithPath:base::SysUTF8ToNSString(helper_bundle_path.value())]; - CHECK(helper_bundle); + if (!helper_bundle) { + return false; + } - CHECK(compiler->SetParameter( + return compiler->SetParameter( sandbox::policy::kParamHelperBundleId, - base::SysNSStringToUTF8(helper_bundle.bundleIdentifier))); + base::SysNSStringToUTF8(helper_bundle.bundleIdentifier)); } } + + return true; } } // namespace -void SetupSandboxParameters(sandbox::mojom::Sandbox sandbox_type, +bool SetupSandboxParameters(sandbox::mojom::Sandbox sandbox_type, const base::CommandLine& command_line, #if BUILDFLAG(ENABLE_PPAPI) const std::vector<content::WebPluginInfo>& plugins, @@ -254,10 +258,8 @@ SetupCommonSandboxParameters(compiler, command_line); break; case sandbox::mojom::Sandbox::kOnDeviceModelExecution: - case sandbox::mojom::Sandbox::kGpu: { - SetupGpuSandboxParameters(compiler, command_line); - break; - } + case sandbox::mojom::Sandbox::kGpu: + return SetupGpuSandboxParameters(compiler, command_line); case sandbox::mojom::Sandbox::kNetwork: SetupNetworkSandboxParameters(compiler, command_line); break; @@ -279,6 +281,7 @@ CHECK(GetContentClient()->browser()->SetupEmbedderSandboxParameters( sandbox_type, compiler)); } + return true; } void SetNetworkTestCertsDirectoryForTesting(const base::FilePath& path) {
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc index 115c4b43..445b786 100644 --- a/content/browser/service_worker/service_worker_container_host.cc +++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -535,8 +535,8 @@ void ServiceWorkerClient::OnExecutionReady() { // Since `OnExecutionReady()` is a part of `ServiceWorkerContainerHost`, - // this method is called only if `is_container_ready_` is true. - CHECK(is_container_ready_); + // this method is called only if `is_container_ready()` is true. + CHECK(is_container_ready()); if (is_execution_ready()) { mojo::ReportBadMessage("SWPH_OER_ALREADY_READY"); @@ -744,7 +744,7 @@ base::WeakPtr<ServiceWorkerObjectHost> object_host = container_host().version_object_manager().GetOrCreateHost(version); - if (!is_container_ready_) { + if (!is_container_ready()) { if (buffered_messages_.size() < kMaxBufferedMessageSize) { buffered_messages_.emplace_back(object_host, std::move(message)); } @@ -775,7 +775,7 @@ // `container_` can be used only if ServiceWorkerContainerInfoForClient has // been passed to the renderer process. Otherwise, the method call will crash // inside the mojo library (See crbug.com/40918057). - if (!is_container_ready_) { + if (!is_container_ready()) { base::UmaHistogramEnumeration( kDropOutMetrics, CountFeatureDropOutReason::kContainerNotReady); buffered_used_features_.insert(feature); @@ -870,7 +870,7 @@ void ServiceWorkerClient::SendSetControllerServiceWorker( bool notify_controllerchange) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - CHECK(is_container_ready_); + CHECK(is_container_ready()); if (!controller_ || !context_) { // Do not set |fetch_request_window_id| when |controller_| is not available. @@ -910,7 +910,7 @@ SCOPED_CRASH_KEY_NUMBER("SWCH_SC", "client_type", static_cast<int32_t>(GetClientType())); SCOPED_CRASH_KEY_BOOL("SWCH_SC", "is_execution_ready", is_execution_ready()); - SCOPED_CRASH_KEY_BOOL("SWCH_SC", "is_container_ready", is_container_ready_); + SCOPED_CRASH_KEY_BOOL("SWCH_SC", "is_container_ready", is_container_ready()); container_host().SendSetController(std::move(controller_info), notify_controllerchange); @@ -1118,6 +1118,7 @@ coep_reporter, ukm::SourceId ukm_source_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + CHECK_EQ(client_phase_, ClientPhase::kInitial); if (IsContainerForWindowClient()) { CHECK(coep_reporter); @@ -1356,8 +1357,23 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); switch (client_phase_) { case ClientPhase::kInitial: + case ClientPhase::kResponseNotCommitted: return false; case ClientPhase::kResponseCommitted: + case ClientPhase::kContainerReady: + case ClientPhase::kExecutionReady: + return true; + } +} + +bool ServiceWorkerClient::is_container_ready() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + switch (client_phase_) { + case ClientPhase::kInitial: + case ClientPhase::kResponseCommitted: + case ClientPhase::kResponseNotCommitted: + return false; + case ClientPhase::kContainerReady: case ClientPhase::kExecutionReady: return true; } @@ -1372,7 +1388,15 @@ bool ServiceWorkerClient::is_execution_ready() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return client_phase_ == ClientPhase::kExecutionReady; + switch (client_phase_) { + case ClientPhase::kInitial: + case ClientPhase::kResponseCommitted: + case ClientPhase::kResponseNotCommitted: + case ClientPhase::kContainerReady: + return false; + case ClientPhase::kExecutionReady: + return true; + } } GlobalRenderFrameHostId ServiceWorkerClient::GetRenderFrameHostId() const { @@ -1587,14 +1611,38 @@ void ServiceWorkerClient::SetExecutionReady() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!is_execution_ready()); - TransitionToClientPhase(ClientPhase::kExecutionReady); - RunExecutionReadyCallbacks(); - if (context_) - context_->NotifyClientIsExecutionReady(*this); + switch (client_phase_) { + case ClientPhase::kInitial: + // When `CommitResponse()` is not yet called, it should be skipped because + // the service worker client initialization failed somewhere, and thus + // ignore the `SetExecutionReady()` call here and transition to + // `kResponseNotCommitted` to confirm that no further transitions are + // attempted. See also the comment at `kResponseNotCommitted` in the + // header file. + TransitionToClientPhase(ClientPhase::kResponseNotCommitted); + break; - FlushFeatures(); + case ClientPhase::kContainerReady: + // Successful case. + TransitionToClientPhase(ClientPhase::kExecutionReady); + RunExecutionReadyCallbacks(); + + if (context_) { + context_->NotifyClientIsExecutionReady(*this); + } + + FlushFeatures(); + break; + + case ClientPhase::kResponseCommitted: + case ClientPhase::kExecutionReady: + case ClientPhase::kResponseNotCommitted: + // Invalid state transition. + NOTREACHED_NORETURN() + << "ServiceWorkerClient::SetExecutionReady() called on ClientPhase " + << static_cast<int>(client_phase_); + } } void ServiceWorkerClient::RunExecutionReadyCallbacks() { @@ -1612,14 +1660,19 @@ return; switch (client_phase_) { case ClientPhase::kInitial: - DCHECK_EQ(new_phase, ClientPhase::kResponseCommitted); + CHECK(new_phase == ClientPhase::kResponseCommitted || + new_phase == ClientPhase::kResponseNotCommitted); break; case ClientPhase::kResponseCommitted: - DCHECK_EQ(new_phase, ClientPhase::kExecutionReady); + CHECK_EQ(new_phase, ClientPhase::kContainerReady); + break; + case ClientPhase::kContainerReady: + CHECK_EQ(new_phase, ClientPhase::kExecutionReady); break; case ClientPhase::kExecutionReady: - NOTREACHED_IN_MIGRATION(); - break; + case ClientPhase::kResponseNotCommitted: + NOTREACHED_NORETURN() + << "Invalid transition from " << static_cast<int>(client_phase_); } client_phase_ = new_phase; } @@ -1668,7 +1721,7 @@ // sent in the same IPC call. Moreover, it is harmful to resend the past // SetController to the renderer because it moves the controller in the // renderer to the past one. - if (!is_container_ready_) { + if (!is_container_ready()) { return; } @@ -2087,7 +2140,7 @@ void ServiceWorkerClient::SetContainerReady() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - is_container_ready_ = true; + TransitionToClientPhase(ClientPhase::kContainerReady); std::vector<std::tuple<base::WeakPtr<ServiceWorkerObjectHost>, blink::TransferableMessage>> messages;
diff --git a/content/browser/service_worker/service_worker_container_host.h b/content/browser/service_worker/service_worker_container_host.h index 2ded05b2..22fe8a42 100644 --- a/content/browser/service_worker/service_worker_container_host.h +++ b/content/browser/service_worker/service_worker_container_host.h
@@ -513,17 +513,48 @@ void RunExecutionReadyCallbacks(); - // For service worker clients. The flow is kInitial -> kResponseCommitted -> - // kExecutionReady. + // For service worker clients. The flow is: + // - kInitial -> kResponseCommitted -> kContainerReady -> kExecutionReady + // - kInitial -> kResponseNotCommitted (client initialization failure cases) + // - kInitial (no transitions, client initialization failure cases) // - // - kInitial: The initial phase. - // - kResponseCommitted: The response for the main resource has been - // committed to the renderer. This client's URL should no longer change. - // - kExecutionReady: This client can be exposed to JavaScript as a Client - // object. - enum class ClientPhase { kInitial, kResponseCommitted, kExecutionReady }; + // - kInitial: The initial phase. Container host mojo messages are buffered + // because the message pipe is piggy-backed and isn't associated to the + // existing message pipe yet. + // + // - kResponseCommitted: `CommitResponse()` is called, i.e. the response for + // the main resource is about to be committed to the renderer and container + // host's mojo endpoints are about to be passed to the renderer. This + // client's URL should no longer change. The client should immediately + // transition to kContainerReady and thus the kResponseCommitted state + // shouldn't be observed (except for the code for response commit and + // transitioning to kContainerReady). + // + // - kContainerReady: `SetContainerReady()` is called. The response commit has + // completed. The container host's mojo pipes are ready to use. + // + // - kExecutionReady: `SetExecutionReady()` is called. This client can be + // exposed to JavaScript as a Client object. + // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-execution-ready-flag + // + // - kResponseNotCommitted: `CommitResponse()` is not called (and worker + // script loading is considered failed) but `SetExecutionReady()` is called. + // This can happen e.g. on COEP errors because its caller + // (`WorkerScriptLoader::CommitCompleted()`) doesn't take COEP errors into + // account. `CommitResponse()` is never called after reaching this state + // (i.e. it's not a race condition between `CommitResponse()` and + // `SetExecutionReady()`). + enum class ClientPhase { + kInitial, + kResponseCommitted, + kContainerReady, + kExecutionReady, + kResponseNotCommitted + }; void TransitionToClientPhase(ClientPhase new_phase); + bool is_container_ready() const; + // Sets the controller to |controller_registration_->active_version()| or null // if there is no associated registration. // @@ -617,13 +648,6 @@ mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> pending_controller_receiver_; - // |is_container_ready_| is set to be true after |container_| has been passed - // to the renderer process. This flag is needed to prevent |container_| used - // before the association to the existing message pipe, which happens when - // |container_| is passed to the renderer via a mojo call. Note that the mojo - // call's message pipe is piggy-backed. - bool is_container_ready_ = false; - // The type of client. std::optional<ServiceWorkerClientInfo> client_info_;
diff --git a/content/browser/service_worker/service_worker_container_host_unittest.cc b/content/browser/service_worker/service_worker_container_host_unittest.cc index 999c6bfa..53c139a40 100644 --- a/content/browser/service_worker/service_worker_container_host_unittest.cc +++ b/content/browser/service_worker/service_worker_container_host_unittest.cc
@@ -1200,6 +1200,7 @@ service_worker_client->CommitResponse( /*rfh_id=*/std::nullopt, PolicyContainerPolicies(), /*coep_reporter=*/{}, ukm::UkmRecorder::GetNewSourceID()); + service_worker_client->SetContainerReady(); service_worker_client->SetExecutionReady(); EXPECT_TRUE(CanFindServiceWorkerClient(service_worker_client.get())); } @@ -1293,6 +1294,7 @@ service_worker_client->CommitResponse( /*rfh_id=*/std::nullopt, PolicyContainerPolicies(), /*coep_reporter=*/{}, ukm::UkmRecorder::GetNewSourceID()); + service_worker_client->SetContainerReady(); service_worker_client->SetExecutionReady(); EXPECT_TRUE(service_worker_client->is_response_committed());
diff --git a/content/browser/site_per_process_oopsif_browsertest.cc b/content/browser/site_per_process_oopsif_browsertest.cc index 361ae41..9674f6d 100644 --- a/content/browser/site_per_process_oopsif_browsertest.cc +++ b/content/browser/site_per_process_oopsif_browsertest.cc
@@ -1054,14 +1054,18 @@ ASSERT_TRUE(WaitForLoadStop(shell()->web_contents())); } - // Verify parent and child frames share a SiteInstance + // Verify parent and child frames share a non-sandboxed SiteInstance. FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); ASSERT_EQ(1U, root->child_count()); FrameTreeNode* child = root->child_at(0); EXPECT_EQ(root->current_frame_host()->GetSiteInstance(), child->current_frame_host()->GetSiteInstance()); + EXPECT_FALSE(child->current_frame_host() + ->GetSiteInstance() + ->GetSiteInfo() + .is_sandboxed()); - // Now make subframe sandboxed. + // Now make the subframe sandboxed. { std::string js_str( "var frame = document.getElementById('test_frame'); " @@ -1070,12 +1074,21 @@ } NavigateFrameToURL(child, embedded_test_server()->GetURL("b.com", "/title1.html")); - // Child should now be in a different SiteInstance. + + // Child should now be in a different, sandboxed SiteInstance. EXPECT_NE(root->current_frame_host()->GetSiteInstance(), child->current_frame_host()->GetSiteInstance()); + EXPECT_TRUE(child->current_frame_host() + ->GetSiteInstance() + ->GetSiteInfo() + .is_sandboxed()); - // Go back and ensure the data: URL committed in the same SiteInstance as the - // original navigation. + // Go back and ensure the data: URL remains sandboxed, and committed in a + // different SiteInstance from the original navigation. From the spec: + // "Generally speaking, dynamically removing or changing the sandbox attribute + // is ill-advised, because it can make it quite hard to reason about what will + // be allowed and what will not." + // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-sandbox EXPECT_TRUE(web_contents()->GetController().CanGoBack()); { TestFrameNavigationObserver frame_observer(child); @@ -1084,6 +1097,14 @@ } EXPECT_NE(root->current_frame_host()->GetSiteInstance(), child->current_frame_host()->GetSiteInstance()); + EXPECT_FALSE(root->current_frame_host() + ->GetSiteInstance() + ->GetSiteInfo() + .is_sandboxed()); + EXPECT_TRUE(child->current_frame_host() + ->GetSiteInstance() + ->GetSiteInfo() + .is_sandboxed()); EXPECT_EQ(GURL(data_url_str), child->current_frame_host()->GetLastCommittedURL()); }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index ee38896..9223bfb 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -238,6 +238,11 @@ #include "content/browser/starscan_load_observer.h" #endif +#if !BUILDFLAG(IS_ANDROID) +#include "content/public/browser/document_picture_in_picture_window_controller.h" +#include "content/public/browser/picture_in_picture_window_controller.h" +#endif // !BUILDFLAG(IS_ANDROID) + namespace content { namespace { @@ -3556,6 +3561,10 @@ if (params.picture_in_picture_options.has_value()) { picture_in_picture_options_ = params.picture_in_picture_options; + if (GetOpener()) { + picture_in_picture_opener_ = + FromRenderFrameHostImpl(GetOpener())->GetWeakPtr(); + } } // This is set before initializing the render manager since @@ -8997,6 +9006,34 @@ CloseListenerManager::DidChangeFocusedFrame(this); } +FrameTree* WebContentsImpl::GetOwnedPictureInPictureFrameTree() { +#if !BUILDFLAG(IS_ANDROID) + if (has_picture_in_picture_document_) { + WebContents* picture_in_picture_web_contents = + PictureInPictureWindowController:: + GetOrCreateDocumentPictureInPictureController(this) + ->GetChildWebContents(); + if (picture_in_picture_web_contents) { + return &(static_cast<WebContentsImpl*>(picture_in_picture_web_contents) + ->GetPrimaryFrameTree()); + } + } +#endif // !BUILDFLAG(IS_ANDROID) + + return nullptr; +} + +FrameTree* WebContentsImpl::GetPictureInPictureOpenerFrameTree() { +#if !BUILDFLAG(IS_ANDROID) + if (picture_in_picture_opener_) { + return &(static_cast<WebContentsImpl*>(picture_in_picture_opener_.get()) + ->GetPrimaryFrameTree()); + } +#endif // !BUILDFLAG(IS_ANDROID) + + return nullptr; +} + void WebContentsImpl::DidCallFocus() { OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::DidCallFocus"); // Any explicit focusing of another window while this WebContents is in
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index e2d6e1d..1ba9274 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -1144,6 +1144,8 @@ RenderFrameHostImpl* GetProspectiveOuterDocument() override; FrameTree* LoadingTree() override; void SetFocusedFrame(FrameTreeNode* node, SiteInstanceGroup* source) override; + FrameTree* GetOwnedPictureInPictureFrameTree() override; + FrameTree* GetPictureInPictureOpenerFrameTree() override; // NavigationControllerDelegate ---------------------------------------------- @@ -2483,6 +2485,11 @@ std::optional<blink::mojom::PictureInPictureWindowOptions> picture_in_picture_options_; + // Only set if this WebContents represents a document picture-in-picture + // window. This points to the WebContents that originally opened this + // WebContents. + base::WeakPtr<WebContents> picture_in_picture_opener_; + VisibleTimeRequestTrigger visible_time_request_trigger_; // Counts the number of open scopes that disallow custom cursors in this web
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index e0495bd..86bb5cc 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -336,10 +336,7 @@ storage_partition_impl->GetServiceWorkerContext(), service_worker_handle_.get(), std::move(blob_url_loader_factory), nullptr, storage_partition_impl, partition_domain, - // TODO(crbug.com/40153087): Propagate dedicated worker ukm::SourceId - // here. - ukm::kInvalidSourceId, DedicatedWorkerDevToolsAgentHost::GetFor(this), - token_.value(), + DedicatedWorkerDevToolsAgentHost::GetFor(this), token_.value(), /*require_cross_site_request_for_cookies=*/false, has_storage_access, base::BindOnce(&DedicatedWorkerHost::DidStartScriptLoad, weak_factory_.GetWeakPtr())); @@ -484,6 +481,15 @@ DedicatedWorkerDevToolsAgentHost::GetFor(this)->devtools_worker_token(), network::URLLoaderCompletionStatus(net::OK)); + if (service_worker_handle_->service_worker_client()) { + // TODO(crbug.com/41478971): Plumb the COEP reporter. + // TODO(crbug.com/40153087): Propagate dedicated worker ukm::SourceId + // here. + service_worker_handle_->service_worker_client()->CommitResponse( + /*rfh_id=*/std::nullopt, std::move(result->policy_container_policies), + /*coep_reporter=*/{}, ukm::kInvalidSourceId); + } + client_->OnScriptLoadStarted( service_worker_handle_->TakeContainerInfo(), std::move(result->main_script_load_params),
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc index 89b7c629..e91c3abe 100644 --- a/content/browser/worker_host/shared_worker_host.cc +++ b/content/browser/worker_host/shared_worker_host.cc
@@ -347,6 +347,13 @@ service_worker_sent_state = result.controller->object_info->state; } + if (service_worker_handle_->service_worker_client()) { + // TODO(crbug.com/41478971): Plumb the COEP reporter. + service_worker_handle_->service_worker_client()->CommitResponse( + /*rfh_id=*/std::nullopt, std::move(result.policy_container_policies), + /*coep_reporter=*/{}, ukm_source_id()); + } + // Send the CreateSharedWorker message. factory_.Bind(std::move(factory)); factory_->CreateSharedWorker(
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc index 633f030..271cc956 100644 --- a/content/browser/worker_host/shared_worker_host_unittest.cc +++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -148,18 +148,19 @@ host->SetServiceWorkerHandle(std::move(service_worker_handle)); TestContentBrowserClient client; - host->Start(std::move(factory), - blink::mojom::FetchClientSettingsObject::New( - network::mojom::ReferrerPolicy::kDefault, - /*outgoing_referrer=*/GURL(), - blink::mojom::InsecureRequestsPolicy::kDoNotUpgrade), - &client, - WorkerScriptFetcherResult( - std::move(subresource_loader_factories), - std::move(main_script_load_params), - /*controller=*/nullptr, - /*controller_service_worker_object_host=*/nullptr, - final_response_url)); + host->Start( + std::move(factory), + blink::mojom::FetchClientSettingsObject::New( + network::mojom::ReferrerPolicy::kDefault, + /*outgoing_referrer=*/GURL(), + blink::mojom::InsecureRequestsPolicy::kDoNotUpgrade), + &client, + WorkerScriptFetcherResult( + std::move(subresource_loader_factories), + std::move(main_script_load_params), PolicyContainerPolicies(), + /*controller=*/nullptr, + /*controller_service_worker_object_host=*/nullptr, + final_response_url)); } MessagePortChannel AddClient(
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc index ccca3bf..73c162d 100644 --- a/content/browser/worker_host/shared_worker_service_impl.cc +++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -409,7 +409,7 @@ network::mojom::RequestDestination::kSharedWorker, service_worker_context_, service_worker_handle_raw, std::move(blob_url_loader_factory), url_loader_factory_override_, - storage_partition_, storage_domain, host->ukm_source_id(), + storage_partition_, storage_domain, SharedWorkerDevToolsAgentHost::GetFor(host), host->GetDevToolsToken(), host->instance().DoesRequireCrossSiteRequestForCookies(), has_storage_access,
diff --git a/content/browser/worker_host/worker_script_fetcher.cc b/content/browser/worker_host/worker_script_fetcher.cc index 86cf0c5e..1a1e1f2e 100644 --- a/content/browser/worker_host/worker_script_fetcher.cc +++ b/content/browser/worker_host/worker_script_fetcher.cc
@@ -17,6 +17,7 @@ #include "content/browser/loader/url_loader_factory_utils.h" #include "content/browser/navigation_subresource_loader_params.h" #include "content/browser/renderer_host/frame_tree_node.h" +#include "content/browser/renderer_host/policy_container_host.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_main_resource_handle.h" @@ -178,10 +179,14 @@ // The load succeeded iff `main_script_load_params` is not nullptr. if (main_script_load_params) { + // TODO(crbug.com/41478971): Pass the PolicyContainerPolicies. It can + // be built from the + // `main_script_load_params.response_head->parsed_headers`. std::move(callback).Run(std::make_optional<WorkerScriptFetcherResult>( std::move(subresource_loader_factories), - std::move(main_script_load_params), std::move(controller), - std::move(controller_service_worker_object_host), final_response_url)); + std::move(main_script_load_params), PolicyContainerPolicies(), + std::move(controller), std::move(controller_service_worker_object_host), + final_response_url)); } else { std::move(callback).Run(std::nullopt); } @@ -211,12 +216,14 @@ std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loader_factories, blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params, + PolicyContainerPolicies policy_container_policies, blink::mojom::ControllerServiceWorkerInfoPtr controller, base::WeakPtr<ServiceWorkerObjectHost> controller_service_worker_object_host, const GURL& final_response_url) : subresource_loader_factories(std::move(subresource_loader_factories)), main_script_load_params(std::move(main_script_load_params)), + policy_container_policies(std::move(policy_container_policies)), controller(std::move(controller)), controller_service_worker_object_host( std::move(controller_service_worker_object_host)), @@ -253,7 +260,6 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override, StoragePartitionImpl* storage_partition, const std::string& storage_domain, - ukm::SourceId worker_source_id, DevToolsAgentHostImpl* devtools_agent_host, const base::UnguessableToken& devtools_worker_token, bool require_cross_site_request_for_cookies, @@ -374,9 +380,9 @@ std::move(subresource_loader_factories), std::move(service_worker_context), service_worker_handle, std::move(blob_url_loader_factory), - std::move(url_loader_factory_override), worker_source_id, - devtools_agent_host, devtools_worker_token, - require_cross_site_request_for_cookies, std::move(callback)); + std::move(url_loader_factory_override), devtools_agent_host, + devtools_worker_token, require_cross_site_request_for_cookies, + std::move(callback)); } void WorkerScriptFetcher::CreateScriptLoader( @@ -396,7 +402,6 @@ ServiceWorkerMainResourceHandle* service_worker_handle, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override, - ukm::SourceId worker_source_id, DevToolsAgentHostImpl* devtools_agent_host, const base::UnguessableToken& devtools_worker_token, bool require_cross_site_request_for_cookies, @@ -518,7 +523,7 @@ std::make_unique<WorkerScriptLoaderFactory>( worker_process_id, worker_token, trusted_isolation_info, service_worker_handle, browser_context_getter, - std::move(url_loader_factory), worker_source_id), + std::move(url_loader_factory)), std::move(resource_request), base::BindOnce(DidCreateScriptLoader, std::move(callback), std::move(subresource_loader_factories),
diff --git a/content/browser/worker_host/worker_script_fetcher.h b/content/browser/worker_host/worker_script_fetcher.h index c3d653cd..b07ee8eb 100644 --- a/content/browser/worker_host/worker_script_fetcher.h +++ b/content/browser/worker_host/worker_script_fetcher.h
@@ -9,12 +9,12 @@ #include "base/functional/callback.h" #include "content/browser/navigation_subresource_loader_params.h" +#include "content/browser/renderer_host/policy_container_host.h" #include "content/common/content_export.h" #include "content/public/browser/service_worker_client_info.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "net/url_request/redirect_info.h" -#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/client_security_state.mojom-forward.h" #include "services/network/public/mojom/url_loader.mojom.h" @@ -59,6 +59,7 @@ std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loader_factories, blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params, + PolicyContainerPolicies policy_container_policies, blink::mojom::ControllerServiceWorkerInfoPtr controller, base::WeakPtr<ServiceWorkerObjectHost> controller_service_worker_object_host, @@ -81,6 +82,8 @@ // `response_head->parsed_headers`. blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params; + PolicyContainerPolicies policy_container_policies; + // May be nullptr. // Contains information about the service worker controller (if any). Once // a ServiceWorker object about the controller is prepared, it is registered @@ -160,7 +163,6 @@ url_loader_factory_override, StoragePartitionImpl* storage_partition, const std::string& storage_domain, - ukm::SourceId worker_source_id, DevToolsAgentHostImpl* devtools_agent_host, const base::UnguessableToken& devtools_worker_token, bool require_cross_site_request_for_cookies, @@ -233,7 +235,6 @@ scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override, - ukm::SourceId worker_source_id, DevToolsAgentHostImpl* devtools_agent_host, const base::UnguessableToken& devtools_worker_token, bool require_cross_site_request_for_cookies,
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc index a0f1dd4f..5b54cd65 100644 --- a/content/browser/worker_host/worker_script_loader.cc +++ b/content/browser/worker_host/worker_script_loader.cc
@@ -31,8 +31,7 @@ base::WeakPtr<ServiceWorkerMainResourceHandle> service_worker_handle, const BrowserContextGetter& browser_context_getter, scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory, - const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, - ukm::SourceId ukm_source_id) + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) : request_id_(request_id), options_(options), resource_request_(resource_request), @@ -40,8 +39,7 @@ service_worker_handle_(std::move(service_worker_handle)), browser_context_getter_(browser_context_getter), default_loader_factory_(std::move(default_loader_factory)), - traffic_annotation_(traffic_annotation), - ukm_source_id_(ukm_source_id) { + traffic_annotation_(traffic_annotation) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!service_worker_handle_) { @@ -326,12 +324,6 @@ if (complete_status_->error_code == net::OK && service_worker_handle_ && service_worker_handle_->service_worker_client()) { - // TODO(crbug.com/41478971): Pass the PolicyContainerPolicies. It can - // be built from `WorkerScriptLoader::OnReceiveResponse` from the - // `response_head->parsed_headers`. - service_worker_handle_->service_worker_client()->CommitResponse( - /*rfh_id=*/std::nullopt, PolicyContainerPolicies(), - /*coep_reporter=*/{}, ukm_source_id_); service_worker_handle_->service_worker_client()->SetExecutionReady(); }
diff --git a/content/browser/worker_host/worker_script_loader.h b/content/browser/worker_host/worker_script_loader.h index f9a7592b..0385c03 100644 --- a/content/browser/worker_host/worker_script_loader.h +++ b/content/browser/worker_host/worker_script_loader.h
@@ -21,7 +21,6 @@ #include "net/base/load_timing_info.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/url_request.h" -#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/single_request_url_loader_factory.h" #include "services/network/public/cpp/url_loader_completion_status.h" @@ -77,8 +76,7 @@ base::WeakPtr<ServiceWorkerMainResourceHandle> service_worker_handle, const BrowserContextGetter& browser_context_getter, scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory, - const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, - ukm::SourceId ukm_source_id); + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation); WorkerScriptLoader(const WorkerScriptLoader&) = delete; WorkerScriptLoader& operator=(const WorkerScriptLoader&) = delete; @@ -140,7 +138,6 @@ BrowserContextGetter browser_context_getter_; scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory_; net::MutableNetworkTrafficAnnotationTag traffic_annotation_; - const ukm::SourceId ukm_source_id_; std::optional<net::RedirectInfo> redirect_info_; int redirect_limit_ = net::URLRequest::kMaxRedirects;
diff --git a/content/browser/worker_host/worker_script_loader_factory.cc b/content/browser/worker_host/worker_script_loader_factory.cc index 60070a79..d6fe9d39 100644 --- a/content/browser/worker_host/worker_script_loader_factory.cc +++ b/content/browser/worker_host/worker_script_loader_factory.cc
@@ -25,14 +25,12 @@ const net::IsolationInfo& isolation_info, ServiceWorkerMainResourceHandle* service_worker_handle, const BrowserContextGetter& browser_context_getter, - scoped_refptr<network::SharedURLLoaderFactory> loader_factory, - ukm::SourceId worker_source_id) + scoped_refptr<network::SharedURLLoaderFactory> loader_factory) : process_id_(process_id), worker_token_(worker_token), isolation_info_(isolation_info), browser_context_getter_(browser_context_getter), - loader_factory_(std::move(loader_factory)), - worker_source_id_(worker_source_id) { + loader_factory_(std::move(loader_factory)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (service_worker_handle) { @@ -63,8 +61,7 @@ auto script_loader = std::make_unique<WorkerScriptLoader>( process_id_, worker_token_, request_id, options, resource_request, isolation_info_, std::move(client), service_worker_handle_, - browser_context_getter_, loader_factory_, traffic_annotation, - worker_source_id_); + browser_context_getter_, loader_factory_, traffic_annotation); script_loader_ = script_loader->GetWeakPtr(); mojo::MakeSelfOwnedReceiver(std::move(script_loader), std::move(receiver)); }
diff --git a/content/browser/worker_host/worker_script_loader_factory.h b/content/browser/worker_host/worker_script_loader_factory.h index 6a4ea04..9f035b6 100644 --- a/content/browser/worker_host/worker_script_loader_factory.h +++ b/content/browser/worker_host/worker_script_loader_factory.h
@@ -12,7 +12,6 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/isolation_info.h" -#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/blink/public/common/tokens/tokens.h" @@ -50,8 +49,7 @@ const net::IsolationInfo& isolation_info, ServiceWorkerMainResourceHandle* service_worker_handle, const BrowserContextGetter& browser_context_getter, - scoped_refptr<network::SharedURLLoaderFactory> loader_factory, - ukm::SourceId worker_source_id); + scoped_refptr<network::SharedURLLoaderFactory> loader_factory); WorkerScriptLoaderFactory(const WorkerScriptLoaderFactory&) = delete; WorkerScriptLoaderFactory& operator=(const WorkerScriptLoaderFactory&) = @@ -80,7 +78,6 @@ base::WeakPtr<ServiceWorkerMainResourceHandle> service_worker_handle_; BrowserContextGetter browser_context_getter_; scoped_refptr<network::SharedURLLoaderFactory> loader_factory_; - const ukm::SourceId worker_source_id_; // This is owned by SelfOwnedReceiver associated with the given // mojo::PendingReceiver<URLLoader>, and invalidated after receiver completion
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc index 75af53d9..80304671 100644 --- a/content/browser/worker_host/worker_script_loader_factory_unittest.cc +++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -102,7 +102,7 @@ kProcessId, DedicatedOrSharedWorkerToken(), net::IsolationInfo::CreateForInternalRequest(url::Origin::Create(url)), service_worker_handle_.get(), browser_context_getter_, - network_loader_factory_, ukm::kInvalidSourceId); + network_loader_factory_); // Load the script. network::TestURLLoaderClient client; @@ -116,6 +116,12 @@ EXPECT_FALSE(service_worker_client->is_response_committed()); EXPECT_FALSE(service_worker_client->is_execution_ready()); + // Emulate CommitResponse() and SetContainerReady() calls that would happen + // inside `WorkerScriptFetcher::callback_`. + service_worker_client->CommitResponse( + /*rfh_id=*/std::nullopt, PolicyContainerPolicies(), + /*coep_reporter=*/{}, ukm::kInvalidSourceId); + service_worker_client->SetContainerReady(); factory->GetScriptLoader()->OnFetcherCallbackCalled(); client.RunUntilComplete(); @@ -137,7 +143,7 @@ kProcessId, DedicatedOrSharedWorkerToken(), net::IsolationInfo::CreateForInternalRequest(url::Origin::Create(url)), service_worker_handle_.get(), browser_context_getter_, - network_loader_factory_, ukm::kInvalidSourceId); + network_loader_factory_); // Destroy the handle. service_worker_handle_.reset(); @@ -163,7 +169,7 @@ kProcessId, DedicatedOrSharedWorkerToken(), net::IsolationInfo::CreateForInternalRequest(url::Origin::Create(url)), service_worker_handle_.get(), browser_context_getter_, - network_loader_factory_, ukm::kInvalidSourceId); + network_loader_factory_); // Set a null browser context. helper_->context_wrapper()->Shutdown();
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 066bea94..7f752f3 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -114,6 +114,8 @@ "input/actions_parser.cc", "input/actions_parser.h", "input/event_with_latency_info.h", + "input/events_helper.cc", + "input/events_helper.h", "input/fling_controller.cc", "input/fling_controller.h", "input/fling_scheduler_base.h",
diff --git a/content/common/input/events_helper.cc b/content/common/input/events_helper.cc new file mode 100644 index 0000000..63ee978 --- /dev/null +++ b/content/common/input/events_helper.cc
@@ -0,0 +1,28 @@ +// 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 "content/common/input/events_helper.h" + +#include "third_party/blink/public/common/features.h" + +namespace content { + +bool InputEventResultStateIsSetBlocking( + blink::mojom::InputEventResultState ack_state) { + // Default input events are marked as kNotConsumed and should not + // be marked as blocking. + switch (ack_state) { + case blink::mojom::InputEventResultState::kConsumed: + return true; + case blink::mojom::InputEventResultState::kUnknown: + case blink::mojom::InputEventResultState::kNotConsumed: + case blink::mojom::InputEventResultState::kNoConsumerExists: + case blink::mojom::InputEventResultState::kIgnored: + case blink::mojom::InputEventResultState::kSetNonBlocking: + case blink::mojom::InputEventResultState::kSetNonBlockingDueToFling: + return false; + } +} + +} // namespace content
diff --git a/content/common/input/events_helper.h b/content/common/input/events_helper.h new file mode 100644 index 0000000..7919e98 --- /dev/null +++ b/content/common/input/events_helper.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 CONTENT_COMMON_INPUT_EVENTS_HELPER_H_ +#define CONTENT_COMMON_INPUT_EVENTS_HELPER_H_ + +#include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" + +namespace content { + +// Utility to map the event ack state from the renderer, returns true if the +// event could be handled blocking. +bool InputEventResultStateIsSetBlocking(blink::mojom::InputEventResultState); + +} // namespace content + +#endif // CONTENT_COMMON_INPUT_EVENTS_HELPER_H_
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index d9007f1..ae9ef300 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -74,20 +74,26 @@ generate_jni("content_main_dex_jni") { sources = [ - "java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java", - "java/src/org/chromium/content/app/ContentMain.java", "java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java", "java/src/org/chromium/content/browser/TracingControllerAndroidImpl.java", "java/src/org/chromium/content/common/SurfaceWrapper.java", "java/src/org/chromium/content_public/common/ResourceRequestBody.java", ] } +generate_jni("content_app_jni") { + sources = [ + "java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java", + "java/src/org/chromium/content/app/ContentMain.java", + ] +} # The minimal //content code needed for the base module. This includes all code # needed in child processes. android_library("content_main_dex_java") { deps = [ + ":content_app_jni_java", ":content_java_resources", + ":content_main_dex_jni_java", "//base:base_java", "//base:process_launcher_java", "//base/version_info/android:version_constants_java", @@ -133,7 +139,6 @@ resources_package = "org.chromium.content" srcjar_deps = [ ":common_aidl", - ":content_main_dex_jni", ":content_public_android_java_enums_srcjar", ":content_public_android_java_switches_srcjar", ":generate_sandboxed_service_srcjar", @@ -412,7 +417,6 @@ # TODO(crbug.com/40279841) simplify these build targets once GMSCore publishes identity-credentials. android_library("identity_credentials_java") { sources = [ - "java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java", "java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegateImpl.java", "java/src/org/chromium/content_public/browser/webid/IdentityCredentialsDelegate.java", ]
diff --git a/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java b/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java deleted file mode 100644 index 29f2233..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/webid/IdentityCredentialsDelegate.java +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2023 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.content.browser.webid; - -/** TODO(crbug.com/332562244): Delete once all implementers are ported to content_public version. */ -public interface IdentityCredentialsDelegate - extends org.chromium.content_public.browser.webid.IdentityCredentialsDelegate {}
diff --git a/content/public/browser/origin_trials_controller_delegate.h b/content/public/browser/origin_trials_controller_delegate.h index fbe0c501..9737d6d 100644 --- a/content/public/browser/origin_trials_controller_delegate.h +++ b/content/public/browser/origin_trials_controller_delegate.h
@@ -83,9 +83,7 @@ // to append third-party origin trials as well. If a token in `tokens` is a // third-party origin trial token, and the corresponding origin is present in // `script_tokens`, then the trial will be enabled for the origin stored in - // the token itself, rather than any origin found in `script_origins`. This - // limitation means that subdomain matching does not work for third-party - // origin trial tokens using this method. + // the token itself, rather than any origin found in `script_origins`. virtual void PersistAdditionalTrialsFromTokens( const url::Origin& origin, const url::Origin& partition_origin,
diff --git a/content/public/browser/preloading_data.h b/content/public/browser/preloading_data.h index bf83a05..81717bbe 100644 --- a/content/public/browser/preloading_data.h +++ b/content/public/browser/preloading_data.h
@@ -94,6 +94,7 @@ // Please see content/browser/preloading/preloading_data_impl.cc for more // details. static PreloadingData* GetOrCreateForWebContents(WebContents* web_contents); + static PreloadingData* GetForWebContents(WebContents* web_contents); // Helper method to return the PreloadingURLMatchCallback for // `destination_url`. This method will return true only for exact matches to @@ -146,6 +147,10 @@ PreloadingPredictor predictor, PredictorDomainCallback is_navigation_in_domain_callback) = 0; + // This flag will be true if there's been at least 1 attempt to do a + // speculation-rules based prerender. + virtual bool HasSpeculationRulesPrerender() = 0; + protected: virtual ~PreloadingData() = default; };
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 0eee32e7..2ae76b5 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -473,9 +473,10 @@ // Enables a new Automatic Fullscreen content setting that lets allowlisted // origins use the HTML Fullscreen API without transient activation. +// https://chromestatus.com/feature/6218822004768768 BASE_FEATURE(kAutomaticFullscreenContentSetting, "AutomaticFullscreenContentSetting", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables process isolation of fenced content (content inside fenced frames) // from non-fenced content. See
diff --git a/content/public/test/preloading_test_util.cc b/content/public/test/preloading_test_util.cc index 5650ccff..d4b2a25 100644 --- a/content/public/test/preloading_test_util.cc +++ b/content/public/test/preloading_test_util.cc
@@ -7,6 +7,7 @@ #include "base/strings/stringprintf.h" #include "content/browser/preloading/preloading_attempt_impl.h" #include "content/browser/preloading/preloading_config.h" +#include "content/browser/preloading/preloading_data_impl.h" #include "preloading_test_util.h" #include "services/metrics/public/cpp/metrics_utils.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -204,4 +205,9 @@ holdback); } +void SetHasSpeculationRulesPrerender(PreloadingData* preloading_data) { + static_cast<PreloadingDataImpl*>(preloading_data) + ->SetHasSpeculationRulesPrerender(); +} + } // namespace content::test
diff --git a/content/public/test/preloading_test_util.h b/content/public/test/preloading_test_util.h index 00370143..f96deb7 100644 --- a/content/public/test/preloading_test_util.h +++ b/content/public/test/preloading_test_util.h
@@ -138,6 +138,8 @@ raw_ptr<PreloadingConfig> overridden_config_; }; +void SetHasSpeculationRulesPrerender(PreloadingData* preloading_data); + } // namespace test } // namespace content
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index ffb1f71..898c86e9 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc
@@ -26,6 +26,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/color_chooser.h" #include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/document_picture_in_picture_window_controller.h" #include "content/public/browser/file_select_listener.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" @@ -304,6 +305,18 @@ const blink::mojom::WindowFeatures& window_features, bool user_gesture, bool* was_blocked) { +#if !BUILDFLAG(IS_ANDROID) + // If the shell is opening a document picture-in-picture window, it needs to + // inform the DocumentPictureInPictureWindowController. + if (disposition == WindowOpenDisposition::NEW_PICTURE_IN_PICTURE) { + DocumentPictureInPictureWindowController* controller = + PictureInPictureWindowController:: + GetOrCreateDocumentPictureInPictureController(source); + controller->SetChildWebContents(new_contents.get()); + controller->Show(); + } +#endif // !BUILDFLAG(IS_ANDROID) + CreateShell( std::move(new_contents), AdjustWindowSize(window_features.bounds.size()), !delay_popup_contents_delegate_for_testing_ /* should_set_delegate */);
diff --git a/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt b/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt index 7bb3ea5..f2f1e72 100644 --- a/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt +++ b/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt
@@ -1,5 +1,5 @@ === Start Continuation === EVENT_SYSTEM_MENUPOPUPSTART on <div#submenu> role=ROLE_SYSTEM_MENUPOPUP IA2_STATE_VERTICAL SetSize=1 === Start Continuation === -EVENT_SYSTEM_MENUPOPUPEND on <div> role=ROLE_SYSTEM_MENUPOPUP INVISIBLE +EVENT_SYSTEM_MENUPOPUPEND on <div#submenu> role=ROLE_SYSTEM_MENUPOPUP INVISIBLE === Start Continuation ===
diff --git a/content/test/data/accessibility/html/popover-api-expected-auralinux.txt b/content/test/data/accessibility/html/popover-api-expected-auralinux.txt index 48a211e..b8a96eb 100644 --- a/content/test/data/accessibility/html/popover-api-expected-auralinux.txt +++ b/content/test/data/accessibility/html/popover-api-expected-auralinux.txt
@@ -28,10 +28,10 @@ ++++[static] name='Popover (showing)' ++++[panel] details-for=[push button] ++++++[static] name='Nested popover (showing)' -++[push button] name='Hide button pointing to showing manual (should add aria-details)' details=[panel] details-roles:popover +++[push button] name='Hide button pointing to showing manual (should add aria-details)' expanded details=[panel] details-roles:popover ++[entry] selectable-text ++[static] name='Url input pointing to showing manual ' -++[push button] name='Hide button pointing to showing manual (should NOT add aria-details)' +++[push button] name='Hide button pointing to showing manual (should NOT add aria-details)' expanded ++[panel] details-for=[push button] ++++[static] name='Manual (showing)' ++[panel]
diff --git a/content/test/data/accessibility/html/popover-api-expected-blink.txt b/content/test/data/accessibility/html/popover-api-expected-blink.txt index c3ac7327..e1e36aa 100644 --- a/content/test/data/accessibility/html/popover-api-expected-blink.txt +++ b/content/test/data/accessibility/html/popover-api-expected-blink.txt
@@ -10,17 +10,17 @@ ++++++++genericContainer ++++++staticText name='Text input pointing to hidden popover ' ++++++++inlineTextBox name='Text input pointing to hidden popover ' -++++++button name='Hide button pointing to hidden manual' +++++++button collapsed name='Hide button pointing to hidden manual' ++++++++staticText name='Hide button pointing to hidden manual' ++++++++++inlineTextBox name='Hide button pointing to hidden manual' ++++++textField ++++++++genericContainer ++++++staticText name='Email input pointing to hidden manual ' ++++++++inlineTextBox name='Email input pointing to hidden manual ' -++++++button name='Button pointing to hint popover' +++++++button collapsed name='Button pointing to hint popover' ++++++++staticText name='Button pointing to hint popover' ++++++++++inlineTextBox name='Button pointing to hint popover' -++++++button name='Button pointing to "rich" hint popover' +++++++button collapsed name='Button pointing to "rich" hint popover' ++++++++staticText name='Button pointing to "rich" hint popover' ++++++++++inlineTextBox name='Button pointing to "rich" hint popover' ++++++button name='Button pointing to non-popover' @@ -33,7 +33,7 @@ ++++++genericContainer ++++++++staticText name='No popover attribute' ++++++++++inlineTextBox name='No popover attribute' -++++++button name='Button pointing to invalid popover value' +++++++button collapsed name='Button pointing to invalid popover value' ++++++++staticText name='Button pointing to invalid popover value' ++++++++++inlineTextBox name='Button pointing to invalid popover value' ++++++textField @@ -66,7 +66,7 @@ ++++++++group ispopup=auto ++++++++++staticText name='Nested popover (showing)' ++++++++++++inlineTextBox name='Nested popover (showing)' -++++++button name='Hide button pointing to showing manual (should add aria-details)' detailsIds=group +++++++button expanded name='Hide button pointing to showing manual (should add aria-details)' detailsIds=group ++++++++staticText name='Hide button pointing to showing manual (should add aria-details)' ++++++++++inlineTextBox name='Hide button pointing to showing manual (should add aria-details)' ++++++textField @@ -74,7 +74,7 @@ ++++++staticText name='Url input pointing to showing manual ' ++++++++inlineTextBox name='Url input pointing to showing ' ++++++++inlineTextBox name='manual ' -++++++button name='Hide button pointing to showing manual (should NOT add aria-details)' +++++++button expanded name='Hide button pointing to showing manual (should NOT add aria-details)' ++++++++staticText name='Hide button pointing to showing manual (should NOT add aria-details)' ++++++++++inlineTextBox name='Hide button pointing to showing manual (should NOT add aria-details)' ++++++group ispopup=manual
diff --git a/content/test/data/accessibility/html/popover-api-expected-mac.txt b/content/test/data/accessibility/html/popover-api-expected-mac.txt index 9ece033..d1c61783 100644 --- a/content/test/data/accessibility/html/popover-api-expected-mac.txt +++ b/content/test/data/accessibility/html/popover-api-expected-mac.txt
@@ -2,17 +2,17 @@ ++AXButton AXExpanded=0 AXTitle='Button pointing to hidden popover' ++AXTextField ++AXStaticText AXValue='Text input pointing to hidden popover ' -++AXButton AXTitle='Hide button pointing to hidden manual' +++AXButton AXExpanded=0 AXTitle='Hide button pointing to hidden manual' ++AXTextField ++AXStaticText AXValue='Email input pointing to hidden manual ' -++AXButton AXTitle='Button pointing to hint popover' -++AXButton AXTitle='Button pointing to "rich" hint popover' +++AXButton AXExpanded=0 AXTitle='Button pointing to hint popover' +++AXButton AXExpanded=0 AXTitle='Button pointing to "rich" hint popover' ++AXButton AXTitle='Button pointing to non-popover' ++AXTextField ++AXStaticText AXValue='Text input pointing to non-popover' ++AXGroup ++++AXStaticText AXValue='No popover attribute' -++AXButton AXTitle='Button pointing to invalid popover value' +++AXButton AXExpanded=0 AXTitle='Button pointing to invalid popover value' ++AXTextField ++AXStaticText AXValue='Text input pointing to invalid popover value' ++AXGroup @@ -28,10 +28,10 @@ ++++AXStaticText AXValue='Popover (showing)' ++++AXGroup AXSubrole=AXApplicationGroup ++++++AXStaticText AXValue='Nested popover (showing)' -++AXButton AXTitle='Hide button pointing to showing manual (should add aria-details)' +++AXButton AXExpanded=1 AXTitle='Hide button pointing to showing manual (should add aria-details)' ++AXTextField ++AXStaticText AXValue='Url input pointing to showing manual ' -++AXButton AXTitle='Hide button pointing to showing manual (should NOT add aria-details)' +++AXButton AXExpanded=1 AXTitle='Hide button pointing to showing manual (should NOT add aria-details)' ++AXGroup AXSubrole=AXApplicationGroup ++++AXStaticText AXValue='Manual (showing)' ++AXGroup AXSubrole=AXApplicationGroup
diff --git a/content/test/data/accessibility/html/popover-api-expected-uia-win.txt b/content/test/data/accessibility/html/popover-api-expected-uia-win.txt index 0b6009a..7c64aa4 100644 --- a/content/test/data/accessibility/html/popover-api-expected-uia-win.txt +++ b/content/test/data/accessibility/html/popover-api-expected-uia-win.txt
@@ -2,17 +2,17 @@ ++Button Name='Button pointing to hidden popover' ExpandCollapse.ExpandCollapseState='Collapsed' ++Edit ++Text Name='Text input pointing to hidden popover ' -++Button Name='Hide button pointing to hidden manual' +++Button Name='Hide button pointing to hidden manual' ExpandCollapse.ExpandCollapseState='Collapsed' ++Edit ++Text Name='Email input pointing to hidden manual ' -++Button Name='Button pointing to hint popover' -++Button Name='Button pointing to "rich" hint popover' +++Button Name='Button pointing to hint popover' ExpandCollapse.ExpandCollapseState='Collapsed' +++Button Name='Button pointing to "rich" hint popover' ExpandCollapse.ExpandCollapseState='Collapsed' ++Button Name='Button pointing to non-popover' ++Edit ++Text Name='Text input pointing to non-popover' ++Group IsControlElement=false ++++Text Name='No popover attribute' -++Button Name='Button pointing to invalid popover value' +++Button Name='Button pointing to invalid popover value' ExpandCollapse.ExpandCollapseState='Collapsed' ++Edit ++Text Name='Text input pointing to invalid popover value' ++Group IsControlElement=false @@ -28,10 +28,10 @@ ++++Text Name='Popover (showing)' ++++Group IsControlElement=false ++++++Text Name='Nested popover (showing)' -++Button Name='Hide button pointing to showing manual (should add aria-details)' +++Button Name='Hide button pointing to showing manual (should add aria-details)' ExpandCollapse.ExpandCollapseState='Expanded' ++Edit ++Text Name='Url input pointing to showing manual ' -++Button Name='Hide button pointing to showing manual (should NOT add aria-details)' +++Button Name='Hide button pointing to showing manual (should NOT add aria-details)' ExpandCollapse.ExpandCollapseState='Expanded' ++Group IsControlElement=false ++++Text Name='Manual (showing)' ++Group IsControlElement=false
diff --git a/content/test/data/accessibility/html/popover-api-expected-win.txt b/content/test/data/accessibility/html/popover-api-expected-win.txt index 05f0e23..523d17c1 100644 --- a/content/test/data/accessibility/html/popover-api-expected-win.txt +++ b/content/test/data/accessibility/html/popover-api-expected-win.txt
@@ -2,17 +2,17 @@ ++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to hidden popover' COLLAPSED FOCUSABLE ++ROLE_SYSTEM_TEXT FOCUSABLE ++ROLE_SYSTEM_STATICTEXT name='Text input pointing to hidden popover ' -++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to hidden manual' FOCUSABLE +++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to hidden manual' COLLAPSED FOCUSABLE ++ROLE_SYSTEM_TEXT FOCUSABLE ++ROLE_SYSTEM_STATICTEXT name='Email input pointing to hidden manual ' -++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to hint popover' FOCUSABLE -++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to "rich" hint popover' FOCUSABLE +++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to hint popover' COLLAPSED FOCUSABLE +++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to "rich" hint popover' COLLAPSED FOCUSABLE ++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to non-popover' FOCUSABLE ++ROLE_SYSTEM_TEXT FOCUSABLE ++ROLE_SYSTEM_STATICTEXT name='Text input pointing to non-popover' ++IA2_ROLE_SECTION ++++ROLE_SYSTEM_STATICTEXT name='No popover attribute' -++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to invalid popover value' FOCUSABLE +++ROLE_SYSTEM_PUSHBUTTON name='Button pointing to invalid popover value' COLLAPSED FOCUSABLE ++ROLE_SYSTEM_TEXT FOCUSABLE ++ROLE_SYSTEM_STATICTEXT name='Text input pointing to invalid popover value' ++IA2_ROLE_PARAGRAPH @@ -28,10 +28,10 @@ ++++ROLE_SYSTEM_STATICTEXT name='Popover (showing)' ++++ROLE_SYSTEM_GROUPING ispopup:auto ++++++ROLE_SYSTEM_STATICTEXT name='Nested popover (showing)' -++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to showing manual (should add aria-details)' FOCUSABLE details-roles:popover +++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to showing manual (should add aria-details)' EXPANDED FOCUSABLE details-roles:popover ++ROLE_SYSTEM_TEXT FOCUSABLE ++ROLE_SYSTEM_STATICTEXT name='Url input pointing to showing manual ' -++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to showing manual (should NOT add aria-details)' FOCUSABLE +++ROLE_SYSTEM_PUSHBUTTON name='Hide button pointing to showing manual (should NOT add aria-details)' EXPANDED FOCUSABLE ++ROLE_SYSTEM_GROUPING ispopup:manual ++++ROLE_SYSTEM_STATICTEXT name='Manual (showing)' ++ROLE_SYSTEM_GROUPING ispopup:manual
diff --git a/content/test/data/accessibility/html/popover-hint-expected-blink.txt b/content/test/data/accessibility/html/popover-hint-expected-blink.txt index 0f0dd32..607de5a 100644 --- a/content/test/data/accessibility/html/popover-hint-expected-blink.txt +++ b/content/test/data/accessibility/html/popover-hint-expected-blink.txt
@@ -1,8 +1,15 @@ rootWebArea ++genericContainer ignored ++++genericContainer -++++++button -++++++button +++++++button collapsed name='popover1' nameFrom=contents +++++++++staticText name='popover1' nameFrom=contents +++++++++++inlineTextBox name='popover1' nameFrom=contents +++++++button collapsed name='popover2' nameFrom=contents +++++++++staticText name='popover2' nameFrom=contents +++++++++++inlineTextBox name='popover2' nameFrom=contents +++++++button collapsed name='popover3' nameFrom=contents +++++++++staticText name='popover3' nameFrom=contents +++++++++++inlineTextBox name='popover3' nameFrom=contents ++++++table ignored invisible ++++++++rowGroup ignored invisible ++++++++++row ignored invisible @@ -11,7 +18,16 @@ ++++++++++row ignored invisible ++++++++++++cell ignored invisible ++++++++++++cell ignored invisible -++++++button ++++++genericContainer ignored invisible -++++++button -++++++button name='the title' nameFrom=title +++++++button collapsed name='popover4' nameFrom=contents +++++++++staticText name='popover4' nameFrom=contents +++++++++++inlineTextBox name='popover4' nameFrom=contents +++++++button collapsed description='the title' name='popover5' nameFrom=contents descriptionFrom=title +++++++++staticText name='popover5' nameFrom=contents +++++++++++inlineTextBox name='popover5' nameFrom=contents +++++++group ispopup=hint +++++++++staticText name='Test popover, open' nameFrom=contents +++++++++++inlineTextBox name='Test popover, open' nameFrom=contents +++++++button expanded description='Test popover, open' name='popover6' nameFrom=contents descriptionFrom=popoverAttribute detailsIds=group +++++++++staticText name='popover6' nameFrom=contents +++++++++++inlineTextBox name='popover6' nameFrom=contents
diff --git a/content/test/data/accessibility/html/popover-hint.html b/content/test/data/accessibility/html/popover-hint.html index ef5ad70..a3b6c70 100644 --- a/content/test/data/accessibility/html/popover-hint.html +++ b/content/test/data/accessibility/html/popover-hint.html
@@ -15,7 +15,7 @@ <div popover="hint" id="popover1"> Test popover! </div> -<button popovertarget="popover1"></button> +<button popovertarget="popover1">popover1</button> <div popover="hint" id="popover2"> <div> @@ -23,8 +23,9 @@ <img title="test 123"> </div> </div> -<button popovertarget="popover2"></button> +<button popovertarget="popover2">popover2</button> +<button popovertarget="popover3">popover3</button> <div popover="hint" id="popover3"> Test popover with rich content like a datatable. <table> @@ -38,7 +39,6 @@ </tr> </table> </div> -<button popovertarget="popover3"></button> <div popover="hint" id="popover4"> Test popover with a textinput! @@ -48,10 +48,16 @@ </span> </div> </div> -<button popovertarget="popover4"></button> - +<button popovertarget="popover4">popover4</button> <div popover="hint" id="popover5"> Test popover with title in button to test description. </div> -<button title="the title" popovertarget="popover5"></button> +<button title="the title" popovertarget="popover5">popover5</button> + +<div popover="hint" id="popover6">Test popover, open</div> +<button popovertarget="popover6">popover6</button> + +<script> + popover6.showPopover(); +</script>
diff --git a/content/test/data/shared_dictionary/README.md b/content/test/data/shared_dictionary/README.md index 945cfbf..1f112b9 100644 --- a/content/test/data/shared_dictionary/README.md +++ b/content/test/data/shared_dictionary/README.md
@@ -7,6 +7,8 @@ - `path/compressed.data` is created using the following command. ```bash + $ echo -en '\xffDCB' > path/compressed.data + $ openssl dgst -sha256 -binary test.dict >> path/compressed.data $ echo -n 'This is compressed test data using a test dictionary' | \ - brotli -D test.dict > path/compressed.data + brotli -D test.dict >> path/compressed.data ```
diff --git a/content/test/data/shared_dictionary/path/compressed.data b/content/test/data/shared_dictionary/path/compressed.data index 9ddb4a11..8594a7a 100644 --- a/content/test/data/shared_dictionary/path/compressed.data +++ b/content/test/data/shared_dictionary/path/compressed.data Binary files differ
diff --git a/content/test/data/shared_dictionary/path/compressed.data.mock-http-headers b/content/test/data/shared_dictionary/path/compressed.data.mock-http-headers index ce29263..cf6c332a 100644 --- a/content/test/data/shared_dictionary/path/compressed.data.mock-http-headers +++ b/content/test/data/shared_dictionary/path/compressed.data.mock-http-headers
@@ -1,4 +1,3 @@ HTTP/1.1 200 OK -Content-Encoding: br-d +Content-Encoding: dcb Content-Type: text/html -Content-Dictionary: :U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:
diff --git a/device/fido/enclave/verify/rekor.cc b/device/fido/enclave/verify/rekor.cc index 998a5536..f0068e8 100644 --- a/device/fido/enclave/verify/rekor.cc +++ b/device/fido/enclave/verify/rekor.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "device/fido/enclave/verify/utils.h" +#include "third_party/boringssl/src/include/openssl/sha.h" namespace device::enclave { @@ -203,4 +204,42 @@ .has_value(); } +bool VerifyRekorBody(const Body& body, + base::span<const uint8_t> contents_bytes) { + if (body.spec.generic_signature.format != "x509" || + body.spec.data.hash.hash_type != kSHA256) { + return false; + } + uint8_t contents_hash[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(contents_bytes.data()), + contents_bytes.size(), contents_hash); + std::string contents_hash_hex = base::ToLowerASCII( + base::HexEncode(contents_hash, std::size(contents_hash))); + std::string_view bytes_str( + reinterpret_cast<const char*>(body.spec.data.hash.bytes.data()), + body.spec.data.hash.bytes.size()); + if (contents_hash_hex != bytes_str) { + return false; + } + + std::string signature; + if (!base::Base64Decode(body.spec.generic_signature.content, &signature)) { + return false; + } + std::string public_key_pem; + if (!base::Base64Decode(body.spec.generic_signature.public_key.content, + &public_key_pem)) { + return false; + } + auto public_key = ConvertPemToRaw(public_key_pem); + if (!public_key.has_value()) { + return false; + } + return VerifySignatureRaw( + base::make_span(static_cast<uint8_t*>((uint8_t*)signature.data()), + signature.size()), + contents_bytes, public_key.value()) + .has_value(); +} + } // namespace device::enclave
diff --git a/device/fido/enclave/verify/rekor.h b/device/fido/enclave/verify/rekor.h index 3edab89..b8a1929f 100644 --- a/device/fido/enclave/verify/rekor.h +++ b/device/fido/enclave/verify/rekor.h
@@ -159,7 +159,8 @@ base::span<const uint8_t> rekor_public_key); // Verifies the signature in the body over the contents. -bool VerifyRekorBody(const Body&, base::span<const uint8_t> contents_bytes); +bool COMPONENT_EXPORT(DEVICE_FIDO) + VerifyRekorBody(const Body& body, base::span<const uint8_t> contents_bytes); // Parses `RekorSignatureBundle` from `log_entry`. std::optional<RekorSignatureBundle> COMPONENT_EXPORT(DEVICE_FIDO)
diff --git a/device/fido/enclave/verify/rekor_unittest.cc b/device/fido/enclave/verify/rekor_unittest.cc index 0275fe4..4d9d11c3 100644 --- a/device/fido/enclave/verify/rekor_unittest.cc +++ b/device/fido/enclave/verify/rekor_unittest.cc
@@ -168,4 +168,54 @@ EXPECT_FALSE(VerifyRekorSignature(log_entry, *pub_key)); } +TEST(RekorTest, VerifyRekorBodySucceeds) { + std::string json = GetContentsFromFile("logentry.json"); + std::string endorsement = GetContentsFromFile("endorsement.json"); + base::span<const uint8_t> span = base::make_span( + reinterpret_cast<const uint8_t*>(json.data()), json.size()); + std::optional<Body> log_entry_body = GetRekorLogEntryBody(span); + EXPECT_TRUE(log_entry_body.has_value()); + base::span<const uint8_t> content_span = base::make_span( + reinterpret_cast<const uint8_t*>(endorsement.data()), endorsement.size()); + EXPECT_TRUE(VerifyRekorBody(log_entry_body.value(), content_span)); +} + +TEST(RekorTest, VerifyRekorBodyWrongSignatureFormatFails) { + std::string json = GetContentsFromFile("logentry.json"); + std::string endorsement = GetContentsFromFile("endorsement.json"); + base::span<const uint8_t> span = base::make_span( + reinterpret_cast<const uint8_t*>(json.data()), json.size()); + std::optional<Body> log_entry_body = GetRekorLogEntryBody(span); + EXPECT_TRUE(log_entry_body.has_value()); + log_entry_body->spec.generic_signature.format = "bad"; + base::span<const uint8_t> content_span = base::make_span( + reinterpret_cast<const uint8_t*>(endorsement.data()), endorsement.size()); + EXPECT_FALSE(VerifyRekorBody(log_entry_body.value(), content_span)); +} + +TEST(RekorTest, VerifyRekorBodyWrongContentFails) { + std::string json = GetContentsFromFile("logentry.json"); + std::string endorsement = "abcd"; + base::span<const uint8_t> span = base::make_span( + reinterpret_cast<const uint8_t*>(json.data()), json.size()); + std::optional<Body> log_entry_body = GetRekorLogEntryBody(span); + EXPECT_TRUE(log_entry_body.has_value()); + base::span<const uint8_t> content_span = base::make_span( + reinterpret_cast<const uint8_t*>(endorsement.data()), endorsement.size()); + EXPECT_FALSE(VerifyRekorBody(log_entry_body.value(), content_span)); +} + +TEST(RekorTest, VerifyRekorBodyWrongPublicKeyFails) { + std::string json = GetContentsFromFile("logentry.json"); + std::string endorsement = GetContentsFromFile("endorsement.json"); + base::span<const uint8_t> span = base::make_span( + reinterpret_cast<const uint8_t*>(json.data()), json.size()); + std::optional<Body> log_entry_body = GetRekorLogEntryBody(span); + EXPECT_TRUE(log_entry_body.has_value()); + log_entry_body->spec.generic_signature.public_key.content = "abcd"; + base::span<const uint8_t> content_span = base::make_span( + reinterpret_cast<const uint8_t*>(endorsement.data()), endorsement.size()); + EXPECT_FALSE(VerifyRekorBody(log_entry_body.value(), content_span)); +} + } // namespace device::enclave
diff --git a/device/fido/enclave/verify/testdata/endorsement.json b/device/fido/enclave/verify/testdata/endorsement.json new file mode 100644 index 0000000..2145f37 --- /dev/null +++ b/device/fido/enclave/verify/testdata/endorsement.json
@@ -0,0 +1,28 @@ +{ + "_type": "https://in-toto.io/Statement/v1", + "predicateType": "https://github.com/project-oak/transparent-release/claim/v1", + "subject": [ + { + "name": "oak_containers_stage1", + "digest": { + "psha2": "020000293b52d03b784e9f9fde1b266d89f807615334cd84f3f5197f734645af318aad024000", + "sha1": "9d0b72e3a22b5508ea80c177752ad51e3acbdc29", + "sha256": "18c34d8cc737fb5709a99acb073cdc5ed8a404503f626cea6e0bad0a406002fc", + "sha512": "5030cbebe5f38ba5a6746b9682c6be568c4ab2aa36dfbffddbd9483f7c5f8d346fa82322846ef11c2e367d4040a6f04bf93e2ae3f6d521015f14198167b1bbe6", + "sha3_512": "8330aaa7da27336f2026827be3750b6d97ea5ba81590d1fac9ef5edc83078e53ac512d45f0c0cd611eb2b37ce836757fd91f9a82edb859592e71a83503cc6bda", + "sha3_384": "b92d75bfccd2347a38b3be2740c3f2cd032b7234b2d0f90cbbe39c7da08af5fdf3168b2fdaa64a9cbd491ffd1db14b4b", + "sha3_256": "20e3e6d0a3d8367bd68f4be91ac3edd61b2a1781e89f1ca4fd755f79d47e16d5", + "sha3_224": "436ee703a6327746726e382650f46fe8fb518c6c5c21b9e6524e9e41", + "sha384": "2236eff6a8ae3ae24dfb0c423fb3f5878b57510ac6c39ac4c4374c36f96541b5451953785594657deff7a31202e7f4ef" + } + } + ], + "predicate": { + "claimType": "https://github.com/project-oak/transparent-release/endorsement/v2", + "issuedOn": "2024-02-28T09:47:12.067000Z", + "validity": { + "notBefore": "2024-02-28T09:47:12.067000Z", + "notAfter": "2025-02-27T09:47:12.067000Z" + } + } +} \ No newline at end of file
diff --git a/device/vr/openxr/openxr_api_wrapper.cc b/device/vr/openxr/openxr_api_wrapper.cc index bb991627..95885fa 100644 --- a/device/vr/openxr/openxr_api_wrapper.cc +++ b/device/vr/openxr/openxr_api_wrapper.cc
@@ -197,6 +197,7 @@ frame_state_ = {}; input_helper_.reset(); + session_options_.reset(); on_session_started_callback_.Reset(); on_session_ended_callback_.Reset(); visibility_changed_callback_.Reset(); @@ -267,7 +268,8 @@ // that it failed, so that the browser doesn't think there's still a pending // session request, and can try again (though it may not recover). if (on_session_started_callback_) { - std::move(on_session_started_callback_).Run(XR_ERROR_INITIALIZATION_FAILED); + std::move(on_session_started_callback_) + .Run(std::move(session_options_), XR_ERROR_INITIALIZATION_FAILED); } Reset(); @@ -319,6 +321,11 @@ return frame_state_.type == XR_TYPE_FRAME_STATE; } +bool OpenXrApiWrapper::IsFeatureEnabled( + device::mojom::XRSessionFeature feature) const { + return base::Contains(enabled_features_, feature); +} + XrResult OpenXrApiWrapper::InitializeViewConfig( XrViewConfigurationType type, OpenXrViewConfiguration& view_config) { @@ -434,7 +441,8 @@ OpenXrAnchorManager* OpenXrApiWrapper::GetOrCreateAnchorManager( const OpenXrExtensionHelper& extension_helper) { - if (session_ && !anchor_manager_) { + if (session_ && !anchor_manager_ && + IsFeatureEnabled(device::mojom::XRSessionFeature::ANCHORS)) { anchor_manager_ = extension_helper.CreateAnchorManager(session_, local_space_); } @@ -443,7 +451,8 @@ OpenXrLightEstimator* OpenXrApiWrapper::GetOrCreateLightEstimator( const OpenXrExtensionHelper& extension_helper) { - if (session_ && !light_estimator_) { + if (session_ && !light_estimator_ && + IsFeatureEnabled(device::mojom::XRSessionFeature::LIGHT_ESTIMATION)) { light_estimator_ = extension_helper.CreateLightEstimator(session_, local_space_); } @@ -451,6 +460,41 @@ return light_estimator_.get(); } +OpenXRSceneUnderstandingManager* +OpenXrApiWrapper::GetOrCreateSceneUnderstandingManager( + const OpenXrExtensionHelper& extension_helper) { + if (session_ && !scene_understanding_manager_ && + IsFeatureEnabled(device::mojom::XRSessionFeature::HIT_TEST)) { + scene_understanding_manager_ = + extension_helper.CreateSceneUnderstandingManager(session_, + local_space_); + } + return scene_understanding_manager_.get(); +} + +void OpenXrApiWrapper::EnableSupportedFeatures( + const OpenXrExtensionHelper& extension_helper, + device::mojom::XRSessionMode mode, + const std::vector<device::mojom::XRSessionFeature>& required_features, + const std::vector<device::mojom::XRSessionFeature>& optional_features) { + enabled_features_.clear(); + + auto enable_function = [&extension_helper, + mode](device::mojom::XRSessionFeature feature) { + return IsFeatureSupportedForMode(feature, mode) && + extension_helper.IsFeatureSupported(feature); + }; + + base::ranges::copy_if( + required_features, + std::inserter(enabled_features_, enabled_features_.begin()), + enable_function); + base::ranges::copy_if( + optional_features, + std::inserter(enabled_features_, enabled_features_.begin()), + enable_function); +} + bool OpenXrApiWrapper::UpdateAndGetSessionEnded() { // Ensure we have the latest state from the OpenXR runtime. if (XR_FAILED(ProcessEvents())) { @@ -463,39 +507,31 @@ return !IsInitialized(); } -OpenXRSceneUnderstandingManager* -OpenXrApiWrapper::GetOrCreateSceneUnderstandingManager( - const OpenXrExtensionHelper& extension_helper) { - if (session_ && !scene_understanding_manager_) { - scene_understanding_manager_ = - extension_helper.CreateSceneUnderstandingManager(session_, - local_space_); - } - return scene_understanding_manager_.get(); -} - // Callers of this function must check the XrResult return value and destroy // this OpenXrApiWrapper object on failure to clean up any intermediate // objects that may have been created before the failure. XrResult OpenXrApiWrapper::InitSession( - const std::unordered_set<mojom::XRSessionFeature>& enabled_features, + mojom::XRRuntimeSessionOptionsPtr options, const OpenXrExtensionHelper& extension_helper, SessionStartedCallback on_session_started_callback, SessionEndedCallback on_session_ended_callback, VisibilityChangedCallback visibility_changed_callback) { DCHECK(IsInitialized()); + DCHECK(options); - enabled_features_ = enabled_features; + EnableSupportedFeatures(extension_helper, options->mode, + options->required_features, + options->optional_features); + if (!base::ranges::all_of( + options->required_features, + [this](const device::mojom::XRSessionFeature& feature) { + return base::Contains(enabled_features_, feature); + })) { + std::move(on_session_started_callback) + .Run(std::move(options), XR_ERROR_INITIALIZATION_FAILED); + } - // These are the only features that use stage parameters. If none of them were - // requested for the session, we can avoid querying this every frame. - stage_parameters_enabled_ = base::ranges::any_of( - enabled_features_, [](mojom::XRSessionFeature feature) { - return feature == mojom::XRSessionFeature::REF_SPACE_LOCAL_FLOOR || - feature == mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR || - feature == mojom::XRSessionFeature::ANCHORS; - }); - + session_options_ = std::move(options); on_session_started_callback_ = std::move(on_session_started_callback); on_session_ended_callback_ = std::move(on_session_ended_callback); visibility_changed_callback_ = std::move(visibility_changed_callback); @@ -508,8 +544,7 @@ RETURN_IF_XR_FAILED(OpenXRInputHelper::CreateOpenXRInputHelper( instance_, system_, extension_helper, session_, local_space_, - base::Contains(enabled_features_, mojom::XRSessionFeature::HAND_INPUT), - &input_helper_)); + IsFeatureEnabled(mojom::XRSessionFeature::HAND_INPUT), &input_helper_)); // Make sure all of the objects we initialized are there. DCHECK(HasSession()); @@ -518,6 +553,15 @@ DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_VIEW)); DCHECK(input_helper_); + // These are the only features that use stage parameters. If none of them were + // requested for the session, we can avoid querying this every frame. + stage_parameters_enabled_ = base::ranges::any_of( + enabled_features_, [](mojom::XRSessionFeature feature) { + return feature == mojom::XRSessionFeature::REF_SPACE_LOCAL_FLOOR || + feature == mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR || + feature == mojom::XRSessionFeature::ANCHORS; + }); + if (stage_parameters_enabled_) { bounds_provider_ = extension_helper.CreateStageBoundsProvider(session_); } @@ -603,8 +647,7 @@ } primary_view_config_.SetViewport(0, 0, total_width, total_height); - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { for (auto& secondary_view_config : secondary_view_configs_) { OpenXrViewConfiguration& view_config = secondary_view_config.second; if (view_config.Active()) { @@ -742,8 +785,7 @@ XrSecondaryViewConfigurationSessionBeginInfoMSFT secondary_view_config_info = {XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT}; std::vector<XrViewConfigurationType> secondary_view_config_types; - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { secondary_view_config_types.reserve(secondary_view_configs_.size()); for (const auto& secondary_view_config : secondary_view_configs_) { secondary_view_config_types.emplace_back(secondary_view_config.first); @@ -759,7 +801,8 @@ if (XR_SUCCEEDED(xr_result)) session_running_ = true; - std::move(on_session_started_callback_).Run(xr_result); + std::move(on_session_started_callback_) + .Run(std::move(session_options_), xr_result); return xr_result; } @@ -778,8 +821,7 @@ XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT}; std::vector<XrSecondaryViewConfigurationStateMSFT> secondary_view_config_states; - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { secondary_view_config_states.resize( secondary_view_configs_.size(), {XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT}); @@ -793,8 +835,7 @@ RETURN_IF_XR_FAILED(xrWaitFrame(session_, &wait_frame_info, &frame_state)); frame_state_ = frame_state; - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { RETURN_IF_XR_FAILED( UpdateSecondaryViewConfigStates(secondary_view_config_states)); } @@ -822,8 +863,7 @@ graphics_binding_->PrepareViewConfigForRender(color_swapchain_, primary_view_config_); - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { for (auto& view_config : secondary_view_configs_) { OpenXrViewConfiguration& config = view_config.second; if (config.Active()) { @@ -841,8 +881,7 @@ // swapchain has also likely changed, so re-create the swapchain. XrResult OpenXrApiWrapper::UpdateSecondaryViewConfigStates( const std::vector<XrSecondaryViewConfigurationStateMSFT>& states) { - DCHECK(base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)); + DCHECK(IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)); bool state_changed = false; for (const XrSecondaryViewConfigurationStateMSFT& state : states) { @@ -899,8 +938,7 @@ primary_view_config_.ProjectionViews()); // Gather all the layers for active secondary views. - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { for (const auto& secondary_view_config : secondary_view_configs_) { const OpenXrViewConfiguration& view_config = secondary_view_config.second; if (view_config.Active()) { @@ -1017,6 +1055,11 @@ return view; } +const std::unordered_set<mojom::XRSessionFeature>& +OpenXrApiWrapper::GetEnabledFeatures() const { + return enabled_features_; +} + std::vector<mojom::XRViewPtr> OpenXrApiWrapper::GetViews() const { // Since WebXR expects all views to be defined in a single swapchain texture, // we need to compute where in the texture each view begins. Each view is @@ -1032,8 +1075,7 @@ x_offset += primary_view_config_.Properties()[i].Width(); } - if (base::Contains(enabled_features_, - mojom::XRSessionFeature::SECONDARY_VIEWS)) { + if (IsFeatureEnabled(mojom::XRSessionFeature::SECONDARY_VIEWS)) { for (const auto& secondary_view_config : secondary_view_configs_) { const OpenXrViewConfiguration& view_config = secondary_view_config.second; if (view_config.Active()) {
diff --git a/device/vr/openxr/openxr_api_wrapper.h b/device/vr/openxr/openxr_api_wrapper.h index 606642f4..36b9427 100644 --- a/device/vr/openxr/openxr_api_wrapper.h +++ b/device/vr/openxr/openxr_api_wrapper.h
@@ -47,7 +47,9 @@ class VRTestHook; class ServiceTestHook; -using SessionStartedCallback = base::OnceCallback<void(XrResult result)>; +using SessionStartedCallback = + base::OnceCallback<void(mojom::XRRuntimeSessionOptionsPtr options, + XrResult result)>; using SessionEndedCallback = base::RepeatingCallback<void(ExitXrPresentReason)>; using VisibilityChangedCallback = base::RepeatingCallback<void(mojom::XRVisibilityState)>; @@ -78,12 +80,11 @@ // The supplied graphics_binding is guaranteed by the caller to exist until // this object is destroyed. - XrResult InitSession( - const std::unordered_set<mojom::XRSessionFeature>& enabled_features, - const OpenXrExtensionHelper& extension_helper, - SessionStartedCallback on_session_started_callback, - SessionEndedCallback on_session_ended_callback, - VisibilityChangedCallback visibility_changed_callback); + XrResult InitSession(mojom::XRRuntimeSessionOptionsPtr options, + const OpenXrExtensionHelper& extension_helper, + SessionStartedCallback on_session_started_callback, + SessionEndedCallback on_session_ended_callback, + VisibilityChangedCallback visibility_changed_callback); XrSpace GetReferenceSpace(device::mojom::XRReferenceSpaceType type) const; @@ -91,7 +92,9 @@ XrResult EndFrame(); bool HasPendingFrame() const; bool HasFrameState() const; + bool IsFeatureEnabled(device::mojom::XRSessionFeature feature) const; + const std::unordered_set<mojom::XRSessionFeature>& GetEnabledFeatures() const; std::vector<mojom::XRViewPtr> GetViews() const; mojom::VRPosePtr GetViewerPose() const; std::vector<mojom::XRInputSourceStatePtr> GetInputState(); @@ -124,6 +127,11 @@ void Reset(); bool Initialize(XrInstance instance, OpenXrGraphicsBinding* graphics_binding); void Uninitialize(); + void EnableSupportedFeatures( + const OpenXrExtensionHelper& extension_helper, + device::mojom::XRSessionMode mode, + const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, + const std::vector<device::mojom::XRSessionFeature>& optionalFeatures); XrResult InitializeSystem(); XrResult InitializeViewConfig(XrViewConfigurationType type, @@ -180,6 +188,7 @@ SessionStartedCallback on_session_started_callback_; SessionEndedCallback on_session_ended_callback_; VisibilityChangedCallback visibility_changed_callback_; + mojom::XRRuntimeSessionOptionsPtr session_options_; // Testing objects static VRTestHook* test_hook_;
diff --git a/device/vr/openxr/openxr_device.cc b/device/vr/openxr/openxr_device.cc index 1a358e4..2f1f5c2e 100644 --- a/device/vr/openxr/openxr_device.cc +++ b/device/vr/openxr/openxr_device.cc
@@ -148,6 +148,11 @@ extension_helper_ = std::make_unique<OpenXrExtensionHelper>( instance_, platform_helper_->GetExtensionEnumeration()); + // Now that we have an instance, check if it's even theoretically possible + // to support all of our required features. While this check isn't final, as + // the OpenXrRenderLoop will make that ultimate determination, it can help + // us early-exit and avoid spinning it up if we know we don't even have the + // extensions necessary to support a required feature. if (!AreAllRequiredFeaturesSupported( options->mode, options->required_features, *extension_helper_)) { DVLOG(1) << __func__ << " Missing a required feature";
diff --git a/device/vr/openxr/openxr_render_loop.cc b/device/vr/openxr/openxr_render_loop.cc index de5a0a7..c715aa7 100644 --- a/device/vr/openxr/openxr_render_loop.cc +++ b/device/vr/openxr/openxr_render_loop.cc
@@ -210,17 +210,9 @@ request_session_callback_ = base::BindPostTask(main_thread_task_runner_, std::move(callback)); - EnableSupportedFeatures(options->mode, options->required_features, - options->optional_features); - StartRuntime(std::move(on_visibility_state_changed), std::move(options)); } -bool OpenXrRenderLoop::IsFeatureEnabled( - device::mojom::XRSessionFeature feature) const { - return base::Contains(enabled_features_, feature); -} - void OpenXrRenderLoop::SetVisibilityState( mojom::XRVisibilityState visibility_state) { if (visibility_state_ != visibility_state) { @@ -364,9 +356,10 @@ session->data_provider = frame_data_receiver_.BindNewPipeAndPassRemote(); session->submit_frame_sink = std::move(submit_frame_sink); + const auto& enabled_features = openxr_->GetEnabledFeatures(); session->enabled_features.insert(session->enabled_features.end(), - enabled_features_.begin(), - enabled_features_.end()); + enabled_features.begin(), + enabled_features.end()); session->device_config = device::mojom::XRSessionDeviceConfig::New(); session->device_config->enable_anti_aliasing = @@ -650,44 +643,37 @@ } if (openxr_->HasFrameState()) { - if (IsFeatureEnabled(device::mojom::XRSessionFeature::ANCHORS)) { - OpenXrAnchorManager* anchor_manager = - openxr_->GetOrCreateAnchorManager(*extension_helper_); + OpenXrAnchorManager* anchor_manager = + openxr_->GetOrCreateAnchorManager(*extension_helper_); - if (anchor_manager) { - frame_data->anchors_data = anchor_manager->ProcessAnchorsForFrame( - openxr_.get(), current_stage_parameters_, - frame_data->input_state.value(), - openxr_->GetPredictedDisplayTime()); - } + if (anchor_manager) { + frame_data->anchors_data = anchor_manager->ProcessAnchorsForFrame( + openxr_.get(), current_stage_parameters_, + frame_data->input_state.value(), openxr_->GetPredictedDisplayTime()); } - if (IsFeatureEnabled(device::mojom::XRSessionFeature::LIGHT_ESTIMATION)) { - OpenXrLightEstimator* light_estimator = - openxr_->GetOrCreateLightEstimator(*extension_helper_); + OpenXrLightEstimator* light_estimator = + openxr_->GetOrCreateLightEstimator(*extension_helper_); - if (light_estimator) { - frame_data->light_estimation_data = light_estimator->GetLightEstimate( - openxr_->GetPredictedDisplayTime()); - } + if (light_estimator) { + frame_data->light_estimation_data = + light_estimator->GetLightEstimate(openxr_->GetPredictedDisplayTime()); } } - if (IsFeatureEnabled(device::mojom::XRSessionFeature::HIT_TEST) && - frame_data->mojo_from_viewer->position && + OpenXRSceneUnderstandingManager* scene_understanding_manager = + openxr_->GetOrCreateSceneUnderstandingManager(*extension_helper_); + + if (scene_understanding_manager && frame_data->mojo_from_viewer->position && frame_data->mojo_from_viewer->orientation) { - OpenXRSceneUnderstandingManager* scene_understanding_manager = - openxr_->GetOrCreateSceneUnderstandingManager(*extension_helper_); - if (scene_understanding_manager) { - scene_understanding_manager->OnFrameUpdate( - openxr_->GetPredictedDisplayTime()); - device::Pose mojo_from_viewer(*frame_data->mojo_from_viewer->position, - *frame_data->mojo_from_viewer->orientation); - // Get results for hit test subscriptions. - frame_data->hit_test_subscription_results = - scene_understanding_manager->GetHitTestResults( - mojo_from_viewer.ToTransform(), frame_data->input_state.value()); - } + scene_understanding_manager->OnFrameUpdate( + openxr_->GetPredictedDisplayTime()); + device::Pose mojo_from_viewer(*frame_data->mojo_from_viewer->position, + *frame_data->mojo_from_viewer->orientation); + // Get results for hit test subscriptions. + frame_data->hit_test_subscription_results = + scene_understanding_manager->GetHitTestResults( + mojo_from_viewer.ToTransform(), frame_data->input_state.value()); } return frame_data; @@ -727,14 +713,14 @@ SessionStartedCallback on_session_started_callback = base::BindOnce( &OpenXrRenderLoop::OnOpenXrSessionStarted, weak_ptr_factory_.GetWeakPtr(), - std::move(on_visibility_state_changed), std::move(options)); + std::move(on_visibility_state_changed)); SessionEndedCallback on_session_ended_callback = base::BindRepeating( &OpenXrRenderLoop::ExitPresent, weak_ptr_factory_.GetWeakPtr()); VisibilityChangedCallback on_visibility_state_changed_callback = base::BindRepeating(&OpenXrRenderLoop::SetVisibilityState, weak_ptr_factory_.GetWeakPtr()); if (XR_FAILED(openxr_->InitSession( - enabled_features_, *extension_helper_, + std::move(options), *extension_helper_, std::move(on_session_started_callback), std::move(on_session_ended_callback), std::move(on_visibility_state_changed_callback)))) { @@ -800,34 +786,6 @@ context_provider_.reset(); } -void OpenXrRenderLoop::EnableSupportedFeatures( - device::mojom::XRSessionMode mode, - const std::vector<device::mojom::XRSessionFeature>& required_features, - const std::vector<device::mojom::XRSessionFeature>& optional_features) { - enabled_features_.clear(); - // `OpenXRDevice::RequestSession` validates that we can support all required - // features so that it can reject the session early, so we assume that all - // required features are enabled. Looping through and doing this string - // comparison again can be redundant, but this will help potentially catch - // a developer error. -#if DCHECK_IS_ON() - CHECK(base::ranges::all_of( - required_features, [this](device::mojom::XRSessionFeature feature) { - return extension_helper_->IsFeatureSupported(feature); - })); -#endif - base::ranges::copy( - required_features, - std::inserter(enabled_features_, enabled_features_.begin())); - base::ranges::copy_if( - optional_features, - std::inserter(enabled_features_, enabled_features_.begin()), - [this, mode](device::mojom::XRSessionFeature feature) { - return IsFeatureSupportedForMode(feature, mode) && - extension_helper_->IsFeatureSupported(feature); - }); -} - bool OpenXrRenderLoop::HasSessionEnded() { return openxr_ && openxr_->UpdateAndGetSessionEnded(); }
diff --git a/device/vr/openxr/openxr_render_loop.h b/device/vr/openxr/openxr_render_loop.h index d8efdea93..5419f03 100644 --- a/device/vr/openxr/openxr_render_loop.h +++ b/device/vr/openxr/openxr_render_loop.h
@@ -206,10 +206,6 @@ void OnSessionStart(); bool HasSessionEnded(); bool SubmitCompositedFrame(); - void EnableSupportedFeatures( - device::mojom::XRSessionMode mode, - const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, - const std::vector<device::mojom::XRSessionFeature>& optionalFeatures); // viz::ContextLostObserver Implementation void OnContextLost() override; @@ -275,7 +271,6 @@ bool IsFeatureEnabled(device::mojom::XRSessionFeature feature) const; int16_t next_frame_id_ = 0; scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - std::unordered_set<device::mojom::XRSessionFeature> enabled_features_; // Owned by OpenXrStatics XrInstance instance_;
diff --git a/docs/design/sandbox.md b/docs/design/sandbox.md index 9be360d6f..b66a03a 100644 --- a/docs/design/sandbox.md +++ b/docs/design/sandbox.md
@@ -21,32 +21,31 @@ [here](http://dev.chromium.org/developers/design-documents/sandbox/osx-sandboxing-design). If you don't feel like reading this whole document you can read the -[Sandbox FAQ](sandbox_faq.md) instead. A -description of what the sandbox does and doesn't protect against may also be -found in the FAQ. +[Sandbox FAQ](sandbox_faq.md) instead. A description of what the sandbox does +and doesn't protect against may also be found in the FAQ. ## Design principles -* **Do not re-invent the wheel:** It is tempting to extend the OS kernel with a - better security model. Don't. Let the operating system apply its security to - the objects it controls. On the other hand, it is OK to create - application-level objects (abstractions) that have a custom security model. -* **Principle of least privilege:** This should be applied both to the sandboxed - code and to the code that controls the sandbox. In other words, the sandbox - should work even if the user cannot elevate to super-user. -* **Assume sandboxed code is malicious code:** For threat-modeling purposes, we - consider the sandbox compromised (that is, running malicious code) once the - execution path reaches past a few early calls in the `main()` function. In - practice, it could happen as soon as the first external input is accepted, or - right before the main loop is entered. -* **Be nimble:** Non-malicious code does not try to access resources it cannot - obtain. In this case the sandbox should impose near-zero performance - impact. It's ok to have performance penalties for exceptional cases when a - sensitive resource needs to be touched once in a controlled manner. This is - usually the case if the OS security is used properly. -* **Emulation is not security:** Emulation and virtual machine solutions do not - by themselves provide security. The sandbox should not rely on code emulation, - code translation, or patching to provide security. +* **Do not re-invent the wheel:** It is tempting to extend the OS kernel with + a better security model. Don't. Let the operating system apply its security + to the objects it controls. On the other hand, it is OK to create + application-level objects (abstractions) that have a custom security model. +* **Principle of least privilege:** This should be applied both to the + sandboxed code and to the code that controls the sandbox. In other words, + the sandbox should work even if the user cannot elevate to super-user. +* **Assume sandboxed code is malicious code:** For threat-modeling purposes, + we consider the sandbox compromised (that is, running malicious code) once + the execution path reaches past a few early calls in the `main()` function. + In practice, it could happen as soon as the first external input is + accepted, or right before the main loop is entered. +* **Be nimble:** Non-malicious code does not try to access resources it cannot + obtain. In this case the sandbox should impose near-zero performance impact. + It's ok to have performance penalties for exceptional cases when a sensitive + resource needs to be touched once in a controlled manner. This is usually + the case if the OS security is used properly. +* **Emulation is not security:** Emulation and virtual machine solutions do + not by themselves provide security. The sandbox should not rely on code + emulation, code translation, or patching to provide security. ## Sandbox Windows architecture @@ -57,8 +56,8 @@ Sandbox operates at process-level granularity. Anything that needs to be sandboxed needs to live on a separate process. The minimal sandbox configuration -has two processes: one that is a privileged controller known as the _broker_, -and one or more sandboxed processes known as the _target_. Throughout the +has two processes: one that is a privileged controller known as the *broker*, +and one or more sandboxed processes known as the *target*. Throughout the documentation and the code these two terms are used with that precise connotation. The sandbox is provided as a static library that must be linked to both the broker and the target executables. @@ -69,12 +68,12 @@ terms, a privileged controller/supervisor of the activities of the sandboxed processes. The responsibilities of the broker process are: -1. Specify the policy for each target process -1. Spawn the target processes -1. Host the sandbox policy engine service -1. Host the sandbox interception manager -1. Host the sandbox IPC service (to the target processes) -1. Perform the policy-allowed actions on behalf of the target process +1. Specify the policy for each target process +1. Spawn the target processes +1. Host the sandbox policy engine service +1. Host the sandbox interception manager +1. Host the sandbox IPC service (to the target processes) +1. Perform the policy-allowed actions on behalf of the target process The broker should always outlive all the target processes that it spawned. The sandbox IPC is a low-level mechanism (different from Chromium's IPC) that is @@ -91,10 +90,10 @@ target process hosts all the code that is going to run inside the sandbox, plus the sandbox infrastructure client side: -1. All code to be sandboxed -1. The sandbox IPC client -1. The sandbox policy engine client -1. The sandbox interceptions +1. All code to be sandboxed +1. The sandbox IPC client +1. The sandbox policy engine client +1. The sandbox interceptions Items 2,3 and 4 are part of the sandbox library that is linked with the code to be sandboxed. @@ -104,7 +103,7 @@ calls and return the results or simply fail the calls. The interception + IPC mechanism does not provide security; it is designed to provide compatibility when code inside the sandbox cannot be modified to cope with sandbox -restrictions. To save unnecessary IPCs, policy is also evaluated in the target +restrictions. To save unnecessary IPCs, policy is also evaluated in the target process before making an IPC call, although this is not used as a security guarantee but merely a speed optimization. @@ -118,18 +117,18 @@ At its core, the sandbox relies on the protection provided by four Windows mechanisms: -* A restricted token -* The Windows _job_ object -* The Windows _desktop_ object -* Integrity levels +* A restricted token +* The Windows *job* object +* The Windows *desktop* object +* Integrity levels These mechanisms are highly effective at protecting the OS, its configuration, and the user's data provided that: -* All the securable resources have a better than null security descriptor. In - other words, there are no critical resources with misconfigured security. -* The computer is not already compromised by malware. -* Third party software does not weaken the security of the system. +* All the securable resources have a better than null security descriptor. In + other words, there are no critical resources with misconfigured security. +* The computer is not already compromised by malware. +* Third party software does not weaken the security of the system. ** Note that extra mitigations above and beyond this base/core will be described in the "Process Mitigations" section below. @@ -141,14 +140,21 @@ Chromium sandbox, the most restrictive token takes the following form: #### Regular Groups -* Logon SID : mandatory -* All other SIDs : deny only, mandatory + +* Logon SID : mandatory +* All other SIDs : deny only, mandatory + #### Restricted Groups -* S-1-0-0 : mandatory + +* S-1-0-0 : mandatory + #### Privileges -* None + +* None + #### Integrity -* Untrusted integrity level label (S-1-16-0x0) + +* Untrusted integrity level label (S-1-16-0x0) With the caveats described above, it is near impossible to find an existing resource that the OS will grant access with such a token. As long as the disk @@ -164,17 +170,17 @@ By design, the sandbox token cannot protect the non-securable resources such as: -* Mounted FAT or FAT32 volumes: The security descriptor on them is effectively - null. Malware running in the target can read and write to these volumes as - long it can guess or deduce their paths. -* TCP/IP: The security of TCP/IP sockets in Windows 2000 and Windows XP (but not - in Vista) is effectively null. It might be possible for malicious code in the - target to send and receive network packets to any host. -* Some unlabelled objects, such as anonymous shared memory sections (e.g. - [bug 338538](https://crbug.com/338538)) +* Mounted FAT or FAT32 volumes: The security descriptor on them is effectively + null. Malware running in the target can read and write to these volumes as + long it can guess or deduce their paths. +* TCP/IP: The security of TCP/IP sockets in Windows 2000 and Windows XP (but + not in Vista) is effectively null. It might be possible for malicious code + in the target to send and receive network packets to any host. +* Some unlabelled objects, such as anonymous shared memory sections (e.g. + [bug 338538](https://crbug.com/338538)) -See NULL DACLs and Other Dangerous ACE Types, _Secure Coding Techniques_, 195-199 -for more information. +See NULL DACLs and Other Dangerous ACE Types, *Secure Coding Techniques*, +195-199 for more information. ### The Job object @@ -182,28 +188,28 @@ some interesting global restrictions that do not have a traditional object or security descriptor associated with them are enforced: -* Forbid per-use system-wide changes using `SystemParametersInfo()`, which can - be used to swap the mouse buttons or set the screen saver timeout -* Forbid the creation or switch of Desktops -* Forbid changes to the per-user display configuration such as resolution and - primary display -* No read or write to the clipboard -* Forbid Windows message broadcasts -* Forbid setting global Windows hooks (using `SetWindowsHookEx()`) -* Forbid access to the global atoms table -* Forbid access to USER handles created outside the Job object -* One active process limit (disallows creating child processes) +* Forbid per-use system-wide changes using `SystemParametersInfo()`, which can + be used to swap the mouse buttons or set the screen saver timeout +* Forbid the creation or switch of Desktops +* Forbid changes to the per-user display configuration such as resolution and + primary display +* No read or write to the clipboard +* Forbid Windows message broadcasts +* Forbid setting global Windows hooks (using `SetWindowsHookEx()`) +* Forbid access to the global atoms table +* Forbid access to USER handles created outside the Job object +* One active process limit (disallows creating child processes) Chromium renderers normally run with all these restrictions active. Each renderer runs in its own Job object. Using the Job object, the sandbox can (but currently does not) prevent: -* Excessive use of CPU cycles -* Excessive use of memory -* Excessive use of IO +* Excessive use of CPU cycles +* Excessive use of memory +* Excessive use of IO -More information about Windows Job Objects can be -found [here](https://docs.microsoft.com/en-us/windows/desktop/procthread/job-objects). +More information about Windows Job Objects can be found +[here](https://docs.microsoft.com/en-us/windows/desktop/procthread/job-objects). ### The alternate desktop @@ -251,20 +257,20 @@ A low integrity level token can access only the following shared resources: -* Read access to most files -* Write access to `%USER PROFILE%\AppData\LocalLow` -* Read access to most of the registry -* Write access to `HKEY_CURRENT_USER\Software\AppDataLow` -* Clipboard (copy and paste for certain formats) -* Remote procedure call (RPC) -* TCP/IP Sockets -* Window messages exposed via `ChangeWindowMessageFilter` -* Shared memory exposed via LI (low integrity) labels -* COM interfaces with LI (low integrity) launch activation rights -* Named pipes exposed via LI (low integrity) labels +* Read access to most files +* Write access to `%USER PROFILE%\AppData\LocalLow` +* Read access to most of the registry +* Write access to `HKEY_CURRENT_USER\Software\AppDataLow` +* Clipboard (copy and paste for certain formats) +* Remote procedure call (RPC) +* TCP/IP Sockets +* Window messages exposed via `ChangeWindowMessageFilter` +* Shared memory exposed via LI (low integrity) labels +* COM interfaces with LI (low integrity) launch activation rights +* Named pipes exposed via LI (low integrity) labels -While an Untrusted integrity level can only write to resources which -have a null DACL or an explicit Untrusted Mandatory Level. +While an Untrusted integrity level can only write to resources which have a null +DACL or an explicit Untrusted Mandatory Level. You'll notice that the previously described attributes of the token, job object, and alternate desktop are more restrictive, and would in fact block access to @@ -273,179 +279,203 @@ defense-in-depth, and its use has no visible impact on performance or resource usage. -The integrity level of different Chrome components will change over -time as functionality is split into smaller services. At M75 the -browser, crash handler, and network utility processes run at Medium -integrity, the GPU process at Low and most remaining services -including isolated renderers at Untrusted. +The integrity level of different Chrome components will change over time as +functionality is split into smaller services. At M75 the browser, crash handler, +and network utility processes run at Medium integrity, the GPU process at Low +and most remaining services including isolated renderers at Untrusted. -More information on integrity levels can be -found [here](http://msdn.microsoft.com/en-us/library/bb625963.aspx) -and in Chapter 7 of *Windows Internals, Part 1, 7th Ed.*. +More information on integrity levels can be found +[here](http://msdn.microsoft.com/en-us/library/bb625963.aspx) and in Chapter 7 +of *Windows Internals, Part 1, 7th Ed.*. ### Process mitigation policies Most process mitigation policies can be applied to the target process by means -of SetProcessMitigationPolicy. The sandbox uses this API to set various -policies on the target process for enforcing security characteristics. +of SetProcessMitigationPolicy. The sandbox uses this API to set various policies +on the target process for enforcing security characteristics. #### Relocate Images: -* >= Win8 -* Address-load randomization (ASLR) on all images in process (and must be - supported by all images). +* >= Win8 +* Address-load randomization (ASLR) on all images in process (and must be + supported by all images). #### Heap Terminate: -* >= Win8 -* Terminates the process on Windows heap corruption. +* >= Win8 +* Terminates the process on Windows heap corruption. #### Bottom-up ASLR: -* >= Win8 -* Sets random lower bound as minimum user address for the process. +* >= Win8 +* Sets random lower bound as minimum user address for the process. #### High-entropy ASLR: -* >= Win8 -* Increases randomness range for bottom-up ASLR to 1TB. +* >= Win8 +* Increases randomness range for bottom-up ASLR to 1TB. #### Strict Handle Checks: -* >= Win8 -* Immediately raises an exception on a bad handle reference. +* >= Win8 +* Immediately raises an exception on a bad handle reference. #### Win32k.sys lockdown: -* >= Win8 -* `ProcessSystemCallDisablePolicy`, which allows selective disabling of system - calls available from the target process. -* Renderer processes now have this set to `DisallowWin32kSystemCalls` which - means that calls from user mode that are serviced by `win32k.sys` are no - longer permitted. This significantly reduces the kernel attack surface - available from a renderer. See - [here](https://docs.google.com/document/d/1gJDlk-9xkh6_8M_awrczWCaUuyr0Zd2TKjNBCiPO_G4) - for more details. +* >= Win8 +* `ProcessSystemCallDisablePolicy`, which allows selective disabling of system + calls available from the target process. +* Renderer processes now have this set to `DisallowWin32kSystemCalls` which + means that calls from user mode that are serviced by `win32k.sys` are no + longer permitted. This significantly reduces the kernel attack surface + available from a renderer. See + [here](https://docs.google.com/document/d/1gJDlk-9xkh6_8M_awrczWCaUuyr0Zd2TKjNBCiPO_G4) + for more details. #### Disable Extension Points (legacy hooking): -* >= Win8 -* `ProcessExtensionPointDisablePolicy` -* The following injection vectors are blocked: - * AppInit DLLs Winsock Layered Service Providers (LSPs) - * Global Window Hooks (not thread-targeted hooks) - * Legacy Input Method Editors (IMEs) +* >= Win8 +* `ProcessExtensionPointDisablePolicy` +* The following injection vectors are blocked: + * AppInit DLLs Winsock Layered Service Providers (LSPs) + * Global Window Hooks (not thread-targeted hooks) + * Legacy Input Method Editors (IMEs) #### Control Flow Guard (CFG): -* >= Win8.1 Update 3 (KB3000850) -* Enabled in all chrome.exe processes. Not compiled into all chrome binaries. -* Takes advantage of CFG security in Microsoft system DLLs in our processes. -* Compiler/Linker opt-in, not a run-time policy opt-in. See -[MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/mt637065(v=vs.85).aspx). +* >= Win8.1 Update 3 (KB3000850) +* Enabled in all chrome.exe processes. Not compiled into all chrome binaries. +* Takes advantage of CFG security in Microsoft system DLLs in our processes. +* Compiler/Linker opt-in, not a run-time policy opt-in. See + [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/mt637065\(v=vs.85\).aspx). #### CET Shadow Stack: -* Available in Windows 10 2004 December Update. -* Is not enabled in the renderer. See -[ticket](https://bugs.chromium.org/p/chromium/issues/detail?id=1136224), -[MSDN](https://docs.microsoft.com/en-us/cpp/build/reference/cetcompat?view=vs-2019). +* Available in Windows 10 2004 December Update. +* Is not enabled in the renderer. See + [ticket](https://bugs.chromium.org/p/chromium/issues/detail?id=1136224), + [MSDN](https://docs.microsoft.com/en-us/cpp/build/reference/cetcompat?view=vs-2019). #### Disable Font Loading: -* >= Win10 -* `ProcessFontDisablePolicy` +* >= Win10 +* `ProcessFontDisablePolicy` #### Disable Loading of Unsigned Code (CIG): -* >= Win10 TH2 -* `ProcessSignaturePolicy` -* Prevents loading unsigned code into our processes. This means attackers can't just LoadLibrary a DLL after gaining execution (which shouldn't be possible anyway due to other sandbox mitigations), but more importantly, prevents third party DLLs from being injected into our processes, which can affect stability and our ability to enable other security mitigations. -* Enabled (post-startup) for all sandboxed child processes. -* Enabled (pre-startup) for sandboxed renderer processes. This eliminates a process launch time gap where local injection of improperly signed DLLs into a renderer process could occur. -* See [msedgedev blog](https://blogs.windows.com/msedgedev/2017/02/23/mitigating-arbitrary-native-code-execution/) for more background on this mitigation. +* >= Win10 TH2 +* `ProcessSignaturePolicy` +* Prevents loading unsigned code into our processes. This means attackers + can't just LoadLibrary a DLL after gaining execution (which shouldn't be + possible anyway due to other sandbox mitigations), but more importantly, + prevents third party DLLs from being injected into our processes, which can + affect stability and our ability to enable other security mitigations. +* Enabled (post-startup) for all sandboxed child processes. +* Enabled (pre-startup) for sandboxed renderer processes. This eliminates a + process launch time gap where local injection of improperly signed DLLs into + a renderer process could occur. +* See + [msedgedev blog](https://blogs.windows.com/msedgedev/2017/02/23/mitigating-arbitrary-native-code-execution/) + for more background on this mitigation. #### Disable Image Load from Remote Devices: -* >= Win10 TH2 -* `ProcessImageLoadPolicy` -* E.g. UNC path to network resource. +* >= Win10 TH2 +* `ProcessImageLoadPolicy` +* E.g. UNC path to network resource. #### Disable Image Load of "mandatory low" (low integrity level): -* >= Win10 TH2 -* `ProcessImageLoadPolicy` -* E.g. temporary internet files. +* >= Win10 TH2 +* `ProcessImageLoadPolicy` +* E.g. temporary internet files. #### Extra Disable Child Process Creation: -* >= Win10 TH2 -* If the Job level <= `JOB_LIMITED_USER`, set - `PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY` to - `PROCESS_CREATION_CHILD_PROCESS_RESTRICTED` via `UpdateProcThreadAttribute()`. -* This is an extra layer of defense, given that Job levels can be broken out of. - See also: -[ticket](https://bugs.chromium.org/p/project-zero/issues/detail?id=213&redir=1), -[Project Zero blog](http://googleprojectzero.blogspot.co.uk/2015/05/in-console-able.html). +* >= Win10 TH2 +* If the Job level <= `JOB_LIMITED_USER`, set + `PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY` to + `PROCESS_CREATION_CHILD_PROCESS_RESTRICTED` via + `UpdateProcThreadAttribute()`. +* This is an extra layer of defense, given that Job levels can be broken out + of. See also: + [ticket](https://bugs.chromium.org/p/project-zero/issues/detail?id=213&redir=1), + [Project Zero blog](http://googleprojectzero.blogspot.co.uk/2015/05/in-console-able.html). + +#### Disable Dynamic Code (ACG): + +* >= Windows 10 RS1 +* `ProcessDynamicCodePolicy` - Also known as Arbitrary Code Guard (ACG). +* With ACG enabled, the Windows kernel prevents a process from creating and + modifying code pages in memory by enforcing that all code pages are + immutable and new unsigned code pages cannot be created. This will cause + code that attempts to modify or inject into these processes to fail, such as + certain attempts to corrupt browser memory, and some third party DLLs. +* This is enabled by default for sandboxed service utility processes, and for + sandboxed renderer processes that perform no JIT (just-in-time) compilation, + and can be enabled for the browser process via the + `BrowserDynamicCodeDisabled` feature. ### App Container (low box token): -* In Windows this is implemented at the kernel level by a Low Box token which is - a stripped version of a normal token with limited privilege (normally just - `SeChangeNotifyPrivilege` and `SeIncreaseWorkingSetPrivilege`), running at Low - integrity level and an array of "Capabilities" which can be mapped to - allow/deny what the process is allowed to do (see - [MSDN](https://msdn.microsoft.com/en-us/library/windows/apps/hh464936.aspx) - for a high level description). The capability most interesting from a sandbox - perspective is denying is access to the network, as it turns out network - checks are enforced if the token is a Low Box token and the `INTERNET_CLIENT` - Capability is not present. -* The sandbox therefore takes the existing restricted token and adds the Low Box - attributes, without granting any Capabilities, so as to gain the additional - protection of no network access from the sandboxed process. +* In Windows this is implemented at the kernel level by a Low Box token which + is a stripped version of a normal token with limited privilege (normally + just `SeChangeNotifyPrivilege` and `SeIncreaseWorkingSetPrivilege`), running + at Low integrity level and an array of "Capabilities" which can be mapped to + allow/deny what the process is allowed to do (see + [MSDN](https://msdn.microsoft.com/en-us/library/windows/apps/hh464936.aspx) + for a high level description). The capability most interesting from a + sandbox perspective is denying is access to the network, as it turns out + network checks are enforced if the token is a Low Box token and the + `INTERNET_CLIENT` Capability is not present. +* The sandbox therefore takes the existing restricted token and adds the Low + Box attributes, without granting any Capabilities, so as to gain the + additional protection of no network access from the sandboxed process. ### Less Privileged App Container (LPAC) -* An extension of the App Container (see above) available on later versions of - Windows 10 (RS2 and greater), the Less Privileged App Container (LPAC) runs - at a lower privilege level than normal App Container, with access granted by - default to only those kernel, filesystem and registry objects marked with the - `ALL RESTRICTED APPLICATION PACKAGES` or a specific package SID. This is - opposed to App Container which uses `ALL APPLICATION PACKAGES`. -* A key characteristic of the LPAC is that specific named capabilities can be - added such as those based on well known SIDs (defined in - [`base/win/sid.h`](https://cs.chromium.org/chromium/src/base/win/sid.h)) or - via 'named capabilities' resolved through call to - [DeriveCapabilitySidsFromName](https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-derivecapabilitysidsfromname) - which are not really strictly defined anywhere but can be found in various - [places](https://social.technet.microsoft.com/Forums/scriptcenter/en-US/3e7d85e3-d0e1-4e79-8141-0bbf8faf3644/windows-10-anniversary-update-the-case-of-the-mysterious-account-sid-causing-the-flood-of-dcom?forum=win10itprosetup) - and include capabilities such as: - * `lpacCom` - * `registryRead` - * `lpacWebPlatform` - * `lpacClipboard` - * etc... - * Each LPAC process can have a process-specific SID created for it and this - can be used to protect files specific to that particular sandbox, and there - can be multiple different overlapping sets of access rights depending on - the interactions between services running in different sandboxes. +* An extension of the App Container (see above) available on later versions of + Windows 10 (RS2 and greater), the Less Privileged App Container (LPAC) runs + at a lower privilege level than normal App Container, with access granted by + default to only those kernel, filesystem and registry objects marked with + the `ALL RESTRICTED APPLICATION PACKAGES` or a specific package SID. This is + opposed to App Container which uses `ALL APPLICATION PACKAGES`. +* A key characteristic of the LPAC is that specific named capabilities can be + added such as those based on well known SIDs (defined in + [`base/win/sid.h`](https://cs.chromium.org/chromium/src/base/win/sid.h)) or + via 'named capabilities' resolved through call to + [DeriveCapabilitySidsFromName](https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-derivecapabilitysidsfromname) + which are not really strictly defined anywhere but can be found in various + [places](https://social.technet.microsoft.com/Forums/scriptcenter/en-US/3e7d85e3-d0e1-4e79-8141-0bbf8faf3644/windows-10-anniversary-update-the-case-of-the-mysterious-account-sid-causing-the-flood-of-dcom?forum=win10itprosetup) + and include capabilities such as: + * `lpacCom` + * `registryRead` + * `lpacWebPlatform` + * `lpacClipboard` + * etc... + * Each LPAC process can have a process-specific SID created for it and + this can be used to protect files specific to that particular sandbox, + and there can be multiple different overlapping sets of access rights + depending on the interactions between services running in different + sandboxes. #### LPAC File System Permissions - * Importantly, all locations in the filesystem and registry that the LPAC - process will access during its lifetime need to have the right ACLs on - them. `registryRead` is important for registry read access, and Windows - system files have `ALL RESTRICTED APPLICATION PACKAGES` ACE on them already, - but other files that the sandbox process needs access to including the - binaries (e.g. chrome.exe, chrome.dll) and also any data files need ACLs to - be laid down. This is typically done by the installer, and also done - automatically for tests. However, if the LPAC sandbox is to be used in other - environments then these filesystem permissions need to be manually laid down - using `icacls`, the installer, or a similar tool. An example of a ACE that - could be used can be found in - [`testing/scripts/common.py`](https://cs.chromium.org/chromium/src/testing/scripts/common.py) - however in high security environments a more restrictive SID should be used - such as one from the - [installer](https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/setup/install_worker.cc;l=74). + +* Importantly, all locations in the filesystem and registry that the LPAC + process will access during its lifetime need to have the right ACLs on them. + `registryRead` is important for registry read access, and Windows system + files have `ALL RESTRICTED APPLICATION PACKAGES` ACE on them already, but + other files that the sandbox process needs access to including the binaries + (e.g. chrome.exe, chrome.dll) and also any data files need ACLs to be laid + down. This is typically done by the installer, and also done automatically + for tests. However, if the LPAC sandbox is to be used in other environments + then these filesystem permissions need to be manually laid down using + `icacls`, the installer, or a similar tool. An example of a ACE that could + be used can be found in + [`testing/scripts/common.py`](https://cs.chromium.org/chromium/src/testing/scripts/common.py) + however in high security environments a more restrictive SID should be used + such as one from the + [installer](https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/setup/install_worker.cc;l=74). ### Other caveats @@ -464,15 +494,15 @@ ## Sandbox policy -The actual restrictions applied to a target process are configured by a -policy. The policy is just a programmatic interface that the broker calls to -define the restrictions and allowances. Four functions control the restrictions, -roughly corresponding to the four Windows mechanisms: +The actual restrictions applied to a target process are configured by a policy. +The policy is just a programmatic interface that the broker calls to define the +restrictions and allowances. Four functions control the restrictions, roughly +corresponding to the four Windows mechanisms: -* `TargetPolicy::SetTokenLevel()` -* `TargetPolicy::SetJobLevel()` -* `TargetPolicy::SetIntegrityLevel()` -* `TargetPolicy::SetDesktop()` +* `TargetPolicy::SetTokenLevel()` +* `TargetPolicy::SetJobLevel()` +* `TargetPolicy::SetIntegrityLevel()` +* `TargetPolicy::SetDesktop()` The first three calls take an integer level parameter that goes from very strict to very loose; for example, the token level has 7 levels and the job level has 5 @@ -490,22 +520,24 @@ call: `AddRule`. The following kinds of rules for different Windows subsystems are supported at this time: -* Files -* Named pipes -* Process creation -* Registry -* Synchronization objects +* Files +* Named pipes +* Process creation +* Registry +* Synchronization objects The exact form of the rules for each subsystem varies, but in general rules are triggered based on a string pattern. For example, a possible file rule is: - AddRule(SUBSYS_FILES, FILES_ALLOW_READONLY, L"c:\\temp\\app_log\\d*.dmp") +``` +AddRule(SUBSYS_FILES, FILES_ALLOW_READONLY, L"c:\\temp\\app_log\\d*.dmp") +``` This rule specifies that access will be granted if a target wants to open a file, for read-only access as long as the file matches the pattern expression; -for example `c:\temp\app_log\domino.dmp` is a file that satisfies the -pattern. Consult the header files for an up-to-date list of supported objects -and supported actions. +for example `c:\temp\app_log\domino.dmp` is a file that satisfies the pattern. +Consult the header files for an up-to-date list of supported objects and +supported actions. Rules can only be added before each target process is spawned, and cannot be modified while a target is running, but different targets can have different @@ -535,7 +567,9 @@ is set as the impersonation token of the initial thread. In fact the actual `SetTokenLevel` definition is: - SetTokenLevel(TokenLevel initial, TokenLevel lockdown) +``` +SetTokenLevel(TokenLevel initial, TokenLevel lockdown) +``` After all the critical initialization is done, execution continues at `main()` or `WinMain()`, here the two tokens are still active, but only the initial @@ -543,7 +577,9 @@ responsibility to discard the initial token when ready. This is done with a single call: - LowerToken() +``` +LowerToken() +``` After this call is issued by the target the only token available is the lockdown token and the full sandbox restrictions go into effect. The effects of this call
diff --git a/docs/experiments/compression-dictionary-transport.md b/docs/experiments/compression-dictionary-transport.md index eb95f50..e5836d8a 100644 --- a/docs/experiments/compression-dictionary-transport.md +++ b/docs/experiments/compression-dictionary-transport.md
@@ -224,6 +224,9 @@ - `compression-dictionary` rel attribute is used for HTML `link` element and HTTP `Link:` header instead of `dictionary`. +- Changed Content-Encoding to use "dcb" and "dcz". + See [this spec change](https://github.com/httpwg/http-extensions/pull/2784). + ## Demo sites
diff --git a/docs/updater/protocol_3_1.md b/docs/updater/protocol_3_1.md index 53fc1a7..e6593142 100644 --- a/docs/updater/protocol_3_1.md +++ b/docs/updater/protocol_3_1.md
@@ -386,8 +386,12 @@ The string should be drawn from a small set of constant values, to minimize entropy and the ability for the client to be fingerprinted. Default: "". * `installsource`: A string describing the immediate cause of this request. - Known values include: "" (a normal background update) and "ondemand" (a - foreground, user-initiated update). Default: "". + Default: "". Known values include: + * "" (a normal background update), + * "ondemand" (a foreground, user-initiated update), + * "taggedmi" (a tagged metainstaller was run), + * "offline" (an offline installer was run), + * "policy" (an install was triggered by group policy), The string should be drawn from a small set of constant values, to minimize entropy and the ability for the client to be fingerprinted. * `ismachine`: "0" if the application is installed for the user specifically
diff --git a/extensions/browser/api/declarative_net_request/composite_matcher.cc b/extensions/browser/api/declarative_net_request/composite_matcher.cc index 22902b27..5c8a7d2 100644 --- a/extensions/browser/api/declarative_net_request/composite_matcher.cc +++ b/extensions/browser/api/declarative_net_request/composite_matcher.cc
@@ -4,8 +4,10 @@ #include "extensions/browser/api/declarative_net_request/composite_matcher.h" +#include <cstdint> #include <functional> #include <iterator> +#include <optional> #include <set> #include <utility> #include <vector> @@ -154,30 +156,33 @@ page_access == PermissionsData::PageAccess::kWithheld); } - std::optional<RequestAction> final_action; + // Get the max priority allow action for this extension, or implicitly assign + // it as nullopt in `params.max_priority_allow_action` if there isn't one. + auto& max_priority_allow_action_for_extension = + params.max_priority_allow_action[extension_id_]; - // The priority of the highest priority matching allow or allowAllRequests - // rule for this matcher's extension for the current request, or std::nullopt - // otherwise. This also serves as the minimum priority needed for a rule to be - // matched. - std::optional<uint64_t>& max_allow_rule_priority_for_request = - params.allow_rule_max_priority[extension_id_]; + // Assign `final_action` to the max priority allow action matched in previous + // request stages (if any). This way, that action will be returned again if it + // outprioritizes all rules that are matched in the current request `stage`. + std::optional<RequestAction> final_action = + max_priority_allow_action_for_extension.has_value() + ? std::make_optional(max_priority_allow_action_for_extension->Clone()) + : std::nullopt; for (const auto& matcher : matchers_) { std::optional<RequestAction> action = matcher->GetAction(params, stage); - // TODO(crbug.com/40727004): Allow/AllowAllRequests rules matched can still - // take effect for stages of the request past the one they're matched in. If - // they are the max priority action, they should be returned instead of - // silently causing no action to be matched. - if (!action || action->index_priority <= - max_allow_rule_priority_for_request.value_or(0)) { + uint64_t max_allow_rule_priority = + max_priority_allow_action_for_extension.has_value() + ? max_priority_allow_action_for_extension->index_priority + : 0u; + if (!action || action->index_priority <= max_allow_rule_priority) { continue; } if (action->IsAllowOrAllowAllRequests()) { - max_allow_rule_priority_for_request = - std::max(max_allow_rule_priority_for_request.value_or(0), - action->index_priority); + // This will update `max_priority_allow_action_for_extension`. + params.max_priority_allow_action.insert_or_assign(extension_id_, + action->Clone()); } final_action = @@ -192,7 +197,7 @@ final_action->type == RequestAction::Type::REDIRECT; if (!requires_host_permission || page_access == PageAccess::kAllowed) { return ActionInfo(std::move(final_action), - false /* notify_request_withheld */); + /*notify_request_withheld=*/false); } // `requires_host_permission` is true and `page_access` is withheld or denied. @@ -205,15 +210,19 @@ const RequestParams& params, RulesetMatchingStage stage) const { std::vector<RequestAction> modify_headers_actions; - DCHECK(params.allow_rule_max_priority.contains(extension_id_)); // The priority of the highest priority matching allow or allowAllRequests - // rule within this matcher, or std::nullopt if no such rule exists. - std::optional<uint64_t> max_allow_rule_priority = - params.allow_rule_max_priority[extension_id_]; + // rule within this matcher, or 0 if no such rule exists (the minimum priority + // for a rule, specified in `kMinValidPriority`, is 1.) + uint64_t max_allow_rule_priority = 0u; + + DCHECK(base::Contains(params.max_priority_allow_action, extension_id_)); + if (auto& allow_action = params.max_priority_allow_action.at(extension_id_)) { + max_allow_rule_priority = allow_action->index_priority; + } for (const auto& matcher : matchers_) { - // Plumb |max_allow_rule_priority| into GetModifyHeadersActions so that + // Plumb `max_allow_rule_priority` into GetModifyHeadersActions so that // modifyHeaders rules with priorities less than or equal to the highest // priority matching allow/allowAllRequests rule are ignored. std::vector<RequestAction> actions_for_matcher = @@ -226,7 +235,7 @@ std::make_move_iterator(actions_for_matcher.end())); } - // Sort |modify_headers_actions| in descending order of priority. + // Sort `modify_headers_actions` in descending order of priority. std::sort(modify_headers_actions.begin(), modify_headers_actions.end(), std::greater<>()); return modify_headers_actions;
diff --git a/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc b/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc index 7ccd060..5b1d7a66 100644 --- a/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc +++ b/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
@@ -10,6 +10,7 @@ #include "base/memory/raw_ref.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" #include "extensions/browser/api/declarative_net_request/constants.h" #include "extensions/browser/api/declarative_net_request/file_backed_ruleset_source.h" #include "extensions/browser/api/declarative_net_request/request_action.h" @@ -19,6 +20,7 @@ #include "extensions/common/api/declarative_net_request.h" #include "extensions/common/api/declarative_net_request/constants.h" #include "extensions/common/api/declarative_net_request/test_utils.h" +#include "extensions/common/extension_features.h" #include "extensions/common/permissions/permissions_data.h" #include "net/http/http_request_headers.h" #include "testing/gmock/include/gmock/gmock.h" @@ -375,7 +377,7 @@ google_params.url = &google_url; // Reset the max allow rule priority cache since a new request is being made. - google_params.allow_rule_max_priority.clear(); + google_params.max_priority_allow_action.clear(); // Call GetBeforeRequestAction first to ensure that test and production code // paths are consistent. @@ -720,5 +722,115 @@ } } +class CompositeMatcherResponseHeadersTest : public CompositeMatcherTest { + public: + CompositeMatcherResponseHeadersTest() { + scoped_feature_list_.InitAndEnableFeature( + extensions_features::kDeclarativeNetRequestResponseHeaderMatching); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Test that an allow rule matched in OnBeforeRequest can be returned when +// matching rules in OnHeadersReceived if said rule outprioritizes all rules +// with response header conditions. +TEST_F(CompositeMatcherResponseHeadersTest, AllowRuleMatchedAcrossStages) { + // TODO(kelvinjiang): A lot of e2e DNR tests for response header rules test + // the matching logic for the onHeadersReceived stage, so a header condition + // that functionally matches on almost any header is used. Put this into + // test_utils. + std::vector<TestHeaderCondition> blank_header_condition = + std::vector<TestHeaderCondition>( + {TestHeaderCondition("nonsense-header", {}, {})}); + + int rule_id = kMinValidID; + + // Add 3 rules: + // - OnBeforeRequest allow (pri = 3) + // - OnHeadersReceived block (pri = 2) + // - OnHeadersReceived allow (pri = 1) + TestRule before_request_allow = CreateGenericRule(rule_id++); + before_request_allow.action->type = "allow"; + before_request_allow.condition->url_filter = "example.test2"; + before_request_allow.priority = 3; + + TestRule headers_received_block = CreateGenericRule(rule_id++); + headers_received_block.condition->url_filter = "example.test"; + headers_received_block.condition->excluded_response_headers = + blank_header_condition; + headers_received_block.priority = 2; + + TestRule headers_received_allow = CreateGenericRule(rule_id++); + headers_received_allow.action->type = "allow"; + headers_received_allow.condition->url_filter = "example.test"; + headers_received_allow.condition->excluded_response_headers = + blank_header_condition; + + std::unique_ptr<RulesetMatcher> matcher; + ASSERT_TRUE(CreateVerifiedMatcher( + {before_request_allow, headers_received_block, headers_received_allow}, + CreateTemporarySource(), &matcher)); + CompositeMatcher::MatcherList matchers; + matchers.push_back(std::move(matcher)); + auto composite_matcher = std::make_unique<CompositeMatcher>( + std::move(matchers), /*extension_id=*/"", + HostPermissionsAlwaysRequired::kTrue); + + struct { + std::string url; + std::optional<int> expected_matched_before_request_id; + std::optional<int> expected_matched_headers_received_id; + } test_cases[] = { + // No rules are matched in OnBeforeRequest, but `headers_received_block` + // is matched in OnHeadersReceived. + {"https://example.test", std::nullopt, headers_received_block.id}, + + // `before_request_allow` is matched in OnBeforeRequest, and that match is + // carried over in `OnHeadersReceived` where it outprioritizes rules with + // header conditions, so it should be matched again. + {"https://example.test2", before_request_allow.id, + before_request_allow.id}, + }; + + for (const auto& test_case : test_cases) { + SCOPED_TRACE(base::StringPrintf("Testing %s", test_case.url.c_str())); + + // Navigate to the given URL. + GURL url(test_case.url); + auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders("HTTP/1.0 200 OK\r\n")); + RequestParams params = + CreateRequestWithResponseHeaders(url, base_headers.get()); + + // Match rules in the OnBeforeRequest phase and verify the matched rule ID + // if any. + ActionInfo before_request_info = composite_matcher->GetAction( + params, RulesetMatchingStage::kOnBeforeRequest, PageAccess::kAllowed); + + std::optional<int> before_request_rule_id; + if (before_request_info.action) { + before_request_rule_id = before_request_info.action->rule_id; + } + EXPECT_EQ(test_case.expected_matched_before_request_id, + before_request_rule_id); + + // Reusing `params`, simulate a request matching flow by continuing to match + // rules in the OnHeadersReceived phase, and verify the matched rule ID if + // any. + ActionInfo headers_received_info = composite_matcher->GetAction( + params, RulesetMatchingStage::kOnHeadersReceived, PageAccess::kAllowed); + + std::optional<int> headers_received_rule_id; + if (headers_received_info.action) { + headers_received_rule_id = headers_received_info.action->rule_id; + } + + EXPECT_EQ(test_case.expected_matched_headers_received_id, + headers_received_rule_id); + } +} + } // namespace } // namespace extensions::declarative_net_request
diff --git a/extensions/browser/api/declarative_net_request/request_params.cc b/extensions/browser/api/declarative_net_request/request_params.cc index eeb430b6..94c87524 100644 --- a/extensions/browser/api/declarative_net_request/request_params.cc +++ b/extensions/browser/api/declarative_net_request/request_params.cc
@@ -184,11 +184,16 @@ parent_routing_id(info.parent_routing_id), embedder_conditions_matcher(base::BindRepeating(DoEmbedderConditionsMatch, info.frame_data.tab_id, - response_headers)), - // Allow/allowAllRequest rules matched in earlier rule matching stages can - // influence rule matches for later matching stages. Hence this - // information is needed from `info`. - allow_rule_max_priority(info.allow_rule_max_priority) { + response_headers)) { + // Allow/allowAllRequest rules matched in earlier rule matching stages can + // influence rule matches for later matching stages. Hence this information + // is needed from `info`. + for (auto& it : info.max_priority_allow_action) { + max_priority_allow_action.emplace( + it.first, it.second.has_value() ? std::make_optional(it.second->Clone()) + : std::nullopt); + } + is_third_party = IsThirdPartyRequest(*url, first_party_origin); }
diff --git a/extensions/browser/api/declarative_net_request/request_params.h b/extensions/browser/api/declarative_net_request/request_params.h index f3fc495..342013c0 100644 --- a/extensions/browser/api/declarative_net_request/request_params.h +++ b/extensions/browser/api/declarative_net_request/request_params.h
@@ -67,12 +67,15 @@ url_pattern_index::UrlPatternIndexMatcher::EmbedderConditionsMatcher embedder_conditions_matcher; - // A map from an extension ID to the priority of its CompositeMatcher's - // highest priority matching allow or allowAllRequests rule (for the request - // associated with this instance) if there is one, or std::nullopt otherwise. - // Used as a cache to prevent additional calls to GetAction. - mutable base::flat_map<ExtensionId, std::optional<uint64_t>> - allow_rule_max_priority; + // A map from an extension ID to its CompositeMatcher's highest priority + // matching allow or allowAllRequests rule (for the request associated with + // this instance). Used as a cache to prevent additional calls to GetAction. + // - If there is no entry for an extension ID: the extension's rulesets have + // not matched against this request yet. + // - If the entry for the extension ID is nullopt: the extension has no + // matching allow/allowAllRequest rules for this request. + mutable base::flat_map<ExtensionId, std::optional<RequestAction>> + max_priority_allow_action; // Lower cased url, used for regex matching. Cached for performance. mutable std::optional<std::string> lower_cased_url_spec;
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc index 2ceabcd..6316302f8 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc +++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -439,7 +439,7 @@ // Check that the allow rule priority cache from `request` is empty if the // request has not been evaluated yet in the kOnBeforeRequest stage. CHECK(stage != RulesetMatchingStage::kOnBeforeRequest || - request.allow_rule_max_priority.empty()); + request.max_priority_allow_action.empty()); const RequestParams params(request, response_headers); std::optional<RequestAction> action = @@ -462,7 +462,8 @@ // Pass the allow rule priority cache to `request` so its current value can be // reused in later rule matching stages. - request.allow_rule_max_priority = params.allow_rule_max_priority; + request.max_priority_allow_action = + std::move(params.max_priority_allow_action); if (!modify_headers_actions.empty()) return modify_headers_actions;
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc index 53c7c0a..fdd2ac5 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc +++ b/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc
@@ -270,6 +270,9 @@ // be matched here, similar to what's done in the webrequest event router for // OnBeforeRequest and OnHeadersReceived. if (navigation_handle->GetResponseHeaders()) { + // The allow rule cache from `params` does not need to be copied into + // `params_with_headers` since it won't have an effect on the final value of + // `frame_action`. RequestParams params_with_headers(host, navigation_handle->IsPost(), navigation_handle->GetResponseHeaders()); // Take the matching allowAllRequests action with the highest priority
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc index 424a00a..feba82a 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc +++ b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
@@ -48,13 +48,6 @@ using RulesetMatcherTest = ExtensionsTest; -RequestParams CreateRequestWithResponseHeaders( - const GURL& url, - const net::HttpResponseHeaders* headers) { - return RequestParams(url, url::Origin(), dnr_api::ResourceType::kSubFrame, - dnr_api::RequestMethod::kGet, -1, headers); -} - // Tests a simple blocking rule. TEST_F(RulesetMatcherTest, BlockingRule) { TestRule rule = CreateGenericRule();
diff --git a/extensions/browser/api/declarative_net_request/test_utils.cc b/extensions/browser/api/declarative_net_request/test_utils.cc index b2fbf10..9f322d0 100644 --- a/extensions/browser/api/declarative_net_request/test_utils.cc +++ b/extensions/browser/api/declarative_net_request/test_utils.cc
@@ -17,6 +17,7 @@ #include "extensions/browser/api/declarative_net_request/composite_matcher.h" #include "extensions/browser/api/declarative_net_request/file_backed_ruleset_source.h" #include "extensions/browser/api/declarative_net_request/indexed_rule.h" +#include "extensions/browser/api/declarative_net_request/request_params.h" #include "extensions/browser/api/declarative_net_request/rule_counts.h" #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h" #include "extensions/browser/api/declarative_net_request/ruleset_source.h" @@ -24,6 +25,7 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/common/api/declarative_net_request/test_utils.h" #include "extensions/common/extension.h" +#include "net/http/http_response_headers.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions::declarative_net_request { @@ -574,4 +576,11 @@ return {}; } +RequestParams CreateRequestWithResponseHeaders( + const GURL& url, + const net::HttpResponseHeaders* headers) { + return RequestParams(url, url::Origin(), dnr_api::ResourceType::kSubFrame, + dnr_api::RequestMethod::kGet, -1, headers); +} + } // namespace extensions::declarative_net_request
diff --git a/extensions/browser/api/declarative_net_request/test_utils.h b/extensions/browser/api/declarative_net_request/test_utils.h index d327722..c87365f 100644 --- a/extensions/browser/api/declarative_net_request/test_utils.h +++ b/extensions/browser/api/declarative_net_request/test_utils.h
@@ -28,6 +28,10 @@ class BrowserContext; } // namespace content +namespace net { +class HttpResponseHeaders; +} // namespace net + namespace extensions { class Extension; @@ -35,6 +39,7 @@ namespace declarative_net_request { class FileBackedRulesetSource; +struct RequestParams; class RulesetMatcher; struct RuleCounts; struct TestRule; @@ -160,6 +165,10 @@ const Extension& extension, const std::string& ruleset_id_string); +RequestParams CreateRequestWithResponseHeaders( + const GURL& url, + const net::HttpResponseHeaders* headers); + } // namespace declarative_net_request } // namespace extensions
diff --git a/extensions/browser/api/web_request/extension_web_request_event_router.cc b/extensions/browser/api/web_request/extension_web_request_event_router.cc index 6826cd2..498cf51 100644 --- a/extensions/browser/api/web_request/extension_web_request_event_router.cc +++ b/extensions/browser/api/web_request/extension_web_request_event_router.cc
@@ -374,6 +374,13 @@ action_tracker.OnRuleMatched(action, request); action.tracked = true; + + // If `action` is tracked and it may match an entry in + // `request.max_priority_allow_action`, the entry doesn't need to have its + // `tracked` updated. + // `request.ShouldRecordMatchedAllowRuleInOnHeadersReceived` will only record + // an allow rule matched in OnHeadersReceived with a greater priority than one + // matched in OnBeforeRequest. } using CallbacksForPageLoad = std::list<base::OnceClosure>;
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc index 589f57b..31ed35d 100644 --- a/extensions/browser/api/web_request/web_request_info.cc +++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -4,6 +4,7 @@ #include "extensions/browser/api/web_request/web_request_info.h" +#include <cstdint> #include <memory> #include <optional> #include <string> @@ -21,6 +22,7 @@ #include "extensions/browser/extension_navigation_ui_data.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" +#include "extensions/common/extension_id.h" #include "net/base/ip_endpoint.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_data_stream.h" @@ -274,8 +276,19 @@ std::erase_if( *dnr_actions, [this](const declarative_net_request::RequestAction& action) { - return action.index_priority < - allow_rule_max_priority[action.extension_id].value_or(0); + // Check that the cache contains the action's extension ID + // to make sure that rule matching was performed for that + // extension. + DCHECK( + base::Contains(max_priority_allow_action, action.extension_id)); + + uint64_t allow_rule_priority_for_extension = 0u; + if (auto& allow_action = + max_priority_allow_action.at(action.extension_id)) { + allow_rule_priority_for_extension = allow_action->index_priority; + } + + return action.index_priority < allow_rule_priority_for_extension; }); } }
diff --git a/extensions/browser/api/web_request/web_request_info.h b/extensions/browser/api/web_request/web_request_info.h index dc2e9d56..6ba891e 100644 --- a/extensions/browser/api/web_request/web_request_info.h +++ b/extensions/browser/api/web_request/web_request_info.h
@@ -12,6 +12,7 @@ #include <string> #include <vector> +#include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" #include "base/values.h" #include "content/public/browser/global_routing_id.h" @@ -188,11 +189,12 @@ dnr_actions; // A map from an extension ID to the highest priority matching allow or - // allowAllRequests rule's priority for this request. This is set from the - // same field as what's in declarative_net_request::RequestParams so it can be - // used between different request stages where DNR rules will be matched. - mutable base::flat_map<ExtensionId, std::optional<uint64_t>> - allow_rule_max_priority; + // allowAllRequests rule for this request. This is set from the same field as + // what's in declarative_net_request::RequestParams so it can be used between + // different request stages where DNR rules will be matched. + mutable base::flat_map<ExtensionId, + std::optional<declarative_net_request::RequestAction>> + max_priority_allow_action; const bool is_service_worker_script;
diff --git a/extensions/common/api/automation.idl b/extensions/common/api/automation.idl index f6bbaf2..ebfee95 100644 --- a/extensions/common/api/automation.idl +++ b/extensions/common/api/automation.idl
@@ -946,6 +946,9 @@ // an <code><input> element. DOMString? value; + // The HTML id for this element, if this node is an HTML element. + DOMString? htmlId; + // The HTML tag for this element, if this node is an HTML element. DOMString? htmlTag;
diff --git a/extensions/renderer/resources/automation/automation_node.js b/extensions/renderer/resources/automation/automation_node.js index 1c444bc..fca94e3 100644 --- a/extensions/renderer/resources/automation/automation_node.js +++ b/extensions/renderer/resources/automation/automation_node.js
@@ -1493,6 +1493,7 @@ 'display', 'doDefaultLabel', 'fontFamily', + 'htmlId', 'htmlTag', 'imageDataUrl', 'innerHtml',
diff --git a/gpu/command_buffer/common/mailbox.cc b/gpu/command_buffer/common/mailbox.cc index ecc3778..0308de4 100644 --- a/gpu/command_buffer/common/mailbox.cc +++ b/gpu/command_buffer/common/mailbox.cc
@@ -64,10 +64,6 @@ memcpy(name, n, sizeof(name)); } -Mailbox Mailbox::GenerateForSharedImage() { - return Generate(); -} - Mailbox Mailbox::Generate() { return GenerateMailbox(); }
diff --git a/gpu/command_buffer/common/mailbox.h b/gpu/command_buffer/common/mailbox.h index 7ab49ec..9cb3bb3d 100644 --- a/gpu/command_buffer/common/mailbox.h +++ b/gpu/command_buffer/common/mailbox.h
@@ -50,11 +50,6 @@ // Generate a unique unguessable mailbox name. static Mailbox Generate(); - // Generate a unique unguessable mailbox name. - // TODO(crbug.com/337538024): Remove this method once all callers have been - // ported. - static Mailbox GenerateForSharedImage(); - // Verify that the mailbox was created through Mailbox::Generate. This only // works in Debug (always returns true in Release). This is not a secure // check, only to catch bugs where clients forgot to call Mailbox::Generate.
diff --git a/infra/config/generated/builders/ci/win11-arm64-rel-tests/properties.json b/infra/config/generated/builders/ci/win11-arm64-rel-tests/properties.json index f1ae75f..2ad4cd6 100644 --- a/infra/config/generated/builders/ci/win11-arm64-rel-tests/properties.json +++ b/infra/config/generated/builders/ci/win11-arm64-rel-tests/properties.json
@@ -91,8 +91,5 @@ ] }, "builder_group": "chromium.win", - "recipe": "chromium", - "sheriff_rotations": [ - "chromium" - ] + "recipe": "chromium" } \ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux-webkit-msan-rel/gn-args.json b/infra/config/generated/builders/try/linux-webkit-msan-rel/gn-args.json index 98409534..385d8a0 100644 --- a/infra/config/generated/builders/try/linux-webkit-msan-rel/gn-args.json +++ b/infra/config/generated/builders/try/linux-webkit-msan-rel/gn-args.json
@@ -1,10 +1,12 @@ { "gn_args": { "dcheck_always_on": false, + "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, "is_msan": true, "msan_track_origins": 2, + "proprietary_codecs": true, "use_remoteexec": true, "use_siso": true }
diff --git a/infra/config/generated/cq-usage/mega_cq_bots.txt b/infra/config/generated/cq-usage/mega_cq_bots.txt index 1301231..e921dcf 100644 --- a/infra/config/generated/cq-usage/mega_cq_bots.txt +++ b/infra/config/generated/cq-usage/mega_cq_bots.txt
@@ -151,7 +151,6 @@ chromium/try/mac_chromium_compile_rel_ng chromium/try/network_service_linux chromium/try/win-arm64-compile-dbg -chromium/try/win-arm64-rel chromium/try/win-asan chromium/try/win-asan-media-rel chromium/try/win-asan-rel
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index d5b4795..4ea92fdd 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -5566,10 +5566,8 @@ projects { name: "chromium/src" ref_regexp: "refs/branch-heads/.*" - ref_regexp_exclude: "refs/branch-heads/5735" ref_regexp_exclude: "refs/branch-heads/5993" ref_regexp_exclude: "refs/branch-heads/6099" - ref_regexp_exclude: "refs/branch-heads/6261" ref_regexp_exclude: "refs/branch-heads/6312" ref_regexp_exclude: "refs/branch-heads/6367" ref_regexp_exclude: "refs/branch-heads/6422"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 9c61f97..e9a0d564 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -59138,10 +59138,7 @@ ' },' ' "builder_group": "chromium.win",' ' "led_builder_is_bootstrapped": true,' - ' "recipe": "chromium",' - ' "sheriff_rotations": [' - ' "chromium"' - ' ]' + ' "recipe": "chromium"' '}' execution_timeout_secs: 10800 build_numbers: YES
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index b0cf95d..2d7f288 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -297,10 +297,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -309,10 +305,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -1284,10 +1276,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -1296,10 +1284,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -2029,10 +2013,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -2041,10 +2021,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -2547,10 +2523,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -2559,10 +2531,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -2916,10 +2884,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -2928,10 +2892,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -3604,10 +3564,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -3616,10 +3572,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -3968,10 +3920,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -3980,10 +3928,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -4402,10 +4346,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -4414,10 +4354,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -4762,10 +4698,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -4774,10 +4706,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -5400,10 +5328,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -5412,10 +5336,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -5823,10 +5743,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -5835,10 +5751,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -6247,10 +6159,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -6259,10 +6167,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -6722,10 +6626,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -6734,10 +6634,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -7205,10 +7101,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -7217,10 +7109,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -7804,10 +7692,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -7816,10 +7700,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -8418,10 +8298,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -8430,10 +8306,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -8799,10 +8671,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -8811,10 +8679,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -9307,10 +9171,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -9319,10 +9179,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -9984,10 +9840,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -9996,10 +9848,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -10393,10 +10241,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -10405,10 +10249,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -11109,10 +10949,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -11121,10 +10957,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -11502,10 +11334,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -11514,10 +11342,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -11925,10 +11749,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -11937,10 +11757,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -12379,10 +12195,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -12391,10 +12203,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -12838,10 +12646,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -12850,10 +12654,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -13207,10 +13007,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -13219,10 +13015,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -13726,10 +13518,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -13738,10 +13526,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -14116,10 +13900,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -14128,10 +13908,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -14510,10 +14286,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -14522,10 +14294,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -15039,10 +14807,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -15051,10 +14815,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -15428,10 +15188,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -15440,10 +15196,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -15858,10 +15610,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -15870,10 +15618,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" } @@ -16277,10 +16021,6 @@ links { name: "Branch Consoles" links { - text: "m114" - url: "/p/chromium-m114/g/main/console" - } - links { text: "m118" url: "/p/chromium-m118/g/main/console" } @@ -16289,10 +16029,6 @@ url: "/p/chromium-m120/g/main/console" } links { - text: "m122" - url: "/p/chromium-m122/g/main/console" - } - links { text: "m123" url: "/p/chromium-m123/g/main/console" }
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg index 78166a7..ebe0dc97 100644 --- a/infra/config/generated/luci/realms.cfg +++ b/infra/config/generated/luci/realms.cfg
@@ -493,10 +493,8 @@ bindings { role: "role/swarming.poolUser" principals: "group:mdb/chrome-build-access-sphinx" - principals: "project:chromium-m114" principals: "project:chromium-m118" principals: "project:chromium-m120" - principals: "project:chromium-m122" principals: "project:chromium-m123" principals: "project:chromium-m124" principals: "project:chromium-m125" @@ -548,10 +546,8 @@ role: "role/swarming.poolUser" principals: "group:chromium-led-users" principals: "group:mdb/chrome-build-access-sphinx" - principals: "project:chromium-m114" principals: "project:chromium-m118" principals: "project:chromium-m120" - principals: "project:chromium-m122" principals: "project:chromium-m123" principals: "project:chromium-m124" principals: "project:chromium-m125"
diff --git a/infra/config/generated/sheriff-rotations/chromium.txt b/infra/config/generated/sheriff-rotations/chromium.txt index 6e850d3..c8e2663a 100644 --- a/infra/config/generated/sheriff-rotations/chromium.txt +++ b/infra/config/generated/sheriff-rotations/chromium.txt
@@ -127,6 +127,5 @@ ci/win-asan ci/win-official ci/win-presubmit -ci/win11-arm64-rel-tests ci/win32-archive-rel ci/win32-official
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl index a76c629e..d0a45b73 100644 --- a/infra/config/generated/testing/variants.pyl +++ b/infra/config/generated/testing/variants.pyl
@@ -267,16 +267,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'identifier': 'Lacros version skew testing ash canary', - 'description': 'Run with ash-chrome version 127.0.6494.0', + 'description': 'Run with ash-chrome version 127.0.6496.0', 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome', ], 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v127.0.6494.0', - 'revision': 'version:127.0.6494.0', + 'location': 'lacros_version_skew_tests_v127.0.6496.0', + 'revision': 'version:127.0.6496.0', }, ], },
diff --git a/infra/config/milestones.json b/infra/config/milestones.json index 767cfb50..a89b634 100644 --- a/infra/config/milestones.json +++ b/infra/config/milestones.json
@@ -1,9 +1,4 @@ { - "114": { - "name": "m114", - "project": "chromium-m114", - "ref": "refs/branch-heads/5735" - }, "118": { "name": "m118", "project": "chromium-m118", @@ -14,11 +9,6 @@ "project": "chromium-m120", "ref": "refs/branch-heads/6099" }, - "122": { - "name": "m122", - "project": "chromium-m122", - "ref": "refs/branch-heads/6261" - }, "123": { "name": "m123", "project": "chromium-m123",
diff --git a/infra/config/subprojects/chromium/ci/chromium.win.star b/infra/config/subprojects/chromium/ci/chromium.win.star index f045ae2..75bd470d 100644 --- a/infra/config/subprojects/chromium/ci/chromium.win.star +++ b/infra/config/subprojects/chromium/ci/chromium.win.star
@@ -386,6 +386,8 @@ ), build_gs_bucket = "chromium-win-archive", ), + # TODO(https://crbug.com/341773363): Bots were quarantined. + sheriff_rotations = args.ignore_default(None), tree_closing = False, console_view_entry = consoles.console_view_entry( category = "release|tester",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star index 963ae90..4653a83 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -478,13 +478,7 @@ mirrors = [ "ci/WebKit Linux MSAN", ], - gn_args = gn_args.config( - configs = [ - "msan", - "release_builder", - "reclient", - ], - ), + gn_args = "ci/WebKit Linux MSAN", # At this time, MSan is only compatibly with Focal. See # //docs/linux/instrumented_libraries.md. os = os.LINUX_FOCAL,
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json index c67338d..c1127b27 100644 --- a/infra/config/targets/lacros-version-skew-variants.json +++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@ { "LACROS_VERSION_SKEW_CANARY": { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "identifier": "Lacros version skew testing ash canary", "swarming": { "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ] }
diff --git a/internal b/internal index c414ca3..af84be9 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit c414ca3036a61b56b801b7e36e55100d04210410 +Subproject commit af84be9cfd1e15eeb537bf247d1929aedbb5f222
diff --git a/ios/chrome/app/feed_app_agent.mm b/ios/chrome/app/feed_app_agent.mm index bd7e33d..70b69d0 100644 --- a/ios/chrome/app/feed_app_agent.mm +++ b/ios/chrome/app/feed_app_agent.mm
@@ -83,7 +83,7 @@ } BOOL isContentNotificationProvisionalEnabled = NO; - if (IsContentNotificationExperimentEnalbed()) { + if (IsContentNotificationExperimentEnabled()) { // Only start doing the content notificaiton user eligibiliey check when // content notification experiment is enabled. AuthenticationService* authService =
diff --git a/ios/chrome/app/main_application_delegate.mm b/ios/chrome/app/main_application_delegate.mm index 579a284..b8d522b 100644 --- a/ios/chrome/app/main_application_delegate.mm +++ b/ios/chrome/app/main_application_delegate.mm
@@ -488,7 +488,7 @@ // `YES` if Content notification is enabled or registered. Called before // register device With APNS. - (BOOL)isContentNotificationAvailable { - if (!IsContentNotificationExperimentEnalbed()) { + if (!IsContentNotificationExperimentEnabled()) { return false; }
diff --git a/ios/chrome/browser/content_notification/model/content_notification_util.mm b/ios/chrome/browser/content_notification/model/content_notification_util.mm index 56c4acc..480a57b 100644 --- a/ios/chrome/browser/content_notification/model/content_notification_util.mm +++ b/ios/chrome/browser/content_notification/model/content_notification_util.mm
@@ -165,7 +165,7 @@ return false; } - if (!IsContentNotificationExperimentEnalbed()) { + if (!IsContentNotificationExperimentEnabled()) { return false; }
diff --git a/ios/chrome/browser/push_notification/model/BUILD.gn b/ios/chrome/browser/push_notification/model/BUILD.gn index dbd80ce..33671d61 100644 --- a/ios/chrome/browser/push_notification/model/BUILD.gn +++ b/ios/chrome/browser/push_notification/model/BUILD.gn
@@ -77,7 +77,9 @@ "//ios/chrome/browser/content_notification/model:content_notification_service_factory", "//ios/chrome/browser/content_notification/model:util", "//ios/chrome/browser/search_engines/model:template_url_service_factory", + "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/model/application_context", + "//ios/chrome/browser/shared/model/browser", "//ios/chrome/browser/shared/model/browser_state", "//ios/chrome/browser/shared/model/prefs:pref_names", "//ios/chrome/browser/shared/public/features:features",
diff --git a/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm b/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm index be5a23c8..912f4a3 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm +++ b/ios/chrome/browser/push_notification/model/push_notification_client_manager.mm
@@ -28,7 +28,7 @@ AddPushNotificationClient(std::make_unique<TipsNotificationClient>()); } - if (IsContentNotificationExperimentEnalbed()) { + if (IsContentNotificationExperimentEnabled()) { AddPushNotificationClient(std::make_unique<ContentNotificationClient>()); } } @@ -98,7 +98,7 @@ PushNotificationClientManager::GetClients() { std::vector<PushNotificationClientId> client_ids = { PushNotificationClientId::kCommerce}; - if (IsContentNotificationExperimentEnalbed()) { + if (IsContentNotificationExperimentEnabled()) { client_ids.push_back(PushNotificationClientId::kContent); client_ids.push_back(PushNotificationClientId::kSports); }
diff --git a/ios/chrome/browser/push_notification/model/push_notification_delegate.mm b/ios/chrome/browser/push_notification/model/push_notification_delegate.mm index f694aa8..27caeb5 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_delegate.mm +++ b/ios/chrome/browser/push_notification/model/push_notification_delegate.mm
@@ -28,7 +28,11 @@ #import "ios/chrome/browser/push_notification/model/push_notification_service.h" #import "ios/chrome/browser/push_notification/model/push_notification_util.h" #import "ios/chrome/browser/search_engines/model/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" +#import "ios/chrome/browser/shared/model/browser/browser.h" +#import "ios/chrome/browser/shared/model/browser/browser_provider.h" +#import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h" #import "ios/chrome/browser/shared/model/browser_state/browser_state_info_cache.h" #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state_manager.h" @@ -243,13 +247,9 @@ ->GetPushNotificationClientManager(); DCHECK(clientManager); clientManager->OnSceneActiveForegroundBrowserReady(); - // TODO(crbug.com/339102426): Cleanup browserStates. - // TODO(crbug.com/341906612) Remove use of - // GetLastUsedBrowserStateDeprecatedDoNotUse. ChromeBrowserState* browserState = - GetApplicationContext() - ->GetChromeBrowserStateManager() - ->GetLastUsedBrowserStateDeprecatedDoNotUse(); + sceneState.browserProviderInterface.mainBrowserProvider.browser + ->GetBrowserState(); if ([self isContentNotificationAvailable:browserState]) { // Send an NAU every time the OS authorization status changes. [PushNotificationUtil @@ -286,7 +286,7 @@ } - (BOOL)isContentNotificationAvailable:(ChromeBrowserState*)browserState { - if (!IsContentNotificationExperimentEnalbed()) { + if (!IsContentNotificationExperimentEnabled()) { return false; } if (!browserState) {
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h index 258057d..131450b6 100644 --- a/ios/chrome/browser/shared/public/features/features.h +++ b/ios/chrome/browser/shared/public/features/features.h
@@ -491,7 +491,7 @@ bool IsFollowUIUpdateEnabled(); // YES if content push notification experiments are enabled. -bool IsContentNotificationExperimentEnalbed(); +bool IsContentNotificationExperimentEnabled(); // YES when any of the content push notification variations are enabled. bool IsContentPushNotificationsEnabled();
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm index 055ba2f..3a7363c 100644 --- a/ios/chrome/browser/shared/public/features/features.mm +++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -388,7 +388,7 @@ "ContentNotificationExperiment", base::FEATURE_DISABLED_BY_DEFAULT); -bool IsContentNotificationExperimentEnalbed() { +bool IsContentNotificationExperimentEnabled() { return base::FeatureList::IsEnabled(kContentNotificationExperiment); }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm index 1df4975..e200d6bc 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller_egtest.mm
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" +#import "components/autofill/core/browser/autofill_test_utils.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/ui/autofill/autofill_app_interface.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_constants.h" @@ -31,8 +33,11 @@ namespace { -constexpr char kFormElementName[] = "name"; +constexpr char kFormElementAddress[] = "address"; constexpr char kFormElementCity[] = "city"; +constexpr char kFormElementName[] = "name"; +constexpr char kFormElementState[] = "state"; +constexpr char kFormElementZip[] = "zip"; constexpr char kFormHTMLFile[] = "/profile_form.html"; @@ -396,11 +401,60 @@ [[EarlGrey selectElementWithMatcher:ManualFallbackProfilesTableViewMatcher()] performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)]; + // Tap the "Autofill Form" button. [[EarlGrey selectElementWithMatcher:AutofillFormButton()] - assertWithMatcher:grey_sufficientlyVisible()]; + performAction:grey_tap()]; - // TODO(crbug.com/326413487): Perform tap on the button and assert that the - // form was filled. + // Verify that the page is filled properly. + [self verifyAddressInfoHasBeenFilled:autofill::test::GetFullProfile()]; +} + +#pragma mark - Private + +// Verify that the address info has been filled. +- (void)verifyAddressInfoHasBeenFilled:(autofill::AutofillProfile)profile { + std::string locale = l10n_util::GetLocaleOverride(); + + // Full name. + NSString* name = + base::SysUTF16ToNSString(profile.GetInfo(autofill::NAME_FULL, locale)); + NSString* nameCondition = [NSString + stringWithFormat:@"window.document.getElementById('%s').value === '%@'", + kFormElementName, name]; + + // Address. + NSString* address = base::SysUTF16ToNSString( + profile.GetInfo(autofill::ADDRESS_HOME_LINE1, locale)); + NSString* addressCondition = [NSString + stringWithFormat:@"window.document.getElementById('%s').value === '%@'", + kFormElementAddress, address]; + + // City. + NSString* city = base::SysUTF16ToNSString( + profile.GetInfo(autofill::ADDRESS_HOME_CITY, locale)); + NSString* cityCondition = [NSString + stringWithFormat:@"window.document.getElementById('%s').value === '%@'", + kFormElementCity, city]; + + // State. + NSString* state = base::SysUTF16ToNSString( + profile.GetInfo(autofill::ADDRESS_HOME_STATE, locale)); + NSString* stateCondition = [NSString + stringWithFormat:@"window.document.getElementById('%s').value === '%@'", + kFormElementState, state]; + + // Zip code. + NSString* zip = base::SysUTF16ToNSString( + profile.GetInfo(autofill::ADDRESS_HOME_ZIP, locale)); + NSString* zipCondition = [NSString + stringWithFormat:@"window.document.getElementById('%s').value === '%@'", + kFormElementZip, zip]; + + NSString* condition = + [NSString stringWithFormat:@"%@ && %@ && %@ && %@ && %@", nameCondition, + addressCondition, cityCondition, + stateCondition, zipCondition]; + [ChromeEarlGrey waitForJavaScriptCondition:condition]; } @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address+AutofillProfile.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address+AutofillProfile.mm index 3414aa9..cb278c4 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address+AutofillProfile.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address+AutofillProfile.mm
@@ -26,6 +26,7 @@ @implementation ManualFillAddress (AutofillProfile) - (instancetype)initWithProfile:(const autofill::AutofillProfile&)profile { + NSString* GUID = base::SysUTF16ToNSString(base::ASCIIToUTF16(profile.guid())); NSString* firstName = FieldValueOfTypeOnProfile(profile, autofill::NAME_FIRST); NSString* middleNameOrInitial = @@ -54,18 +55,19 @@ NSString* emailAddress = FieldValueOfTypeOnProfile(profile, autofill::EMAIL_ADDRESS); - return [self initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + return [self initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; } + (NSArray<ManualFillAddress*>*)manualFillAddressesFromProfiles:
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.h index be4b869..f46e0f1 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.h
@@ -10,6 +10,9 @@ // This represents an address to use with manual fill. @interface ManualFillAddress : NSObject +// The address' GUID. +@property(nonatomic, readonly) NSString* GUID; + // The addressee's first name. @property(nonatomic, readonly) NSString* firstName; @@ -47,19 +50,19 @@ @property(nonatomic, readonly) NSString* emailAddress; // Default init. -- (instancetype)initWithFirstName:(NSString*)firstName - middleNameOrInitial:(NSString*)middleNameOrInitial - lastName:(NSString*)lastName - company:(NSString*)company - line1:(NSString*)line1 - line2:(NSString*)line2 - zip:(NSString*)zip - city:(NSString*)city - state:(NSString*)state - country:(NSString*)country - phoneNumber:(NSString*)phoneNumber - emailAddress:(NSString*)emailAddress - NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithGUID:(NSString*)GUID + firstName:(NSString*)firstName + middleNameOrInitial:(NSString*)middleNameOrInitial + lastName:(NSString*)lastName + company:(NSString*)company + line1:(NSString*)line1 + line2:(NSString*)line2 + zip:(NSString*)zip + city:(NSString*)city + state:(NSString*)state + country:(NSString*)country + phoneNumber:(NSString*)phoneNumber + emailAddress:(NSString*)emailAddress NS_DESIGNATED_INITIALIZER; // Unavailable. Please use `initWithFirstName:middleNameOrInitial:lastName: // line1:line2:zip:city:state:country:`.
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.mm index fea9b07..db569b1 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address.mm
@@ -6,20 +6,22 @@ @implementation ManualFillAddress -- (instancetype)initWithFirstName:(NSString*)firstName - middleNameOrInitial:(NSString*)middleNameOrInitial - lastName:(NSString*)lastName - company:(NSString*)company - line1:(NSString*)line1 - line2:(NSString*)line2 - zip:(NSString*)zip - city:(NSString*)city - state:(NSString*)state - country:(NSString*)country - phoneNumber:(NSString*)phoneNumber - emailAddress:(NSString*)emailAddress { +- (instancetype)initWithGUID:(NSString*)GUID + firstName:(NSString*)firstName + middleNameOrInitial:(NSString*)middleNameOrInitial + lastName:(NSString*)lastName + company:(NSString*)company + line1:(NSString*)line1 + line2:(NSString*)line2 + zip:(NSString*)zip + city:(NSString*)city + state:(NSString*)state + country:(NSString*)country + phoneNumber:(NSString*)phoneNumber + emailAddress:(NSString*)emailAddress { self = [super init]; if (self) { + _GUID = GUID; _firstName = [firstName copy]; _middleNameOrInitial = [middleNameOrInitial copy]; _lastName = [lastName copy]; @@ -47,6 +49,9 @@ return NO; } ManualFillAddress* otherObject = (ManualFillAddress*)object; + if (![otherObject.GUID isEqualToString:self.GUID]) { + return NO; + } if (![otherObject.firstName isEqualToString:self.firstName]) { return NO; } @@ -88,23 +93,25 @@ } - (NSUInteger)hash { - return [self.firstName hash] ^ [self.middleNameOrInitial hash] ^ - [self.lastName hash] ^ [self.company hash] ^ [self.line1 hash] ^ - [self.line2 hash] ^ [self.zip hash] ^ [self.city hash] ^ - [self.state hash] ^ [self.country hash] ^ [self.phoneNumber hash] ^ + return [self.GUID hash] ^ [self.firstName hash] ^ + [self.middleNameOrInitial hash] ^ [self.lastName hash] ^ + [self.company hash] ^ [self.line1 hash] ^ [self.line2 hash] ^ + [self.zip hash] ^ [self.city hash] ^ [self.state hash] ^ + [self.country hash] ^ [self.phoneNumber hash] ^ [self.emailAddress hash]; } - (NSString*)description { return [NSString - stringWithFormat:@"<%@ (%p): firstName: %@, middleNameOrInitial: %@, " - @"lastName: %@, company: %@, line1: %@, " - @"line2: %@, zip: %@, city: %@, state: %@, country: %@, " - @"phoneNumber: %@, emailAddress: %@>", - NSStringFromClass([self class]), self, self.firstName, - self.middleNameOrInitial, self.lastName, self.company, - self.line1, self.line2, self.zip, self.city, self.state, - self.country, self.phoneNumber, self.emailAddress]; + stringWithFormat: + @"<%@ (%p): GUID: %@, firstName: %@, middleNameOrInitial: %@, " + @"lastName: %@, company: %@, line1: %@, " + @"line2: %@, zip: %@, city: %@, state: %@, country: %@, " + @"phoneNumber: %@, emailAddress: %@>", + NSStringFromClass([self class]), self, self.GUID, self.firstName, + self.middleNameOrInitial, self.lastName, self.company, self.line1, + self.line2, self.zip, self.city, self.state, self.country, + self.phoneNumber, self.emailAddress]; } @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.mm index 0794d773..e3eaafe 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.mm
@@ -5,12 +5,16 @@ #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_cell.h" #import "base/metrics/user_metrics.h" +#import "base/strings/sys_string_conversions.h" +#import "components/autofill/ios/browser/form_suggestion.h" +#import "components/strings/grit/components_strings.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/list_model/list_model.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_cell_utils.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_content_injector.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" +#import "ui/base/l10n/l10n_util.h" @interface ManualFillAddressItem () @@ -100,6 +104,9 @@ // Button to autofill the current form with the address' data. @property(nonatomic, strong) UIButton* autofillFormButton; +// The address data for this cell. +@property(nonatomic, weak) ManualFillAddress* address; + @end @implementation ManualFillAddressCell @@ -125,6 +132,7 @@ [self.phoneNumberButton setTitle:@"" forState:UIControlStateNormal]; [self.emailAddressButton setTitle:@"" forState:UIControlStateNormal]; self.contentInjector = nil; + self.address = nil; } - (void)setUpWithAddress:(ManualFillAddress*)address @@ -133,6 +141,7 @@ [self createViewHierarchy]; } self.contentInjector = contentInjector; + self.address = address; // Holds the views whose leading anchor is constrained relative to the cell's // leading anchor. @@ -459,6 +468,9 @@ if (IsKeyboardAccessoryUpgradeEnabled()) { self.autofillFormButton = CreateAutofillFormButton(); [self.contentView addSubview:self.autofillFormButton]; + [self.autofillFormButton addTarget:self + action:@selector(onAutofillFormButtonTapped) + forControlEvents:UIControlEventTouchUpInside]; AppendHorizontalConstraintsForViews( staticConstraints, @[ self.autofillFormButton ], self.layoutGuide); } @@ -505,4 +517,22 @@ requiresHTTPS:NO]; } +// Called when the "Autofill Form" button is tapped. Fills the current form with +// the address' data. +- (void)onAutofillFormButtonTapped { + FormSuggestion* suggestion = [FormSuggestion + suggestionWithValue:nil + minorValue:nil + displayDescription:nil + icon:nil + popupItemId:autofill::SuggestionType::kAddressEntry + backendIdentifier:[self.address GUID] + requiresReauth:NO + acceptanceA11yAnnouncement: + base::SysUTF16ToNSString(l10n_util::GetStringUTF16( + IDS_AUTOFILL_A11Y_ANNOUNCE_FILLED_FORM))]; + + [self.contentInjector autofillFormWithSuggestion:suggestion]; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_unittest.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_unittest.mm index 1ddd8966..533c459 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_unittest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_address_unittest.mm
@@ -10,6 +10,7 @@ // Tests that a credential is correctly created. TEST_F(ManualFillAddressiOSTest, Creation) { + NSString* GUID = @"1234-5678-abcd"; NSString* firstName = @"First"; NSString* middleNameOrInitial = @"M"; NSString* lastName = @"Last"; @@ -23,19 +24,21 @@ NSString* phoneNumber = @"123-456-789"; NSString* emailAddress = @"john@doe"; ManualFillAddress* address = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_TRUE(address); + EXPECT_TRUE([GUID isEqualToString:address.GUID]); EXPECT_TRUE([firstName isEqualToString:address.firstName]); EXPECT_TRUE( [middleNameOrInitial isEqualToString:address.middleNameOrInitial]); @@ -53,6 +56,7 @@ // Test equality between addresses (lexicographically). TEST_F(ManualFillAddressiOSTest, Equality) { + NSString* GUID = @"1234-5678-abcd"; NSString* firstName = @"First"; NSString* middleNameOrInitial = @"M"; NSString* lastName = @"Last"; @@ -66,211 +70,241 @@ NSString* phoneNumber = @"123-456-789"; NSString* emailAddress = @"john@doe"; ManualFillAddress* address = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; ManualFillAddress* equalAddress = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_TRUE([address isEqual:equalAddress]); + ManualFillAddress* differentAddressGUID = + [[ManualFillAddress alloc] initWithGUID:@"1234-5678-wxyz" + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; + EXPECT_FALSE([address isEqual:differentAddressGUID]); + ManualFillAddress* differentAddressFirstName = - [[ManualFillAddress alloc] initWithFirstName:@"Bilbo" - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:@"Bilbo" + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressFirstName]); ManualFillAddress* differentAddressMiddleNameOrInitial = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:@"R" - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:@"R" + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressMiddleNameOrInitial]); ManualFillAddress* differentAddressLastName = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:@"Hobbit" - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:@"Hobbit" + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressLastName]); ManualFillAddress* differentAddressCompany = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:@"Tokien" - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:@"Tokien" + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressCompany]); ManualFillAddress* differentAddressLine1 = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:@"A House" - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:@"A House" + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressLine1]); ManualFillAddress* differentAddressLine2 = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:@"" - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:@"" + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressLine2]); ManualFillAddress* differentAddressZip = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:@"1937" - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:@"1937" + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressZip]); ManualFillAddress* differentAddressCity = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:@"Shire" - state:state - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:@"Shire" + state:state + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressCity]); ManualFillAddress* differentAddressState = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:@"Eriador" - country:country - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:@"Eriador" + country:country + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressState]); ManualFillAddress* differentAddressCountry = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:@"Arnor" - phoneNumber:phoneNumber - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:@"Arnor" + phoneNumber:phoneNumber + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentAddressCountry]); ManualFillAddress* differentPhoneNumber = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:@"999-999-999" - emailAddress:emailAddress]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:@"999-999-999" + emailAddress:emailAddress]; EXPECT_FALSE([address isEqual:differentPhoneNumber]); ManualFillAddress* differentEmailAddress = - [[ManualFillAddress alloc] initWithFirstName:firstName - middleNameOrInitial:middleNameOrInitial - lastName:lastName - company:company - line1:line1 - line2:line2 - zip:zip - city:city - state:state - country:country - phoneNumber:phoneNumber - emailAddress:@"jane@doe"]; + [[ManualFillAddress alloc] initWithGUID:GUID + firstName:firstName + middleNameOrInitial:middleNameOrInitial + lastName:lastName + company:company + line1:line1 + line2:line2 + zip:zip + city:city + state:state + country:country + phoneNumber:phoneNumber + emailAddress:@"jane@doe"]; EXPECT_FALSE([address isEqual:differentEmailAddress]); }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.mm index e97b149..2f4167a 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_card_cell.mm
@@ -587,8 +587,8 @@ } } -// Called the "Autofill Form" button is tapped. Fills the current form with the -// card's data. +// Called when the "Autofill Form" button is tapped. Fills the current form with +// the card's data. - (void)onAutofillFormButtonTapped { autofill::SuggestionType popupItemId = autofill::VirtualCardFeatureEnabled() &&
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm index cabe860c..38f1f6c 100644 --- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm
@@ -169,7 +169,7 @@ [_sceneState addObserver:self]; BOOL isContentNotificationEnabled = - IsContentNotificationExperimentEnalbed() && + IsContentNotificationExperimentEnabled() && IsContentNotificationSetUpListEnabled( identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin), self.isDefaultSearchEngine, prefService);
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm index a71c4f7..2d78b87 100644 --- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm +++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -46,8 +46,12 @@ const CGFloat kContainerStackVerticalPadding = 18.0; const CGFloat kContainerStackHorizontalPadding = 15.0; +// Labels stack constants. +const CGFloat kLabelsStackViewVerticalSpacing = 2.0; + // Icon constants. const CGFloat kIconCornerRadius = 5.0; +const CGFloat kCustomSpacingAfterIcon = 14.0; // Favicon constants. const CGFloat kFaviconShadowRadius = 3.0; @@ -191,6 +195,7 @@ labelsStackView.layoutMarginsRelativeArrangement = YES; labelsStackView.directionalLayoutMargins = NSDirectionalEdgeInsetsMake( kContainerStackVerticalPadding, 0, kContainerStackVerticalPadding, 0); + labelsStackView.spacing = kLabelsStackViewVerticalSpacing; labelsStackView.accessibilityIdentifier = kInfobarBannerLabelsStackViewIdentifier; labelsStackView.isAccessibilityElement = YES; @@ -233,6 +238,8 @@ // Check if it should have an icon. if (iconContainerView) { [containerStack addArrangedSubview:iconContainerView]; + [containerStack setCustomSpacing:kCustomSpacingAfterIcon + afterView:iconContainerView]; } // Add labels. [containerStack addArrangedSubview:labelsStackView];
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm index 83f0c38..8262c2a 100644 --- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm
@@ -219,10 +219,12 @@ "ContentNotifications.Promo.TopOfFeed.Permission.Declined")); [self logHistogramForAction:ContentNotificationTopOfFeedPromoAction:: kDecline]; + [self.feedTopSectionMediator updateFeedTopSectionWhenClosed]; break; case NotificationsOptInAlertResult::kCanceled: [self logHistogramForEvent:ContentNotificationTopOfFeedPromoEvent:: kCanceled]; + [self.feedTopSectionMediator updateFeedTopSectionWhenClosed]; break; case NotificationsOptInAlertResult::kError: [self @@ -231,12 +233,14 @@ case NotificationsOptInAlertResult::kOpenedSettings: [self logHistogramForEvent:ContentNotificationTopOfFeedPromoEvent:: kNotifActive]; + [self.feedTopSectionMediator updateFeedTopSectionWhenClosed]; break; case NotificationsOptInAlertResult::kPermissionGranted: RecordAction(UserMetricsAction( "ContentNotifications.Promo.TopOfFeed.Permission.Accepted")); [self logHistogramForAction:ContentNotificationTopOfFeedPromoAction:: kAccept]; + [self.feedTopSectionMediator updateFeedTopSectionWhenClosed]; break; } }
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h index df36b98b..9a401ec 100644 --- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h +++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h
@@ -70,6 +70,9 @@ // Cleans the mediator. - (void)shutdown; +// Used from the coordinator to respond to the OS prompt outcome. +- (void)updateFeedTopSectionWhenClosed; + @end #endif // IOS_CHROME_BROWSER_UI_NTP_FEED_TOP_SECTION_FEED_TOP_SECTION_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm index 9ea2ae81..e29bd77 100644 --- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm +++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm
@@ -92,6 +92,14 @@ self.prefService = nullptr; } +// Handles closing the promo, and the NTP and Feed Top Section layout when the +// promo is closed. +- (void)updateFeedTopSectionWhenClosed { + [self.NTPDelegate handleFeedTopSectionClosed]; + [self.consumer hidePromo]; + [self.NTPDelegate updateFeedLayout]; +} + #pragma mark - FeedTopSectionViewControllerDelegate - (SigninPromoViewConfigurator*)signinPromoConfigurator { @@ -184,19 +192,10 @@ [self logHistogramForAction:ContentNotificationTopOfFeedPromoAction:: kMainButtonTapped]; [self.presenter presentPushNotificationPermissionAlert]; - [self updateFeedTopSectionWhenClosed]; } #pragma mark - Private -// Handles closing the promo, and the NTP and Feed Top Section layout when the -// promo is closed. -- (void)updateFeedTopSectionWhenClosed { - [self.NTPDelegate handleFeedTopSectionClosed]; - [self.consumer hidePromo]; - [self.NTPDelegate updateFeedLayout]; -} - - (BOOL)isUserSignedIn { return self.identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin); } @@ -233,7 +232,7 @@ return true; } - if (!IsContentNotificationExperimentEnalbed() || + if (!IsContentNotificationExperimentEnabled() || !IsContentNotificationPromoEnabled([self isUserSignedIn], self.isDefaultSearchEngine, self.prefService)) {
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn index 13c93147..0be53d6 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -63,7 +63,6 @@ source_set("password_details_ui") { sources = [ "add_password_details_consumer.h", - "add_password_handler.h", "add_password_view_controller.h", "add_password_view_controller.mm", "add_password_view_controller_delegate.h", @@ -163,6 +162,7 @@ "//ios/chrome/browser/ui/settings/cells", "//ios/chrome/browser/ui/settings/password:features", "//ios/chrome/browser/ui/settings/password/password_details/cells", + "//ios/chrome/browser/ui/settings/password/password_settings:common", "//ios/chrome/browser/ui/settings/password/password_sharing:password_sharing_metrics", "//ios/chrome/common/ui/reauthentication", "//ios/chrome/common/ui/table_view:cells_constants",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h index b8d85d7..19ef068c 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h
@@ -13,15 +13,6 @@ // This coordinator presents add password sheet for the user. @interface AddPasswordCoordinator : ChromeCoordinator -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browser:(Browser*)browser - reauthModule: - (id<ReauthenticationProtocol>)reauthModule - NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browser:(Browser*)browser NS_UNAVAILABLE; - // Delegate. @property(nonatomic, weak) id<AddPasswordCoordinatorDelegate> delegate;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.mm index 695849f..1ea6e8dd 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.mm
@@ -13,7 +13,6 @@ #import "ios/chrome/browser/passwords/model/ios_chrome_password_check_manager_factory.h" #import "ios/chrome/browser/passwords/model/metrics/ios_password_manager_metrics.h" #import "ios/chrome/browser/passwords/model/metrics/ios_password_manager_visits_recorder.h" -#import "ios/chrome/browser/shared/coordinator/alert/alert_coordinator.h" #import "ios/chrome/browser/shared/model/browser/browser.h" #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" @@ -22,19 +21,16 @@ #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/sync/model/sync_service_factory.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator_delegate.h" -#import "ios/chrome/browser/ui/settings/password/password_details/add_password_handler.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_mediator.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_mediator_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h" #import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h" #import "ios/chrome/browser/ui/settings/password/reauthentication/reauthentication_coordinator.h" -#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" #import "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util.h" #import "url/gurl.h" -@interface AddPasswordCoordinator () <AddPasswordHandler, - AddPasswordMediatorDelegate, +@interface AddPasswordCoordinator () <AddPasswordMediatorDelegate, ReauthenticationCoordinatorDelegate, UIAdaptivePresentationControllerDelegate> @@ -44,13 +40,6 @@ // Main mediator for this coordinator. @property(nonatomic, strong) AddPasswordMediator* mediator; -// Module containing the reauthentication mechanism for editing existing -// passwords. -@property(nonatomic, weak) id<ReauthenticationProtocol> reauthenticationModule; - -// Modal alert for interactions with password. -@property(nonatomic, strong) AlertCoordinator* alertCoordinator; - // Dispatcher. @property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher; @@ -68,14 +57,10 @@ @synthesize baseNavigationController = _baseNavigationController; - (instancetype)initWithBaseViewController:(UIViewController*)viewController - browser:(Browser*)browser - reauthModule: - (id<ReauthenticationProtocol>)reauthModule { + browser:(Browser*)browser { self = [super initWithBaseViewController:viewController browser:browser]; if (self) { DCHECK(viewController); - DCHECK(reauthModule); - _reauthenticationModule = reauthModule; _dispatcher = static_cast<id<BrowserCommands, ApplicationCommands>>( browser->GetCommandDispatcher()); } @@ -97,8 +82,6 @@ browserState)]; self.mediator.consumer = self.viewController; self.viewController.delegate = self.mediator; - self.viewController.addPasswordHandler = self; - self.viewController.reauthModule = self.reauthenticationModule; UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; @@ -115,9 +98,7 @@ kAddPassword]; [_visitsRecorder maybeRecordVisitMetric]; - if (password_manager::features::IsAuthOnEntryV2Enabled()) { - [self startReauthCoordinator]; - } + [self startReauthCoordinator]; } - (void)stop { @@ -139,7 +120,6 @@ completion:nil]; } - [self dismissAlertCoordinator]; self.mediator = nil; self.viewController = nil; @@ -170,41 +150,6 @@ coordinator:self]; } -#pragma mark - AddPasswordHandler - -- (void)showPasscodeDialog { - NSString* title = - l10n_util::GetNSString(IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE); - NSString* message = - l10n_util::GetNSString(IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_CONTENT); - self.alertCoordinator = - [[AlertCoordinator alloc] initWithBaseViewController:self.viewController - browser:self.browser - title:title - message:message]; - - __weak __typeof(self) weakSelf = self; - OpenNewTabCommand* command = - [OpenNewTabCommand commandWithURLFromChrome:GURL(kPasscodeArticleURL)]; - - [self.alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_OK) - action:^{ - [weakSelf dismissAlertCoordinator]; - } - style:UIAlertActionStyleCancel]; - - [self.alertCoordinator - addItemWithTitle:l10n_util::GetNSString( - IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW) - action:^{ - [weakSelf.dispatcher closeSettingsUIAndOpenURL:command]; - [weakSelf dismissAlertCoordinator]; - } - style:UIAlertActionStyleDefault]; - - [self.alertCoordinator start]; -} - #pragma mark - ReauthenticationCoordinatorDelegate - (void)successfulReauthenticationWithCoordinator: @@ -219,16 +164,11 @@ } - (void)willPushReauthenticationViewController { - [self dismissAlertCoordinator]; + // No-op as the surface does not present other surfaces. } #pragma mark - Private -- (void)dismissAlertCoordinator { - [self.alertCoordinator stop]; - self.alertCoordinator = nil; -} - // Starts reauthCoordinator. // Local authentication is required every time the current // scene is backgrounded and foregrounded until reauthCoordinator is stopped. @@ -236,7 +176,7 @@ _reauthCoordinator = [[ReauthenticationCoordinator alloc] initWithBaseNavigationController:_baseNavigationController browser:self.browser - reauthenticationModule:_reauthenticationModule + reauthenticationModule:nil authOnStart:NO]; _reauthCoordinator.delegate = self;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator_unittest.mm index d0e3582..092ed338 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator_unittest.mm
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h" + #import <UIKit/UIKit.h> #import "base/apple/foundation_util.h" @@ -24,9 +26,8 @@ #import "ios/chrome/browser/shared/public/commands/settings_commands.h" #import "ios/chrome/browser/sync/model/mock_sync_service_utils.h" #import "ios/chrome/browser/sync/model/sync_service_factory.h" -#import "ios/chrome/browser/ui/settings/password/password_details/add_password_coordinator.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h" -#import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h" +#import "ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h" #import "ios/chrome/test/app/mock_reauthentication_module.h" #import "ios/chrome/test/scoped_key_window.h" #import "ios/web/public/test/web_task_environment.h" @@ -45,9 +46,6 @@ void SetUp() override { PlatformTest::SetUp(); - scoped_feature_list_.InitAndEnableFeature( - password_manager::features::kIOSPasswordAuthOnEntryV2); - TestChromeBrowserState::Builder builder; // Add test password store. Used by the mediator. builder.AddTestingFactory( @@ -88,10 +86,14 @@ mock_reauth_module_.shouldReturnSynchronously = NO; mock_reauth_module_.expectedResult = ReauthenticationResult::kSuccess; + // Replace reauthentication module with mock implementation for testing. + scoped_reauth_module_override_ = + ScopedPasswordSettingsReauthModuleOverride::MakeAndArmForTesting( + mock_reauth_module_); + coordinator_ = [[AddPasswordCoordinator alloc] initWithBaseViewController:base_view_controller_ - browser:browser_.get() - reauthModule:mock_reauth_module_]; + browser:browser_.get()]; scoped_window_.Get().rootViewController = base_view_controller_; @@ -136,6 +138,8 @@ std::unique_ptr<ChromeBrowserState> browser_state_; std::unique_ptr<TestBrowser> browser_; ScopedKeyWindow scoped_window_; + std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> + scoped_reauth_module_override_; UIViewController* base_view_controller_ = nil; MockReauthenticationModule* mock_reauth_module_ = nil; base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_handler.h b/ios/chrome/browser/ui/settings/password/password_details/add_password_handler.h deleted file mode 100644 index 3a3bc52..0000000 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_handler.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_ADD_PASSWORD_HANDLER_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_ADD_PASSWORD_HANDLER_H_ - -// Presenter which handles commands from `AddPasswordViewController`. -@protocol AddPasswordHandler - -// Called when the reauthentication protocol is not ready for the -// authentication. -- (void)showPasscodeDialog; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_ADD_PASSWORD_HANDLER_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h index 85355d3..e73d154 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.h
@@ -10,7 +10,6 @@ #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h" @protocol ApplicationCommands; -@protocol AddPasswordHandler; @protocol PasswordDetailsHandler; @protocol AddPasswordViewControllerDelegate; @protocol ReauthenticationProtocol; @@ -25,9 +24,6 @@ - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE; -// Handler for AddPasswordDetails related actions. -@property(nonatomic, weak) id<AddPasswordHandler> addPasswordHandler; - // Delegate for PasswordDetails related actions e.g. Password editing. @property(nonatomic, weak) id<AddPasswordViewControllerDelegate> delegate;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm index 59fa80c..9fe4f8ca 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm
@@ -6,12 +6,9 @@ #import "base/apple/foundation_util.h" #import "base/ios/ios_util.h" -#import "base/metrics/histogram_functions.h" -#import "base/metrics/histogram_macros.h" #import "base/metrics/user_metrics.h" #import "base/metrics/user_metrics_action.h" #import "base/strings/sys_string_conversions.h" -#import "components/device_reauth/device_reauth_metrics_util.h" #import "components/password_manager/core/browser/password_manager_metrics_util.h" #import "components/password_manager/core/common/password_manager_constants.h" #import "components/password_manager/core/common/password_manager_features.h" @@ -27,11 +24,9 @@ #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h" #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" -#import "ios/chrome/browser/ui/settings/password/password_details/add_password_handler.h" #import "ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.h" -#import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h" #import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #import "ios/chrome/common/ui/elements/popover_label_view_controller.h" @@ -43,10 +38,7 @@ namespace { -using base::UmaHistogramEnumeration; -using device_reauth::ReauthResult; using password_manager::constants::kMaxPasswordNoteLength; -using password_manager::metrics_util::LogPasswordSettingsReauthResult; using password_manager::metrics_util::PasswordCheckInteraction; typedef NS_ENUM(NSInteger, SectionIdentifier) { @@ -395,14 +387,8 @@ AddCredentialFromSettingsUserInteractions:: kDuplicateCredentialViewed); - if (password_manager::features::IsAuthOnEntryV2Enabled()) { NSString* usernameTextValue = _usernameTextItem.textFieldValue; [_delegate showExistingCredential:usernameTextValue]; - } else { - // Require auth before showing existing credential if authentication wasn't - // required to open the password manager in the first place. - [self reauthAndShowExistingCredential]; - } } - (UITableViewCellEditingStyle)tableView:(UITableView*)tableView @@ -770,35 +756,6 @@ } } -- (void)reauthAndShowExistingCredential { - if ([self.reauthModule canAttemptReauth]) { - __weak __typeof(self) weakSelf = self; - void (^viewExistingPasswordHandler)(ReauthenticationResult) = ^( - ReauthenticationResult result) { - AddPasswordViewController* strongSelf = weakSelf; - if (!strongSelf) - return; - [strongSelf logPasswordSettingsReauthResult:result]; - - if (result == ReauthenticationResult::kFailure) { - return; - } - - [strongSelf.delegate - showExistingCredential:strongSelf.usernameTextItem.textFieldValue]; - }; - - [self.reauthModule - attemptReauthWithLocalizedReason: - l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_SHOW) - canReusePreviousAuth:YES - handler:viewExistingPasswordHandler]; - } else { - DCHECK(self.addPasswordHandler); - [self.addPasswordHandler showPasscodeDialog]; - } -} - // Enables/Disables the right bar button item in the navigation bar. - (void)toggleNavigationBarRightButtonItem { self.navigationItem.rightBarButtonItem.enabled = @@ -886,24 +843,6 @@ [self presentViewController:errorInfoPopover animated:YES completion:nil]; } -#pragma mark - Metrics - -// Logs metrics for the given reauthentication `result` (success, failure or -// skipped). -- (void)logPasswordSettingsReauthResult:(ReauthenticationResult)result { - switch (result) { - case ReauthenticationResult::kSuccess: - LogPasswordSettingsReauthResult(ReauthResult::kSuccess); - break; - case ReauthenticationResult::kFailure: - LogPasswordSettingsReauthResult(ReauthResult::kFailure); - break; - case ReauthenticationResult::kSkipped: - LogPasswordSettingsReauthResult(ReauthResult::kSkipped); - break; - } -} - #pragma mark - ForTesting - (void)setPassword:(NSString*)password {
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_unittest.mm index 58c6f43..828527c 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_unittest.mm
@@ -11,7 +11,6 @@ #import "base/strings/sys_string_conversions.h" #import "base/strings/utf_string_conversions.h" #import "base/test/metrics/histogram_tester.h" -#import "base/test/scoped_feature_list.h" #import "components/password_manager/core/browser/password_form.h" #import "components/password_manager/core/browser/ui/credential_ui_entry.h" #import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h" @@ -21,19 +20,15 @@ #import "ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h" -#import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h" #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h" #import "ios/chrome/grit/ios_branded_strings.h" #import "ios/chrome/grit/ios_strings.h" -#import "ios/chrome/test/app/mock_reauthentication_module.h" #import "ios/chrome/test/app/password_test_util.h" #import "ios/web/public/test/web_task_environment.h" #import "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" #import "ui/base/l10n/l10n_util_mac.h" -using base::test::ScopedFeatureList; -using password_manager::features::kIOSPasswordAuthOnEntryV2; namespace { constexpr char kPassword[] = "test"; @@ -98,23 +93,13 @@ : public LegacyChromeTableViewControllerTest { protected: AddPasswordViewControllerTest() { - feature_list_.InitWithFeatures( - /*enabled_features=*/{kIOSPasswordAuthOnEntryV2}, - /*disabled_features=*/{}); delegate_ = [[FakeAddPasswordDelegate alloc] init]; - mock_reauthentication_module_ = [[MockReauthenticationModule alloc] init]; - mock_reauthentication_module_.expectedResult = - ReauthenticationResult::kSuccess; - // Delay mocked result delivery to test behavior only executed after auth is - // passed. - mock_reauthentication_module_.shouldReturnSynchronously = NO; } LegacyChromeTableViewController* InstantiateController() override { AddPasswordViewController* controller = [[AddPasswordViewController alloc] init]; controller.delegate = delegate_; - controller.reauthModule = mock_reauthentication_module_; return controller; } @@ -147,9 +132,7 @@ cell.detailText); } - ScopedFeatureList feature_list_; FakeAddPasswordDelegate* delegate_ = nil; - MockReauthenticationModule* mock_reauthentication_module_ = nil; }; // Tests that password is shown/hidden. @@ -235,10 +218,9 @@ 4); } -// Tests tapping on the show duplicated credential button calls the delegate -// without authentication required. -TEST_F(AddPasswordViewControllerTest, - TestShowDuplicatedCredentialWithoutAuthRequired) { +// Tests tapping on the show duplicated credential button asks the delegate to +// display the existing credential. +TEST_F(AddPasswordViewControllerTest, TestShowDuplicatedCredential) { SetPassword(); AddPasswordViewController* passwords_controller = @@ -257,47 +239,6 @@ [passwords_controller tableView:passwords_controller.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:3]]; - // The mocked reauth module is setup return its result only on command thus at - // this point the result has not been delivered. The delegate should have been - // called without auth required. - EXPECT_TRUE(delegate_.showExistingCredentialCalled); -} - -// Tests tapping on the show duplicated credential button calls the delegate -// with authentication required. -TEST_F(AddPasswordViewControllerTest, - TestShowDuplicatedCredentialWithAuthRequired) { - // Auth on entry removes the need for auth within add passwords as auth is - // required when opening any of the Password Manager entry points. - ScopedFeatureList auth_on_entry_disabled_feature_list; - auth_on_entry_disabled_feature_list.InitAndDisableFeature( - kIOSPasswordAuthOnEntryV2); - SetPassword(); - - AddPasswordViewController* passwords_controller = - static_cast<AddPasswordViewController*>(controller()); - [passwords_controller loadModel]; - - SetEditCellText(@"http://www.example.com/", 0, 0); - SetEditCellText(@"test@egmail.com", 2, 0); - - // Simulate the credential was found to be duplicated. - // This adds the show existing credential button to the model - [passwords_controller onDuplicateCheckCompletion:YES]; - - EXPECT_FALSE(delegate_.showExistingCredentialCalled); - // Simulate tap on show existing credential button. - [passwords_controller tableView:passwords_controller.tableView - didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:3]]; - - // The mocked reauth module is setup return its result only on command thus at - // this point the result has not been delivered. The delegate should not have - // been called before auth is passed. - EXPECT_FALSE(delegate_.showExistingCredentialCalled); - - // Deliver successful auth result. - [mock_reauthentication_module_ returnMockedReauthenticationResult]; - - // Delegate should have been called now. + // Validate the delegate was asked to show the existing credential. EXPECT_TRUE(delegate_.showExistingCredentialCalled); }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm index 33e28d15b..f135eb1 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -302,8 +302,7 @@ [self stopReauthCoordinatorBeforeStartingChildCoordinator]; self.addPasswordCoordinator = [[AddPasswordCoordinator alloc] initWithBaseViewController:self.viewController - browser:self.browser - reauthModule:self.reauthModule]; + browser:self.browser]; self.addPasswordCoordinator.delegate = self; [self.addPasswordCoordinator start]; }
diff --git a/ios/web/content/ui/content_context_menu_controller.mm b/ios/web/content/ui/content_context_menu_controller.mm index e44d2dc..20ce419 100644 --- a/ios/web/content/ui/content_context_menu_controller.mm +++ b/ios/web/content/ui/content_context_menu_controller.mm
@@ -81,7 +81,7 @@ case network::mojom::ReferrerPolicy::kStrictOrigin: return web::ReferrerPolicy::ReferrerPolicyStrictOrigin; } - NOTREACHED(); + NOTREACHED_IN_MIGRATION(); return web::ReferrerPolicy::ReferrerPolicyDefault; }
diff --git a/ios_internal b/ios_internal index 380efce..ddc67fe 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 380efce15f92daa9a34e1c96fcfc10cd0464ff9e +Subproject commit ddc67fe02ca572ab3c10c406506a45b727265d71
diff --git a/media/base/audio_codecs_unittest.cc b/media/base/audio_codecs_unittest.cc index 1d5075e..8d0c542 100644 --- a/media/base/audio_codecs_unittest.cc +++ b/media/base/audio_codecs_unittest.cc
@@ -3,8 +3,7 @@ // found in the LICENSE file. #include "media/base/audio_codecs.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" + #include "testing/gtest/include/gtest/gtest.h" namespace media {
diff --git a/media/base/audio_hash.h b/media/base/audio_hash.h index f0df5a8..75dd1008 100644 --- a/media/base/audio_hash.h +++ b/media/base/audio_hash.h
@@ -10,7 +10,6 @@ #include <string> -#include "base/strings/string_piece.h" #include "media/base/media_export.h" namespace media {
diff --git a/media/base/memory_dump_provider_proxy.h b/media/base/memory_dump_provider_proxy.h index 16c003f9..fe84f05 100644 --- a/media/base/memory_dump_provider_proxy.h +++ b/media/base/memory_dump_provider_proxy.h
@@ -9,7 +9,6 @@ #include <stdint.h> #include "base/memory/scoped_refptr.h" -#include "base/strings/string_piece.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/trace_event/memory_dump_provider.h"
diff --git a/media/base/status.cc b/media/base/status.cc index 5a2eb02..b776247 100644 --- a/media/base/status.cc +++ b/media/base/status.cc
@@ -5,7 +5,7 @@ #include "media/base/status.h" #include <memory> -#include "base/strings/string_piece.h" + #include "media/base/media_serializers.h" namespace media {
diff --git a/media/filters/hls_data_source_provider.h b/media/filters/hls_data_source_provider.h index 1c6629b..10e5faa 100644 --- a/media/filters/hls_data_source_provider.h +++ b/media/filters/hls_data_source_provider.h
@@ -8,10 +8,10 @@ #include <cstdint> #include <memory> #include <optional> +#include <string_view> #include "base/containers/queue.h" #include "base/functional/callback.h" -#include "base/strings/string_piece.h" #include "base/types/id_type.h" #include "media/base/media_export.h" #include "media/base/status.h"
diff --git a/media/formats/hls/attribute_list_fuzzer.cc b/media/formats/hls/attribute_list_fuzzer.cc index db9c8071b..6e1987b 100644 --- a/media/formats/hls/attribute_list_fuzzer.cc +++ b/media/formats/hls/attribute_list_fuzzer.cc
@@ -4,9 +4,9 @@ #include <cstddef> #include <cstdint> +#include <string_view> #include "base/check.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/types.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/media/formats/hls/items.cc b/media/formats/hls/items.cc index 7912259..e0c8a3b 100644 --- a/media/formats/hls/items.cc +++ b/media/formats/hls/items.cc
@@ -5,8 +5,8 @@ #include "media/formats/hls/items.h" #include <optional> +#include <string_view> -#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "media/formats/hls/parse_status.h" #include "third_party/abseil-cpp/absl/types/variant.h"
diff --git a/media/formats/hls/items_fuzzer.cc b/media/formats/hls/items_fuzzer.cc index d1e7f01..f7dca9b3 100644 --- a/media/formats/hls/items_fuzzer.cc +++ b/media/formats/hls/items_fuzzer.cc
@@ -7,9 +7,9 @@ #include <cstddef> #include <cstdint> #include <optional> +#include <string_view> #include "base/check.h" -#include "base/strings/string_piece.h" #include "third_party/abseil-cpp/absl/types/variant.h" namespace {
diff --git a/media/formats/hls/items_unittest.cc b/media/formats/hls/items_unittest.cc index 1129b1e..2866b1f 100644 --- a/media/formats/hls/items_unittest.cc +++ b/media/formats/hls/items_unittest.cc
@@ -4,8 +4,9 @@ #include "media/formats/hls/items.h" +#include <string_view> + #include "base/location.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/source_string.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/variant.h"
diff --git a/media/formats/hls/media_playlist.cc b/media/formats/hls/media_playlist.cc index 4c374100..3d64912 100644 --- a/media/formats/hls/media_playlist.cc +++ b/media/formats/hls/media_playlist.cc
@@ -6,12 +6,12 @@ #include <cmath> #include <optional> +#include <string_view> #include <utility> #include <vector> #include "base/memory/scoped_refptr.h" #include "base/numerics/clamped_math.h" -#include "base/strings/string_piece.h" #include "base/time/time.h" #include "media/formats/hls/media_segment.h" #include "media/formats/hls/multivariant_playlist.h"
diff --git a/media/formats/hls/media_playlist_fuzzer.cc b/media/formats/hls/media_playlist_fuzzer.cc index b31810e..431c2d38c 100644 --- a/media/formats/hls/media_playlist_fuzzer.cc +++ b/media/formats/hls/media_playlist_fuzzer.cc
@@ -2,16 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "media/formats/hls/media_playlist.h" + #include <fuzzer/FuzzedDataProvider.h> + #include <cstddef> #include <cstdint> +#include <string_view> #include "base/at_exit.h" #include "base/check.h" #include "base/i18n/icu_util.h" #include "base/memory/scoped_refptr.h" -#include "base/strings/string_piece.h" -#include "media/formats/hls/media_playlist.h" #include "media/formats/hls/multivariant_playlist.h" #include "media/formats/hls/playlist.h" #include "third_party/abseil-cpp/absl/types/variant.h"
diff --git a/media/formats/hls/media_playlist_unittest.cc b/media/formats/hls/media_playlist_unittest.cc index ec3fe2d..3b1b955 100644 --- a/media/formats/hls/media_playlist_unittest.cc +++ b/media/formats/hls/media_playlist_unittest.cc
@@ -7,10 +7,10 @@ #include <initializer_list> #include <limits> #include <string> +#include <string_view> #include <utility> #include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/media_playlist_test_builder.h" #include "media/formats/hls/multivariant_playlist.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/multivariant_playlist.cc b/media/formats/hls/multivariant_playlist.cc index e7fd61f..be3f2b2d 100644 --- a/media/formats/hls/multivariant_playlist.cc +++ b/media/formats/hls/multivariant_playlist.cc
@@ -5,6 +5,7 @@ #include "media/formats/hls/multivariant_playlist.h" #include <optional> +#include <string_view> #include <utility> #include <vector> @@ -12,7 +13,6 @@ #include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" #include "base/notreached.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/audio_rendition.h" #include "media/formats/hls/items.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/multivariant_playlist.h b/media/formats/hls/multivariant_playlist.h index 3ff7247..0145efc 100644 --- a/media/formats/hls/multivariant_playlist.h +++ b/media/formats/hls/multivariant_playlist.h
@@ -5,10 +5,10 @@ #ifndef MEDIA_FORMATS_HLS_MULTIVARIANT_PLAYLIST_H_ #define MEDIA_FORMATS_HLS_MULTIVARIANT_PLAYLIST_H_ +#include <string_view> #include <vector> #include "base/memory/scoped_refptr.h" -#include "base/strings/string_piece.h" #include "base/types/pass_key.h" #include "media/base/media_export.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/multivariant_playlist_fuzzer.cc b/media/formats/hls/multivariant_playlist_fuzzer.cc index 84d18d99..a8088b7 100644 --- a/media/formats/hls/multivariant_playlist_fuzzer.cc +++ b/media/formats/hls/multivariant_playlist_fuzzer.cc
@@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "media/formats/hls/multivariant_playlist.h" + #include <cstddef> #include <cstdint> +#include <string_view> #include "base/at_exit.h" #include "base/check.h" #include "base/i18n/icu_util.h" -#include "base/strings/string_piece.h" -#include "media/formats/hls/multivariant_playlist.h" #include "media/formats/hls/playlist.h" #include "third_party/abseil-cpp/absl/types/variant.h" #include "url/gurl.h" @@ -35,7 +36,7 @@ } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Create a StringPiece from the given input + // Create a string_view from the given input const std::string_view source(reinterpret_cast<const char*>(data), size); // Determine playlist version (ignoring type mismatch)
diff --git a/media/formats/hls/multivariant_playlist_test_builder.h b/media/formats/hls/multivariant_playlist_test_builder.h index 0860974..563aa5a 100644 --- a/media/formats/hls/multivariant_playlist_test_builder.h +++ b/media/formats/hls/multivariant_playlist_test_builder.h
@@ -11,7 +11,6 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/location.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/audio_rendition.h" #include "media/formats/hls/multivariant_playlist.h" #include "media/formats/hls/playlist_test_builder.h"
diff --git a/media/formats/hls/parse_status.cc b/media/formats/hls/parse_status.cc index cc3443f..b2b485e 100644 --- a/media/formats/hls/parse_status.cc +++ b/media/formats/hls/parse_status.cc
@@ -4,8 +4,9 @@ #include "media/formats/hls/parse_status.h" +#include <string_view> + #include "base/notreached.h" -#include "base/strings/string_piece.h" namespace media::hls {
diff --git a/media/formats/hls/parse_status.h b/media/formats/hls/parse_status.h index 501a8e2..6e29c8a 100644 --- a/media/formats/hls/parse_status.h +++ b/media/formats/hls/parse_status.h
@@ -5,7 +5,8 @@ #ifndef MEDIA_FORMATS_HLS_PARSE_STATUS_H_ #define MEDIA_FORMATS_HLS_PARSE_STATUS_H_ -#include "base/strings/string_piece.h" +#include <string_view> + #include "media/base/media_export.h" #include "media/base/status.h"
diff --git a/media/formats/hls/playlist_unittest.cc b/media/formats/hls/playlist_unittest.cc index 6b9480d..3f56642 100644 --- a/media/formats/hls/playlist_unittest.cc +++ b/media/formats/hls/playlist_unittest.cc
@@ -3,9 +3,11 @@ // found in the LICENSE file. #include "media/formats/hls/playlist.h" + +#include <string_view> + #include "base/location.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/parse_status.h" #include "media/formats/hls/tag_name.h" #include "media/formats/hls/types.h"
diff --git a/media/formats/hls/rendition_manager.h b/media/formats/hls/rendition_manager.h index 25cb3bc..3db941b2 100644 --- a/media/formats/hls/rendition_manager.h +++ b/media/formats/hls/rendition_manager.h
@@ -9,6 +9,7 @@ #include <optional> #include <set> #include <string> +#include <string_view> #include <vector> #include "base/containers/flat_set.h" @@ -16,7 +17,6 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" -#include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/types/id_type.h" #include "media/base/demuxer.h"
diff --git a/media/formats/hls/source_string.cc b/media/formats/hls/source_string.cc index d90384e..e037639 100644 --- a/media/formats/hls/source_string.cc +++ b/media/formats/hls/source_string.cc
@@ -4,7 +4,8 @@ #include "media/formats/hls/source_string.h" -#include "base/strings/string_piece.h" +#include <string_view> + #include "base/strings/string_util.h" #include "base/types/pass_key.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/source_string.h b/media/formats/hls/source_string.h index fd30e2c..cdf5794 100644 --- a/media/formats/hls/source_string.h +++ b/media/formats/hls/source_string.h
@@ -6,7 +6,8 @@ #define MEDIA_FORMATS_HLS_SOURCE_STRING_H_ #include <cstdint> -#include "base/strings/string_piece.h" +#include <string_view> + #include "base/types/pass_key.h" #include "media/base/media_export.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/tag_name.cc b/media/formats/hls/tag_name.cc index 2f4757b..45b9c64 100644 --- a/media/formats/hls/tag_name.cc +++ b/media/formats/hls/tag_name.cc
@@ -4,10 +4,11 @@ #include "media/formats/hls/tag_name.h" +#include <string_view> #include <utility> + #include "base/containers/fixed_flat_map.h" #include "base/notreached.h" -#include "base/strings/string_piece.h" namespace media::hls {
diff --git a/media/formats/hls/tag_name.h b/media/formats/hls/tag_name.h index a106359..9296de7 100644 --- a/media/formats/hls/tag_name.h +++ b/media/formats/hls/tag_name.h
@@ -7,8 +7,8 @@ #include <cstdint> #include <optional> +#include <string_view> -#include "base/strings/string_piece.h" #include "media/base/media_export.h" namespace media::hls {
diff --git a/media/formats/hls/tags_unittest.cc b/media/formats/hls/tags_unittest.cc index bc0ea8f..f29aad2 100644 --- a/media/formats/hls/tags_unittest.cc +++ b/media/formats/hls/tags_unittest.cc
@@ -6,12 +6,12 @@ #include <array> #include <optional> +#include <string_view> #include <utility> #include "base/location.h" #include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" #include "media/base/media_serializers.h" #include "media/formats/hls/items.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/test_util.h b/media/formats/hls/test_util.h index ca54eba..7bebb27 100644 --- a/media/formats/hls/test_util.h +++ b/media/formats/hls/test_util.h
@@ -6,8 +6,8 @@ #define MEDIA_FORMATS_HLS_TEST_UTIL_H_ #include <optional> +#include <string_view> -#include "base/strings/string_piece.h" #include "base/time/time.h" #include "media/formats/hls/source_string.h" #include "media/formats/hls/types.h"
diff --git a/media/formats/hls/types_unittest.cc b/media/formats/hls/types_unittest.cc index eca7f99..6fdbe735 100644 --- a/media/formats/hls/types_unittest.cc +++ b/media/formats/hls/types_unittest.cc
@@ -6,10 +6,10 @@ #include <initializer_list> #include <string> +#include <string_view> #include <utility> #include "base/location.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/parse_status.h" #include "media/formats/hls/source_string.h" #include "media/formats/hls/test_util.h"
diff --git a/media/formats/hls/variable_dictionary.cc b/media/formats/hls/variable_dictionary.cc index cf8160f..4a99f55 100644 --- a/media/formats/hls/variable_dictionary.cc +++ b/media/formats/hls/variable_dictionary.cc
@@ -4,7 +4,8 @@ #include "media/formats/hls/variable_dictionary.h" -#include "base/strings/string_piece.h" +#include <string_view> + #include "base/strings/string_util.h" #include "media/formats/hls/parse_status.h" #include "media/formats/hls/source_string.h"
diff --git a/media/formats/hls/variable_dictionary.h b/media/formats/hls/variable_dictionary.h index 954398d..3e7d9221 100644 --- a/media/formats/hls/variable_dictionary.h +++ b/media/formats/hls/variable_dictionary.h
@@ -8,8 +8,8 @@ #include <list> #include <optional> #include <string> +#include <string_view> -#include "base/strings/string_piece.h" #include "base/types/pass_key.h" #include "media/base/media_export.h" #include "media/formats/hls/parse_status.h"
diff --git a/media/formats/hls/variable_dictionary_unittest.cc b/media/formats/hls/variable_dictionary_unittest.cc index 81927e1..7912220 100644 --- a/media/formats/hls/variable_dictionary_unittest.cc +++ b/media/formats/hls/variable_dictionary_unittest.cc
@@ -5,10 +5,10 @@ #include "media/formats/hls/variable_dictionary.h" #include <optional> +#include <string_view> #include <utility> #include "base/location.h" -#include "base/strings/string_piece.h" #include "media/formats/hls/parse_status.h" #include "media/formats/hls/source_string.h" #include "media/formats/hls/test_util.h"
diff --git a/media/formats/hls/variant_stream.h b/media/formats/hls/variant_stream.h index ae89c47..dc8aa39 100644 --- a/media/formats/hls/variant_stream.h +++ b/media/formats/hls/variant_stream.h
@@ -8,7 +8,6 @@ #include <optional> #include "base/memory/scoped_refptr.h" -#include "base/strings/string_piece.h" #include "media/base/media_export.h" #include "media/formats/hls/types.h" #include "url/gurl.h"
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn index 492b40d..3c8cda1 100644 --- a/media/gpu/BUILD.gn +++ b/media/gpu/BUILD.gn
@@ -383,6 +383,8 @@ if (is_win || use_vaapi) { sources += [ + "av1_builder.cc", + "av1_builder.h", "h264_builder.cc", "h264_builder.h", "vp9_svc_layers.cc", @@ -672,6 +674,7 @@ if (is_win || use_vaapi) { sources += [ + "av1_builder_unittest.cc", "h264_builder_unittest.cc", "vp9_svc_layers_unittest.cc", ]
diff --git a/media/gpu/av1_builder.cc b/media/gpu/av1_builder.cc new file mode 100644 index 0000000..a3ceec7e --- /dev/null +++ b/media/gpu/av1_builder.cc
@@ -0,0 +1,114 @@ +// 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 "media/gpu/av1_builder.h" + +#include "base/check_op.h" + +namespace media { + +AV1BitstreamBuilder::AV1BitstreamBuilder() = default; +AV1BitstreamBuilder::~AV1BitstreamBuilder() = default; +AV1BitstreamBuilder::AV1BitstreamBuilder(AV1BitstreamBuilder&&) = default; + +void AV1BitstreamBuilder::Write(uint64_t val, int num_bits) { + queued_writes_.emplace_back(val, num_bits); + total_outstanding_bits_ += num_bits; +} + +void AV1BitstreamBuilder::WriteBool(bool val) { + Write(val, 1); +} + +std::vector<uint8_t> AV1BitstreamBuilder::Flush() && { + std::vector<uint8_t> ret; + uint8_t curr_byte = 0; + int rem_bits_in_byte = 8; + for (auto queued_write : queued_writes_) { + uint64_t val = queued_write.first; + int outstanding_bits = queued_write.second; + while (outstanding_bits) { + if (rem_bits_in_byte >= outstanding_bits) { + curr_byte |= val << (rem_bits_in_byte - outstanding_bits); + rem_bits_in_byte -= outstanding_bits; + outstanding_bits = 0; + } else { + curr_byte |= (val >> (outstanding_bits - rem_bits_in_byte)) & + ((1 << rem_bits_in_byte) - 1); + outstanding_bits -= rem_bits_in_byte; + rem_bits_in_byte = 0; + } + if (!rem_bits_in_byte) { + ret.push_back(curr_byte); + curr_byte = 0; + rem_bits_in_byte = 8; + } + } + } + + if (rem_bits_in_byte != 8) { + ret.push_back(curr_byte); + } + + queued_writes_.clear(); + total_outstanding_bits_ = 0; + + return ret; +} + +void AV1BitstreamBuilder::PutAlignBits() { + int misalignment = total_outstanding_bits_ % 8; + if (misalignment != 0) { + int num_zero_bits = 8 - misalignment; + Write(0, num_zero_bits); + } +} + +void AV1BitstreamBuilder::PutTrailingBits() { + WriteBool(true); // trialing one bit. + PutAlignBits(); +} + +void AV1BitstreamBuilder::WriteOBUHeader(libgav1::ObuType type, + bool extension_flag, + bool has_size) { + DCHECK_LE(1, type); + DCHECK_LE(type, 8); + WriteBool(false); // forbidden bit must be set to 0. + Write(static_cast<uint64_t>(type), 4); + WriteBool(extension_flag); + WriteBool(has_size); + WriteBool(false); // reserved bit must be set to 0. +} + +// Encode a variable length unsigned integer of up to 4 bytes. +// Most significant bit of each byte indicates if parsing should continue, and +// the 7 least significant bits hold the actual data. So the encoded length +// may be 5 bytes under some circumstances. +// This function also has a fixed size mode where we pass in a fixed size for +// the data and the function zero pads up to that size. +// See section 4.10.5 of the AV1 specification. +void AV1BitstreamBuilder::WriteValueInLeb128(uint32_t value, + std::optional<int> fixed_size) { + for (int i = 0; i < fixed_size.value_or(5); i++) { + uint8_t curr_byte = value & 0x7F; + value >>= 7; + if (value || fixed_size) { + curr_byte |= 0x80; + Write(curr_byte, 8); + } else { + Write(curr_byte, 8); + break; + } + } +} + +void AV1BitstreamBuilder::AppendBitstreamBuffer(AV1BitstreamBuilder buffer) { + queued_writes_.insert(queued_writes_.end(), + std::make_move_iterator(buffer.queued_writes_.begin()), + std::make_move_iterator(buffer.queued_writes_.end())); + total_outstanding_bits_ += buffer.total_outstanding_bits_; +} + +} // namespace media
diff --git a/media/gpu/av1_builder.h b/media/gpu/av1_builder.h new file mode 100644 index 0000000..c7cdf874 --- /dev/null +++ b/media/gpu/av1_builder.h
@@ -0,0 +1,48 @@ +// 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 MEDIA_GPU_AV1_BUILDER_H_ +#define MEDIA_GPU_AV1_BUILDER_H_ + +#include <optional> +#include <vector> + +#include "media/gpu/media_gpu_export.h" +#include "third_party/libgav1/src/src/utils/constants.h" +#include "third_party/libgav1/src/src/utils/types.h" + +namespace media { + +// Helper class for AV1 to write packed bitstream data. +class MEDIA_GPU_EXPORT AV1BitstreamBuilder { + public: + AV1BitstreamBuilder(); + ~AV1BitstreamBuilder(); + AV1BitstreamBuilder(AV1BitstreamBuilder&&); + + void Write(uint64_t val, int num_bits); + void WriteBool(bool val); + // Spec 5.3.2. + void WriteOBUHeader(libgav1::ObuType type, + bool extension_flag, + bool has_size); + // Writes a value encoded in LEB128. Spec 4.10.5. + void WriteValueInLeb128(uint32_t value, + std::optional<int> fixed_size = std::nullopt); + std::vector<uint8_t> Flush() &&; + size_t OutstandingBits() const { return total_outstanding_bits_; } + // Writes bits for the byte alignment. Spec 5.3.5. + void PutAlignBits(); + // Writes trailing bits. Spec 5.3.4. + void PutTrailingBits(); + void AppendBitstreamBuffer(AV1BitstreamBuilder buffer); + + private: + std::vector<std::pair<uint64_t, int>> queued_writes_; + size_t total_outstanding_bits_ = 0; +}; + +} // namespace media + +#endif // MEDIA_GPU_AV1_BUILDER_H_
diff --git a/media/gpu/av1_builder_unittest.cc b/media/gpu/av1_builder_unittest.cc new file mode 100644 index 0000000..de0411e --- /dev/null +++ b/media/gpu/av1_builder_unittest.cc
@@ -0,0 +1,53 @@ +// 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 "media/gpu/av1_builder.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +class AV1BuilderTest : public ::testing::Test { + public: + AV1BuilderTest() = default; + ~AV1BuilderTest() override = default; +}; + +TEST_F(AV1BuilderTest, AV1BitstreamBuilderOutstandingBits) { + const size_t kExpectedDataBits = 8; + AV1BitstreamBuilder packed_data; + packed_data.Write(0, 3); + packed_data.WriteBool(false); + packed_data.PutAlignBits(); + EXPECT_EQ(packed_data.OutstandingBits(), kExpectedDataBits); +} + +TEST_F(AV1BuilderTest, AV1BitstreamBuilderWriteOBUHeader) { + const std::vector<uint8_t> expected_packed_data = {0b00010010, 0b00000011, + 0b10100000}; + AV1BitstreamBuilder packed_obu_header; + packed_obu_header.WriteOBUHeader(/*type=*/libgav1::kObuTemporalDelimiter, + /*extension_flag=*/false, + /*has_size=*/true); + packed_obu_header.WriteValueInLeb128(3); + packed_obu_header.WriteBool(true); + packed_obu_header.Write(1, 2); + EXPECT_EQ(std::move(packed_obu_header).Flush(), expected_packed_data); +} + +TEST_F(AV1BuilderTest, AV1BitstreamBuilderAppendBitstreamBuffer) { + const std::vector<uint8_t> expected_packed_data = {0b11010100, 0b11000000}; + AV1BitstreamBuilder append_data; + append_data.Write(9, 5); + append_data.PutTrailingBits(); + + AV1BitstreamBuilder packed_data; + packed_data.Write(6, 3); + packed_data.WriteBool(true); + packed_data.AppendBitstreamBuffer(std::move(append_data)); + packed_data.PutAlignBits(); + EXPECT_EQ(std::move(packed_data).Flush(), expected_packed_data); +} + +} // namespace media
diff --git a/media/gpu/vaapi/av1_vaapi_video_encoder_delegate.cc b/media/gpu/vaapi/av1_vaapi_video_encoder_delegate.cc index 69a54b58..b0a2e2f 100644 --- a/media/gpu/vaapi/av1_vaapi_video_encoder_delegate.cc +++ b/media/gpu/vaapi/av1_vaapi_video_encoder_delegate.cc
@@ -9,6 +9,7 @@ #include "base/bits.h" #include "base/logging.h" +#include "media/gpu/av1_builder.h" #include "media/gpu/macros.h" #include "media/gpu/vaapi/vaapi_common.h" #include "media/gpu/vaapi/vaapi_wrapper.h" @@ -181,103 +182,6 @@ return -1; } -// Helper class for writing packed bitstream data. -class PackedData { - public: - void Write(uint64_t val, int num_bits); - void WriteBool(bool val); - void WriteOBUHeader(libgav1::ObuType type, - bool extension_flag, - bool has_size); - void EncodeLeb128(uint32_t value, - std::optional<int> fixed_size = std::nullopt); - std::vector<uint8_t> Flush(); - size_t OutstandingBits() { return total_outstanding_bits_; } - - private: - std::vector<std::pair<uint64_t, int>> queued_writes_; - size_t total_outstanding_bits_ = 0; -}; - -void PackedData::Write(uint64_t val, int num_bits) { - queued_writes_.push_back(std::make_pair(val, num_bits)); - total_outstanding_bits_ += num_bits; -} - -void PackedData::WriteBool(bool val) { - Write(val, 1); -} - -std::vector<uint8_t> PackedData::Flush() { - std::vector<uint8_t> ret; - uint8_t curr_byte = 0; - int rem_bits_in_byte = 8; - for (auto queued_write : queued_writes_) { - uint64_t val = queued_write.first; - int outstanding_bits = queued_write.second; - while (outstanding_bits) { - if (rem_bits_in_byte >= outstanding_bits) { - curr_byte |= val << (rem_bits_in_byte - outstanding_bits); - rem_bits_in_byte -= outstanding_bits; - outstanding_bits = 0; - } else { - curr_byte |= (val >> (outstanding_bits - rem_bits_in_byte)) & - ((1 << rem_bits_in_byte) - 1); - outstanding_bits -= rem_bits_in_byte; - rem_bits_in_byte = 0; - } - if (!rem_bits_in_byte) { - ret.push_back(curr_byte); - curr_byte = 0; - rem_bits_in_byte = 8; - } - } - } - - if (rem_bits_in_byte != 8) { - ret.push_back(curr_byte); - } - - queued_writes_.clear(); - total_outstanding_bits_ = 0; - - return ret; -} - -// See section 5.3.2 of the AV1 specification. -void PackedData::WriteOBUHeader(libgav1::ObuType type, - bool extension_flag, - bool has_size) { - DCHECK_LE(1, type); - DCHECK_LE(type, 8); - WriteBool(false); // forbidden bit - Write(base::checked_cast<uint64_t>(type), 4); - WriteBool(extension_flag); - WriteBool(has_size); - WriteBool(false); // reserved bit -} - -// Encode a variable length unsigned integer of up to 4 bytes. -// Most significant bit of each byte indicates if parsing should continue, and -// the 7 least significant bits hold the actual data. So the encoded length -// may be 5 bytes under some circumstances. -// This function also has a fixed size mode where we pass in a fixed size for -// the data and the function zero pads up to that size. -// See section 4.10.5 of the AV1 specification. -void PackedData::EncodeLeb128(uint32_t value, std::optional<int> fixed_size) { - for (int i = 0; i < fixed_size.value_or(5); i++) { - uint8_t curr_byte = value & 0x7F; - value >>= 7; - if (value || fixed_size) { - curr_byte |= 0x80; - Write(curr_byte, 8); - } else { - Write(curr_byte, 8); - break; - } - } -} - scoped_refptr<AV1Picture> GetAV1Picture( const VaapiVideoEncoderDelegate::EncodeJob& job) { return base::WrapRefCounted( @@ -557,15 +461,15 @@ // See section 5.6 of the AV1 specification. bool AV1VaapiVideoEncoderDelegate::SubmitTemporalDelimiter( size_t& temporal_delimiter_obu_size) { - PackedData temporal_delimiter_obu; + AV1BitstreamBuilder temporal_delimiter_obu; temporal_delimiter_obu.WriteOBUHeader( /*type=*/libgav1::ObuType::kObuTemporalDelimiter, /*extension_flag=*/false, /*has_size=*/true); - temporal_delimiter_obu.EncodeLeb128(0); + temporal_delimiter_obu.WriteValueInLeb128(0); std::vector<uint8_t> temporal_delimiter_obu_data = - temporal_delimiter_obu.Flush(); + std::move(temporal_delimiter_obu).Flush(); temporal_delimiter_obu_size = temporal_delimiter_obu_data.size(); return SubmitPackedData(temporal_delimiter_obu_data); } @@ -631,7 +535,7 @@ bool AV1VaapiVideoEncoderDelegate::SubmitSequenceHeaderOBU( size_t& sequence_header_obu_size) { - PackedData sequence_header_obu; + AV1BitstreamBuilder sequence_header_obu; sequence_header_obu.WriteOBUHeader( /*type=*/libgav1::ObuType::kObuSequenceHeader, @@ -639,9 +543,10 @@ /*has_size=*/true); std::vector<uint8_t> packed_sequence_data = PackSequenceHeader(); - sequence_header_obu.EncodeLeb128(packed_sequence_data.size()); + sequence_header_obu.WriteValueInLeb128(packed_sequence_data.size()); - std::vector<uint8_t> sequence_header_obu_data = sequence_header_obu.Flush(); + std::vector<uint8_t> sequence_header_obu_data = + std::move(sequence_header_obu).Flush(); sequence_header_obu_data.insert( sequence_header_obu_data.end(), std::make_move_iterator(packed_sequence_data.begin()), @@ -653,7 +558,7 @@ // See AV1 specification 5.5.1 std::vector<uint8_t> AV1VaapiVideoEncoderDelegate::PackSequenceHeader() const { - PackedData ret; + AV1BitstreamBuilder ret; ret.Write(seq_param_.seq_profile, 3); ret.WriteBool(seq_param_.seq_fields.bits.still_picture); @@ -707,7 +612,7 @@ ret.WriteBool(true); // Trailing bit must be 1 per 5.3.4 - return ret.Flush(); + return std::move(ret).Flush(); } bool AV1VaapiVideoEncoderDelegate::SubmitFrame(const EncodeJob& job, @@ -964,15 +869,15 @@ bool AV1VaapiVideoEncoderDelegate::SubmitFrameOBU( const VAEncPictureParameterBufferAV1& pic_param, size_t& frame_header_obu_size_offset) { - PackedData frame_obu; + AV1BitstreamBuilder frame_obu; frame_obu.WriteOBUHeader(/*type=*/libgav1::ObuType::kObuFrame, /*extension_flag=*/false, /*has_size=*/true); frame_header_obu_size_offset = frame_obu.OutstandingBits() / 8; std::vector<uint8_t> frame_header_data = PackFrameHeader(pic_param); - frame_obu.EncodeLeb128(frame_header_data.size(), 4); - std::vector<uint8_t> frame_obu_data = frame_obu.Flush(); + frame_obu.WriteValueInLeb128(frame_header_data.size(), 4); + std::vector<uint8_t> frame_obu_data = std::move(frame_obu).Flush(); frame_obu_data.insert(frame_obu_data.end(), std::make_move_iterator(frame_header_data.begin()), std::make_move_iterator(frame_header_data.end())); @@ -985,7 +890,7 @@ // https://github.com/intel/libva-utils/blob/master/encode/av1encode.c std::vector<uint8_t> AV1VaapiVideoEncoderDelegate::PackFrameHeader( const VAEncPictureParameterBufferAV1& pic_param) const { - PackedData ret; + AV1BitstreamBuilder ret; libgav1::FrameType frame_type = static_cast<libgav1::FrameType>(pic_param.picture_flags.bits.frame_type); @@ -1116,7 +1021,7 @@ } } - return ret.Flush(); + return std::move(ret).Flush(); } bool AV1VaapiVideoEncoderDelegate::SubmitPictureParam(
diff --git a/media/muxers/live_webm_muxer_delegate.h b/media/muxers/live_webm_muxer_delegate.h index ebab52a..e9272ff 100644 --- a/media/muxers/live_webm_muxer_delegate.h +++ b/media/muxers/live_webm_muxer_delegate.h
@@ -6,7 +6,6 @@ #define MEDIA_MUXERS_LIVE_WEBM_MUXER_DELEGATE_H_ #include "base/functional/callback.h" -#include "base/strings/string_piece.h" #include "base/thread_annotations.h" #include "media/base/media_export.h" #include "media/muxers/webm_muxer.h"
diff --git a/media/muxers/mp4_muxer_delegate.h b/media/muxers/mp4_muxer_delegate.h index 7c0aea1..33bf467 100644 --- a/media/muxers/mp4_muxer_delegate.h +++ b/media/muxers/mp4_muxer_delegate.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/sequence_checker.h" -#include "base/strings/string_piece.h" #include "base/thread_annotations.h" #include "base/time/time.h" #include "media/base/audio_encoder.h"
diff --git a/media/muxers/mp4_muxer_unittest.cc b/media/muxers/mp4_muxer_unittest.cc index da6e7b12..f460579 100644 --- a/media/muxers/mp4_muxer_unittest.cc +++ b/media/muxers/mp4_muxer_unittest.cc
@@ -13,7 +13,6 @@ #include "base/files/file_path.h" #include "base/files/memory_mapped_file.h" #include "base/path_service.h" -#include "base/strings/string_piece.h" #include "base/test/bind.h" #include "base/test/task_environment.h" #include "base/time/time.h"
diff --git a/media/renderers/win/media_foundation_protection_manager.cc b/media/renderers/win/media_foundation_protection_manager.cc index cd4b85d9..7ba50a6c 100644 --- a/media/renderers/win/media_foundation_protection_manager.cc +++ b/media/renderers/win/media_foundation_protection_manager.cc
@@ -8,7 +8,6 @@ #include <windows.foundation.h> #include "base/logging.h" -#include "base/strings/string_piece.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "base/win/core_winrt_util.h"
diff --git a/net/base/load_timing_info.h b/net/base/load_timing_info.h index a93f961..7a17540 100644 --- a/net/base/load_timing_info.h +++ b/net/base/load_timing_info.h
@@ -140,6 +140,8 @@ // Corresponds to |fetchStart| in ResourceTiming // (http://www.w3.org/TR/resource-timing/) for Web-surfacing requests. + // Note that this field is not used in ResourceTiming as |requestStart|, which + // has the same name but exposes a different field. base::TimeTicks request_start; // The time immediately before ServiceWorker static routing API starts
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 7895c59a..049d187a 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h
@@ -830,9 +830,7 @@ // The compression dictionary cannot be loaded. NET_ERROR(DICTIONARY_LOAD_FAILED, -387) -// The "content-dictionary" response header is unexpected. This is used both -// when there is no "content-dictionary" response header and when the received -// "content-dictionary" response header does not match the expected value. +// The header of dictionary compressed stream does not match the expected value. NET_ERROR(UNEXPECTED_CONTENT_DICTIONARY_HEADER, -388) // The cache does not have the requested entry.
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index 31daa37a72..6539330 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -248,6 +248,9 @@ // while resolution is still ongoing. In general, should be called only // after resolution completed. virtual ResolveErrorInfo GetResolveErrorInfo() = 0; + + // Change the priority of this request. + virtual void ChangeRequestPriority(RequestPriority priority) = 0; }; // Handler for an activation of probes controlled by a HostResolver. Created
diff --git a/net/dns/host_resolver_manager_job.cc b/net/dns/host_resolver_manager_job.cc index 7957ec4..75087f4 100644 --- a/net/dns/host_resolver_manager_job.cc +++ b/net/dns/host_resolver_manager_job.cc
@@ -300,6 +300,15 @@ } } +void HostResolverManager::Job::ChangeServiceEndpointRequestPriority( + ServiceEndpointRequestImpl* request, + RequestPriority priority) { + priority_tracker_.Remove(request->priority()); + request->set_priority(priority); + priority_tracker_.Add(request->priority()); + UpdatePriority(); +} + void HostResolverManager::Job::Abort() { CompleteRequestsWithError(ERR_NETWORK_CHANGED, /*task_type=*/std::nullopt); }
diff --git a/net/dns/host_resolver_manager_job.h b/net/dns/host_resolver_manager_job.h index d4ba4ca1..98ec65a 100644 --- a/net/dns/host_resolver_manager_job.h +++ b/net/dns/host_resolver_manager_job.h
@@ -96,6 +96,10 @@ // this job. void CancelServiceEndpointRequest(ServiceEndpointRequestImpl* request); + // Similar to ChangeRequestPriority(), but for a ServiceEndpointRequest. + void ChangeServiceEndpointRequestPriority(ServiceEndpointRequestImpl* request, + RequestPriority priority); + // Called from AbortJobsWithoutTargetNetwork(). Completes all requests and // destroys the job. This currently assumes the abort is due to a network // change.
diff --git a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc index 2678926..ea0547d 100644 --- a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc +++ b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
@@ -157,6 +157,16 @@ return error_info_; } +void HostResolverManager::ServiceEndpointRequestImpl::ChangeRequestPriority( + RequestPriority priority) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!job_.has_value()) { + priority_ = priority; + return; + } + job_.value()->ChangeServiceEndpointRequestPriority(this, priority); +} + void HostResolverManager::ServiceEndpointRequestImpl::AssignJob( base::SafeRef<Job> job) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/net/dns/host_resolver_manager_service_endpoint_request_impl.h b/net/dns/host_resolver_manager_service_endpoint_request_impl.h index 93b5c8e3..b3e2e35 100644 --- a/net/dns/host_resolver_manager_service_endpoint_request_impl.h +++ b/net/dns/host_resolver_manager_service_endpoint_request_impl.h
@@ -53,6 +53,7 @@ const std::set<std::string>& GetDnsAliasResults() override; bool EndpointsCryptoReady() override; ResolveErrorInfo GetResolveErrorInfo() override; + void ChangeRequestPriority(RequestPriority priority) override; // These should only be called from HostResolver::Job. void AssignJob(base::SafeRef<Job> job); @@ -64,8 +65,8 @@ const ResolveHostParameters& parameters() const { return parameters_; } - // TODO(crbug.com/41493696): Support setting priority. RequestPriority priority() const { return priority_; } + void set_priority(RequestPriority priority) { priority_ = priority; } HostCache* host_cache() const { return resolve_context_ ? resolve_context_->host_cache() : nullptr;
diff --git a/net/dns/host_resolver_service_endpoint_request_unittest.cc b/net/dns/host_resolver_service_endpoint_request_unittest.cc index 224f9318..a7e1d58d 100644 --- a/net/dns/host_resolver_service_endpoint_request_unittest.cc +++ b/net/dns/host_resolver_service_endpoint_request_unittest.cc
@@ -18,6 +18,7 @@ #include "net/base/features.h" #include "net/base/net_errors.h" #include "net/base/network_anonymization_key.h" +#include "net/base/request_priority.h" #include "net/dns/address_sorter.h" #include "net/dns/dns_task_results_manager.h" #include "net/dns/dns_test_util.h" @@ -936,4 +937,107 @@ EXPECT_THAT(*requester.finished_result(), IsOk()); } +TEST_F(HostResolverServiceEndpointRequestTest, ChangePriority) { + proc_->AddRuleForAllFamilies("req1", "192.0.2.1"); + proc_->AddRuleForAllFamilies("req2", "192.0.2.2"); + proc_->AddRuleForAllFamilies("req3", "192.0.2.3"); + + CreateSerialResolver(/*check_ipv6_on_wifi=*/true); + + // Start three requests with the same initial priority, then change the + // priority of the third request to HIGHEST. The first request starts + // immediately so it should finish first. The third request should finish + // second because its priority is changed to HIGHEST. The second request + // should finish last. + + ResolveHostParameters params; + params.initial_priority = RequestPriority::LOW; + + size_t request_finish_order = 0; + + Requester requester1 = CreateRequester("https://req1", params); + requester1.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 1u); + })); + int rv = requester1.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + Requester requester2 = CreateRequester("https://req2", params); + requester2.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 3u); + })); + rv = requester2.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + Requester requester3 = CreateRequester("https://req3", params); + requester3.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 2u); + })); + rv = requester3.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + requester3.request()->ChangeRequestPriority(RequestPriority::HIGHEST); + + proc_->SignalMultiple(3u); + + requester1.WaitForFinished(); + requester3.WaitForFinished(); + requester2.WaitForFinished(); +} + +TEST_F(HostResolverServiceEndpointRequestTest, ChangePriorityBeforeStart) { + proc_->AddRuleForAllFamilies("req1", "192.0.2.1"); + proc_->AddRuleForAllFamilies("req2", "192.0.2.2"); + proc_->AddRuleForAllFamilies("req3", "192.0.2.3"); + + CreateSerialResolver(/*check_ipv6_on_wifi=*/true); + + // Create three requests with the same initial priority, then change the + // priority of the third request to HIGHEST before starting the requests. The + // first request starts immediately so it should finish first. The third + // request should finish second because its priority is changed to HIGHEST. + // The second request should finish last. + + ResolveHostParameters params; + params.initial_priority = RequestPriority::LOW; + + size_t request_finish_order = 0; + + Requester requester1 = CreateRequester("https://req1", params); + requester1.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 1u); + })); + + Requester requester2 = CreateRequester("https://req2", params); + requester2.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 3u); + })); + + Requester requester3 = CreateRequester("https://req3", params); + requester3.SetOnFinishedCallback(base::BindLambdaForTesting([&] { + ++request_finish_order; + ASSERT_EQ(request_finish_order, 2u); + })); + + requester3.request()->ChangeRequestPriority(RequestPriority::HIGHEST); + + int rv = requester1.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = requester2.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = requester3.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + proc_->SignalMultiple(3u); + + requester1.WaitForFinished(); + requester3.WaitForFinished(); + requester2.WaitForFinished(); +} + } // namespace net
diff --git a/pdf/ink/BUILD.gn b/pdf/ink/BUILD.gn index deeb751..2ec48eab 100644 --- a/pdf/ink/BUILD.gn +++ b/pdf/ink/BUILD.gn
@@ -34,6 +34,8 @@ "ink_brush_tip.cc", "ink_brush_tip.h", "ink_in_progress_stroke.h", + "ink_intersects.h", + "ink_modeled_shape.h", "ink_skia_renderer.h", "ink_stroke.h", "ink_stroke_input.h",
diff --git a/pdf/ink/ink_intersects.h b/pdf/ink/ink_intersects.h new file mode 100644 index 0000000..c0e94c8 --- /dev/null +++ b/pdf/ink/ink_intersects.h
@@ -0,0 +1,20 @@ +// 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 PDF_INK_INK_INTERSECTS_H_ +#define PDF_INK_INK_INTERSECTS_H_ + +namespace chrome_pdf { + +class InkModeledShape; +struct InkAffineTransform; + +bool InkIntersectsPointWithShape(float point_x, + float point_y, + const InkModeledShape& shape, + const InkAffineTransform& transform); + +} // namespace chrome_pdf + +#endif // PDF_INK_INK_INTERSECTS_H_
diff --git a/pdf/ink/ink_modeled_shape.h b/pdf/ink/ink_modeled_shape.h new file mode 100644 index 0000000..425ae318b --- /dev/null +++ b/pdf/ink/ink_modeled_shape.h
@@ -0,0 +1,30 @@ +// 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 PDF_INK_INK_MODELED_SHAPE_H_ +#define PDF_INK_INK_MODELED_SHAPE_H_ + +#include <stdint.h> + +#include <vector> + +namespace chrome_pdf { + +class InkModeledShape { + public: + struct VertexIndexPair { + uint16_t mesh_index; + uint16_t vertex_index; + }; + using Outline = std::vector<VertexIndexPair>; + + virtual ~InkModeledShape() = default; + + virtual uint32_t RenderGroupCount() const = 0; + virtual std::vector<Outline> GetOutlines(uint32_t group_index) const = 0; +}; + +} // namespace chrome_pdf + +#endif // PDF_INK_INK_MODELED_SHAPE_H_
diff --git a/pdf/ink/ink_stroke.h b/pdf/ink/ink_stroke.h index d386871..34c7926 100644 --- a/pdf/ink/ink_stroke.h +++ b/pdf/ink/ink_stroke.h
@@ -7,12 +7,13 @@ namespace chrome_pdf { +class InkModeledShape; + class InkStroke { public: - ~InkStroke() = default; + virtual ~InkStroke() = default; - protected: - InkStroke() = default; + virtual const InkModeledShape* GetShape() const = 0; }; } // namespace chrome_pdf
diff --git a/pdf/ink/stub/BUILD.gn b/pdf/ink/stub/BUILD.gn index 70d171b..f8df4ac 100644 --- a/pdf/ink/stub/BUILD.gn +++ b/pdf/ink/stub/BUILD.gn
@@ -14,10 +14,15 @@ "ink_brush_stub.cc", "ink_in_progress_stroke_stub.cc", "ink_in_progress_stroke_stub.h", + "ink_intersects_stub.cc", + "ink_modeled_shape_stub.cc", + "ink_modeled_shape_stub.h", "ink_skia_renderer_stub.cc", "ink_skia_renderer_stub.h", "ink_stroke_input_batch_stub.cc", "ink_stroke_input_batch_stub.h", + "ink_stroke_stub.cc", + "ink_stroke_stub.h", ] configs += [ "//pdf:strict" ]
diff --git a/pdf/ink/stub/ink_in_progress_stroke_stub.cc b/pdf/ink/stub/ink_in_progress_stroke_stub.cc index e77ae06..29bb5ad6 100644 --- a/pdf/ink/stub/ink_in_progress_stroke_stub.cc +++ b/pdf/ink/stub/ink_in_progress_stroke_stub.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "pdf/ink/ink_stroke.h" +#include "pdf/ink/stub/ink_stroke_stub.h" namespace chrome_pdf { @@ -34,7 +34,7 @@ } std::unique_ptr<InkStroke> InkInProgressStrokeStub::CopyToStroke() const { - return nullptr; + return std::make_unique<InkStrokeStub>(); } } // namespace chrome_pdf
diff --git a/pdf/ink/stub/ink_intersects_stub.cc b/pdf/ink/stub/ink_intersects_stub.cc new file mode 100644 index 0000000..c73baa4 --- /dev/null +++ b/pdf/ink/stub/ink_intersects_stub.cc
@@ -0,0 +1,16 @@ +// 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 "pdf/ink/ink_intersects.h" + +namespace chrome_pdf { + +bool InkIntersectsPointWithShape(float point_x, + float point_y, + const InkModeledShape& shape, + const InkAffineTransform& transform) { + return false; +} + +} // namespace chrome_pdf
diff --git a/pdf/ink/stub/ink_modeled_shape_stub.cc b/pdf/ink/stub/ink_modeled_shape_stub.cc new file mode 100644 index 0000000..f247ccff --- /dev/null +++ b/pdf/ink/stub/ink_modeled_shape_stub.cc
@@ -0,0 +1,22 @@ +// 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 "pdf/ink/stub/ink_modeled_shape_stub.h" + +namespace chrome_pdf { + +InkModeledShapeStub::InkModeledShapeStub() = default; + +InkModeledShapeStub::~InkModeledShapeStub() = default; + +uint32_t InkModeledShapeStub::RenderGroupCount() const { + return 0; +} + +std::vector<InkModeledShape::Outline> InkModeledShapeStub::GetOutlines( + uint32_t group_index) const { + return {}; +} + +} // namespace chrome_pdf
diff --git a/pdf/ink/stub/ink_modeled_shape_stub.h b/pdf/ink/stub/ink_modeled_shape_stub.h new file mode 100644 index 0000000..3c144bb --- /dev/null +++ b/pdf/ink/stub/ink_modeled_shape_stub.h
@@ -0,0 +1,24 @@ +// 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 PDF_INK_STUB_INK_MODELED_SHAPE_STUB_H_ +#define PDF_INK_STUB_INK_MODELED_SHAPE_STUB_H_ + +#include "pdf/ink/ink_modeled_shape.h" + +namespace chrome_pdf { + +class InkModeledShapeStub : public InkModeledShape { + public: + InkModeledShapeStub(); + ~InkModeledShapeStub() override; + + // InkModeledShape: + uint32_t RenderGroupCount() const override; + std::vector<Outline> GetOutlines(uint32_t group_index) const override; +}; + +} // namespace chrome_pdf + +#endif // PDF_INK_STUB_INK_MODELED_SHAPE_STUB_H_
diff --git a/pdf/ink/stub/ink_stroke_stub.cc b/pdf/ink/stub/ink_stroke_stub.cc new file mode 100644 index 0000000..0e7fde9 --- /dev/null +++ b/pdf/ink/stub/ink_stroke_stub.cc
@@ -0,0 +1,22 @@ +// 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 "pdf/ink/stub/ink_stroke_stub.h" + +#include <memory> + +#include "pdf/ink/stub/ink_modeled_shape_stub.h" + +namespace chrome_pdf { + +InkStrokeStub::InkStrokeStub() + : shape_(std::make_unique<InkModeledShapeStub>()) {} + +InkStrokeStub::~InkStrokeStub() = default; + +const InkModeledShape* InkStrokeStub::GetShape() const { + return shape_.get(); +} + +} // namespace chrome_pdf
diff --git a/pdf/ink/stub/ink_stroke_stub.h b/pdf/ink/stub/ink_stroke_stub.h new file mode 100644 index 0000000..9fef7b3 --- /dev/null +++ b/pdf/ink/stub/ink_stroke_stub.h
@@ -0,0 +1,31 @@ +// 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 PDF_INK_STUB_INK_STROKE_STUB_H_ +#define PDF_INK_STUB_INK_STROKE_STUB_H_ + +#include <memory> + +#include "pdf/ink/ink_stroke.h" + +namespace chrome_pdf { + +class InkModeledShape; +class InkModeledShapeStub; + +class InkStrokeStub : public InkStroke { + public: + InkStrokeStub(); + ~InkStrokeStub() override; + + // InkStroke: + const InkModeledShape* GetShape() const override; + + private: + const std::unique_ptr<InkModeledShapeStub> shape_; +}; + +} // namespace chrome_pdf + +#endif // PDF_INK_STUB_INK_STROKE_STUB_H_
diff --git a/pdf/ink_module.cc b/pdf/ink_module.cc index eb68ca691..f1dfb1e 100644 --- a/pdf/ink_module.cc +++ b/pdf/ink_module.cc
@@ -5,7 +5,6 @@ #include "pdf/ink_module.h" #include <memory> -#include <numbers> #include <optional> #include <string> #include <string_view> @@ -18,14 +17,12 @@ #include "base/time/time.h" #include "base/values.h" #include "pdf/ink/ink_brush.h" -#include "pdf/ink/ink_brush_family.h" -#include "pdf/ink/ink_brush_paint.h" -#include "pdf/ink/ink_brush_tip.h" #include "pdf/ink/ink_in_progress_stroke.h" #include "pdf/ink/ink_stroke.h" #include "pdf/ink/ink_stroke_input_batch.h" #include "pdf/input_utils.h" #include "pdf/pdf_features.h" +#include "pdf/pdf_ink_brush.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/common/input/web_mouse_event.h" #include "third_party/skia/include/core/SkColor.h" @@ -36,54 +33,36 @@ namespace { -std::string CreateBrushUri() { - // TODO(crbug.com/335524380): Use real value here. - return "ink://ink/texture:test-texture"; -} - -std::unique_ptr<InkBrush> CreateBrush() { - // TODO(crbug.com/335524380): Use real values here. - InkBrushTip tip; - tip.corner_rounding = 0; - tip.opacity_multiplier = 1.0f; - - InkBrushPaint::TextureLayer layer; - layer.color_texture_uri = CreateBrushUri(); - layer.mapping = InkBrushPaint::TextureMapping::kWinding; - layer.size_unit = InkBrushPaint::TextureSizeUnit::kBrushSize; - layer.size_x = 3; - layer.size_y = 5; - layer.size_jitter_x = 0.1; - layer.size_jitter_y = 2; - layer.keyframes = { - {.progress = 0.1, .rotation_in_radians = std::numbers::pi_v<float> / 4}}; - layer.blend_mode = InkBrushPaint::BlendMode::kSrcIn; - - InkBrushPaint paint; - paint.texture_layers.push_back(layer); - auto family = InkBrushFamily::Create(tip, paint, ""); - CHECK(family); - return InkBrush::Create(std::move(family), - /*color=*/SkColorSetRGB(0x18, 0x80, 0x38), - /*size=*/1.0f, /*epsilon=*/0.1f); +// Default to a black pen brush. +std::unique_ptr<PdfInkBrush> CreateDefaultBrush() { + const PdfInkBrush::Params kDefaultBrushParams = {SK_ColorBLACK, 1.0f}; + return std::make_unique<PdfInkBrush>(PdfInkBrush::Type::kPen, + kDefaultBrushParams); } } // namespace -InkModule::InkModule(Client& client) : client_(client) { +InkModule::InkModule(Client& client) + : client_(client), pdf_ink_brush_(CreateDefaultBrush()) { CHECK(base::FeatureList::IsEnabled(features::kPdfInk2)); } InkModule::~InkModule() = default; void InkModule::Draw(SkCanvas& canvas) { + // TODO(crbug.com/335524381): Strokes should still be drawn, even when the + // brush type is eraser. + if (!pdf_ink_brush_) { + return; + } + auto stroke = InkInProgressStroke::Create(); // TODO(crbug.com/339682315): This should not fail with the wrapper. if (!stroke) { return; } - std::unique_ptr<InkBrush> brush = CreateBrush(); + std::unique_ptr<InkBrush> brush = pdf_ink_brush_->CreateInkBrush(); CHECK(brush); stroke->Start(*brush); auto input_batch = InkStrokeInputBatch::Create(ink_inputs_); @@ -212,9 +191,13 @@ } void InkModule::ConvertInkInputsIntoStroke() { + if (!pdf_ink_brush_) { + return; + } + auto stroke = InkInProgressStroke::Create(); CHECK(stroke); - std::unique_ptr<InkBrush> brush = CreateBrush(); + std::unique_ptr<InkBrush> brush = pdf_ink_brush_->CreateInkBrush(); CHECK(brush); stroke->Start(*brush); // TODO(crbug.com/335524380): Add `event` to `ink_inputs_`?
diff --git a/pdf/ink_module.h b/pdf/ink_module.h index c463ba3..bb47a859 100644 --- a/pdf/ink_module.h +++ b/pdf/ink_module.h
@@ -31,6 +31,7 @@ namespace chrome_pdf { class InkStroke; +class PdfInkBrush; class InkModule { public: @@ -74,6 +75,9 @@ bool enabled_ = false; + // The current brush to use for drawing strokes. + std::unique_ptr<PdfInkBrush> pdf_ink_brush_; + // Set when InkModule is in the middle of drawing a stroke. std::optional<base::Time> ink_start_time_; std::vector<InkStrokeInput> ink_inputs_;
diff --git a/pdf/pdf_ink_brush.cc b/pdf/pdf_ink_brush.cc index c612c3a5..1e24a15 100644 --- a/pdf/pdf_ink_brush.cc +++ b/pdf/pdf_ink_brush.cc
@@ -4,12 +4,26 @@ #include "pdf/pdf_ink_brush.h" +#include <numbers> #include <optional> #include "base/check_op.h" +#include "pdf/ink/ink_brush.h" +#include "pdf/ink/ink_brush_family.h" +#include "pdf/ink/ink_brush_paint.h" +#include "pdf/ink/ink_brush_tip.h" namespace chrome_pdf { +namespace { + +std::string CreateBrushUri() { + // TODO(crbug.com/335524380): Use real value here. + return "ink://ink/texture:test-texture"; +} + +} // namespace + // static std::optional<PdfInkBrush::Type> PdfInkBrush::StringToType( const std::string& brush_type) { @@ -30,8 +44,32 @@ PdfInkBrush::~PdfInkBrush() = default; std::unique_ptr<InkBrush> PdfInkBrush::CreateInkBrush() { - // TODO(crbug.com/335524382): Implement this. - return nullptr; + // TODO(crbug.com/335524380): Use real values here. + InkBrushTip tip; + tip.corner_rounding = 0; + tip.opacity_multiplier = 1.0f; + + InkBrushPaint::TextureLayer layer; + layer.color_texture_uri = CreateBrushUri(); + layer.mapping = InkBrushPaint::TextureMapping::kWinding; + layer.size_unit = InkBrushPaint::TextureSizeUnit::kBrushSize; + layer.size_x = 3; + layer.size_y = 5; + layer.size_jitter_x = 0.1; + layer.size_jitter_y = 2; + layer.keyframes = { + {.progress = 0.1, .rotation_in_radians = std::numbers::pi_v<float> / 4}}; + layer.blend_mode = InkBrushPaint::BlendMode::kSrcIn; + + InkBrushPaint paint; + paint.texture_layers.push_back(layer); + auto family = InkBrushFamily::Create(tip, paint, ""); + CHECK(family); + + // TODO(crbug.com/335524382): Use the color and size fields in `PdfInkBrush`. + return InkBrush::Create(std::move(family), + /*color=*/SkColorSetRGB(0x18, 0x80, 0x38), + /*size=*/1.0f, /*epsilon=*/0.1f); } } // namespace chrome_pdf
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc index 39611d06..75fb08dd 100644 --- a/printing/backend/print_backend_cups.cc +++ b/printing/backend/print_backend_cups.cc
@@ -26,12 +26,12 @@ #include "printing/mojom/print.mojom.h" #include "url/gurl.h" -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) #include "base/feature_list.h" #include "printing/backend/cups_connection.h" #include "printing/backend/print_backend_cups_ipp.h" #include "printing/printing_features.h" -#endif // BUILDFLAG(IS_MAC) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) namespace printing { @@ -296,11 +296,11 @@ #if !BUILDFLAG(IS_CHROMEOS) scoped_refptr<PrintBackend> PrintBackend::CreateInstanceImpl( const std::string& locale) { -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) if (base::FeatureList::IsEnabled(features::kCupsIppPrintingBackend)) { return base::MakeRefCounted<PrintBackendCupsIpp>(CupsConnection::Create()); } -#endif // BUILDFLAG(IS_MAC) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) return base::MakeRefCounted<PrintBackendCUPS>( GURL(), HTTP_ENCRYPT_NEVER, /*cups_blocking=*/false, locale); }
diff --git a/printing/buildflags/buildflags.gni b/printing/buildflags/buildflags.gni index db99fe1..db5972aa 100644 --- a/printing/buildflags/buildflags.gni +++ b/printing/buildflags/buildflags.gni
@@ -63,5 +63,5 @@ declare_args() { # Enables the CUPS IPP printing backend. # TODO(crbug.com/41003486): Remove this after CUPS PPD API calls are removed. - use_cups_ipp = use_cups && !is_linux + use_cups_ipp = use_cups }
diff --git a/printing/printing_features.cc b/printing/printing_features.cc index 56bdf4d..b0eaa0d 100644 --- a/printing/printing_features.cc +++ b/printing/printing_features.cc
@@ -21,13 +21,18 @@ base::FEATURE_ENABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_CHROMEOS) -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) // Use the CUPS IPP printing backend instead of the original CUPS backend that // calls the deprecated PPD API. BASE_FEATURE(kCupsIppPrintingBackend, "CupsIppPrintingBackend", - base::FEATURE_ENABLED_BY_DEFAULT); -#endif // BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) + base::FEATURE_DISABLED_BY_DEFAULT +#else + base::FEATURE_ENABLED_BY_DEFAULT +#endif +); +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_WIN) // When using PostScript level 3 printing, render text with Type 42 fonts if
diff --git a/printing/printing_features.h b/printing/printing_features.h index ed2ed38..37e9706 100644 --- a/printing/printing_features.h +++ b/printing/printing_features.h
@@ -22,9 +22,9 @@ BASE_DECLARE_FEATURE(kAddPrinterViaPrintscanmgr); #endif // BUILDFLAG(IS_CHROMEOS) -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) COMPONENT_EXPORT(PRINTING_BASE) BASE_DECLARE_FEATURE(kCupsIppPrintingBackend); -#endif // BUILDFLAG(IS_MAC) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_WIN) COMPONENT_EXPORT(PRINTING_BASE)
diff --git a/services/network/public/cpp/content_security_policy/csp_source.cc b/services/network/public/cpp/content_security_policy/csp_source.cc index 3d4c4cd..42f7a547 100644 --- a/services/network/public/cpp/content_security_policy/csp_source.cc +++ b/services/network/public/cpp/content_security_policy/csp_source.cc
@@ -13,6 +13,7 @@ #include "services/network/public/cpp/content_security_policy/content_security_policy.h" #include "services/network/public/mojom/content_security_policy.mojom.h" #include "url/url_canon.h" +#include "url/url_features.h" #include "url/url_util.h" namespace network { @@ -85,7 +86,17 @@ } bool SourceAllowHost(const mojom::CSPSource& source, const GURL& url) { - return SourceAllowHost(source, url.host()); + // Chromium currently has an issue handling non-special URLs. The url.host() + // function returns an empty string for them. See + // crbug.com/40063064 for details. + // + // In the future, once non-special URLs are fully supported, we might consider + // checking the host information for them too. + // + // For now, we check `url.IsStandard()` to maintain consistent behavior + // regardless of the url::StandardCompliantNonSpecialSchemeURLParsing feature + // state. + return SourceAllowHost(source, url.IsStandard() ? url.host() : ""); } PortMatchingResult SourceAllowPort(const mojom::CSPSource& source,
diff --git a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc index bda0b696..0426a2c 100644 --- a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc +++ b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
@@ -3,10 +3,13 @@ // found in the LICENSE file. #include "services/network/public/cpp/content_security_policy/csp_source.h" + +#include "base/test/scoped_feature_list.h" #include "net/http/http_response_headers.h" #include "services/network/public/cpp/content_security_policy/content_security_policy.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/origin.h" +#include "url/url_features.h" namespace network { @@ -27,29 +30,47 @@ policies[0]->directives[mojom::CSPDirectiveName::ScriptSrc]->sources[0]); } +enum class NonSpecialUrlBehavior { Compliant, NonCompliant }; + } // namespace -class CSPSourceTest : public testing::TestWithParam<CSPSourceContext> { +class CSPSourceTest : public testing::TestWithParam< + std::tuple<CSPSourceContext, NonSpecialUrlBehavior>> { public: + CSPSourceTest() { + scoped_feature_list_.InitWithFeatureState( + url::kStandardCompliantNonSpecialSchemeURLParsing, + std::get<1>(GetParam()) == NonSpecialUrlBehavior::Compliant); + } + bool Allow(const network::mojom::CSPSource& source, const GURL& url, const network::mojom::CSPSource& self_source = no_self, bool is_redirect = false, bool is_opaque_fenced_frame = false) { - return CheckCSPSource(source, url, self_source, GetParam(), is_redirect, - is_opaque_fenced_frame); + return CheckCSPSource(source, url, self_source, std::get<0>(GetParam()), + is_redirect, is_opaque_fenced_frame); } bool IsPermissionsPolicyContext() { - return GetParam() == CSPSourceContext::PermissionsPolicy; + return std::get<0>(GetParam()) == CSPSourceContext::PermissionsPolicy; } + + bool UseStandardCompliantNonSpecialSchemeUrlParsing() { + return std::get<1>(GetParam()) == NonSpecialUrlBehavior::Compliant; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; INSTANTIATE_TEST_SUITE_P( All, CSPSourceTest, - ::testing::Values(CSPSourceContext::ContentSecurityPolicy, - CSPSourceContext::PermissionsPolicy)); + ::testing::Combine(testing::Values(CSPSourceContext::ContentSecurityPolicy, + CSPSourceContext::PermissionsPolicy), + testing::Values(NonSpecialUrlBehavior::Compliant, + NonSpecialUrlBehavior::NonCompliant))); TEST_P(CSPSourceTest, BasicMatching) { auto source = network::mojom::CSPSource::New("http", "example.com", 8000, @@ -673,13 +694,7 @@ auto csp_source = CSPSource(uri); auto url = GURL(uri); - // Most URI schemes do not define a host part. As a result, contrary to - // CSPSource, the GURL do not populate the host when the scheme is unknown. - // See also: https://crbug.com/1236651 - EXPECT_EQ("", url.host()); EXPECT_EQ("a", csp_source->host); - - // ... as a result the URL doesn't match the CSPSource. EXPECT_FALSE(Allow(*csp_source, url)); // It is still possible for developers to use a scheme-only CSPSource.
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index 5c699d8d..47966eb 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -389,7 +389,7 @@ // * The network service loads the metadata database. // * If there is a matching dictionary for a sending request, it adds the // `sec-available-dictionary` header. -// * And if the `content-encoding` header of the response is `sbr`, it +// * And if the `content-encoding` header of the response is `dcb`, it // decompresses the response body using the dictionary. BASE_FEATURE(kCompressionDictionaryTransportBackend, "CompressionDictionaryTransportBackend",
diff --git a/services/network/public/cpp/shared_dictionary_encoding_names.cc b/services/network/public/cpp/shared_dictionary_encoding_names.cc index 0fe0903..c893628e 100644 --- a/services/network/public/cpp/shared_dictionary_encoding_names.cc +++ b/services/network/public/cpp/shared_dictionary_encoding_names.cc
@@ -9,11 +9,11 @@ namespace network { const char* GetSharedBrotliContentEncodingName() { - return "br-d"; + return "dcb"; } const char* GetSharedZstdContentEncodingName() { - return "zstd-d"; + return "dcz"; } } // namespace network
diff --git a/services/network/public/cpp/shared_dictionary_encoding_names.h b/services/network/public/cpp/shared_dictionary_encoding_names.h index cb54b00..7bfbe56 100644 --- a/services/network/public/cpp/shared_dictionary_encoding_names.h +++ b/services/network/public/cpp/shared_dictionary_encoding_names.h
@@ -9,10 +9,10 @@ namespace network { -// Returns the content encoding name of Shared Brotli: "br-d" +// Returns the content encoding name of Dictionary-Compressed Brotli: "dcb" COMPONENT_EXPORT(NETWORK_CPP) const char* GetSharedBrotliContentEncodingName(); -// Returns the content encoding name of Shared Zstd: "zstd-d". +// Returns the content encoding name of Dictionary-Compressed Zstandard: "dcz". COMPONENT_EXPORT(NETWORK_CPP) const char* GetSharedZstdContentEncodingName(); } // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.cc b/services/network/shared_dictionary/shared_dictionary_constants.cc index 44dca4d8..f4237fe 100644 --- a/services/network/shared_dictionary/shared_dictionary_constants.cc +++ b/services/network/shared_dictionary/shared_dictionary_constants.cc
@@ -18,7 +18,6 @@ const char kAvailableDictionaryHeaderName[] = "available-dictionary"; const char kUseAsDictionaryHeaderName[] = "use-as-dictionary"; -const char kContentDictionaryHeaderName[] = "content-dictionary"; const char kOptionNameMatch[] = "match"; const char kOptionNameMatchDest[] = "match-dest"; const char kOptionNameType[] = "type";
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.h b/services/network/shared_dictionary/shared_dictionary_constants.h index 721245f..f89d1c7f 100644 --- a/services/network/shared_dictionary/shared_dictionary_constants.h +++ b/services/network/shared_dictionary/shared_dictionary_constants.h
@@ -38,10 +38,6 @@ COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kUseAsDictionaryHeaderName[]; -// The header name of "content-dictionary". -COMPONENT_EXPORT(NETWORK_SERVICE) -extern const char kContentDictionaryHeaderName[]; - // The dictionary option name of "match". COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameMatch[];
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc index 2515f5a..3e49775 100644 --- a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc +++ b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
@@ -41,6 +41,7 @@ #include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "services/network/shared_dictionary/shared_dictionary.h" #include "services/network/shared_dictionary/shared_dictionary_constants.h" +#include "services/network/shared_dictionary/shared_dictionary_header_checker_source_stream.h" #include "services/network/shared_dictionary/shared_dictionary_manager.h" #include "services/network/shared_dictionary/shared_dictionary_storage.h" @@ -138,36 +139,19 @@ net_log); } -base::expected<SharedDictionaryNetworkTransaction::SharedDictionaryEncodingType, - net::Error> +SharedDictionaryNetworkTransaction::SharedDictionaryEncodingType SharedDictionaryNetworkTransaction::ParseSharedDictionaryEncodingType( const net::HttpResponseHeaders& headers) { - SharedDictionaryEncodingType result = SharedDictionaryEncodingType::kNotUsed; - std::string content_encoding; if (!headers.GetNormalizedHeader("Content-Encoding", &content_encoding)) { - result = SharedDictionaryEncodingType::kNotUsed; + return SharedDictionaryEncodingType::kNotUsed; } else if (content_encoding == GetSharedBrotliContentEncodingName()) { - result = SharedDictionaryEncodingType::kSharedBrotli; + return SharedDictionaryEncodingType::kSharedBrotli; } else if (base::FeatureList::IsEnabled(network::features::kSharedZstd) && content_encoding == GetSharedZstdContentEncodingName()) { - result = SharedDictionaryEncodingType::kSharedZstd; + return SharedDictionaryEncodingType::kSharedZstd; } - - // Check "Content-Dictionary" header when the content encoding indicates that - // a dictionary is used. - if (result != SharedDictionaryEncodingType::kNotUsed) { - CHECK(!dictionary_hash_base64_.empty()); - std::string content_dictionary; - if (!headers.GetNormalizedHeader( - shared_dictionary::kContentDictionaryHeaderName, - &content_dictionary) || - dictionary_hash_base64_ != content_dictionary) { - return base::unexpected(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER); - } - } - - return result; + return SharedDictionaryEncodingType::kNotUsed; } void SharedDictionaryNetworkTransaction::OnStartCompleted( @@ -187,14 +171,8 @@ return; } - auto parse_result = ParseSharedDictionaryEncodingType( + shared_dictionary_encoding_type_ = ParseSharedDictionaryEncodingType( *network_transaction_->GetResponseInfo()->headers); - if (!parse_result.has_value()) { - std::move(callback).Run(parse_result.error()); - return; - } - - shared_dictionary_encoding_type_ = parse_result.value(); if (shared_dictionary_encoding_type_ == SharedDictionaryEncodingType::kNotUsed) { std::move(callback).Run(result); @@ -391,6 +369,20 @@ return net::ERR_IO_PENDING; case DictionaryStatus::kFinished: if (!shared_compression_stream_) { + // Wrap the source `network_transaction_` with a + // SharedDictionaryHeaderCheckerSourceStream to check the header + // of Dictionary-Compressed stream. + std::unique_ptr<net::SourceStream> header_checker_source_stream = + std::make_unique<SharedDictionaryHeaderCheckerSourceStream>( + std::make_unique<ProxyingSourceStream>( + network_transaction_.get()), + shared_dictionary_encoding_type_ == + SharedDictionaryEncodingType::kSharedBrotli + ? SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedBrotli + : SharedDictionaryHeaderCheckerSourceStream::Type:: + kDictionaryCompressedZstd, + shared_dictionary_->hash()); if (shared_dictionary_encoding_type_ == SharedDictionaryEncodingType::kSharedBrotli) { SCOPED_UMA_HISTOGRAM_TIMER_MICROS( @@ -398,8 +390,7 @@ "CreateBrotliSourceStreamWithDictionary"); shared_compression_stream_ = net::CreateBrotliSourceStreamWithDictionary( - std::make_unique<ProxyingSourceStream>( - network_transaction_.get()), + std::move(header_checker_source_stream), shared_dictionary_->data(), shared_dictionary_->size()); } else if (shared_dictionary_encoding_type_ == SharedDictionaryEncodingType::kSharedZstd) { @@ -407,8 +398,7 @@ "Network.SharedDictionary.CreateZstdSourceStreamWithDictionary"); shared_compression_stream_ = net::CreateZstdSourceStreamWithDictionary( - std::make_unique<ProxyingSourceStream>( - network_transaction_.get()), + std::move(header_checker_source_stream), shared_dictionary_->data(), shared_dictionary_->size()); }
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction.h b/services/network/shared_dictionary/shared_dictionary_network_transaction.h index 3de3c51..4d3d19c 100644 --- a/services/network/shared_dictionary/shared_dictionary_network_transaction.h +++ b/services/network/shared_dictionary/shared_dictionary_network_transaction.h
@@ -39,9 +39,9 @@ // that will be called just before the request is sent to the network. When this // callback is called, this class tries to get a registered dictionary from the // `shared_dictionary_manager`. If a matching dictionary is found, and the -// "content-encoding" header of the response from the server is "sbr", this -// class will decode the response body using a `BrotliSourceStream` with the -// dictionary. +// "content-encoding" header of the response from the server is "dcb" or "dcz", +// this class will decode the response body using a `BrotliSourceStream` or +// `ZstdSourceStream` with the dictionary. class COMPONENT_EXPORT(NETWORK_SERVICE) SharedDictionaryNetworkTransaction : public net::HttpTransaction { public: @@ -136,8 +136,8 @@ net::CompletionOnceCallback callback; }; - base::expected<SharedDictionaryEncodingType, net::Error> - ParseSharedDictionaryEncodingType(const net::HttpResponseHeaders& headers); + SharedDictionaryEncodingType ParseSharedDictionaryEncodingType( + const net::HttpResponseHeaders& headers); void OnStartCompleted(net::CompletionOnceCallback callback, int result);
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc b/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc index 3eabaa44..6e75f5b 100644 --- a/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc
@@ -51,11 +51,16 @@ // kBrotliEncodedData is generated using the following commands: // $ echo -n "HelloHallo你好こんにちは" > /tmp/dict // $ echo -n "HelloこんにちはHallo你好HelloこんにちはHallo你好" > /tmp/data -// $ brotli -o /tmp/out.sbr -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.sbr -const uint8_t kBrotliEncodedData[] = {0xa1, 0xe8, 0x01, 0x00, 0x22, 0x8d, 0x54, - 0xc6, 0xf6, 0x26, 0x81, 0x69, 0x46, 0x9d, - 0xb2, 0x60, 0x0e, 0x6b, 0xf5, 0x07, 0x02}; +// $ echo -en '\xffDCB' > /tmp/out.dcb +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb +// $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb +// $ xxd -i /tmp/out.dcb +const uint8_t kBrotliEncodedData[] = { + 0xff, 0x44, 0x43, 0x42, 0xc1, 0x97, 0x28, 0xae, 0xd3, 0x65, 0x03, 0xcf, + 0xc8, 0x1a, 0x0f, 0x53, 0x59, 0xe6, 0xf4, 0x72, 0xe1, 0x21, 0xf7, 0x7b, + 0xf2, 0x0a, 0x2f, 0xaa, 0xc7, 0x99, 0x41, 0x91, 0x29, 0x3c, 0x06, 0x23, + 0xa1, 0xe8, 0x01, 0x00, 0x22, 0x8d, 0x54, 0xc6, 0xf6, 0x26, 0x81, 0x69, + 0x46, 0x9d, 0xb2, 0x60, 0x0e, 0x6b, 0xf5, 0x07, 0x02}; const std::string kBrotliEncodedDataString = std::string(reinterpret_cast<const char*>(kBrotliEncodedData), sizeof(kBrotliEncodedData)); @@ -65,11 +70,17 @@ // kZstdEncodedData is generated using the following commands: // $ echo -n "HelloHallo你好こんにちは" > /tmp/dict // $ echo -n "HelloこんにちはHallo你好HelloこんにちはHallo你好" > /tmp/data -// $ zstd -o /tmp/out.szst -D /tmp/dict /tmp/data -// $ xxd -i /tmp/out.szst +// $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz +// $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz +// $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data +// $ cat /tmp/tmp.zstd >> /tmp/out.dcz +// $ xxd -i /tmp/out.dcz const uint8_t kZstdEncodedData[] = { - 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3e, 0x85, 0x00, 0x00, 0x28, - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x03, 0x00, 0x42, 0x35, 0x88, + 0x5e, 0x2a, 0x4d, 0x18, 0x20, 0x00, 0x00, 0x00, 0xc1, 0x97, 0x28, 0xae, + 0xd3, 0x65, 0x03, 0xcf, 0xc8, 0x1a, 0x0f, 0x53, 0x59, 0xe6, 0xf4, 0x72, + 0xe1, 0x21, 0xf7, 0x7b, 0xf2, 0x0a, 0x2f, 0xaa, 0xc7, 0x99, 0x41, 0x91, + 0x29, 0x3c, 0x06, 0x23, 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3e, 0x85, 0x00, + 0x00, 0x28, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x03, 0x00, 0x42, 0x35, 0x88, 0x6a, 0x03, 0x87, 0x4c, 0x2d, 0xcd, 0x1e, 0xde, 0x25}; const std::string kZstdEncodedDataString = std::string(reinterpret_cast<const char*>(kZstdEncodedData), @@ -274,9 +285,7 @@ .load_flags = net::LOAD_CAN_USE_SHARED_DICTIONARY, .transport_info = TestSpdyTransportInfo(), .status = "HTTP/1.1 200 OK", - .response_headers = - "content-encoding: br-d\n" - "content-dictionary: :wZcortNlA8/IGg9TWeb0cuEh93vyCi+qx5lBkSk8BiM=:\n", + .response_headers = "content-encoding: dcb\n", .response_time = base::Time(), .data = "", // We set the body in the `handler` function. .dns_aliases = {}, @@ -300,9 +309,7 @@ .load_flags = net::LOAD_CAN_USE_SHARED_DICTIONARY, .transport_info = TestSpdyTransportInfo(), .status = "HTTP/1.1 200 OK", - .response_headers = - "content-encoding: zstd-d\n" - "content-dictionary: :wZcortNlA8/IGg9TWeb0cuEh93vyCi+qx5lBkSk8BiM=:\n", + .response_headers = "content-encoding: dcz\n", .response_time = base::Time(), .data = "", // We set the body in the `handler` function. .dns_aliases = {}, @@ -748,7 +755,7 @@ base::MakeRefCounted<DummySharedDictionaryStorage>( std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - // Change MockTransaction to remove `content-encoding: sbr`. + // Change MockTransaction to remove `content-encoding: dcb`. scoped_mock_transaction_->response_headers = ""; net::MockHttpRequest request(*scoped_mock_transaction_); @@ -771,19 +778,26 @@ net::test::IsError(net::ERR_IO_PENDING)); int read_result = read_callback.WaitForResult(); - // When there is no "content-encoding: sbr" header, + // When there is no "content-encoding: dcb" header, // SharedDictionaryNetworkTransaction must not decode the body. EXPECT_THAT(read_result, kBrotliEncodedDataString.size()); EXPECT_EQ(kBrotliEncodedDataString, std::string(buf->data(), read_result)); } -TEST_F(SharedDictionaryNetworkTransactionTest, NoContentDictionary) { +TEST_F(SharedDictionaryNetworkTransactionTest, WrongContentDictionaryHeader) { DummySharedDictionaryManager manager( base::MakeRefCounted<DummySharedDictionaryStorage>( std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - // Change MockTransaction to remove "content-dictionary" header. - scoped_mock_transaction_->response_headers = "content-encoding: br-d\n"; + scoped_mock_transaction_->handler = base::BindRepeating( + [](const net::HttpRequestInfo* request, std::string* response_status, + std::string* response_headers, std::string* response_data) { + std::string data = kBrotliEncodedDataString; + // Change the first byte of the compressed data to trigger + // UNEXPECTED_CONTENT_DICTIONARY_HEADER error. + ++data[0]; + *response_data = data; + }); net::MockHttpRequest request(*scoped_mock_transaction_); SharedDictionaryNetworkTransaction transaction(manager, @@ -792,52 +806,26 @@ base::BindRepeating([]() { return true; })); net::TestCompletionCallback start_callback; - ASSERT_THAT(transaction.Start(&request, start_callback.callback(), - net::NetLogWithSource()), - net::test::IsError(net::ERR_IO_PENDING)); - EXPECT_THAT( - start_callback.WaitForResult(), + ASSERT_THAT( + start_callback.GetResult(transaction.Start( + &request, start_callback.callback(), net::NetLogWithSource())), + net::test::IsError(net::OK)); + scoped_refptr<net::IOBufferWithSize> buf = + base::MakeRefCounted<net::IOBufferWithSize>(kDefaultBufferSize); + net::TestCompletionCallback read_callback; + ASSERT_THAT( + read_callback.GetResult( + transaction.Read(buf.get(), buf->size(), read_callback.callback())), net::test::IsError(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER)); } - -TEST_F(SharedDictionaryNetworkTransactionTest, WrongContentDictionary) { - DummySharedDictionaryManager manager( - base::MakeRefCounted<DummySharedDictionaryStorage>( - std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - - // Change MockTransaction to change the "content-dictionary" header. - // The hash `kTestDictionaryData` is - // ":wZcortNlA8/IGg9TWeb0cuEh93vyCi+qx5lBkSk8BiM=:". But the header contains - // "content-dictionary" header with a different hash - // ":U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:". - scoped_mock_transaction_->response_headers = - "content-encoding: br-d\n" - "content-dictionary: " - ":U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:\n"; - - net::MockHttpRequest request(*scoped_mock_transaction_); - SharedDictionaryNetworkTransaction transaction(manager, - CreateNetworkTransaction()); - transaction.SetIsSharedDictionaryReadAllowedCallback( - base::BindRepeating([]() { return true; })); - - net::TestCompletionCallback start_callback; - ASSERT_THAT(transaction.Start(&request, start_callback.callback(), - net::NetLogWithSource()), - net::test::IsError(net::ERR_IO_PENDING)); - EXPECT_THAT( - start_callback.WaitForResult(), - net::test::IsError(net::ERR_UNEXPECTED_CONTENT_DICTIONARY_HEADER)); -} - TEST_F(SharedDictionaryNetworkTransactionTest, MultipleContentEncodingWithSbr) { DummySharedDictionaryManager manager( base::MakeRefCounted<DummySharedDictionaryStorage>( std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - // Change MockTransaction to set `content-encoding: sbr, deflate`. + // Change MockTransaction to set `content-encoding: dcb, deflate`. scoped_mock_transaction_->response_headers = - "content-encoding: sbr, deflate\n"; + "content-encoding: dcb, deflate\n"; net::MockHttpRequest request(*scoped_mock_transaction_); SharedDictionaryNetworkTransaction transaction(manager, @@ -859,7 +847,7 @@ net::test::IsError(net::ERR_IO_PENDING)); int read_result = read_callback.WaitForResult(); - // When there is Content-Encoding header which value is other than "sbr", + // When there is Content-Encoding header which value is other than "dcb", // SharedDictionaryNetworkTransaction must not decode the body. EXPECT_THAT(read_result, kBrotliEncodedDataString.size()); EXPECT_EQ(kBrotliEncodedDataString, std::string(buf->data(), read_result)); @@ -1157,7 +1145,7 @@ base::MakeRefCounted<DummySharedDictionaryStorage>( std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - // Override MockTransaction to use `content-encoding: zstd-d`. + // Override MockTransaction to use `content-encoding: dcz`. scoped_mock_transaction_.reset(); net::ScopedMockTransaction new_mock_transaction( kZstdDictionaryTestTransaction); @@ -1193,7 +1181,7 @@ base::MakeRefCounted<DummySharedDictionaryStorage>( std::make_unique<DummySyncDictionary>(kTestDictionaryData))); - // Change MockTransaction to remove `content-encoding: zstd-d`. + // Change MockTransaction to remove `content-encoding: dcz`. scoped_mock_transaction_.reset(); net::ScopedMockTransaction scoped_mock_transaction( kZstdDictionaryTestTransaction); @@ -1219,7 +1207,7 @@ net::test::IsError(net::ERR_IO_PENDING)); int read_result = read_callback.WaitForResult(); - // When there is no "content-encoding: zstd-d" header, + // When there is no "content-encoding: dcz" header, // SharedDictionaryNetworkTransaction must not decode the body. EXPECT_THAT(read_result, kZstdEncodedDataString.size()); EXPECT_EQ(kZstdEncodedDataString, std::string(buf->data(), read_result));
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc index 5da3a66..7332b13 100644 --- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc +++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -633,6 +633,25 @@ frame, output)); } +TEST_F(StructTraitsTest, ViewTransitionElementResourceId) { + ViewTransitionElementResourceId empty_id; + ASSERT_FALSE(empty_id.IsValid()); + ViewTransitionElementResourceId empty_output_id; + ASSERT_TRUE( + mojo::test::SerializeAndDeserialize< + mojom::ViewTransitionElementResourceId>(empty_id, empty_output_id)); + ASSERT_FALSE(empty_output_id.IsValid()); + + ViewTransitionElementResourceId valid_id(blink::ViewTransitionToken(), 2u); + ASSERT_TRUE(valid_id.IsValid()); + ViewTransitionElementResourceId valid_output_id; + ASSERT_TRUE( + mojo::test::SerializeAndDeserialize< + mojom::ViewTransitionElementResourceId>(valid_id, valid_output_id)); + ASSERT_TRUE(valid_output_id.IsValid()); + ASSERT_EQ(valid_output_id, valid_id); +} + TEST_F(StructTraitsTest, SurfaceInfo) { const SurfaceId surface_id( FrameSinkId(1234, 4321),
diff --git a/services/viz/public/cpp/compositing/view_transition_element_resource_id_mojom_traits.h b/services/viz/public/cpp/compositing/view_transition_element_resource_id_mojom_traits.h index e55eff4..dd4b71d 100644 --- a/services/viz/public/cpp/compositing/view_transition_element_resource_id_mojom_traits.h +++ b/services/viz/public/cpp/compositing/view_transition_element_resource_id_mojom_traits.h
@@ -19,20 +19,27 @@ return resource_id.local_id(); } - static const blink::ViewTransitionToken& transition_token( + static std::optional<blink::ViewTransitionToken> transition_token( const viz::ViewTransitionElementResourceId& resource_id) { - return resource_id.transition_token(); + if (resource_id.IsValid()) { + return {resource_id.transition_token()}; + } + return std::nullopt; } static bool Read(viz::mojom::ViewTransitionElementResourceIdDataView data, viz::ViewTransitionElementResourceId* out) { - blink::ViewTransitionToken transition_token; + std::optional<blink::ViewTransitionToken> transition_token; if (!data.ReadTransitionToken(&transition_token)) { return false; } - *out = - viz::ViewTransitionElementResourceId(transition_token, data.local_id()); - return out->IsValid(); + if (transition_token) { + *out = viz::ViewTransitionElementResourceId(*transition_token, + data.local_id()); + } else { + *out = viz::ViewTransitionElementResourceId(); + } + return true; } };
diff --git a/services/viz/public/mojom/compositing/view_transition_element_resource_id.mojom b/services/viz/public/mojom/compositing/view_transition_element_resource_id.mojom index 40d9f8ae..0772be9 100644 --- a/services/viz/public/mojom/compositing/view_transition_element_resource_id.mojom +++ b/services/viz/public/mojom/compositing/view_transition_element_resource_id.mojom
@@ -25,6 +25,6 @@ // transition. The `local_id` identifies a specific snapshot resource and is // unique only with respect to a given `transition_token`. struct ViewTransitionElementResourceId { - blink.mojom.ViewTransitionToken transition_token; + blink.mojom.ViewTransitionToken? transition_token; uint32 local_id; };
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc index 5fe2bcb..13fec7d 100644 --- a/services/webnn/coreml/graph_builder_coreml.cc +++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -1638,6 +1638,13 @@ MILDataTypeToOperandType(input_operand_info.mil_data_type))); } + CHECK(indices_operand_info.mil_data_type == + CoreML::Specification::MILSpec::DataType::INT32 || + indices_operand_info.mil_data_type == + CoreML::Specification::MILSpec::DataType::UINT32 || + indices_operand_info.mil_data_type == + CoreML::Specification::MILSpec::DataType::INT64); + // TODO: crbug.com/338640913 - figure out what data type should be allowed for // WebNN. static constexpr auto kSupportedGatherIndicesTypes = @@ -1649,6 +1656,7 @@ indices_operand_info.mil_data_type)) { return NewNotSupportedError("Unsupported indices datatype."); } + static constexpr char kParamIndices[] = "indices"; static constexpr char kParamValidateIndices[] = "validate_indices";
diff --git a/services/webnn/dml/graph_builder_dml_test.cc b/services/webnn/dml/graph_builder_dml_test.cc index ae134ce..47f5b6f 100644 --- a/services/webnn/dml/graph_builder_dml_test.cc +++ b/services/webnn/dml/graph_builder_dml_test.cc
@@ -92,7 +92,10 @@ // Test building a DML graph with single operator conv2d which has multiple // inputs. -TEST_F(WebNNGraphBuilderDmlTest, BuildSingleOperatorConv2d) { +// +// TODO(crbug.com/331250158): Migrate to a WPT. This test was disabled due to +// crashing/failling on Qualcomm GPU bots (see crbug.com/325123735). +TEST_F(WebNNGraphBuilderDmlTest, DISABLED_BuildSingleOperatorConv2d) { GraphBuilderDml graph_builder(dml_device_); TensorDesc input_tensor_desc(DML_TENSOR_DATA_TYPE_FLOAT32, {1, 1, 3, 3}); @@ -200,7 +203,10 @@ // relu / // \ / // conv2d -TEST_F(WebNNGraphBuilderDmlTest, BuildGraphWithReluAndConv2d) { +// +// TODO(crbug.com/331250158): Migrate to a WPT. This test was disabled due to +// crashing/failling on Qualcomm GPU bots (see crbug.com/325123735). +TEST_F(WebNNGraphBuilderDmlTest, DISABLED_BuildGraphWithReluAndConv2d) { GraphBuilderDml graph_builder(dml_device_); TensorDesc input_tensor_desc(DML_TENSOR_DATA_TYPE_FLOAT32, {1, 1, 3, 3});
diff --git a/services/webnn/dml/graph_impl_dml.cc b/services/webnn/dml/graph_impl_dml.cc index 01c788d..9e82e4e 100644 --- a/services/webnn/dml/graph_impl_dml.cc +++ b/services/webnn/dml/graph_impl_dml.cc
@@ -2596,6 +2596,9 @@ const NodeOutput* indices = GetNodeOutputForOperand( id_to_node_output_map, gather->indices_operand_id); auto indices_tensor_desc = indices->GetTensorDesc(); + CHECK(indices_tensor_desc.GetDataType() == DML_TENSOR_DATA_TYPE_INT32 || + indices_tensor_desc.GetDataType() == DML_TENSOR_DATA_TYPE_UINT32 || + indices_tensor_desc.GetDataType() == DML_TENSOR_DATA_TYPE_INT64); size_t indices_rank = indices_tensor_desc.GetDimensions().size(); if (!base::MakeCheckedNum(indices_rank).IsValid<uint32_t>()) { return base::unexpected(
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc index ebae8a7..17074613 100644 --- a/services/webnn/tflite/graph_builder_tflite.cc +++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -361,6 +361,11 @@ case mojom::Operation::Tag::kHardSwish: operator_offset = SerializeHardSwish(*op.get_hard_swish()); break; + case mojom::Operation::Tag::kInstanceNormalization: { + ASSIGN_OR_RETURN(operator_offset, SerializeInstanceNormalization( + *op.get_instance_normalization())); + break; + } case mojom::Operation::Tag::kLeakyRelu: operator_offset = SerializeLeakyRelu(*op.get_leaky_relu()); break; @@ -437,7 +442,6 @@ case mojom::Operation::Tag::kGru: case mojom::Operation::Tag::kGruCell: case mojom::Operation::Tag::kLayerNormalization: - case mojom::Operation::Tag::kInstanceNormalization: case mojom::Operation::Tag::kLstm: case mojom::Operation::Tag::kLstmCell: case mojom::Operation::Tag::kTriangular: @@ -708,6 +712,29 @@ return normalization_offset; } +auto GraphBuilderTflite::SerializeReduceOperation( + ::tflite::BuiltinOperator operator_code, + int32_t input_tensor_index, + int32_t output_tensor_index, + base::span<const int32_t> axes, + bool keep_dimensions) -> OperatorOffset { + const std::array<int32_t, 1> axes_tensor_shape = { + base::checked_cast<int32_t>(axes.size())}; + const int32_t axes_tensor_index = + SerializeTensorWithBuffer<int32_t>(axes, axes_tensor_shape); + + const auto reduce_options = + ::tflite::CreateReducerOptions(builder_, keep_dimensions); + const uint32_t operator_code_index = GetOperatorCodeIndex(operator_code); + const std::array<int32_t, 2> op_inputs = {input_tensor_index, + axes_tensor_index}; + const std::array<int32_t, 1> op_outputs = {output_tensor_index}; + return ::tflite::CreateOperator( + builder_, operator_code_index, builder_.CreateVector<int32_t>(op_inputs), + builder_.CreateVector<int32_t>(op_outputs), + ::tflite::BuiltinOptions_ReducerOptions, reduce_options.Union()); +} + auto GraphBuilderTflite::SerializeReshapeOperation( int32_t input_tensor_index, int32_t output_tensor_index, @@ -1420,6 +1447,103 @@ operand_to_index_map_.at(hard_swish.output_operand_id)); } +auto GraphBuilderTflite::SerializeInstanceNormalization( + const mojom::InstanceNormalization& instance_normalization) + -> base::expected<OperatorOffset, std::string> { + const mojom::Operand& input_operand = + GetOperand(instance_normalization.input_operand_id); + // TODO(crbug.com/339654398): Support 16-bit float with dequantize operator + // https://www.tensorflow.org/mlir/tfl_ops#tfldequantize_tfldequantizeop. + if (input_operand.data_type == mojom::Operand::DataType::kFloat16) { + return base::unexpected("The 16-bit float data type is not supported."); + } + CHECK_EQ(input_operand.data_type, mojom::Operand::DataType::kFloat32); + // The input shape has been validated to not overflow before creating tensor. + const auto signed_input_dimensions = + ToSignedDimensions(input_operand.dimensions); + CHECK(signed_input_dimensions.has_value()); + CHECK_EQ(signed_input_dimensions->size(), 4u); + const ::tflite::TensorType input_tensor_type = + MojoOperandTypeToTFLite(input_operand.data_type); + std::array<int32_t, 2> spatial_dimensions; + uint32_t channel_axis; + switch (instance_normalization.layout) { + case mojom::InputOperandLayout::kChannelsFirst: { + spatial_dimensions = {2, 3}; + channel_axis = 1; + break; + } + case mojom::InputOperandLayout::kChannelsLast: + spatial_dimensions = {1, 2}; + channel_axis = 3; + break; + } + std::vector<int32_t> new_shape(signed_input_dimensions->size(), 1); + new_shape[channel_axis] = (*signed_input_dimensions)[channel_axis]; + + // Get mean values with reduceMean over the spatial dimensions of the input. + const int32_t input_tensor_index = + operand_to_index_map_.at(instance_normalization.input_operand_id); + const int32_t mean_tensor_index = + SerializeTemporaryTensor(new_shape, input_tensor_type); + operators_.emplace_back(SerializeReduceOperation( + ::tflite::BuiltinOperator_MEAN, input_tensor_index, mean_tensor_index, + spatial_dimensions, /*keep_dimensions=*/true)); + + // Get variance with expression `Variance = ReduceMean(Pow(Input - Mean, 2))` + // over the spatial dimensions of the input. + const int32_t output_tensor_index_of_sub = + SerializeTemporaryTensor(*signed_input_dimensions, input_tensor_type); + operators_.emplace_back(SerializeBinaryOperation( + ::tflite::BuiltinOperator_SUB, input_tensor_index, mean_tensor_index, + output_tensor_index_of_sub)); + const int32_t pow_constant_tensor_index = SerializeTensorWithBuffer<float>( + /*buffer=*/std::array<float, 1>{2.0}, + /*dimensions=*/{}); + const int32_t output_tensor_index_of_pow = + SerializeTemporaryTensor(*signed_input_dimensions, input_tensor_type); + operators_.emplace_back(SerializeBinaryOperation( + ::tflite::BuiltinOperator_POW, output_tensor_index_of_sub, + pow_constant_tensor_index, output_tensor_index_of_pow)); + const int32_t variance_tensor_index = + SerializeTemporaryTensor(new_shape, input_tensor_type); + operators_.emplace_back(SerializeReduceOperation( + ::tflite::BuiltinOperator_MEAN, output_tensor_index_of_pow, + variance_tensor_index, spatial_dimensions, /*keep_dimensions=*/true)); + + // Reshape the 1-D tensor of the scale operand to the new shape if needed. + std::optional<int32_t> reshape_scale_tensor_index; + if (instance_normalization.scale_operand_id) { + const mojom::Operand& scale_operand = + GetOperand(*instance_normalization.scale_operand_id); + CHECK_EQ(scale_operand.dimensions.size(), 1u); + reshape_scale_tensor_index = + SerializeTemporaryTensor(new_shape, input_tensor_type); + operators_.emplace_back(SerializeReshapeOperation( + operand_to_index_map_.at(*instance_normalization.scale_operand_id), + *reshape_scale_tensor_index, new_shape)); + } + + // Reshape the 1-D tensor of the bias operand to the new shape if needed. + std::optional<int32_t> reshape_bias_tensor_index; + if (instance_normalization.bias_operand_id) { + const mojom::Operand& bias_operand = + GetOperand(*instance_normalization.bias_operand_id); + CHECK_EQ(bias_operand.dimensions.size(), 1u); + reshape_bias_tensor_index = + SerializeTemporaryTensor(new_shape, input_tensor_type); + operators_.emplace_back(SerializeReshapeOperation( + operand_to_index_map_.at(*instance_normalization.bias_operand_id), + *reshape_bias_tensor_index, new_shape)); + } + + return SerializeNormalizationOperation( + *signed_input_dimensions, input_tensor_type, input_tensor_index, + operand_to_index_map_.at(instance_normalization.output_operand_id), + mean_tensor_index, variance_tensor_index, instance_normalization.epsilon, + reshape_scale_tensor_index, reshape_bias_tensor_index); +} + auto GraphBuilderTflite::SerializeLeakyRelu(const mojom::LeakyRelu& leaky_relu) -> OperatorOffset { const auto leaky_rely_options = @@ -1721,10 +1845,6 @@ // Serialize the axes tensor to reduce input tensor. ASSIGN_OR_RETURN(const std::vector<int32_t> signed_axes, ToSignedDimensions(reduce.axes)); - const std::array<int32_t, 1> axes_tensor_shape = { - base::checked_cast<int32_t>(signed_axes.size())}; - const int32_t axes_tensor_index = - SerializeTensorWithBuffer<int32_t>(signed_axes, axes_tensor_shape); ::tflite::BuiltinOperator operator_code; const mojom::Operand& input_operand = GetOperand(reduce.input_operand_id); @@ -1763,17 +1883,10 @@ " is not implemented."); } - const auto reduce_options = - ::tflite::CreateReducerOptions(builder_, reduce.keep_dimensions); - const uint32_t operator_code_index = GetOperatorCodeIndex(operator_code); - const std::array<int32_t, 2> op_inputs = { - operand_to_index_map_.at(reduce.input_operand_id), axes_tensor_index}; - const std::array<int32_t, 1> op_outputs = { - operand_to_index_map_.at(reduce.output_operand_id)}; - return ::tflite::CreateOperator( - builder_, operator_code_index, builder_.CreateVector<int32_t>(op_inputs), - builder_.CreateVector<int32_t>(op_outputs), - ::tflite::BuiltinOptions_ReducerOptions, reduce_options.Union()); + return SerializeReduceOperation( + operator_code, operand_to_index_map_.at(reduce.input_operand_id), + operand_to_index_map_.at(reduce.output_operand_id), signed_axes, + reduce.keep_dimensions); } auto GraphBuilderTflite::SerializeRelu(const mojom::Relu& relu)
diff --git a/services/webnn/tflite/graph_builder_tflite.h b/services/webnn/tflite/graph_builder_tflite.h index 325aa17..83d3077 100644 --- a/services/webnn/tflite/graph_builder_tflite.h +++ b/services/webnn/tflite/graph_builder_tflite.h
@@ -148,6 +148,15 @@ std::optional<int32_t> scale_tensor_index, std::optional<int32_t> bias_tensor_index); + // This function is called by `SerializeReduce` to serialize WebNN + // reduce operators or used to emulate WebNN operations. + OperatorOffset SerializeReduceOperation( + ::tflite::BuiltinOperator operator_code, + int32_t input_tensor_index, + int32_t output_tensor_index, + base::span<const int32_t> axes, + bool keep_dimensions); + // This function is called by `SerializeReshape` to serialize WebNN // reshape operator or used to emulate WebNN operations. OperatorOffset SerializeReshapeOperation(int32_t input_tensor_index, @@ -207,6 +216,8 @@ const mojom::Gemm& gemm); OperatorOffset SerializeHardSigmoid(const mojom::HardSigmoid& hard_sigmoid); OperatorOffset SerializeHardSwish(const mojom::HardSwish& hard_swish); + base::expected<OperatorOffset, std::string> SerializeInstanceNormalization( + const mojom::InstanceNormalization& instance_normalization); OperatorOffset SerializeLeakyRelu(const mojom::LeakyRelu& leaky_relu); OperatorOffset SerializeLinear(const mojom::Linear& linear); OperatorOffset SerializeLogicalNot(
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc index 8eba108..3e81ee8 100644 --- a/services/webnn/webnn_graph_impl.cc +++ b/services/webnn/webnn_graph_impl.cc
@@ -77,7 +77,7 @@ NOTREACHED_NORETURN(); } -webnn::Operand ConvertToComponentOperand(const mojom::Operand* mojo_operand) { +webnn::Operand MojoOperandToComponent(const mojom::Operand* mojo_operand) { return webnn::Operand(MojoOperandTypeToComponent(mojo_operand->data_type), mojo_operand->dimensions); } @@ -220,13 +220,13 @@ if (scale_operand_id) { const mojom::OperandPtr& scale_operand = id_to_operand_map.at(scale_operand_id.value()); - component_attributes.scale = ConvertToComponentOperand(scale_operand.get()); + component_attributes.scale = MojoOperandToComponent(scale_operand.get()); } const auto& bias_operand_id = batch_normalization->bias_operand_id; if (bias_operand_id) { const mojom::OperandPtr& bias_operand = id_to_operand_map.at(bias_operand_id.value()); - component_attributes.bias = ConvertToComponentOperand(bias_operand.get()); + component_attributes.bias = MojoOperandToComponent(bias_operand.get()); } component_attributes.axis = batch_normalization->axis; @@ -313,29 +313,28 @@ if (lstm->bias_operand_id.has_value()) { const auto* bias = GetMojoOperand(id_to_operand_map, lstm->bias_operand_id.value()); - attributes.bias = ConvertToComponentOperand(bias); + attributes.bias = MojoOperandToComponent(bias); } if (lstm->recurrent_bias_operand_id.has_value()) { const auto* recurrent_bias = GetMojoOperand( id_to_operand_map, lstm->recurrent_bias_operand_id.value()); - attributes.recurrent_bias = ConvertToComponentOperand(recurrent_bias); + attributes.recurrent_bias = MojoOperandToComponent(recurrent_bias); } if (lstm->peephole_weight_operand_id.has_value()) { const auto* peephole_weight = GetMojoOperand( id_to_operand_map, lstm->peephole_weight_operand_id.value()); - attributes.peephole_weight = ConvertToComponentOperand(peephole_weight); + attributes.peephole_weight = MojoOperandToComponent(peephole_weight); } if (lstm->initial_hidden_state_operand_id.has_value()) { const auto* initial_hidden_state = GetMojoOperand( id_to_operand_map, lstm->initial_hidden_state_operand_id.value()); attributes.initial_hidden_state = - ConvertToComponentOperand(initial_hidden_state); + MojoOperandToComponent(initial_hidden_state); } if (lstm->initial_cell_state_operand_id.has_value()) { const auto* initial_cell_state = GetMojoOperand( id_to_operand_map, lstm->initial_cell_state_operand_id.value()); - attributes.initial_cell_state = - ConvertToComponentOperand(initial_cell_state); + attributes.initial_cell_state = MojoOperandToComponent(initial_cell_state); } return attributes; @@ -350,17 +349,17 @@ if (lstm_cell.bias_operand_id.has_value()) { const auto* bias = GetMojoOperand(id_to_operand_map, lstm_cell.bias_operand_id.value()); - attributes.bias = ConvertToComponentOperand(bias); + attributes.bias = MojoOperandToComponent(bias); } if (lstm_cell.recurrent_bias_operand_id.has_value()) { const auto* recurrent_bias = GetMojoOperand( id_to_operand_map, lstm_cell.recurrent_bias_operand_id.value()); - attributes.recurrent_bias = ConvertToComponentOperand(recurrent_bias); + attributes.recurrent_bias = MojoOperandToComponent(recurrent_bias); } if (lstm_cell.peephole_weight_operand_id.has_value()) { const auto* peephole_weight = GetMojoOperand( id_to_operand_map, lstm_cell.peephole_weight_operand_id.value()); - attributes.peephole_weight = ConvertToComponentOperand(peephole_weight); + attributes.peephole_weight = MojoOperandToComponent(peephole_weight); } return attributes; @@ -403,14 +402,14 @@ if (scale_operand_id.has_value()) { const mojom::OperandPtr& scale_operand = id_to_operand_map.at(scale_operand_id.value()); - component_attributes.scale = ConvertToComponentOperand(scale_operand.get()); + component_attributes.scale = MojoOperandToComponent(scale_operand.get()); } const auto& bias_operand_id = layer_normalization->bias_operand_id; if (bias_operand_id.has_value()) { const mojom::OperandPtr& bias_operand = id_to_operand_map.at(bias_operand_id.value()); - component_attributes.bias = ConvertToComponentOperand(bias_operand.get()); + component_attributes.bias = MojoOperandToComponent(bias_operand.get()); } return component_attributes; @@ -458,7 +457,7 @@ if (c_operand_id) { const mojom::OperandPtr& c_operand = id_to_operand_map.at(c_operand_id.value()); - component_attributes.c_operand = ConvertToComponentOperand(c_operand.get()); + component_attributes.c_operand = MojoOperandToComponent(c_operand.get()); } component_attributes.alpha = gemm->alpha; component_attributes.beta = gemm->beta; @@ -474,19 +473,19 @@ if (gru->bias_operand_id.has_value()) { const auto* bias = GetMojoOperand(id_to_operand_map, gru->bias_operand_id.value()); - component_attributes.bias = ConvertToComponentOperand(bias); + component_attributes.bias = MojoOperandToComponent(bias); } if (gru->recurrent_bias_operand_id.has_value()) { const auto* recurrent_bias = GetMojoOperand( id_to_operand_map, gru->recurrent_bias_operand_id.value()); component_attributes.recurrent_bias = - ConvertToComponentOperand(recurrent_bias); + MojoOperandToComponent(recurrent_bias); } if (gru->initial_hidden_state_operand_id.has_value()) { const auto* initial_hidden_state = GetMojoOperand( id_to_operand_map, gru->initial_hidden_state_operand_id.value()); component_attributes.initial_hidden_state = - ConvertToComponentOperand(initial_hidden_state); + MojoOperandToComponent(initial_hidden_state); } component_attributes.return_sequence = gru->return_sequence; @@ -504,13 +503,13 @@ if (gru_cell.bias_operand_id.has_value()) { const auto* bias = GetMojoOperand(id_to_operand_map, gru_cell.bias_operand_id.value()); - component_attributes.bias = ConvertToComponentOperand(bias); + component_attributes.bias = MojoOperandToComponent(bias); } if (gru_cell.recurrent_bias_operand_id.has_value()) { const auto* recurrent_bias = GetMojoOperand( id_to_operand_map, gru_cell.recurrent_bias_operand_id.value()); component_attributes.recurrent_bias = - ConvertToComponentOperand(recurrent_bias); + MojoOperandToComponent(recurrent_bias); } component_attributes.activation_count = gru_cell.activations.size(); @@ -525,13 +524,13 @@ if (scale_operand_id) { const mojom::OperandPtr& scale_operand = id_to_operand_map.at(scale_operand_id.value()); - component_attributes.scale = ConvertToComponentOperand(scale_operand.get()); + component_attributes.scale = MojoOperandToComponent(scale_operand.get()); } const auto& bias_operand_id = instance_normalization->bias_operand_id; if (bias_operand_id) { const mojom::OperandPtr& bias_operand = id_to_operand_map.at(bias_operand_id.value()); - component_attributes.bias = ConvertToComponentOperand(bias_operand.get()); + component_attributes.bias = MojoOperandToComponent(bias_operand.get()); } component_attributes.layout = MojoInputOperandLayoutToComponent(instance_normalization->layout); @@ -658,14 +657,14 @@ } const auto validated_output = ValidateBatchNormalizationAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(mean), - ConvertToComponentOperand(variance), + MojoOperandToComponent(input), MojoOperandToComponent(mean), + MojoOperandToComponent(variance), ConvertToBatchNormalizationAttributes(id_to_operand_map, batch_normalization)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -690,12 +689,12 @@ } const auto validated_output = ValidateArgMinMaxAndInferOutput( - ConvertToComponentOperand(input), arg_min_max->axes, + MojoOperandToComponent(input), arg_min_max->axes, arg_min_max->keep_dimensions); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -737,14 +736,14 @@ if (!input || input == output) { return false; } - inputs.push_back(ConvertToComponentOperand(input)); + inputs.push_back(MojoOperandToComponent(input)); } auto validated_output = ValidateConcatAndInferOutput(inputs, concat->axis); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } processed_operands.insert(concat->output_operand_id); @@ -787,8 +786,7 @@ // Invalid bias operand. return false; } - bias_operand = - ConvertToComponentOperand(bias_operand_iterator->second.get()); + bias_operand = MojoOperandToComponent(bias_operand_iterator->second.get()); } processed_operands.insert(conv2d->output_operand_id); @@ -803,7 +801,7 @@ switch (conv2d->kind) { case mojom::Conv2d::Kind::kDirect: { validated_output = ValidateConv2dAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(filter), + MojoOperandToComponent(input), MojoOperandToComponent(filter), ConvertToConv2dAttributes(id_to_operand_map, conv2d, std::move(bias_operand))); break; @@ -811,7 +809,7 @@ case mojom::Conv2d::Kind::kTransposed: { validated_output = ValidateConvTranspose2dAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(filter), + MojoOperandToComponent(input), MojoOperandToComponent(filter), ConvertToConvTranspose2dAttributes(id_to_operand_map, conv2d, std::move(bias_operand))); break; @@ -820,7 +818,7 @@ if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -998,12 +996,12 @@ } auto validated_output = ValidateGatherAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(indices), + MojoOperandToComponent(input), MojoOperandToComponent(indices), gather->axis); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1033,12 +1031,12 @@ return false; } auto validated_output = ValidateGemmAndInferOutput( - ConvertToComponentOperand(a), ConvertToComponentOperand(b), + MojoOperandToComponent(a), MojoOperandToComponent(b), ConvertToGemmAttributes(id_to_operand_map, gemm)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1098,8 +1096,8 @@ } const auto validated_outputs = ValidateGruAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), gru->steps, gru->hidden_size, + MojoOperandToComponent(input), MojoOperandToComponent(weight), + MojoOperandToComponent(recurrent_weight), gru->steps, gru->hidden_size, ConvertToGruAttributes(id_to_operand_map, gru)); if (!validated_outputs.has_value()) { return false; @@ -1113,7 +1111,7 @@ if (!output) { return false; } - if (validated_outputs->at(i) != ConvertToComponentOperand(output)) { + if (validated_outputs->at(i) != MojoOperandToComponent(output)) { return false; } } @@ -1175,9 +1173,9 @@ const base::expected<webnn::Operand, std::string> validated_output = ValidateGruCellAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), - ConvertToComponentOperand(hidden_state), gru_cell.hidden_size, + MojoOperandToComponent(input), MojoOperandToComponent(weight), + MojoOperandToComponent(recurrent_weight), + MojoOperandToComponent(hidden_state), gru_cell.hidden_size, ConvertToGruCellAttributes(id_to_operand_map, gru_cell)); if (!validated_output.has_value()) { return false; @@ -1188,7 +1186,7 @@ if (!output) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1251,13 +1249,13 @@ } const auto validated_output = ValidateLayerNormalizationAndInferOutput( - ConvertToComponentOperand(input), layer_normalization->axes, + MojoOperandToComponent(input), layer_normalization->axes, ConvertToLayerNormalizationAttributes(id_to_operand_map, layer_normalization)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1359,9 +1357,9 @@ } const auto validated_outputs = ValidateLstmAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), lstm->steps, - lstm->hidden_size, ConvertToLstmAttributes(id_to_operand_map, lstm)); + MojoOperandToComponent(input), MojoOperandToComponent(weight), + MojoOperandToComponent(recurrent_weight), lstm->steps, lstm->hidden_size, + ConvertToLstmAttributes(id_to_operand_map, lstm)); if (!validated_outputs.has_value()) { return false; } @@ -1374,7 +1372,7 @@ if (!output) { return false; } - if (validated_outputs->at(i) != ConvertToComponentOperand(output)) { + if (validated_outputs->at(i) != MojoOperandToComponent(output)) { return false; } } @@ -1447,10 +1445,10 @@ const base::expected<std::vector<webnn::Operand>, std::string> validated_outputs = ValidateLstmCellAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), - ConvertToComponentOperand(hidden_state), - ConvertToComponentOperand(cell_state), lstm_cell.hidden_size, + MojoOperandToComponent(input), MojoOperandToComponent(weight), + MojoOperandToComponent(recurrent_weight), + MojoOperandToComponent(hidden_state), + MojoOperandToComponent(cell_state), lstm_cell.hidden_size, ConvertToLstmCellAttributes(id_to_operand_map, lstm_cell)); if (!validated_outputs.has_value()) { return false; @@ -1464,7 +1462,7 @@ if (!output) { return false; } - if (validated_outputs->at(i) != ConvertToComponentOperand(output)) { + if (validated_outputs->at(i) != MojoOperandToComponent(output)) { return false; } } @@ -1511,13 +1509,13 @@ } const auto validated_output = ValidateInstanceNormalizationAndInferOutput( - ConvertToComponentOperand(input), + MojoOperandToComponent(input), ConvertToInstanceNormalizationAttributes(id_to_operand_map, instance_normalization)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1541,11 +1539,11 @@ return false; } auto validated_output = ValidateMatmulAndInferOutput( - ConvertToComponentOperand(a), ConvertToComponentOperand(b)); + MojoOperandToComponent(a), MojoOperandToComponent(b)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1568,12 +1566,12 @@ } auto validated_output = - ValidatePadAndInferOutput(ConvertToComponentOperand(input), + ValidatePadAndInferOutput(MojoOperandToComponent(input), pad->beginning_padding, pad->ending_padding); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1607,13 +1605,12 @@ // The element of output dimensions should be 4. return false; } - auto validated_output = - ValidatePool2dAndInferOutput(ConvertToComponentOperand(input), - ConvertToPool2dAttributes(pool2d, output)); + auto validated_output = ValidatePool2dAndInferOutput( + MojoOperandToComponent(input), ConvertToPool2dAttributes(pool2d, output)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1638,11 +1635,11 @@ } auto validated_output = ValidatePreluAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(slope)); + MojoOperandToComponent(input), MojoOperandToComponent(slope)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1684,11 +1681,11 @@ } auto validated_output = ValidateResample2dAndInferOutput( - ConvertToComponentOperand(input), scales_or_sizes, axes); + MojoOperandToComponent(input), scales_or_sizes, axes); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1746,11 +1743,11 @@ } auto validated_output = ValidateSliceAndInferOutput( - ConvertToComponentOperand(input), ConvertToSliceAttributes(slice)); + MojoOperandToComponent(input), ConvertToSliceAttributes(slice)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1772,11 +1769,11 @@ return false; } auto validated_output = - ValidateSoftmaxAndInferOutput(ConvertToComponentOperand(input)); + ValidateSoftmaxAndInferOutput(MojoOperandToComponent(input)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1810,9 +1807,8 @@ processed_operands.insert(output_id); } - auto validated_output = - ValidateSplitAndInferOutput(ConvertToComponentOperand(input), - {.splits = splits, .axis = split->axis}); + auto validated_output = ValidateSplitAndInferOutput( + MojoOperandToComponent(input), {.splits = splits, .axis = split->axis}); if (!validated_output.has_value()) { return false; } @@ -1826,7 +1822,7 @@ for (uint32_t i = 0; i < validated_output->size(); ++i) { auto* output = GetMojoOperand(id_to_operand_map, split->output_operand_ids[i]); - if (validated_output->at(i) != ConvertToComponentOperand(output)) { + if (validated_output->at(i) != MojoOperandToComponent(output)) { return false; } } @@ -1851,11 +1847,11 @@ } auto validated_output = ValidateTransposeAndInferOutput( - ConvertToComponentOperand(input), transpose->permutation); + MojoOperandToComponent(input), transpose->permutation); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1879,11 +1875,11 @@ } base::expected<Operand, std::string> validated_output = - ValidateTriangularAndInferOutput(ConvertToComponentOperand(input)); + ValidateTriangularAndInferOutput(MojoOperandToComponent(input)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1913,14 +1909,13 @@ return false; } - auto validated_output = - ValidateWhereAndInferOutput(ConvertToComponentOperand(condition), - ConvertToComponentOperand(true_value), - ConvertToComponentOperand(false_value)); + auto validated_output = ValidateWhereAndInferOutput( + MojoOperandToComponent(condition), MojoOperandToComponent(true_value), + MojoOperandToComponent(false_value)); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; } @@ -1943,12 +1938,12 @@ } auto validated_output = ValidateReduceAndInferOutput( - MojoReduceTypeToComponent(reduce->kind), ConvertToComponentOperand(input), + MojoReduceTypeToComponent(reduce->kind), MojoOperandToComponent(input), reduce->axes, reduce->keep_dimensions); if (!validated_output.has_value()) { return false; } - if (validated_output != ConvertToComponentOperand(output)) { + if (validated_output != MojoOperandToComponent(output)) { return false; }
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc index 6219b0e..44bbb84 100644 --- a/services/webnn/webnn_graph_impl_unittest.cc +++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -2895,6 +2895,20 @@ .Test(); } { + // Test the invalid graph for the indices data type is not one of uint32, + // int32 or int64. + GatherTester{ + .input = {.type = mojom::Operand::DataType::kFloat32, + .dimensions = {3, 4, 5}}, + .attributes = {.indices = {.type = mojom::Operand::DataType::kFloat32, + .dimensions = {6, 7}}, + .axis = 1}, + .output = {.type = mojom::Operand::DataType::kFloat32, + .dimensions = {3, 6, 7, 5}}, + .expected = false} + .Test(); + } + { // Test the invalid graph for the output shapes are not expected. GatherTester{ .input = {.type = mojom::Operand::DataType::kFloat32,
diff --git a/storage/browser/file_system/local_file_util.cc b/storage/browser/file_system/local_file_util.cc index 9519002..5313081 100644 --- a/storage/browser/file_system/local_file_util.cc +++ b/storage/browser/file_system/local_file_util.cc
@@ -48,26 +48,20 @@ ~LocalFileEnumerator() override = default; base::FilePath Next() override { - base::FilePath next = file_enum_.Next(); - while (!next.empty() && file_util_->IsHiddenItem(next)) { - next = file_enum_.Next(); - } - if (next.empty()) { - // TODO(b/329523214): in the long term, setting error_ should not be - // conditional on the enumeration coming up empty (equivalently, - // !had_some_results_). But, as per that bug, we do so in the short term - // "as an intermediate checkpoint". - if (!had_some_results_) { + while (true) { + base::FilePath next = file_enum_.Next(); + if (next.empty()) { error_ = file_enum_.GetError(); + return next; + } else if (file_util_->IsHiddenItem(next)) { + continue; } - return next; - } - file_util_info_ = file_enum_.GetInfo(); - had_some_results_ = true; + file_util_info_ = file_enum_.GetInfo(); - base::FilePath path; - platform_root_path_.AppendRelativePath(next, &path); - return virtual_root_path_.Append(path); + base::FilePath path; + platform_root_path_.AppendRelativePath(next, &path); + return virtual_root_path_.Append(path); + } } base::File::Error GetError() override { return error_; } @@ -85,7 +79,6 @@ // through the whole lifetime of the enumerator. const raw_ptr<const LocalFileUtil> file_util_; base::File::Error error_ = base::File::FILE_OK; - bool had_some_results_ = false; base::FileEnumerator file_enum_; base::FileEnumerator::FileInfo file_util_info_; base::FilePath platform_root_path_;
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 5c0f6cd..924e8c4 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5487,9 +5487,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5499,8 +5499,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -5643,9 +5643,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5655,8 +5655,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index ad7f3e6..2b91d132 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -19664,9 +19664,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -19676,8 +19676,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -19820,9 +19820,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -19832,8 +19832,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 192322e..97ce7a8 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -41840,9 +41840,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41851,8 +41851,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -41990,9 +41990,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -42001,8 +42001,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -43339,9 +43339,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -43351,8 +43351,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -43495,9 +43495,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -43507,8 +43507,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -44820,9 +44820,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -44831,8 +44831,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -44970,9 +44970,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -44981,8 +44981,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index e7ed297..3bf9f24 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -15763,12 +15763,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -15778,8 +15778,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": { @@ -15939,12 +15939,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 127.0.6494.0", + "description": "Run with ash-chrome version 127.0.6496.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -15954,8 +15954,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v127.0.6494.0", - "revision": "version:127.0.6494.0" + "location": "lacros_version_skew_tests_v127.0.6496.0", + "revision": "version:127.0.6496.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index c7f4e9c6..5fe80a24 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -674,7 +674,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "oriole", "os": "Android", @@ -718,7 +717,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "oriole", "os": "Android", @@ -762,7 +760,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "raven", "os": "Android", @@ -806,7 +803,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "raven", "os": "Android",
diff --git a/testing/buildbot/chromium.perf.pinpoint.json b/testing/buildbot/chromium.perf.pinpoint.json index bfae4a0..12fe8a20 100644 --- a/testing/buildbot/chromium.perf.pinpoint.json +++ b/testing/buildbot/chromium.perf.pinpoint.json
@@ -602,7 +602,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "oriole", "os": "Android", @@ -646,7 +645,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "oriole", "os": "Android", @@ -690,7 +688,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "raven", "os": "Android", @@ -734,7 +731,6 @@ "swarming": { "can_use_on_swarming_builders": true, "dimensions": { - "device_os": "TP1A.220624.021", "device_os_flavor": "google", "device_type": "raven", "os": "Android",
diff --git a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter index f63b32f..b4652d93 100644 --- a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter +++ b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
@@ -58,11 +58,6 @@ -TabDragging/DetachToBrowserTabDragControllerTest.NewBrowserWindowState/* -TabDragging/DetachToBrowserTabDragControllerTest.OffsetForDraggingInMaximizedWindow/* -TabDragging/DetachToBrowserTabDragControllerTest.OffsetForDraggingTab/* -# The following tests are flaky. --TabDragging/DetachToBrowserTabDragControllerTest.DragGroupHeaderToSeparateWindow/0 --TabDragging/DetachToBrowserTabDragControllerTest.DragGroupHeaderToSeparateWindow/2 --TabDragging/DetachToBrowserTabDragControllerTest.DragToSeparateWindow/0 --TabDragging/DetachToBrowserTabDragControllerTest.DragToSeparateWindow/2 # TODO(b/256212431): Re-enable when linux-lacros-rel support # signin::MakePrimaryAccountAvailable().
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index a76c629e..d0a45b73 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -267,16 +267,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'identifier': 'Lacros version skew testing ash canary', - 'description': 'Run with ash-chrome version 127.0.6494.0', + 'description': 'Run with ash-chrome version 127.0.6496.0', 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6494.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v127.0.6496.0/test_ash_chrome', ], 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v127.0.6494.0', - 'revision': 'version:127.0.6494.0', + 'location': 'lacros_version_skew_tests_v127.0.6496.0', + 'revision': 'version:127.0.6496.0', }, ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 4eebb38..f09246f 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -557,21 +557,6 @@ ] } ], - "AndroidOmniboxUxRevampPhase3": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled_Tablets", - "enable_features": [ - "OmniboxModernizeVisualUpdate" - ] - } - ] - } - ], "AndroidSandboxRendererProcessPolicy": [ { "platforms": [ @@ -3069,29 +3054,6 @@ ] } ], - "CCTMinimized": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "EnabledWithIPH", - "params": { - "availability": "any", - "event_1": "name:cct_minimized_iph_trigger;comparator:<1;window:1;storage:360", - "event_trigger": "name:cct_minimized_iph_trigger;comparator:<3;window:360;storage:360", - "event_used": "name:cct_minimize_button_clicked;comparator:==0;window:360;storage:360", - "session_rate": "==0" - }, - "enable_features": [ - "CCTMinimized", - "IPH_CCTMinimized" - ] - } - ] - } - ], "CPSS-V2-Android": [ { "platforms": [ @@ -9970,6 +9932,75 @@ ] } ], + "IOSContentNotification": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled_Promo_20240522", + "params": { + "ContentPushNotificationsExperimentType": "1" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + }, + { + "name": "Registered_Promo_20240522", + "params": { + "ContentPushNotificationsExperimentType": "5" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + }, + { + "name": "Enabled_Provisional_20240522", + "params": { + "ContentPushNotificationsExperimentType": "3" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + }, + { + "name": "Registered_Provisional_20240522", + "params": { + "ContentPushNotificationsExperimentType": "6" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + }, + { + "name": "Enabled_Setuplist_20240522", + "params": { + "ContentPushNotificationsExperimentType": "2" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + }, + { + "name": "Registered_Setuplist_20240522", + "params": { + "ContentPushNotificationsExperimentType": "7" + }, + "enable_features": [ + "ContentNotificationExperiment", + "ContentPushNotifications" + ] + } + ] + } + ], "IOSDiscoverFeedSportCard": [ { "platforms": [ @@ -12608,9 +12639,9 @@ ], "experiments": [ { - "name": "Enabled_20240503", + "name": "Enabled_20240522", "params": { - "intersection_observer_delay": "500ms", + "intersection_observer_delay": "1000ms", "max_intersection_observations": "345", "random_anchor_sampling_period": "1" }, @@ -23867,6 +23898,39 @@ ] } ], + "WebViewThreadReduction": [ + { + "platforms": [ + "android_webview" + ], + "experiments": [ + { + "name": "ReduceAllThreads", + "params": { + "BrowserThreadPoolCoresMultiplierFor16GBAndAbove": "0.4", + "BrowserThreadPoolCoresMultiplierFor1GBTo2GB": "0.4", + "BrowserThreadPoolCoresMultiplierFor2GBTo4GB": "0.4", + "BrowserThreadPoolCoresMultiplierFor4GBTo8GB": "0.4", + "BrowserThreadPoolCoresMultiplierFor512MBTo1GB": "0.4", + "BrowserThreadPoolCoresMultiplierFor8GBTo16GB": "0.4", + "BrowserThreadPoolCoresMultiplierForLessThan512MB": "0.4", + "BrowserThreadPoolMinFor16GBAndAbove": "2", + "BrowserThreadPoolMinFor1GBTo2GB": "2", + "BrowserThreadPoolMinFor2GBTo4GB": "2", + "BrowserThreadPoolMinFor4GBTo8GB": "2", + "BrowserThreadPoolMinFor512MBTo1GB": "2", + "BrowserThreadPoolMinFor8GBTo16GB": "2", + "BrowserThreadPoolMinForLessThan512MB": "2" + }, + "enable_features": [ + "BrowserThreadPoolAdjustment", + "InProcessGpuUseIOThread", + "NetworkServiceDedicatedThread" + ] + } + ] + } + ], "WebViewThreadSafeMedia": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index 3226089..602c0ed 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 322608986a23c1d76507d5b66b3f3b915393d95a +Subproject commit 602c0edfc1f23b062bd138f989e43c765594dd27
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index 706a85e..486490338 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -851,6 +851,7 @@ array of string allowedSites number optOutPercentage boolean isOptOutTopLevel + CookieOperation operation type ClientHintIssueReason extends string enum @@ -5589,6 +5590,10 @@ experimental number workerFetchStart # Settled fetch event respondWith promise. experimental number workerRespondWithSettled + # Started ServiceWorker static routing source evaluation. + experimental optional number workerRouterEvaluationStart + # Started cache lookup when the source was evaluated to `cache`. + experimental optional number workerCacheLookupStart # Started sending request. number sendStart # Finished sending request. @@ -5874,6 +5879,8 @@ # The router source of the matched rule. If there is a matched rule, this # field will be set, otherwise no value will be set. optional ServiceWorkerRouterSource matchedSourceType + # The actual router source used. + optional ServiceWorkerRouterSource actualSourceType # HTTP response data. type Response extends object
diff --git a/third_party/blink/public/mojom/devtools/inspector_issue.mojom b/third_party/blink/public/mojom/devtools/inspector_issue.mojom index 41464e00..d69712cc 100644 --- a/third_party/blink/public/mojom/devtools/inspector_issue.mojom +++ b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
@@ -285,6 +285,7 @@ array<string> allowed_sites; uint32 opt_out_percentage; bool is_opt_out_top_level; + CookieOperation operation; }; enum GenericIssueErrorType {
diff --git a/third_party/blink/public/web/web_element.h b/third_party/blink/public/web/web_element.h index 97a83c25..023ce709 100644 --- a/third_party/blink/public/web/web_element.h +++ b/third_party/blink/public/web/web_element.h
@@ -83,11 +83,6 @@ WebString TextContentAbridged(unsigned int max_length) const; WebString InnerHTML() const; - // Returns true if the element's contenteditable attribute is in the true - // state or in the plaintext-only state: - // https://html.spec.whatwg.org/multipage/interaction.html#attr-contenteditable - bool IsContentEditable() const; - // Returns true if the element's computed writing suggestions value is true. // https://html.spec.whatwg.org/#writing-suggestions:computed-writing-suggestions-value bool WritingSuggestions() const;
diff --git a/third_party/blink/public/web/web_node.h b/third_party/blink/public/web/web_node.h index 41fc646..8f59a0c 100644 --- a/third_party/blink/public/web/web_node.h +++ b/third_party/blink/public/web/web_node.h
@@ -101,6 +101,10 @@ bool IsElementNode() const; void SimulateClick(); + // Returns the top-most ancestor such this WebNode and that ancestor and all + // nodes in between are contenteditable. + WebElement RootEditableElement() const; + // See cc/paint/element_id.h for the definition of these ids. cc::ElementId ScrollingElementIdForTesting() const;
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index cbaa75c..70456ab5 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -276,8 +276,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_filter_dictionary.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.h", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_webgpu_access_option.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_webgpu_access_option.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_2d_webgpu_transfer_option.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_2d_webgpu_transfer_option.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_capture_handle.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_capture_handle.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_capture_handle_config.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index bb899da..d243a2c 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -91,8 +91,8 @@ "//third_party/blink/renderer/modules/cache_storage/window_cache_storage.idl", "//third_party/blink/renderer/modules/cache_storage/worker_cache_storage.idl", "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter.idl", - "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access.idl", - "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access_option.idl", + "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer.idl", + "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer_option.idl", "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_dictionary.idl", "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl", "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl",
diff --git a/third_party/blink/renderer/controller/javascript_call_stack_collector.cc b/third_party/blink/renderer/controller/javascript_call_stack_collector.cc index d080ec52c4..57b39ae5 100644 --- a/third_party/blink/renderer/controller/javascript_call_stack_collector.cc +++ b/third_party/blink/renderer/controller/javascript_call_stack_collector.cc
@@ -44,9 +44,12 @@ const std::string stack_trace = oss.str(); std::istringstream iss(stack_trace); std::string line; - while (std::getline(iss, line)) { + const int stack_trace_limit = isolate->GetStackTraceLimit(); + int frame_count = 0; + while (std::getline(iss, line) && frame_count < stack_trace_limit) { builder.Append("\n at "); builder.Append(line.data(), base::checked_cast<unsigned>(line.size())); + frame_count++; } }
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_interpolation_type.cc index b988e55d..f257323f 100644 --- a/third_party/blink/renderer/core/animation/css_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
@@ -99,17 +99,15 @@ class ResolvedRegisteredCustomPropertyChecker : public InterpolationType::ConversionChecker { public: - ResolvedRegisteredCustomPropertyChecker( - const PropertyHandle& property, - const CSSValue& value, - scoped_refptr<CSSVariableData> resolved_tokens) - : property_(property), - value_(value), - resolved_tokens_(std::move(resolved_tokens)) {} + ResolvedRegisteredCustomPropertyChecker(const PropertyHandle& property, + const CSSValue& value, + CSSVariableData* resolved_tokens) + : property_(property), value_(value), resolved_tokens_(resolved_tokens) {} void Trace(Visitor* visitor) const final { CSSInterpolationType::ConversionChecker::Trace(visitor); visitor->Trace(value_); + visitor->Trace(resolved_tokens_); } private: @@ -117,17 +115,17 @@ const InterpolationValue&) const final { const auto& css_environment = To<CSSInterpolationEnvironment>(environment); const CSSValue* resolved = css_environment.Resolve(property_, value_); - scoped_refptr<CSSVariableData> resolved_tokens; + CSSVariableData* resolved_tokens = nullptr; if (const auto* decl = DynamicTo<CSSUnparsedDeclarationValue>(resolved)) { resolved_tokens = decl->VariableDataValue(); } - return base::ValuesEquivalent(resolved_tokens, resolved_tokens_); + return base::ValuesEquivalent(resolved_tokens, resolved_tokens_.Get()); } PropertyHandle property_; Member<const CSSValue> value_; - scoped_refptr<CSSVariableData> resolved_tokens_; + Member<CSSVariableData> resolved_tokens_; }; template <typename RevertValueType> @@ -279,8 +277,7 @@ // CSSUnparsedDeclarationValue. Expand those keywords into real CSSValues // if present. bool is_inherited = Registration().Inherits(); - const StyleInitialData* initial_data = - state.StyleBuilder().InitialData().get(); + const StyleInitialData* initial_data = state.StyleBuilder().InitialData(); DCHECK(initial_data); const CSSValue* initial_value = initial_data->GetVariableValue(name);
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc index 2e49f669..2e4e1f4 100644 --- a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc +++ b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
@@ -716,7 +716,7 @@ Color(0, 128, 0)); constexpr gfx::SizeF initial_page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(initial_page_size); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(initial_page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); EXPECT_EQ(
diff --git a/third_party/blink/renderer/core/css/css_paint_value.cc b/third_party/blink/renderer/core/css/css_paint_value.cc index 2613370..b459c48 100644 --- a/third_party/blink/renderer/core/css/css_paint_value.cc +++ b/third_party/blink/renderer/core/css/css_paint_value.cc
@@ -39,9 +39,9 @@ CSSPaintValue::CSSPaintValue( CSSCustomIdentValue* name, - Vector<scoped_refptr<CSSVariableData>>& variable_data) + HeapVector<Member<CSSVariableData>>&& variable_data) : CSSPaintValue(name) { - argument_variable_data_.swap(variable_data); + argument_variable_data_ = variable_data; } CSSPaintValue::~CSSPaintValue() = default; @@ -52,7 +52,7 @@ result.Append(name_->CustomCSSText()); for (const auto& variable_data : argument_variable_data_) { result.Append(", "); - result.Append(variable_data.get()->Serialize()); + result.Append(variable_data.Get()->Serialize()); } result.Append(')'); return result.ReleaseString(); @@ -255,6 +255,7 @@ visitor->Trace(generators_); visitor->Trace(paint_image_generator_observer_); visitor->Trace(parsed_input_arguments_); + visitor->Trace(argument_variable_data_); CSSImageGeneratorValue::TraceAfterDispatch(visitor); }
diff --git a/third_party/blink/renderer/core/css/css_paint_value.h b/third_party/blink/renderer/core/css/css_paint_value.h index cfe2491a..8e30ed06 100644 --- a/third_party/blink/renderer/core/css/css_paint_value.h +++ b/third_party/blink/renderer/core/css/css_paint_value.h
@@ -23,7 +23,7 @@ explicit CSSPaintValue(CSSCustomIdentValue* name); CSSPaintValue(CSSCustomIdentValue* name, bool threaded_compositing_enabled); CSSPaintValue(CSSCustomIdentValue* name, - Vector<scoped_refptr<CSSVariableData>>&); + HeapVector<Member<CSSVariableData>>&&); ~CSSPaintValue(); String CustomCSSText() const; @@ -102,7 +102,7 @@ generators_; Member<Observer> paint_image_generator_observer_; Member<CSSStyleValueVector> parsed_input_arguments_; - Vector<scoped_refptr<CSSVariableData>> argument_variable_data_; + HeapVector<Member<CSSVariableData>> argument_variable_data_; enum class OffThreadPaintState { kUnknown, kOffThread, kMainThread }; // Indicates whether this paint worklet is composited or not. kUnknown // indicates that it has not been decided yet.
diff --git a/third_party/blink/renderer/core/css/css_test_helpers.cc b/third_party/blink/renderer/core/css/css_test_helpers.cc index d725943..eae653f0 100644 --- a/third_party/blink/renderer/core/css/css_test_helpers.cc +++ b/third_party/blink/renderer/core/css/css_test_helpers.cc
@@ -175,7 +175,7 @@ document.GetStyleEngine().PropertyRegistryChanged(); } -scoped_refptr<CSSVariableData> CreateVariableData(String s) { +CSSVariableData* CreateVariableData(String s) { bool is_animation_tainted = false; bool needs_variable_resolution = false; return CSSVariableData::Create(s, is_animation_tainted,
diff --git a/third_party/blink/renderer/core/css/css_test_helpers.h b/third_party/blink/renderer/core/css/css_test_helpers.h index f65e8a0..6e82358 100644 --- a/third_party/blink/renderer/core/css/css_test_helpers.h +++ b/third_party/blink/renderer/core/css/css_test_helpers.h
@@ -82,7 +82,7 @@ const std::optional<String>& initial_value, bool is_inherited); -scoped_refptr<CSSVariableData> CreateVariableData(String); +CSSVariableData* CreateVariableData(String); const CSSValue* CreateCustomIdent(const char*); const CSSValue* ParseLonghand(Document& document, const CSSProperty&,
diff --git a/third_party/blink/renderer/core/css/css_unparsed_declaration_value.cc b/third_party/blink/renderer/core/css/css_unparsed_declaration_value.cc index ca062b1..f3962e0 100644 --- a/third_party/blink/renderer/core/css/css_unparsed_declaration_value.cc +++ b/third_party/blink/renderer/core/css/css_unparsed_declaration_value.cc
@@ -10,6 +10,7 @@ blink::Visitor* visitor) const { CSSValue::TraceAfterDispatch(visitor); visitor->Trace(parser_context_); + visitor->Trace(data_); } String CSSUnparsedDeclarationValue::CustomCSSText() const {
diff --git a/third_party/blink/renderer/core/css/css_unparsed_declaration_value.h b/third_party/blink/renderer/core/css/css_unparsed_declaration_value.h index 69d9524..189abd8 100644 --- a/third_party/blink/renderer/core/css/css_unparsed_declaration_value.h +++ b/third_party/blink/renderer/core/css/css_unparsed_declaration_value.h
@@ -34,16 +34,16 @@ // https://drafts.csswg.org/css-variables/#defining-variables class CORE_EXPORT CSSUnparsedDeclarationValue final : public CSSValue { public: - explicit CSSUnparsedDeclarationValue(scoped_refptr<CSSVariableData> data) - : CSSValue(kUnparsedDeclarationClass), data_(std::move(data)) {} + explicit CSSUnparsedDeclarationValue(CSSVariableData* data) + : CSSValue(kUnparsedDeclarationClass), data_(data) {} - CSSUnparsedDeclarationValue(scoped_refptr<CSSVariableData> data, + CSSUnparsedDeclarationValue(CSSVariableData* data, const CSSParserContext* context) : CSSValue(kUnparsedDeclarationClass), parser_context_(context), - data_(std::move(data)) {} + data_(data) {} - CSSVariableData* VariableDataValue() const { return data_.get(); } + CSSVariableData* VariableDataValue() const { return data_.Get(); } const CSSParserContext* ParserContext() const { // TODO(crbug.com/985028): CSSUnparsedDeclarationValue should always have // a CSSParserContext. @@ -61,7 +61,7 @@ // The parser context is used to resolve relative URLs, as described in: // https://drafts.css-houdini.org/css-properties-values-api-1/#relative-urls const Member<const CSSParserContext> parser_context_; - scoped_refptr<CSSVariableData> data_; + Member<CSSVariableData> data_; }; template <>
diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc index a747697..c54eb1b 100644 --- a/third_party/blink/renderer/core/css/css_variable_data.cc +++ b/third_party/blink/renderer/core/css/css_variable_data.cc
@@ -62,10 +62,9 @@ has_line_height_units |= IsLineHeightUnitToken(token); } -scoped_refptr<CSSVariableData> CSSVariableData::Create( - CSSTokenizedValue value, - bool is_animation_tainted, - bool needs_variable_resolution) { +CSSVariableData* CSSVariableData::Create(CSSTokenizedValue value, + bool is_animation_tainted, + bool needs_variable_resolution) { bool has_font_units = false; bool has_root_font_units = false; bool has_line_height_units = false; @@ -77,10 +76,9 @@ has_font_units, has_root_font_units, has_line_height_units); } -scoped_refptr<CSSVariableData> CSSVariableData::Create( - const String& original_text, - bool is_animation_tainted, - bool needs_variable_resolution) { +CSSVariableData* CSSVariableData::Create(const String& original_text, + bool is_animation_tainted, + bool needs_variable_resolution) { bool has_font_units = false; bool has_root_font_units = false; bool has_line_height_units = false; @@ -142,7 +140,8 @@ return OriginalText() == other.OriginalText(); } -CSSVariableData::CSSVariableData(StringView original_text, +CSSVariableData::CSSVariableData(PassKey, + StringView original_text, bool is_animation_tainted, bool needs_variable_resolution, bool has_font_units,
diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h index 885f69a..526b3381 100644 --- a/third_party/blink/renderer/core/css/css_variable_data.h +++ b/third_party/blink/renderer/core/css/css_variable_data.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VARIABLE_DATA_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VARIABLE_DATA_H_ +#include "base/types/pass_key.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/parser/css_parser_token.h" #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h" @@ -18,52 +19,64 @@ class CSSSyntaxDefinition; enum class SecureContextMode; -class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> { - USING_FAST_MALLOC(CSSVariableData); - +class CORE_EXPORT CSSVariableData : public GarbageCollected<CSSVariableData> { public: - static scoped_refptr<CSSVariableData> Create() { - return base::AdoptRef(new CSSVariableData()); - } + CSSVariableData() + : length_(0), + is_animation_tainted_(false), + needs_variable_resolution_(false), + is_8bit_(true), + has_font_units_(false), + has_root_font_units_(false), + has_line_height_units_(false), + unused_(0) {} + + using PassKey = base::PassKey<CSSVariableData>; + CSSVariableData(PassKey, + StringView, + bool is_animation_tainted, + bool needs_variable_resolution, + bool has_font_units, + bool has_root_font_units, + bool has_line_height_units); // This is the fastest (non-trivial) constructor if you've got the has_* data // already, e.g. because you extracted them while tokenizing (see // ExtractFeatures()) or got them from another CSSVariableData instance during // substitution. - static scoped_refptr<CSSVariableData> Create(StringView original_text, - bool is_animation_tainted, - bool needs_variable_resolution, - bool has_font_units, - bool has_root_font_units, - bool has_line_height_units) { + static CSSVariableData* Create(StringView original_text, + bool is_animation_tainted, + bool needs_variable_resolution, + bool has_font_units, + bool has_root_font_units, + bool has_line_height_units) { if (original_text.length() > kMaxVariableBytes) { // This should have been blocked off during variable substitution. NOTREACHED_IN_MIGRATION(); return nullptr; } - wtf_size_t bytes_needed = - sizeof(CSSVariableData) + (original_text.Is8Bit() - ? original_text.length() - : 2 * original_text.length()); - void* buf = WTF::Partitions::FastMalloc( - bytes_needed, WTF::GetStringWithTypeName<CSSVariableData>()); - return base::AdoptRef(new (buf) CSSVariableData( - original_text, is_animation_tainted, needs_variable_resolution, - has_font_units, has_root_font_units, has_line_height_units)); + return MakeGarbageCollected<CSSVariableData>( + AdditionalBytes(original_text.Is8Bit() ? original_text.length() + : 2 * original_text.length()), + PassKey(), original_text, is_animation_tainted, + needs_variable_resolution, has_font_units, has_root_font_units, + has_line_height_units); } // Second-fastest; scans through all the tokens to determine the has_* data. // (The tokens are not used apart from that; only the original string is // stored.) The tokens must correspond to the given string. - static scoped_refptr<CSSVariableData> Create(CSSTokenizedValue value, - bool is_animation_tainted, - bool needs_variable_resolution); + static CSSVariableData* Create(CSSTokenizedValue value, + bool is_animation_tainted, + bool needs_variable_resolution); // Like the previous, but also needs to tokenize the string. - static scoped_refptr<CSSVariableData> Create(const String& original_text, - bool is_animation_tainted, - bool needs_variable_resolution); + static CSSVariableData* Create(const String& original_text, + bool is_animation_tainted, + bool needs_variable_resolution); + + void Trace(Visitor*) const {} StringView OriginalText() const { if (is_8bit_) { @@ -116,24 +129,6 @@ static const size_t kMaxVariableBytes = 2097152; private: - CSSVariableData() - : length_(0), - is_animation_tainted_(false), - needs_variable_resolution_(false), - is_8bit_(true), - has_font_units_(false), - has_root_font_units_(false), - has_line_height_units_(false), - unused_(0) {} - - CSSVariableData(StringView, - bool is_animation_tainted, - bool needs_variable_resolution, - bool has_font_units, - bool has_root_font_units, - bool has_line_height_units); - - // 32 bits refcount before this. // We'd like to use bool for the booleans, but this causes the struct to // balloon in size on Windows: @@ -154,7 +149,7 @@ }; #if !DCHECK_IS_ON() -static_assert(sizeof(CSSVariableData) <= 8, +static_assert(sizeof(CSSVariableData) <= 4, "CSSVariableData must not grow without thinking"); #endif
diff --git a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc index c907515a..a74d344e 100644 --- a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc +++ b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc
@@ -121,7 +121,7 @@ if (range.AtEnd()) { return MakeGarbageCollected<CSSUnparsedDeclarationValue>( - CSSVariableData::Create()); + MakeGarbageCollected<CSSVariableData>()); } // The string we just parsed has /**/ inserted between every token
diff --git a/third_party/blink/renderer/core/css/cssom/style_value_factory.cc b/third_party/blink/renderer/core/css/cssom/style_value_factory.cc index 84aed61..abae423 100644 --- a/third_party/blink/renderer/core/css/cssom/style_value_factory.cc +++ b/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
@@ -337,7 +337,7 @@ if ((property_id == CSSPropertyID::kVariable && !tokens.empty()) || CSSVariableParser::ContainsValidVariableReferences( range, parser_context->GetExecutionContext())) { - const auto variable_data = CSSVariableData::Create( + const auto* variable_data = CSSVariableData::Create( {range, StringView(css_text)}, false /* is_animation_tainted */, false /* needs variable resolution */); CSSStyleValueVector values;
diff --git a/third_party/blink/renderer/core/css/document_style_environment_variables.cc b/third_party/blink/renderer/core/css/document_style_environment_variables.cc index a11b99f3b..c98806fa 100644 --- a/third_party/blink/renderer/core/css/document_style_environment_variables.cc +++ b/third_party/blink/renderer/core/css/document_style_environment_variables.cc
@@ -23,19 +23,6 @@ return StringHasher::ComputeHash(name.Characters16(), name.length()); } -// static -scoped_refptr<DocumentStyleEnvironmentVariables> -DocumentStyleEnvironmentVariables::Create(StyleEnvironmentVariables& parent, - Document& document) { - scoped_refptr<DocumentStyleEnvironmentVariables> obj = - base::AdoptRef(new DocumentStyleEnvironmentVariables(document)); - - // Add a reference to this instance from the root. - obj->BindToParent(parent); - - return obj; -} - CSSVariableData* DocumentStyleEnvironmentVariables::ResolveVariable( const AtomicString& name, WTF::Vector<unsigned> indices, @@ -74,8 +61,9 @@ } DocumentStyleEnvironmentVariables::DocumentStyleEnvironmentVariables( + StyleEnvironmentVariables& parent, Document& document) - : document_(&document) {} + : StyleEnvironmentVariables(parent), document_(&document) {} void DocumentStyleEnvironmentVariables::RecordVariableUsage(unsigned id) { UseCounter::Count(document_, WebFeature::kCSSEnvironmentVariable);
diff --git a/third_party/blink/renderer/core/css/document_style_environment_variables.h b/third_party/blink/renderer/core/css/document_style_environment_variables.h index 8f1e5ad..d8ce065 100644 --- a/third_party/blink/renderer/core/css/document_style_environment_variables.h +++ b/third_party/blink/renderer/core/css/document_style_environment_variables.h
@@ -26,9 +26,13 @@ // Create an instance bound to |parent| that will invalidate |document|'s // style when a variable is changed. - static scoped_refptr<DocumentStyleEnvironmentVariables> Create( - StyleEnvironmentVariables& parent, - Document& document); + DocumentStyleEnvironmentVariables(StyleEnvironmentVariables& parent, + Document& document); + + void Trace(Visitor* visitor) const override { + visitor->Trace(document_); + StyleEnvironmentVariables::Trace(visitor); + } // Resolve the variable |name| and return the data. This will also cause // future changes to this variable to invalidate the associated document's @@ -52,13 +56,11 @@ void InvalidateVariable(const AtomicString& name) override; private: - DocumentStyleEnvironmentVariables(Document& document); - // Record variable usage using |UseCounter|. void RecordVariableUsage(unsigned id); HashSet<unsigned> seen_variables_; - Persistent<Document> document_; + Member<Document> document_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc b/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc index 7df5990..1b0a8b9 100644 --- a/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc +++ b/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc
@@ -124,6 +124,8 @@ bool InvalidationSet::InvalidatesElement(Element& element) const { if (invalidation_flags_.WholeSubtreeInvalid()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED( + element, kInvalidationSetInvalidatesSubtree, *this, g_empty_atom); return true; } @@ -373,6 +375,9 @@ return; } + InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + this, InvalidationSetToSelectorMap::SelectorFeatureType::kWholeSubtree, + g_empty_atom); invalidation_flags_.SetWholeSubtreeInvalid(true); invalidation_flags_.SetInvalidateCustomPseudo(false); invalidation_flags_.SetTreeBoundaryCrossing(false);
diff --git a/third_party/blink/renderer/core/css/invalidation/pending_invalidations.cc b/third_party/blink/renderer/core/css/invalidation/pending_invalidations.cc index 09f3e47..0094746 100644 --- a/third_party/blink/renderer/core/css/invalidation/pending_invalidations.cc +++ b/third_party/blink/renderer/core/css/invalidation/pending_invalidations.cc
@@ -30,6 +30,11 @@ if (invalidation_set->WholeSubtreeInvalid()) { auto* shadow_root = DynamicTo<ShadowRoot>(node); auto* subtree_root = shadow_root ? &shadow_root->host() : &node; + if (subtree_root->IsElementNode()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SET( + To<Element>(*subtree_root), kInvalidationSetInvalidatesSubtree, + *invalidation_set); + } subtree_root->SetNeedsStyleRecalc( kSubtreeStyleChange, StyleChangeReasonForTracing::Create( style_change_reason::kRelatedStyleRule)); @@ -38,6 +43,9 @@ } if (invalidation_set->InvalidatesSelf() && node.IsElementNode()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SET( + To<Element>(node), kInvalidationSetInvalidatesSelf, + *invalidation_set); node.SetNeedsStyleRecalc(kLocalStyleChange, StyleChangeReasonForTracing::Create( style_change_reason::kRelatedStyleRule)); @@ -126,8 +134,17 @@ for (auto& invalidation_set : invalidation_lists.siblings) { DescendantInvalidationSet* descendants = To<SiblingInvalidationSet>(*invalidation_set).SiblingDescendants(); - if (invalidation_set->WholeSubtreeInvalid() || - (descendants && descendants->WholeSubtreeInvalid())) { + bool whole_subtree_invalid = false; + if (invalidation_set->WholeSubtreeInvalid()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SET( + *subtree_root, kInvalidationSetInvalidatesSubtree, *invalidation_set); + whole_subtree_invalid = true; + } else if (descendants && descendants->WholeSubtreeInvalid()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SET( + *subtree_root, kInvalidationSetInvalidatesSubtree, *descendants); + whole_subtree_invalid = true; + } + if (whole_subtree_invalid) { subtree_root->SetNeedsStyleRecalc( kSubtreeStyleChange, StyleChangeReasonForTracing::Create( style_change_reason::kRelatedStyleRule));
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc index 2d5fbe6..9ddc186 100644 --- a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc +++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
@@ -179,6 +179,8 @@ if (const DescendantInvalidationSet* descendants = invalidation_set.SiblingDescendants()) { if (descendants->WholeSubtreeInvalid()) { + TRACE_STYLE_INVALIDATOR_INVALIDATION_SET( + element, kInvalidationSetInvalidatesSubtree, *descendants); element.SetNeedsStyleRecalc( kSubtreeStyleChange, StyleChangeReasonForTracing::Create( style_change_reason::kRelatedStyleRule));
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.cc b/third_party/blink/renderer/core/css/parser/container_query_parser.cc index b73dc3c..4ec90dd 100644 --- a/third_party/blink/renderer/core/css/parser/container_query_parser.cc +++ b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
@@ -132,7 +132,8 @@ MediaQueryParser::SyntaxLevel::kLevel4) {} const MediaQueryExpNode* ContainerQueryParser::ParseCondition(String value) { - auto [tokens, raw_offsets] = CSSTokenizer(value).TokenizeToEOFWithOffsets(); + CSSTokenizer tokenizer(value); + auto [tokens, raw_offsets] = tokenizer.TokenizeToEOFWithOffsets(); CSSParserTokenRange range(tokens); CSSParserTokenOffsets offsets(tokens, std::move(raw_offsets), value); return ParseCondition(range, offsets);
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc index 94ef0e9..1672403 100644 --- a/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc +++ b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
@@ -86,6 +86,11 @@ EXPECT_EQ(String(test), ParseQuery(test)); } + // Escaped (unnecessarily but validly) characters in the identifier. + EXPECT_EQ("(width)", ParseQuery("(\\77 idth)")); + // Repro case for b/341640868 + EXPECT_EQ("(min-width: 100px)", ParseQuery("(min\\2d width: 100px)")); + // Invalid: EXPECT_EQ("<unknown>", ParseQuery("(min-width)")); EXPECT_EQ("<unknown>", ParseQuery("((width) or (width) and (width))"));
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc index c76b0d0f..44ec4200 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc +++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -2166,7 +2166,7 @@ } // Parse the actual returned value. - scoped_refptr<CSSVariableData> return_value; + CSSVariableData* return_value = nullptr; { CSSParserTokenStream::Boundary boundary(stream, kSemicolonToken); CSSTokenizedValue tokenized_value = @@ -2185,8 +2185,8 @@ } return MakeGarbageCollected<StyleRuleFunction>( - name.Value().ToAtomicString(), std::move(*parameters), - std::move(return_value), std::move(*return_type)); + name.Value().ToAtomicString(), std::move(*parameters), return_value, + std::move(*return_type)); } // Parse the parameters of a CSS function: Zero or more comma-separated
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_token.h b/third_party/blink/renderer/core/css/parser/css_parser_token.h index 0a8b174..a678d645 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_token.h +++ b/third_party/blink/renderer/core/css/parser/css_parser_token.h
@@ -95,6 +95,8 @@ value_is_8bit_(false), // Don't care. padding_(0) // Don't care. {} + + // The resulting CSSParserToken may hold a reference to the data in value. CSSParserToken(CSSParserTokenType type, StringView value, BlockType block_type = kNotBlock)
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer.h b/third_party/blink/renderer/core/css/parser/css_tokenizer.h index 830e8ffa..de46445c 100644 --- a/third_party/blink/renderer/core/css/parser/css_tokenizer.h +++ b/third_party/blink/renderer/core/css/parser/css_tokenizer.h
@@ -31,6 +31,9 @@ CSSTokenizer(const CSSTokenizer&) = delete; CSSTokenizer& operator=(const CSSTokenizer&) = delete; + // The CSSParserTokens in the result may hold references to the CSSTokenizer + // object, or the string data referenced by the CSSTokenizer. Do not use the + // tokens after the CSSTokenizer or its underlying String goes out of scope. Vector<CSSParserToken, 32> TokenizeToEOF(); wtf_size_t TokenCount(); @@ -38,6 +41,8 @@ // There's an extra offset at the very end that returns the end byte // of the last token, i.e., the length of the input string. // This matches the convention CSSParserTokenOffsets expects. + // + // See the warning about holding a reference in TokenizeToEOF(). std::pair<Vector<CSSParserToken, 32>, Vector<wtf_size_t, 32>> TokenizeToEOFWithOffsets(); @@ -45,6 +50,8 @@ // to solve a design mistake in CSS. // // https://drafts.csswg.org/css-syntax/#consume-unicode-range-value + // + // See the warning about holding a reference in TokenizeToEOF(). Vector<CSSParserToken, 32> TokenizeToEOFWithUnicodeRanges(); wtf_size_t Offset() const { return input_.Offset(); }
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 d016112..06e6e9a3 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
@@ -693,7 +693,7 @@ // Add CSSVariableData to variableData vector. bool AddCSSPaintArgument( const Vector<CSSParserToken>& tokens, - Vector<scoped_refptr<CSSVariableData>>* const variable_data, + HeapVector<Member<CSSVariableData>>* const variable_data, const CSSParserContext& context) { CSSParserTokenRange token_range(tokens); if (CSSVariableParser::ContainsValidVariableReferences( @@ -707,10 +707,9 @@ // if we get normalized whitespace etc., so we work around it by creating // a fake “original text” by serializing the tokens back. String text = token_range.Serialize(); - scoped_refptr<CSSVariableData> unparsed_css_variable_data = - CSSVariableData::Create({token_range, text}, false, false); - if (unparsed_css_variable_data.get()) { - variable_data->push_back(std::move(unparsed_css_variable_data)); + if (CSSVariableData* unparsed_css_variable_data = + CSSVariableData::Create({token_range, text}, false, false)) { + variable_data->push_back(unparsed_css_variable_data); return true; } } @@ -3816,7 +3815,7 @@ // TODO(renjieliu): We may want to optimize the implementation by resolve // variables early if paint function is registered. Vector<CSSParserToken> argument_tokens; - Vector<scoped_refptr<CSSVariableData>> variable_data; + HeapVector<Member<CSSVariableData>> variable_data; while (!args.AtEnd()) { if (args.Peek().GetType() != kCommaToken) { argument_tokens.AppendVector(ConsumeFunctionArgsOrNot(args)); @@ -3834,7 +3833,7 @@ return nullptr; } - return MakeGarbageCollected<CSSPaintValue>(name, variable_data); + return MakeGarbageCollected<CSSPaintValue>(name, std::move(variable_data)); } template <typename T>
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc index 9da67e4..c06b5ed 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -87,8 +87,7 @@ return; } - const StyleInitialData* initial_data = - state.StyleBuilder().InitialData().get(); + const StyleInitialData* initial_data = state.StyleBuilder().InitialData(); DCHECK(initial_data); CSSVariableData* initial_variable_data = initial_data->GetVariableData(name_); const CSSValue* initial_value = initial_data->GetVariableValue(name_); @@ -206,7 +205,7 @@ registered_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue( state, *registered_value, context); - scoped_refptr<CSSVariableData> data = + CSSVariableData* data = StyleBuilderConverter::ConvertRegisteredPropertyVariableData( *registered_value, is_animation_tainted);
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc index fb27d3c..fc68031 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -297,8 +297,7 @@ CustomProperty property(AtomicString("--x"), GetDocument()); - scoped_refptr<CSSVariableData> data = - css_test_helpers::CreateVariableData("100px"); + CSSVariableData* data = css_test_helpers::CreateVariableData("100px"); ASSERT_FALSE(data->IsAnimationTainted()); auto* declaration = MakeGarbageCollected<CSSUnparsedDeclarationValue>( data, /* parser_context */ nullptr);
diff --git a/third_party/blink/renderer/core/css/property_registration.cc b/third_party/blink/renderer/core/css/property_registration.cc index 786f0755..1551943 100644 --- a/third_party/blink/renderer/core/css/property_registration.cc +++ b/third_party/blink/renderer/core/css/property_registration.cc
@@ -135,7 +135,7 @@ if (!initial_value) { return syntax.IsUniversal() ? std::make_optional(nullptr) : std::nullopt; } - scoped_refptr<CSSVariableData> initial_variable_data = + CSSVariableData* initial_variable_data = To<CSSUnparsedDeclarationValue>(*initial_value).VariableDataValue(); // Parse initial value, if we have it.
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc index 1ed2855..e5ecfc1 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -3060,8 +3060,7 @@ // (and registered) custom properties work correctly. // // https://drafts.css-houdini.org/css-properties-values-api-1/#substitution -scoped_refptr<CSSVariableData> -StyleBuilderConverter::ConvertRegisteredPropertyVariableData( +CSSVariableData* StyleBuilderConverter::ConvertRegisteredPropertyVariableData( const CSSValue& value, bool is_animation_tainted) { // TODO(andruud): Produce tokens directly from CSSValue.
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h index de038661a..f6515bdd 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -332,7 +332,7 @@ const CSSValue&, const CSSParserContext*); - static scoped_refptr<CSSVariableData> ConvertRegisteredPropertyVariableData( + static CSSVariableData* ConvertRegisteredPropertyVariableData( const CSSValue&, bool is_animation_tainted);
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc index e948cdd..7a31d7c9 100644 --- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc +++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -972,8 +972,7 @@ original_text_.Append(original_text); } -scoped_refptr<CSSVariableData> -StyleCascade::TokenSequence::BuildVariableData() { +CSSVariableData* StyleCascade::TokenSequence::BuildVariableData() { return CSSVariableData::Create(original_text_, is_animation_tainted_, /*needs_variable_resolution=*/false, has_font_units_, has_root_font_units_, @@ -1037,17 +1036,17 @@ DCHECK(!resolver.IsLocked(property)); CascadeResolver::AutoLock lock(property, resolver); - scoped_refptr<CSSVariableData> data = decl.VariableDataValue(); + CSSVariableData* data = decl.VariableDataValue(); if (data->NeedsVariableResolution()) { - data = ResolveVariableData(data.get(), *GetParserContext(decl), resolver); + data = ResolveVariableData(data, *GetParserContext(decl), resolver); } - if (HasFontSizeDependency(To<CustomProperty>(property), data.get())) { + if (HasFontSizeDependency(To<CustomProperty>(property), data)) { resolver.DetectCycle(GetCSSPropertyFontSize()); } - if (HasLineHeightDependency(To<CustomProperty>(property), data.get())) { + if (HasLineHeightDependency(To<CustomProperty>(property), data)) { resolver.DetectCycle(GetCSSPropertyLineHeight()); } @@ -1326,7 +1325,7 @@ return scoped_math_value; } -scoped_refptr<CSSVariableData> StyleCascade::ResolveVariableData( +CSSVariableData* StyleCascade::ResolveVariableData( CSSVariableData* data, const CSSParserContext& context, CascadeResolver& resolver) { @@ -1429,13 +1428,13 @@ // Note that even if we are in a cycle, we must proceed in order to discover // secondary cycles via the var() fallback. - scoped_refptr<CSSVariableData> data = GetVariableData(property); + CSSVariableData* data = GetVariableData(property); // If substitution is not allowed, treat the value as // invalid-at-computed-value-time. // // https://drafts.csswg.org/css-variables/#animation-tainted - if (!resolver.AllowSubstitution(data.get())) { + if (!resolver.AllowSubstitution(data)) { data = nullptr; } @@ -1467,8 +1466,7 @@ return false; } - return out.Append(data.get(), parent_tokenizer, - CSSVariableData::kMaxVariableBytes); + return out.Append(data, parent_tokenizer, CSSVariableData::kMaxVariableBytes); } bool StyleCascade::ResolveFunctionInto(StringView function_name,
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.h b/third_party/blink/renderer/core/css/resolver/style_cascade.h index 469a6cd..f820c253 100644 --- a/third_party/blink/renderer/core/css/resolver/style_cascade.h +++ b/third_party/blink/renderer/core/css/resolver/style_cascade.h
@@ -298,7 +298,7 @@ // template machinery) of TokenSequence and everything calling it. void StripCommentTokens(); - scoped_refptr<CSSVariableData> BuildVariableData(); + CSSVariableData* BuildVariableData(); private: // In cases where we're not building a CSSValue, we don't really care about @@ -380,9 +380,9 @@ const CSSMathFunctionValue&, CascadePriority); - scoped_refptr<CSSVariableData> ResolveVariableData(CSSVariableData*, - const CSSParserContext&, - CascadeResolver&); + CSSVariableData* ResolveVariableData(CSSVariableData*, + const CSSParserContext&, + CascadeResolver&); // Certain parts of CSS function evaluation may need some local context // supplied by the caller. Given the current scoping strategy, the only
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc index 1c4c9796..3fe3e40 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1871,10 +1871,8 @@ : EUserModify::kReadOnly); FontBuilder(&GetDocument()).CreateInitialFont(builder); - scoped_refptr<StyleInitialData> initial_data = - engine.MaybeCreateAndGetInitialData(); - if (initial_data) { - builder.SetInitialData(std::move(initial_data)); + if (StyleInitialData* initial_data = engine.MaybeCreateAndGetInitialData()) { + builder.SetInitialData(initial_data); } if (RuntimeEnabledFeatures::PreferDefaultScrollbarStylesEnabled()) {
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index 45973f7..15b8073 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -3253,22 +3253,23 @@ DocumentStyleEnvironmentVariables& StyleEngine::EnsureEnvironmentVariables() { if (!environment_variables_) { - environment_variables_ = DocumentStyleEnvironmentVariables::Create( - StyleEnvironmentVariables::GetRootInstance(), *document_); + environment_variables_ = + MakeGarbageCollected<DocumentStyleEnvironmentVariables>( + StyleEnvironmentVariables::GetRootInstance(), *document_); } - return *environment_variables_.get(); + return *environment_variables_.Get(); } -scoped_refptr<StyleInitialData> StyleEngine::MaybeCreateAndGetInitialData() { - if (initial_data_) { - return initial_data_; - } - if (const PropertyRegistry* registry = document_->GetPropertyRegistry()) { - if (!registry->IsEmpty()) { - initial_data_ = StyleInitialData::Create(GetDocument(), *registry); +StyleInitialData* StyleEngine::MaybeCreateAndGetInitialData() { + if (!initial_data_) { + if (const PropertyRegistry* registry = document_->GetPropertyRegistry()) { + if (!registry->IsEmpty()) { + initial_data_ = + MakeGarbageCollected<StyleInitialData>(GetDocument(), *registry); + } } } - return initial_data_; + return initial_data_.Get(); } bool StyleEngine::RecalcHighlightStylesForContainer(Element& container) { @@ -4286,6 +4287,8 @@ visitor->Trace(font_palette_values_rule_map_); visitor->Trace(user_counter_style_map_); visitor->Trace(user_cascade_layer_map_); + visitor->Trace(environment_variables_); + visitor->Trace(initial_data_); visitor->Trace(inspector_style_sheet_); visitor->Trace(document_style_sheet_collection_); visitor->Trace(style_sheet_collection_map_);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h index 18ed93f..05ff223 100644 --- a/third_party/blink/renderer/core/css/style_engine.h +++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -604,7 +604,7 @@ DocumentStyleEnvironmentVariables& EnsureEnvironmentVariables(); - scoped_refptr<StyleInitialData> MaybeCreateAndGetInitialData(); + StyleInitialData* MaybeCreateAndGetInitialData(); bool NeedsStyleInvalidation() const { return style_invalidation_root_.GetRootNode(); @@ -1035,9 +1035,9 @@ Member<CascadeLayerMap> user_cascade_layer_map_; - scoped_refptr<DocumentStyleEnvironmentVariables> environment_variables_; + Member<DocumentStyleEnvironmentVariables> environment_variables_; - scoped_refptr<StyleInitialData> initial_data_; + Member<StyleInitialData> initial_data_; // Page color schemes set by the viewport meta tag. E.g. // <meta name="color-scheme" content="light dark">.
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index 480e3f4..f79d97c 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -571,7 +571,7 @@ t8->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor())); gfx::SizeF page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(page_size, 1); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size)); ASSERT_TRUE(t8->GetComputedStyle()); EXPECT_EQ( Color::FromRGB(0, 0, 0), @@ -2710,7 +2710,7 @@ // After registering, there should be initial data. css_test_helpers::RegisterProperty(GetDocument(), "--x", "<length>", "10px", false); - auto data1 = GetStyleEngine().MaybeCreateAndGetInitialData(); + auto* data1 = GetStyleEngine().MaybeCreateAndGetInitialData(); EXPECT_TRUE(data1); // After a full recalc, we should have the same initial data. @@ -2718,7 +2718,7 @@ EXPECT_TRUE(GetDocument().documentElement()->NeedsStyleRecalc()); EXPECT_TRUE(GetDocument().documentElement()->ChildNeedsStyleRecalc()); UpdateAllLifecyclePhases(); - auto data2 = GetStyleEngine().MaybeCreateAndGetInitialData(); + auto* data2 = GetStyleEngine().MaybeCreateAndGetInitialData(); EXPECT_TRUE(data2); EXPECT_EQ(data1, data2); @@ -3554,7 +3554,7 @@ body->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor())); gfx::SizeF page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(page_size, 1); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size)); EXPECT_EQ(Color::kBlack, root->GetComputedStyle()->VisitedDependentColor( GetCSSPropertyColor())); EXPECT_EQ(mojom::blink::ColorScheme::kLight, @@ -3589,7 +3589,7 @@ true); gfx::SizeF page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(page_size, 1); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size)); EXPECT_EQ(frame_view->DocumentBackgroundColor(), Color::kWhite); EXPECT_EQ(GetDocument().documentElement()->GetComputedStyle()->ForceDark(), false); @@ -3624,7 +3624,7 @@ body->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor())); gfx::SizeF page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(page_size, 1); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size)); EXPECT_EQ( Color::FromRGB(0, 128, 0), body->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor())); @@ -4940,7 +4940,7 @@ EXPECT_FALSE(html_audio->GetComputedStyle()); gfx::SizeF page_size(400, 400); - GetDocument().GetFrame()->StartPrinting(page_size, 1); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size)); // Also for printing. EXPECT_TRUE(audio->GetComputedStyle());
diff --git a/third_party/blink/renderer/core/css/style_environment_variables.cc b/third_party/blink/renderer/core/css/style_environment_variables.cc index 2f2c0f3..9bbf0db 100644 --- a/third_party/blink/renderer/core/css/style_environment_variables.cc +++ b/third_party/blink/renderer/core/css/style_environment_variables.cc
@@ -43,26 +43,15 @@ } // namespace. -// This owns the static root instance. -class StyleEnvironmentVariables::RootOwner { - public: - StyleEnvironmentVariables& GetRoot() { - if (!instance_) { - instance_ = base::AdoptRef(new StyleEnvironmentVariables()); - SetDefaultEnvironmentVariables(instance_.get()); - } - - return *instance_.get(); - } - - private: - scoped_refptr<StyleEnvironmentVariables> instance_; -}; +StyleEnvironmentVariables::StyleEnvironmentVariables() : parent_(nullptr) { + SetDefaultEnvironmentVariables(this); +} // static StyleEnvironmentVariables& StyleEnvironmentVariables::GetRootInstance() { - static auto* instance = new StyleEnvironmentVariables::RootOwner(); - return instance->GetRoot(); + DEFINE_STATIC_LOCAL(Persistent<StyleEnvironmentVariables>, instance, + (MakeGarbageCollected<StyleEnvironmentVariables>())); + return *instance; } // static @@ -134,33 +123,11 @@ NOTREACHED_IN_MIGRATION(); } -// static -scoped_refptr<StyleEnvironmentVariables> StyleEnvironmentVariables::Create( - StyleEnvironmentVariables& parent) { - scoped_refptr<StyleEnvironmentVariables> obj = - base::AdoptRef(new StyleEnvironmentVariables()); - - // Add a reference to this instance from the parent. - obj->BindToParent(parent); - - return obj; -} - -StyleEnvironmentVariables::~StyleEnvironmentVariables() { - // Remove a reference to this instance from the parent. - if (parent_) { - auto it = parent_->children_.Find(this); - DCHECK(it != kNotFound); - parent_->children_.EraseAt(it); - } -} - void StyleEnvironmentVariables::SetVariable(const AtomicString& name, const String& value) { - scoped_refptr<CSSVariableData> variable_data = - CSSVariableData::Create(value, false /* is_animation_tainted */, - false /* needs_variable_resolution */); - data_.Set(name, std::move(variable_data)); + data_.Set(name, + CSSVariableData::Create(value, false /* is_animation_tainted */, + false /* needs_variable_resolution */)); InvalidateVariable(name); } @@ -180,7 +147,7 @@ return; } - scoped_refptr<CSSVariableData> variable_data = + CSSVariableData* variable_data = CSSVariableData::Create(value, false /* is_animation_tainted */, false /* needs_variable_resolution */); @@ -250,7 +217,7 @@ if (result == data_.end()) { return nullptr; } - return result->value.get(); + return result->value.Get(); } else if (indices.size() == 2u) { auto result = two_dimension_data_.find(name); if (result == two_dimension_data_.end() && parent_) { @@ -266,7 +233,7 @@ second_dimension >= result->value[first_dimension].size()) { return nullptr; } - return result->value[first_dimension][second_dimension].get(); + return result->value[first_dimension][second_dimension].Get(); } return nullptr; @@ -301,13 +268,6 @@ } } -void StyleEnvironmentVariables::BindToParent( - StyleEnvironmentVariables& parent) { - DCHECK_EQ(nullptr, parent_); - parent_ = &parent; - parent.children_.push_back(this); -} - void StyleEnvironmentVariables::ParentInvalidatedVariable( const AtomicString& name) { // If we have not overridden the variable then we should invalidate it
diff --git a/third_party/blink/renderer/core/css/style_environment_variables.h b/third_party/blink/renderer/core/css/style_environment_variables.h index e4828a8b..482a8369 100644 --- a/third_party/blink/renderer/core/css/style_environment_variables.h +++ b/third_party/blink/renderer/core/css/style_environment_variables.h
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/css_variable_data.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -71,7 +72,7 @@ // UADefinedVariable. Note that UADefinedVariables are not always set/defined, // as they depend on the environment. class CORE_EXPORT StyleEnvironmentVariables - : public RefCounted<StyleEnvironmentVariables> { + : public GarbageCollected<StyleEnvironmentVariables> { public: static StyleEnvironmentVariables& GetRootInstance(); @@ -85,11 +86,23 @@ UADefinedTwoDimensionalVariable variable, const FeatureContext* feature_context); - // Create a new instance bound to |parent|. - static scoped_refptr<StyleEnvironmentVariables> Create( - StyleEnvironmentVariables& parent); + // Create a new root instance. + StyleEnvironmentVariables(); - virtual ~StyleEnvironmentVariables(); + // Create a new instance bound to |parent|. + StyleEnvironmentVariables(StyleEnvironmentVariables& parent) + : parent_(parent) { + parent.children_.push_back(this); + } + + virtual ~StyleEnvironmentVariables() = default; + + virtual void Trace(Visitor* visitor) const { + visitor->Trace(children_); + visitor->Trace(data_); + visitor->Trace(two_dimension_data_); + visitor->Trace(parent_); + } // Tokenize |value| and set it. This will invalidate any dependents. void SetVariable(UADefinedVariable variable, const String& value); @@ -137,28 +150,21 @@ void ClearForTesting(); - // Bind this instance to a |parent|. This should only be called once. - void BindToParent(StyleEnvironmentVariables& parent); - // Called by the parent to tell the child that variable |name| has changed. void ParentInvalidatedVariable(const AtomicString& name); - StyleEnvironmentVariables() : parent_(nullptr) {} - // Called when variable |name| is changed. This will notify any children that // this variable has changed. virtual void InvalidateVariable(const AtomicString& name); private: - class RootOwner; - - typedef WTF::Vector<WTF::Vector<scoped_refptr<CSSVariableData>>> + typedef HeapVector<HeapVector<Member<CSSVariableData>>> TwoDimensionVariableValues; - Vector<scoped_refptr<StyleEnvironmentVariables>> children_; - HashMap<AtomicString, scoped_refptr<CSSVariableData>> data_; - HashMap<AtomicString, TwoDimensionVariableValues> two_dimension_data_; - scoped_refptr<StyleEnvironmentVariables> parent_; + HeapVector<Member<StyleEnvironmentVariables>> children_; + HeapHashMap<AtomicString, Member<CSSVariableData>> data_; + HeapHashMap<AtomicString, TwoDimensionVariableValues> two_dimension_data_; + Member<StyleEnvironmentVariables> parent_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_rule.cc b/third_party/blink/renderer/core/css/style_rule.cc index efde8b4..019bbd5 100644 --- a/third_party/blink/renderer/core/css/style_rule.cc +++ b/third_party/blink/renderer/core/css/style_rule.cc
@@ -940,7 +940,7 @@ StyleRuleFunction::StyleRuleFunction( AtomicString name, Vector<StyleRuleFunction::Parameter> parameters, - scoped_refptr<CSSVariableData> function_body, + CSSVariableData* function_body, StyleRuleFunction::Type return_type) : StyleRuleBase(kFunction), name_(std::move(name)), @@ -949,6 +949,7 @@ return_type_(return_type) {} void StyleRuleFunction::TraceAfterDispatch(blink::Visitor* visitor) const { + visitor->Trace(function_body_); StyleRuleBase::TraceAfterDispatch(visitor); }
diff --git a/third_party/blink/renderer/core/css/style_rule.h b/third_party/blink/renderer/core/css/style_rule.h index 1dc6ffc..593e4c0b 100644 --- a/third_party/blink/renderer/core/css/style_rule.h +++ b/third_party/blink/renderer/core/css/style_rule.h
@@ -711,7 +711,7 @@ StyleRuleFunction(AtomicString name, Vector<Parameter> parameters, - scoped_refptr<CSSVariableData> function_body, + CSSVariableData* function_body, Type return_type); StyleRuleFunction(const StyleRuleFunction&) = delete; @@ -725,7 +725,7 @@ private: AtomicString name_; Vector<Parameter> parameters_; - scoped_refptr<CSSVariableData> function_body_; + Member<CSSVariableData> function_body_; Type return_type_; };
diff --git a/third_party/blink/renderer/core/dom/document_test.cc b/third_party/blink/renderer/core/dom/document_test.cc index 2d03bcb..b206e4d 100644 --- a/third_party/blink/renderer/core/dom/document_test.cc +++ b/third_party/blink/renderer/core/dom/document_test.cc
@@ -497,7 +497,8 @@ gfx::SizeF page_size(400, 400); float maximum_shrink_ratio = 1.6; - GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_EQ(GetDocument().documentElement()->OffsetWidth(), 400); GetDocument().GetFrame()->EndPrinting(); EXPECT_EQ(GetDocument().documentElement()->OffsetWidth(), 800); @@ -1248,7 +1249,7 @@ constexpr gfx::SizeF initial_page_size(800, 600); - GetDocument().GetFrame()->StartPrinting(initial_page_size); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(initial_page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); WebPrintPageDescription description = GetDocument().GetPageDescription(0);
diff --git a/third_party/blink/renderer/core/dom/tree_scope_adopter.cc b/third_party/blink/renderer/core/dom/tree_scope_adopter.cc index d9aecde..23c87217 100644 --- a/third_party/blink/renderer/core/dom/tree_scope_adopter.cc +++ b/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
@@ -225,21 +225,20 @@ element, new_document); } } - - if (old_document.HasAnyListenerTypes()) { - node.MoveEventListenersToNewDocument(old_document, new_document); - } } else { // DCHECK all the fast adoption conditions DCHECK(!old_document.HasNodeIterators()); DCHECK(!old_document.HasRanges()); - DCHECK(!old_document.HasAnyListenerTypes()); DCHECK(!old_document.HasMutationObservers()); DCHECK(!old_document.ShouldInvalidateNodeListCaches()); DCHECK(!old_document.HasExplicitlySetAttrElements()); DCHECK(!old_document.HasCachedAttrAssociatedElements()); } + // TODO(crbug.com/341104769): revisit to see if the logic of moving event + // listeners could be optimized for fast adoption. + node.MoveEventListenersToNewDocument(old_document, new_document); + if (node.GetCustomElementState() == CustomElementState::kCustom) { CustomElement::EnqueueAdoptedCallback(To<Element>(node), old_document, new_document); @@ -259,7 +258,6 @@ inline bool TreeScopeAdopter::IsDocumentEligibleForFastAdoption( Document& old_document) const { return !old_document.HasNodeIterators() && !old_document.HasRanges() && - !old_document.HasAnyListenerTypes() && !old_document.HasMutationObservers() && !old_document.ShouldInvalidateNodeListCaches() && !old_document.HasExplicitlySetAttrElements() &&
diff --git a/third_party/blink/renderer/core/exported/web_element.cc b/third_party/blink/renderer/core/exported/web_element.cc index df64535..da6ab648 100644 --- a/third_party/blink/renderer/core/exported/web_element.cc +++ b/third_party/blink/renderer/core/exported/web_element.cc
@@ -130,18 +130,6 @@ return ConstUnwrap<Element>()->innerHTML(); } -bool WebElement::IsContentEditable() const { - const auto* html_element = - blink::DynamicTo<HTMLElement>(ConstUnwrap<Element>()); - if (!html_element) { - return false; - } - ContentEditableType normalized_value = - html_element->contentEditableNormalized(); - return normalized_value == ContentEditableType::kContentEditable || - normalized_value == ContentEditableType::kPlaintextOnly; -} - bool WebElement::WritingSuggestions() const { if (!RuntimeEnabledFeatures::WritingSuggestionsEnabled()) { return true;
diff --git a/third_party/blink/renderer/core/exported/web_node.cc b/third_party/blink/renderer/core/exported/web_node.cc index 2e895ec..2f51273 100644 --- a/third_party/blink/renderer/core/exported/web_node.cc +++ b/third_party/blink/renderer/core/exported/web_node.cc
@@ -161,6 +161,10 @@ return blink::IsEditable(*private_); } +WebElement WebNode::RootEditableElement() const { + return blink::RootEditableElement(*private_); +} + bool WebNode::IsInsideFocusableElementOrARIAWidget() const { return AXObjectCache::IsInsideFocusableElementOrARIAWidget( *this->ConstUnwrap<Node>());
diff --git a/third_party/blink/renderer/core/frame/csp/DEPS b/third_party/blink/renderer/core/frame/csp/DEPS index d95d1311..a4763f0 100644 --- a/third_party/blink/renderer/core/frame/csp/DEPS +++ b/third_party/blink/renderer/core/frame/csp/DEPS
@@ -8,4 +8,7 @@ "content_security_policy.h": [ "+services/network/public/cpp/content_security_policy/content_security_policy.h", ], + "csp_source_test\.cc": [ + "+url/url_features.h", + ], }
diff --git a/third_party/blink/renderer/core/frame/csp/csp_source.cc b/third_party/blink/renderer/core/frame/csp/csp_source.cc index d20da32..5d016b7 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_source.cc +++ b/third_party/blink/renderer/core/frame/csp/csp_source.cc
@@ -133,6 +133,26 @@ return result == SchemeMatchingResult::kMatchingUpgrade; } +const StringView HostForCSP(const KURL& url) { + // Chromium currently has an issue handling non-special URLs. The url.Host() + // function returns an empty string for them. See + // crbug.com/40063064 for details. + // + // In the future, once non-special URLs are fully supported, we might consider + // checking the host information for them too. + // + // For now, we check `url.IsStandard()` to maintain consistent behavior + // regardless of the url::StandardCompliantNonSpecialSchemeURLParsing feature + // state. + if (!url.IsStandard()) { + return ""; + } + if (base::FeatureList::IsEnabled(kAvoidWastefulHostCopies)) { + return url.HostView(); + } + return url.Host(); +} + } // namespace bool CSPSourceMatches(const network::mojom::blink::CSPSource& source, @@ -161,10 +181,7 @@ return false; } - return HostMatches(source, - base::FeatureList::IsEnabled(kAvoidWastefulHostCopies) - ? url.HostView() - : url.Host()) && + return HostMatches(source, HostForCSP(url)) && ports_match != PortMatchingResult::kNotMatching && paths_match; } @@ -184,10 +201,7 @@ return true; } - bool hosts_match = - HostMatches(source, base::FeatureList::IsEnabled(kAvoidWastefulHostCopies) - ? url.HostView() - : url.Host()); + bool hosts_match = HostMatches(source, HostForCSP(url)); PortMatchingResult ports_match = PortMatches( source, source.scheme, url.HasPort() ? url.Port() : url::PORT_UNSPECIFIED, url.Protocol());
diff --git a/third_party/blink/renderer/core/frame/csp/csp_source_test.cc b/third_party/blink/renderer/core/frame/csp/csp_source_test.cc index b6dc25e1..cb02dea9 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_source_test.cc +++ b/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/frame/csp/csp_source.h" +#include "base/test/scoped_feature_list.h" #include "services/network/public/mojom/content_security_policy.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -11,6 +12,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" +#include "url/url_features.h" namespace blink { @@ -148,7 +150,25 @@ KURL(base, "https://not-example.com:8000/"))); } -TEST(CSPSourceTest, SchemeIsEmpty) { +class CSPSourceParamTest : public ::testing::TestWithParam<bool> { + public: + CSPSourceParamTest() + : use_standard_compliant_non_special_scheme_url_parsing_(GetParam()) { + scoped_feature_list_.InitWithFeatureState( + url::kStandardCompliantNonSpecialSchemeURLParsing, + use_standard_compliant_non_special_scheme_url_parsing_); + } + + protected: + bool use_standard_compliant_non_special_scheme_url_parsing_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(All, CSPSourceParamTest, ::testing::Bool()); + +TEST_P(CSPSourceParamTest, SchemeIsEmpty) { KURL base; // Self scheme is http. @@ -324,7 +344,7 @@ } } -TEST(CSPSourceTest, MatchingAsSelf) { +TEST_P(CSPSourceParamTest, MatchingAsSelf) { // Testing Step 4 of // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression struct Source {
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index 0e21d9c3..55343df3 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -40,6 +40,7 @@ #include "third_party/blink/public/web/web_local_frame_client.h" #include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" +#include "third_party/blink/renderer/core/buildflags.h" #include "third_party/blink/renderer/core/dom/document_type.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/increment_load_event_delay_count.h" @@ -68,6 +69,10 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" +#if !BUILDFLAG(TARGET_OS_IS_ANDROID) +#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h" +#endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) + namespace blink { // static @@ -296,16 +301,25 @@ mojom::blink::UserActivationNotificationType notification_type, bool sticky_only) { for (Frame* node = this; node; node = node->Tree().Parent()) { - if (sticky_only) { - node->user_activation_state_.SetHasBeenActive(); - } else { - node->user_activation_state_.Activate(notification_type); - } - auto* local_node = DynamicTo<LocalFrame>(node); - if (local_node) { - local_node->SetHadUserInteraction(true); + NotifyUserActivationInFrame(node, notification_type, sticky_only); + } + +#if !BUILDFLAG(TARGET_OS_IS_ANDROID) + if (RuntimeEnabledFeatures::DocumentPictureInPictureUserActivationEnabled()) { + // If we are contained in a document picture-in-picture window, then also + // propagate the activation up to our opener frame. + auto* local_top_frame = DynamicTo<LocalFrame>(Tree().Top()); + if (local_top_frame && local_top_frame->GetDocument()) { + LocalDOMWindow* pip_owner = + PictureInPictureController::GetDocumentPictureInPictureOwner( + *local_top_frame->GetDocument()); + if (pip_owner) { + NotifyUserActivationInFrame(pip_owner->GetFrame(), notification_type, + sticky_only); + } } } +#endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) // See the "Same-origin Visibility" section in |UserActivationState| class // doc. @@ -321,14 +335,33 @@ if (local_frame_node && security_origin->CanAccess( local_frame_node->GetSecurityContext()->GetSecurityOrigin())) { - if (sticky_only) { - node->user_activation_state_.SetHasBeenActive(); - } else { - node->user_activation_state_.Activate(notification_type); - } - local_frame_node->SetHadUserInteraction(true); + NotifyUserActivationInFrame(node, notification_type, sticky_only); } } + +#if !BUILDFLAG(TARGET_OS_IS_ANDROID) + if (RuntimeEnabledFeatures:: + DocumentPictureInPictureUserActivationEnabled()) { + // If we are contained in a frame that owns a document picture-in-picture + // window, then also activate same-origin frames in the document + // picture-in-picture window. + auto* local_top_frame = DynamicTo<LocalFrame>(Tree().Top()); + if (local_top_frame) { + LocalDOMWindow* pip_window = + PictureInPictureController::GetDocumentPictureInPictureWindow( + *local_top_frame->GetDocument()); + for (Frame* node = pip_window ? pip_window->GetFrame() : nullptr; node; + node = node->Tree().TraverseNext()) { + auto* local_frame_node = DynamicTo<LocalFrame>(node); + if (local_frame_node && + security_origin->CanAccess(local_frame_node->GetSecurityContext() + ->GetSecurityOrigin())) { + NotifyUserActivationInFrame(node, notification_type, sticky_only); + } + } + } + } +#endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) } } @@ -344,6 +377,34 @@ for (Frame* node = &root; node; node = node->Tree().TraverseNext()) node->user_activation_state_.ConsumeIfActive(); +#if !BUILDFLAG(TARGET_OS_IS_ANDROID) + if (RuntimeEnabledFeatures::DocumentPictureInPictureUserActivationEnabled()) { + auto* local_top_frame = DynamicTo<LocalFrame>(Tree().Top()); + if (local_top_frame) { + // If we are contained in a document picture-in-picture window, then also + // consume user activation in our owner. + LocalDOMWindow* pip_owner = + PictureInPictureController::GetDocumentPictureInPictureOwner( + *local_top_frame->GetDocument()); + for (Frame* node = pip_owner ? pip_owner->GetFrame() : nullptr; node; + node = node->Tree().TraverseNext()) { + node->user_activation_state_.ConsumeIfActive(); + } + + // If we are contained in a frame that owns a document picture-in-picture + // window, then also consume user activation in same-origin frames in the + // document picture-in-picture window. + LocalDOMWindow* pip_window = + PictureInPictureController::GetDocumentPictureInPictureWindow( + *local_top_frame->GetDocument()); + for (Frame* node = pip_window ? pip_window->GetFrame() : nullptr; node; + node = node->Tree().TraverseNext()) { + node->user_activation_state_.ConsumeIfActive(); + } + } + } +#endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) + return was_active; } @@ -883,6 +944,23 @@ return true; } +// static +void Frame::NotifyUserActivationInFrame( + Frame* node, + mojom::blink::UserActivationNotificationType notification_type, + bool sticky_only) { + CHECK(node); + if (sticky_only) { + node->user_activation_state_.SetHasBeenActive(); + } else { + node->user_activation_state_.Activate(notification_type); + } + auto* local_node = DynamicTo<LocalFrame>(node); + if (local_node) { + local_node->SetHadUserInteraction(true); + } +} + void Frame::RemoveChild(Frame* child) { CHECK_EQ(child->parent_, this); child->parent_ = nullptr;
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index c3d246d..d153edf 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h
@@ -527,6 +527,14 @@ mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame> remote_frame_receiver); + // Notifies a specific frame that it now has user activation. Used to prevent + // duplicated logic in `NotifyUserActivationInFrameTree()`, which notifies + // various sets of Frames that they're now activated. + static void NotifyUserActivationInFrame( + Frame* node, + mojom::blink::UserActivationNotificationType notification_type, + bool sticky_only); + Member<FrameClient> client_; const Member<WindowProxyManager> window_proxy_manager_; FrameLifecycle lifecycle_;
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index abe89ace..73536e18 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1379,11 +1379,6 @@ SetPrinting(true, maximum_shrink_ratio); } -void LocalFrame::StartPrinting(const gfx::SizeF& page_size, - float maximum_shrink_ratio) { - StartPrinting(WebPrintParams(page_size), maximum_shrink_ratio); -} - void LocalFrame::EndPrinting() { RestoreScrollOffsets(); SetPrinting(false, 0); @@ -1420,10 +1415,11 @@ for (Frame* child = Tree().FirstChild(); child; child = child->Tree().NextSibling()) { if (auto* child_local_frame = DynamicTo<LocalFrame>(child)) { - if (printing) - child_local_frame->StartPrinting(); - else + if (printing) { + child_local_frame->StartPrinting(WebPrintParams()); + } else { child_local_frame->EndPrinting(); + } } } @@ -1454,7 +1450,7 @@ return true; auto* local_parent = DynamicTo<LocalFrame>(parent); return local_parent ? !local_parent->GetDocument()->Printing() - : Client()->UsePrintingLayout(); + : print_params_.use_printing_layout; } void LocalFrame::StartPaintPreview() { @@ -1652,12 +1648,8 @@ UADefinedTwoDimensionalVariable::kViewportSegmentWidth, UADefinedTwoDimensionalVariable::kViewportSegmentHeight, }; - ExecutionContext* context = - GetDocument() ? GetDocument()->GetExecutionContext() : nullptr; - if (!context) { - return; - } + ExecutionContext* context = GetDocument()->GetExecutionContext(); for (auto var : vars_to_remove) { vars.RemoveVariable(var, context); }
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index d308371..e38faf8 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -106,7 +106,6 @@ class Point; class Range; class Size; -class SizeF; } // namespace gfx namespace network { @@ -403,10 +402,9 @@ // Begin printing. // If too large (in the inline direction), the frame content will fit to the - // page size with the specified maximum shrink ratio. + // page size with the specified maximum shrink ratio, if this value is larger + // than 1. If this value is 1 or less, there will be no shrinking. void StartPrinting(const WebPrintParams&, float maximum_shrink_ratio = 0); - void StartPrinting(const gfx::SizeF& page_size = gfx::SizeF(), - float maximum_shrink_ratio = 0); void EndPrinting(); bool ShouldUsePrintingLayout() const;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h index 69c46be..ce0f4df 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client.h +++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -427,10 +427,6 @@ virtual void NotifyAutoscrollForSelectionInMainFrame(bool) {} - // Returns whether we are associated with a print context who suggests to use - // printing layout. - virtual bool UsePrintingLayout() const { return false; } - virtual std::unique_ptr<ResourceLoadInfoNotifierWrapper> CreateResourceLoadInfoNotifierWrapper() { return nullptr;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc index 0cee9fc..e3e6054 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -1186,10 +1186,6 @@ ->NotifyAutoscrollForSelectionInMainFrame(autoscroll_selection); } -bool LocalFrameClientImpl::UsePrintingLayout() const { - return web_frame_->UsePrintingLayout(); -} - std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> LocalFrameClientImpl::CreateResourceLoadInfoNotifierWrapper() { DCHECK(web_frame_->Client());
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h index a70c4a7..de6a2faa 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -286,8 +286,6 @@ void NotifyAutoscrollForSelectionInMainFrame( bool autoscroll_selection) override; - bool UsePrintingLayout() const override; - std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> CreateResourceLoadInfoNotifierWrapper() override;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view_test.cc b/third_party/blink/renderer/core/frame/local_frame_view_test.cc index 8cf8898..d3d84b4 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view_test.cc
@@ -163,7 +163,7 @@ SetBodyInnerHTML("<iframe style='display: none'></iframe>"); SetChildFrameHTML("A"); - ChildFrame().StartPrinting(gfx::SizeF(200, 200), 1); + ChildFrame().StartPrinting(WebPrintParams(gfx::SizeF(200, 200))); ChildDocument().View()->UpdateLifecyclePhasesForPrinting(); // The following checks that the detached frame has been walked for PrePaint. @@ -179,7 +179,7 @@ SetBodyInnerHTML("<iframe></iframe>"); SetChildFrameHTML("A"); - ChildFrame().StartPrinting(gfx::SizeF(200, 200), 1); + ChildFrame().StartPrinting(WebPrintParams(gfx::SizeF(200, 200))); ChildDocument().View()->UpdateLifecyclePhasesForPrinting(); EXPECT_EQ(DocumentLifecycle::kPrePaintClean,
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc b/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc index facfa55..91df7db4 100644 --- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc +++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.cc
@@ -53,6 +53,18 @@ #endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) } +// static +LocalDOMWindow* PictureInPictureController::GetDocumentPictureInPictureOwner( + const Document& document) { +#if !BUILDFLAG(TARGET_OS_IS_ANDROID) + PictureInPictureController* controller = + Supplement<Document>::From<PictureInPictureController>(document); + return controller ? controller->GetDocumentPictureInPictureOwner() : nullptr; +#else + return nullptr; +#endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) +} + void PictureInPictureController::Trace(Visitor* visitor) const { Supplement<Document>::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h index 50ca10c..00370944 100644 --- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h +++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -45,6 +45,12 @@ // Document or if PictureInPictureController is not attached to the Document. static LocalDOMWindow* GetDocumentPictureInPictureWindow(const Document&); + // If the provided document is attached to a document picture-in-picture + // window, then this returns the LocalDOMWindow that owns and originally + // opened the document picture-in-picture window. Returns null if the provided + // document is not attached to a document picture-in-picture window. + static LocalDOMWindow* GetDocumentPictureInPictureOwner(const Document&); + // List of Picture-in-Picture support statuses. If status is kEnabled, // Picture-in-Picture is enabled for a document or element, otherwise it is // not supported. @@ -109,6 +115,12 @@ // It is protected so that clients use the static method // GetDocumentPictureInPictureWindow() that avoids creating the controller. virtual LocalDOMWindow* GetDocumentPictureInPictureWindow() const = 0; + + // If this is attached to a document picture-in-picture window, then this + // returns the LocalDOMWindow that owns and originally opened the document + // picture-in-picture window. Returns null if the this is not attached to a + // document picture-in-picture window. + virtual LocalDOMWindow* GetDocumentPictureInPictureOwner() const = 0; #endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) };
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index 64e0ec7..fd10a6aa 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -1100,7 +1100,7 @@ { name: "preferredRootScrollbarColorScheme", initial: "mojom::blink::PreferredColorScheme::kLight", - invalidate: ["ColorScheme"], + invalidate: ["Paint"], type: "mojom::blink::PreferredColorScheme", include_paths: [ "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-shared.h"
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc index 8da8909..ff209df 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -13149,7 +13149,8 @@ gfx::SizeF page_size(400, 400); float maximum_shrink_ratio = 1.0; - iframe_doc->GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + iframe_doc->GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_TRUE(iframe_doc->documentElement()->GetLayoutObject()); iframe_doc->GetFrame()->EndPrinting();
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index cf9c89f..1de59ff7 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -838,10 +838,6 @@ return ViewImpl()->GetPage()->DispatchedPagehideAndStillHidden(); } -bool WebLocalFrameImpl::UsePrintingLayout() const { - return print_context_ ? print_context_->use_printing_layout() : false; -} - void WebLocalFrameImpl::CopyToFindPboard() { #if BUILDFLAG(IS_MAC) if (HasSelection())
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h index 3f1d515..36138c55 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -536,9 +536,6 @@ // Returns true if the frame is focused. bool IsFocused() const; - // Returns true if our print context suggests using printing layout. - bool UsePrintingLayout() const; - // Copy the current selection to the pboard. void CopyToFindPboard();
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.cc b/third_party/blink/renderer/core/html/canvas/text_metrics.cc index 7dbdda7f..605640b 100644 --- a/third_party/blink/renderer/core/html/canvas/text_metrics.cc +++ b/third_party/blink/renderer/core/html/canvas/text_metrics.cc
@@ -186,7 +186,7 @@ // Checks indexes that go over the maximum for the text. For indexes less than // 0, an exception is thrown by [EnforceRange] in the idl binding. - if (start >= text_length_ || end >= text_length_) { + if (start > text_length_ || end > text_length_) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, String::Format("The %s index is out of bounds.", @@ -199,16 +199,24 @@ double accumulated_width = 0.0; unsigned int accumulated_string_length = 0; + // Handle start >= end case with end = 0 the same way the DOM does, returning + // a zero-width rect before the start of the text. + if (start >= end && end == 0) { + selection_rects.push_back(DOMRectReadOnly::Create( + -text_align_dx_, -font_bounding_box_ascent_, /*width=*/0, height)); + return selection_rects; + } + for (const auto& text_run : text_runs_) { // Accumulate string length to know the indexes of this run on the input // string. const unsigned int run_start_index = accumulated_string_length; const unsigned int run_end_index = - accumulated_string_length + text_run.length() - 1; + accumulated_string_length + text_run.length(); accumulated_string_length += text_run.length(); // Past the selection interval. - if (run_start_index > end) { + if (run_start_index >= end) { break; } @@ -216,10 +224,12 @@ const double left_border = accumulated_width; accumulated_width += font_.Width(text_run); - // Handle start > end case the same way the DOM does, returning a zero-width - // rect after the advance of the character at the end position. - if (start > end && run_start_index <= end && end <= run_end_index) { - const unsigned index = base::CheckSub(end, run_start_index).ValueOrDie(); + // Handle start >= end case the same way the DOM does, returning a + // zero-width rect after the advance of the character right before the end + // position. + if (start >= end && run_start_index < end && end <= run_end_index) { + const unsigned index = + base::CheckSub(end - 1, run_start_index).ValueOrDie(); gfx::RectF rect = font_.SelectionRectForText( text_run, gfx::PointF(left_border - text_align_dx_, y), height, index, index + 1); @@ -230,7 +240,7 @@ } // Before the selection interval. - if (run_end_index < start) { + if (run_end_index <= start) { continue; } @@ -238,7 +248,7 @@ const unsigned int starting_index = start > run_start_index ? start - run_start_index : 0; const unsigned int ending_index = - end < run_end_index ? end - run_start_index + 1 : text_run.length(); + end <= run_end_index ? end - run_start_index : text_run.length(); gfx::RectF selection_rect = font_.SelectionRectForText( text_run, gfx::PointF(left_border - text_align_dx_, y), height,
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index 7f295a0..da6f704 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -1097,13 +1097,34 @@ router_info->setMatchedSourceType(BuildServiceWorkerRouterSourceType( *response.GetServiceWorkerRouterInfo()->MatchedSourceType())); } + + if (response.GetServiceWorkerRouterInfo()->ActualSourceType()) { + router_info->setActualSourceType(BuildServiceWorkerRouterSourceType( + *response.GetServiceWorkerRouterInfo()->ActualSourceType())); + } response_object->setServiceWorkerRouterInfo(std::move(router_info)); } response_object->setFromPrefetchCache(response.WasInPrefetchCache()); - if (response.GetResourceLoadTiming()) - response_object->setTiming( - BuildObjectForTiming(*response.GetResourceLoadTiming())); + if (auto* resource_load_timing = response.GetResourceLoadTiming()) { + auto load_timing = BuildObjectForTiming(*resource_load_timing); + + if (RuntimeEnabledFeatures::ServiceWorkerStaticRouterTimingInfoEnabled()) { + if (!resource_load_timing->WorkerRouterEvaluationStart().is_null()) { + load_timing->setWorkerRouterEvaluationStart( + resource_load_timing->CalculateMillisecondDelta( + resource_load_timing->WorkerRouterEvaluationStart())); + } + + if (!resource_load_timing->WorkerCacheLokupStart().is_null()) { + load_timing->setWorkerCacheLookupStart( + resource_load_timing->CalculateMillisecondDelta( + resource_load_timing->WorkerCacheLokupStart())); + } + } + + response_object->setTiming(std::move(load_timing)); + } const net::IPEndPoint& remote_ip_endpoint = response.RemoteIPEndpoint(); if (remote_ip_endpoint.address().IsValid()) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc index 08080f2..d5286db 100644 --- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc +++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -616,6 +616,11 @@ inspector_style_invalidator_invalidate_event::kInvalidateCustomPseudo[] = "Invalidate custom pseudo element"; const char inspector_style_invalidator_invalidate_event:: + kInvalidationSetInvalidatesSelf[] = "Invalidation set invalidates self"; +const char inspector_style_invalidator_invalidate_event:: + kInvalidationSetInvalidatesSubtree[] = + "Invalidation set invalidates subtree"; +const char inspector_style_invalidator_invalidate_event:: kInvalidationSetMatchedAttribute[] = "Invalidation set matched attribute"; const char inspector_style_invalidator_invalidate_event:: kInvalidationSetMatchedClass[] = "Invalidation set matched class"; @@ -680,6 +685,9 @@ } else if (reason == kInvalidationSetMatchedAttribute) { feature_type = InvalidationSetToSelectorMap::SelectorFeatureType::kAttribute; + } else if (reason == kInvalidationSetInvalidatesSubtree) { + feature_type = + InvalidationSetToSelectorMap::SelectorFeatureType::kWholeSubtree; } if (feature_type != InvalidationSetToSelectorMap::SelectorFeatureType::kUnknown) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.h b/third_party/blink/renderer/core/inspector/inspector_trace_events.h index d409733f..282ebc14 100644 --- a/third_party/blink/renderer/core/inspector/inspector_trace_events.h +++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.h
@@ -218,6 +218,8 @@ namespace inspector_style_invalidator_invalidate_event { extern const char kElementHasPendingInvalidationList[]; extern const char kInvalidateCustomPseudo[]; +extern const char kInvalidationSetInvalidatesSelf[]; +extern const char kInvalidationSetInvalidatesSubtree[]; extern const char kInvalidationSetMatchedAttribute[]; extern const char kInvalidationSetMatchedClass[]; extern const char kInvalidationSetMatchedId[]; @@ -251,6 +253,11 @@ (inspector_style_invalidator_invalidate_event::reason), \ (invalidationSet), (singleSelectorPart)) +#define TRACE_STYLE_INVALIDATOR_INVALIDATION_SET(element, reason, \ + invalidationSet) \ + TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART( \ + element, reason, invalidationSet, g_empty_atom) + // From a web developer's perspective: what caused this layout? This is strictly // for tracing. Blink logic must not depend on these. namespace layout_invalidation_reason {
diff --git a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h index 2ff0ad9..23b59bb 100644 --- a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h +++ b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h
@@ -45,7 +45,8 @@ kClass, kId, kTagName, - kAttribute + kAttribute, + kWholeSubtree }; // Instantiates a new mapping if a diagnostic tracing session with the
diff --git a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc index 2eb5e74..6c335450 100644 --- a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc +++ b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc
@@ -198,4 +198,95 @@ EXPECT_EQ(found_event_count, 1u); } +TEST_F(InvalidationSetToSelectorMapTest, SelfInvalidation) { + StartTracing(); + SetBodyInnerHTML(R"HTML( + <style> + .a { color: red; } + .b { color: green; } + .c { color: blue; } + </style> + <div id=parent class=a>Parent + <div class=x>Child</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + GetElementById("parent")->setAttribute(html_names::kClassAttr, + AtomicString("b")); + UpdateAllLifecyclePhasesForTest(); + + auto analyzer = StopTracing(); + trace_analyzer::TraceEventVector events; + + analyzer->FindEvents( + trace_analyzer::Query::EventNameIs("ScheduleStyleInvalidationTracking") || + trace_analyzer::Query::EventNameIs( + "StyleInvalidatorInvalidationTracking"), + &events); + ASSERT_EQ(events.size(), 4u); + EXPECT_EQ(events[0]->name, "ScheduleStyleInvalidationTracking"); + EXPECT_EQ(*(events[0]->GetKnownArgAsDict("data").FindString( + "invalidatedSelectorId")), + "class"); + EXPECT_EQ(*(events[0]->GetKnownArgAsDict("data").FindString("changedClass")), + "b"); + EXPECT_EQ(events[1]->name, "ScheduleStyleInvalidationTracking"); + EXPECT_EQ(*(events[1]->GetKnownArgAsDict("data").FindString( + "invalidatedSelectorId")), + "class"); + EXPECT_EQ(*(events[1]->GetKnownArgAsDict("data").FindString("changedClass")), + "a"); + // Because self invalidations are largely handled via the Bloom filter and/or + // the singleton SelfInvalidationSet, we don't expect selectors. But the + // preceding schedule events do give us context for what changed. + EXPECT_EQ(events[2]->name, "StyleInvalidatorInvalidationTracking"); + EXPECT_EQ(*(events[2]->GetKnownArgAsDict("data").FindString("reason")), + "Invalidation set invalidates self"); + EXPECT_EQ(events[3]->name, "StyleInvalidatorInvalidationTracking"); + EXPECT_EQ(*(events[3]->GetKnownArgAsDict("data").FindString("reason")), + "Invalidation set invalidates self"); +} + +TEST_F(InvalidationSetToSelectorMapTest, SubtreeInvalidation) { + StartTracing(); + SetBodyInnerHTML(R"HTML( + <style> + .a * { color: red; } + .b * { color: green; } + .c * { color: blue; } + </style> + <div id=parent class=a>Parent + <div class=x>Child</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + GetElementById("parent")->setAttribute(html_names::kClassAttr, + AtomicString("b")); + UpdateAllLifecyclePhasesForTest(); + + auto analyzer = StopTracing(); + trace_analyzer::TraceEventVector events; + analyzer->FindEvents(trace_analyzer::Query::EventNameIs( + "StyleInvalidatorInvalidationTracking"), + &events); + size_t found_event_count = 0; + for (auto event : events) { + ASSERT_TRUE(event->HasDictArg("data")); + base::Value::Dict data_dict = event->GetKnownArgAsDict("data"); + std::string* reason = data_dict.FindString("reason"); + if (reason != nullptr && + *reason == "Invalidation set invalidates subtree") { + base::Value::List* selector_list = data_dict.FindList("selectors"); + if (selector_list != nullptr) { + EXPECT_EQ(selector_list->size(), 1u); + EXPECT_EQ((*selector_list)[0], ".b *"); + found_event_count++; + } + } + } + EXPECT_EQ(found_event_count, 1u); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/block_layout_algorithm.cc index c2faafb0..18a03ff 100644 --- a/third_party/blink/renderer/core/layout/block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/block_layout_algorithm.cc
@@ -2570,32 +2570,25 @@ } if (!container_builder_.BfcBlockOffset()) DCHECK_EQ(logical_block_offset, LayoutUnit()); - } else if (layout_result.IsBlockEndTrimmed() && child.IsInline()) { - // Trim the space to respect the `text-box-trim` property here. Only trim - // inline nodes as its containers will adjust themselves accordingly. - const PhysicalFragment& inline_physical_fragment = - layout_result.GetPhysicalFragment(); - CHECK(inline_physical_fragment.IsLineBox()); - const auto& line_box = - To<PhysicalLineBoxFragment>(inline_physical_fragment); - LayoutUnit block_end_to_be_trimmed = - Style().IsFlippedLinesWritingMode() - ? line_box.Metrics().ascent - line_box.IntrinsicMetrics().ascent - : line_box.Metrics().descent - line_box.IntrinsicMetrics().descent; - logical_block_offset = logical_offset.block_offset + fragment.BlockSize() - - block_end_to_be_trimmed; } else { - // We add the greater of AnnotationOverflow and ClearanceAfterLine here. - // Then, we cancel the AnnotationOverflow part if - // - The next line box has block-start annotation space, or - // - There are no following child boxes and this container has block-end - // padding. - // - // See InlineLayoutAlgorithm::CreateLine() and - // BlockLayoutAlgorithm::Layout(). - logical_block_offset = logical_offset.block_offset + fragment.BlockSize() + - std::max(layout_result.AnnotationOverflow(), - layout_result.ClearanceAfterLine()); + logical_block_offset = logical_offset.block_offset + fragment.BlockSize(); + + if (const std::optional<LayoutUnit> trim_block_end_by = + layout_result.TrimBlockEndBy()) { + // Trim the space to respect the `text-box-trim` property here. + logical_block_offset -= *trim_block_end_by; + } else { + // We add the greater of AnnotationOverflow and ClearanceAfterLine here. + // Then, we cancel the AnnotationOverflow part if + // - The next line box has block-start annotation space, or + // - There are no following child boxes and this container has block-end + // padding. + // + // See InlineLayoutAlgorithm::CreateLine() and + // BlockLayoutAlgorithm::Layout(). + logical_block_offset += std::max(layout_result.AnnotationOverflow(), + layout_result.ClearanceAfterLine()); + } } MarginStrut margin_strut = layout_result.EndMarginStrut();
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index 1e3cf85..7df5465101 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -203,6 +203,7 @@ "grid/grid_track_collection.h", "grid/layout_grid.cc", "grid/layout_grid.h", + "grid/subgrid_min_max_sizes_cache.h", "hit_test_cache.cc", "hit_test_cache.h", "hit_test_canvas_result.cc",
diff --git a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc index 50b4352..32aa6ee 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
@@ -1744,7 +1744,7 @@ } else { // If this grid has a standalone axis, invalidate its min/max sizes cache, // since they're only valid for the current step of the sizing algorithm. - Node().InvalidateMinMaxSizesCache(); + Node().InvalidateSubgridMinMaxSizesCache(); auto& track_collection = layout_data.SizingCollection(track_direction); CacheGridItemsProperties(track_collection, &grid_items);
diff --git a/third_party/blink/renderer/core/layout/grid/grid_node.cc b/third_party/blink/renderer/core/layout/grid/grid_node.cc index d7e41cbc..66f71f0d 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_node.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_node.cc
@@ -189,16 +189,16 @@ auto* layout_grid = To<LayoutGrid>(box_.Get()); - if (!layout_grid->HasCachedMinMaxSizes()) { + if (!layout_grid->HasCachedSubgridMinMaxSizes()) { const auto fragment_geometry = CalculateInitialFragmentGeometry( space, *this, /*break_token=*/nullptr, /*is_intrinsic=*/true); - layout_grid->SetMinMaxSizesCache( + layout_grid->SetSubgridMinMaxSizesCache( GridLayoutAlgorithm({*this, fragment_geometry, space}) .ComputeSubgridMinMaxSizes(sizing_subtree)); } - return {layout_grid->CachedMinMaxSizes(), + return {layout_grid->CachedSubgridMinMaxSizes(), /*depends_on_block_constraints=*/false}; } @@ -210,7 +210,7 @@ auto* layout_grid = To<LayoutGrid>(box_.Get()); - if (!layout_grid->HasCachedMinMaxSizes()) { + if (!layout_grid->HasCachedSubgridMinMaxSizes()) { const auto fragment_geometry = CalculateInitialFragmentGeometry( space, *this, /*break_token=*/nullptr, /*is_intrinsic=*/true); @@ -220,12 +220,12 @@ // The min and max-content block size are both the box's "ideal" size after // layout (see https://drafts.csswg.org/css-sizing-3/#max-content). - layout_grid->SetMinMaxSizesCache( + layout_grid->SetSubgridMinMaxSizesCache( {intrinsic_block_size, intrinsic_block_size}); } // Both intrinsic sizes are the same, so we can return either. - return layout_grid->CachedMinMaxSizes().max_size; + return layout_grid->CachedSubgridMinMaxSizes().max_size; } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid/grid_node.h b/third_party/blink/renderer/core/layout/grid/grid_node.h index c30441b..0fef87b 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_node.h +++ b/third_party/blink/renderer/core/layout/grid/grid_node.h
@@ -30,8 +30,8 @@ return CachedPlacementData().line_resolver; } - void InvalidateMinMaxSizesCache() const { - To<LayoutGrid>(box_.Get())->InvalidateMinMaxSizesCache(); + void InvalidateSubgridMinMaxSizesCache() const { + To<LayoutGrid>(box_.Get())->InvalidateSubgridMinMaxSizesCache(); } // If `oof_children` is provided, aggregate any out of flow children.
diff --git a/third_party/blink/renderer/core/layout/grid/layout_grid.cc b/third_party/blink/renderer/core/layout/grid/layout_grid.cc index 999cb741b..b537c38 100644 --- a/third_party/blink/renderer/core/layout/grid/layout_grid.cc +++ b/third_party/blink/renderer/core/layout/grid/layout_grid.cc
@@ -4,12 +4,18 @@ #include "third_party/blink/renderer/core/layout/grid/layout_grid.h" +#include "third_party/blink/renderer/core/layout/grid/subgrid_min_max_sizes_cache.h" #include "third_party/blink/renderer/core/layout/layout_result.h" namespace blink { LayoutGrid::LayoutGrid(Element* element) : LayoutBlock(element) {} +void LayoutGrid::Trace(Visitor* visitor) const { + visitor->Trace(cached_subgrid_min_max_sizes_); + LayoutBlock::Trace(visitor); +} + void LayoutGrid::AddChild(LayoutObject* new_child, LayoutObject* before_child) { NOT_DESTROYED(); LayoutBlock::AddChild(new_child, before_child); @@ -106,21 +112,22 @@ SetGridPlacementDirty(false); } -bool LayoutGrid::HasCachedMinMaxSizes() const { - return cached_min_max_sizes_.has_value(); +bool LayoutGrid::HasCachedSubgridMinMaxSizes() const { + return static_cast<bool>(cached_subgrid_min_max_sizes_); } -const MinMaxSizes& LayoutGrid::CachedMinMaxSizes() const { - DCHECK(HasCachedMinMaxSizes()); - return *cached_min_max_sizes_; +const MinMaxSizes& LayoutGrid::CachedSubgridMinMaxSizes() const { + DCHECK(HasCachedSubgridMinMaxSizes()); + return **cached_subgrid_min_max_sizes_; } -void LayoutGrid::SetMinMaxSizesCache(MinMaxSizes&& min_max_sizes) { - cached_min_max_sizes_ = std::move(min_max_sizes); +void LayoutGrid::SetSubgridMinMaxSizesCache(MinMaxSizes&& min_max_sizes) { + cached_subgrid_min_max_sizes_ = + MakeGarbageCollected<SubgridMinMaxSizesCache>(std::move(min_max_sizes)); } -void LayoutGrid::InvalidateMinMaxSizesCache() { - cached_min_max_sizes_.reset(); +void LayoutGrid::InvalidateSubgridMinMaxSizesCache() { + cached_subgrid_min_max_sizes_.Clear(); } const GridLayoutData* LayoutGrid::LayoutData() const { @@ -133,7 +140,7 @@ } wtf_size_t LayoutGrid::AutoRepeatCountForDirection( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); if (!HasCachedPlacementData()) return 0; @@ -141,7 +148,7 @@ } wtf_size_t LayoutGrid::ExplicitGridStartForDirection( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); if (!HasCachedPlacementData()) return 0; @@ -149,7 +156,7 @@ } wtf_size_t LayoutGrid::ExplicitGridEndForDirection( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); if (!HasCachedPlacementData()) return 0; @@ -159,8 +166,7 @@ cached_placement_data_->ExplicitGridTrackCount(track_direction)); } -LayoutUnit LayoutGrid::GridGap( - const GridTrackSizingDirection track_direction) const { +LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); const auto* grid_layout_data = LayoutData(); if (!grid_layout_data) @@ -172,14 +178,14 @@ } LayoutUnit LayoutGrid::GridItemOffset( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); // Distribution offset is baked into the gutter_size in GridNG. return LayoutUnit(); } Vector<LayoutUnit, 1> LayoutGrid::TrackSizesForComputedStyle( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); Vector<LayoutUnit, 1> track_sizes; const auto* grid_layout_data = LayoutData(); @@ -260,7 +266,7 @@ } Vector<LayoutUnit> LayoutGrid::ComputeExpandedPositions( - const GridTrackSizingDirection track_direction) const { + GridTrackSizingDirection track_direction) const { Vector<LayoutUnit> expanded_positions; const auto* grid_layout_data = LayoutData(); if (!grid_layout_data)
diff --git a/third_party/blink/renderer/core/layout/grid/layout_grid.h b/third_party/blink/renderer/core/layout/grid/layout_grid.h index a49e87d..c23a526 100644 --- a/third_party/blink/renderer/core/layout/grid/layout_grid.h +++ b/third_party/blink/renderer/core/layout/grid/layout_grid.h
@@ -6,14 +6,18 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LAYOUT_GRID_H_ #include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/layout/layout_block.h" #include "third_party/blink/renderer/core/layout/grid/grid_data.h" +#include "third_party/blink/renderer/core/layout/layout_block.h" namespace blink { +class SubgridMinMaxSizesCache; + class CORE_EXPORT LayoutGrid : public LayoutBlock { public: - explicit LayoutGrid(Element*); + explicit LayoutGrid(Element* element); + + void Trace(Visitor* visitor) const override; const char* GetName() const override { NOT_DESTROYED(); @@ -26,22 +30,21 @@ const GridPlacementData& CachedPlacementData() const; void SetCachedPlacementData(GridPlacementData&& placement_data); - bool HasCachedMinMaxSizes() const; - const MinMaxSizes& CachedMinMaxSizes() const; - void SetMinMaxSizesCache(MinMaxSizes&& min_max_sizes); - void InvalidateMinMaxSizesCache(); + bool HasCachedSubgridMinMaxSizes() const; + const MinMaxSizes& CachedSubgridMinMaxSizes() const; + void SetSubgridMinMaxSizesCache(MinMaxSizes&& min_max_sizes); + void InvalidateSubgridMinMaxSizesCache(); wtf_size_t AutoRepeatCountForDirection( - const GridTrackSizingDirection track_direction) const; + GridTrackSizingDirection track_direction) const; wtf_size_t ExplicitGridStartForDirection( - const GridTrackSizingDirection track_direction) const; + GridTrackSizingDirection track_direction) const; wtf_size_t ExplicitGridEndForDirection( - const GridTrackSizingDirection track_direction) const; - LayoutUnit GridGap(const GridTrackSizingDirection track_direction) const; - LayoutUnit GridItemOffset( - const GridTrackSizingDirection track_direction) const; + GridTrackSizingDirection track_direction) const; + LayoutUnit GridGap(GridTrackSizingDirection track_direction) const; + LayoutUnit GridItemOffset(GridTrackSizingDirection track_direction) const; Vector<LayoutUnit, 1> TrackSizesForComputedStyle( - const GridTrackSizingDirection track_direction) const; + GridTrackSizingDirection track_direction) const; Vector<LayoutUnit> RowPositions() const; Vector<LayoutUnit> ColumnPositions() const; @@ -58,16 +61,15 @@ const GridLayoutTrackCollection& track_collection, wtf_size_t range_index) const; Vector<LayoutUnit> ComputeExpandedPositions( - const GridTrackSizingDirection track_direction) const; + GridTrackSizingDirection track_direction) const; - void AddChild(LayoutObject* new_child, - LayoutObject* before_child = nullptr) override; + void AddChild(LayoutObject* new_child, LayoutObject* before_child) override; void RemoveChild(LayoutObject* child) override; void StyleDidChange(StyleDifference diff, const ComputedStyle* old_style) override; std::optional<GridPlacementData> cached_placement_data_; - std::optional<MinMaxSizes> cached_min_max_sizes_; + Member<const SubgridMinMaxSizesCache> cached_subgrid_min_max_sizes_; }; // wtf/casting.h helper.
diff --git a/third_party/blink/renderer/core/layout/grid/subgrid_min_max_sizes_cache.h b/third_party/blink/renderer/core/layout/grid/subgrid_min_max_sizes_cache.h new file mode 100644 index 0000000..32dab453 --- /dev/null +++ b/third_party/blink/renderer/core/layout/grid/subgrid_min_max_sizes_cache.h
@@ -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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_SUBGRID_MIN_MAX_SIZES_CACHE_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_SUBGRID_MIN_MAX_SIZES_CACHE_H_ + +#include "third_party/blink/renderer/core/layout/min_max_sizes.h" + +namespace blink { + +class SubgridMinMaxSizesCache + : public GarbageCollected<SubgridMinMaxSizesCache> { + public: + SubgridMinMaxSizesCache() = delete; + SubgridMinMaxSizesCache(const SubgridMinMaxSizesCache&) = delete; + SubgridMinMaxSizesCache& operator=(const SubgridMinMaxSizesCache&) = delete; + + explicit SubgridMinMaxSizesCache(MinMaxSizes&& min_max_sizes) + : cached_min_max_sizes_(std::move(min_max_sizes)) {} + + const MinMaxSizes& operator*() const { return cached_min_max_sizes_; } + + void Trace(Visitor*) const {} + + private: + MinMaxSizes cached_min_max_sizes_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_SUBGRID_MIN_MAX_SIZES_CACHE_H_
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 7c628f0a..530c278 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
@@ -648,6 +648,11 @@ if (should_apply_end) { // Ask the block layout algorithm to trim the end of the line box. + const LayoutUnit block_end_to_be_trimmed = + UNLIKELY(is_flipped_line) + ? line_box_metrics.ascent - intrinsic_metrics.ascent + : line_box_metrics.descent - intrinsic_metrics.descent; + container_builder_.SetTrimBlockEndBy(block_end_to_be_trimmed); container_builder_.SetIsBlockEndTrimmed(); }
diff --git a/third_party/blink/renderer/core/layout/inline/line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/inline/line_box_fragment_builder.h index 61dff57a..a77a65e 100644 --- a/third_party/blink/renderer/core/layout/inline/line_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/inline/line_box_fragment_builder.h
@@ -68,6 +68,10 @@ line_box_bfc_block_offset_ = offset; } + void SetTrimBlockEndBy(LayoutUnit trim_block_end_by) { + trim_block_end_by_ = trim_block_end_by; + } + void SetAnnotationBlockOffsetAdjustment(LayoutUnit adjustment) { annotation_block_offset_adjustment_ = adjustment; } @@ -104,6 +108,7 @@ void PropagateChildrenDataFromLineItems(LogicalLineItems& children); std::optional<LayoutUnit> line_box_bfc_block_offset_; + std::optional<LayoutUnit> trim_block_end_by_; LayoutUnit annotation_block_offset_adjustment_; FontHeight metrics_ = FontHeight::Empty(); FontHeight intrinsic_metrics_ = FontHeight::Empty();
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 f17ef503..ea341d52 100644 --- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc +++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -3358,6 +3358,9 @@ return true; } + if (!RuntimeEnabledFeatures::RubyShortHeuristicsEnabled()) { + return false; + } // Not breakable if the number of the base letters is <= 4 and the number of // the annotation letters is <= 8. //
diff --git a/third_party/blink/renderer/core/layout/layout_result.cc b/third_party/blink/renderer/core/layout/layout_result.cc index 5698061..cee2b43 100644 --- a/third_party/blink/renderer/core/layout/layout_result.cc +++ b/third_party/blink/renderer/core/layout/layout_result.cc
@@ -122,14 +122,21 @@ EnsureRareData()->SetLineBoxBfcBlockOffset( *builder->line_box_bfc_block_offset_); } + + // `EnsureLineData()` must be done before `EnsureLineSmallData()`. + DCHECK(!rare_data_ || !rare_data_->HasData(RareData::kLineSmallData)); if (builder->annotation_block_offset_adjustment_) { EnsureRareData()->EnsureLineData()->annotation_block_offset_adjustment = builder->annotation_block_offset_adjustment_; } if (builder->clearance_after_line_) { - EnsureRareData()->EnsureLineData()->clearance_after_line = + EnsureRareData()->EnsureLineSmallData()->clearance_after_line = builder->clearance_after_line_; } + if (builder->trim_block_end_by_) { + EnsureRareData()->EnsureLineSmallData()->trim_block_end_by = + *builder->trim_block_end_by_; + } } LayoutResult::LayoutResult(FragmentBuilderPassKey key,
diff --git a/third_party/blink/renderer/core/layout/layout_result.h b/third_party/blink/renderer/core/layout/layout_result.h index 60cf1365..3ee65aa0 100644 --- a/third_party/blink/renderer/core/layout/layout_result.h +++ b/third_party/blink/renderer/core/layout/layout_result.h
@@ -314,10 +314,18 @@ if (!rare_data_) { return LayoutUnit(); } - const RareData::LineData* data = rare_data_->GetLineData(); + const RareData::LineSmallData* data = rare_data_->GetLineSmallData(); return data ? data->clearance_after_line : LayoutUnit(); } + // Return the amount to trim the block size by the `text-box-trim` property. + std::optional<LayoutUnit> TrimBlockEndBy() const { + if (!rare_data_) { + return std::nullopt; + } + return rare_data_->TrimBlockEndBy(); + } + std::optional<LayoutUnit> MinimalSpaceShortage() const { if (!rare_data_ || space_.IsInitialColumnBalancingPass() || rare_data_->minimal_space_shortage == kIndefiniteSize) { @@ -619,6 +627,7 @@ kBlockData, kFlexData, kGridData, + kLineSmallData, kLineData, kMathData, kTableData, @@ -664,11 +673,33 @@ std::unique_ptr<const GridLayoutData> grid_layout_data; }; - struct LineData { + // `LineSmallData` can save allocations When only fields in it are needed. + struct LineSmallData { + std::optional<LayoutUnit> TrimBlockEndBy() const { + if (trim_block_end_by == LayoutUnit::Min()) { + return std::nullopt; + } + return trim_block_end_by; + } + LayoutUnit clearance_after_line; + LayoutUnit trim_block_end_by = LayoutUnit::Min(); + }; + + // `LineData` is allocated separately as it's larger than data unions. + struct LineData : public LineSmallData { LayoutUnit annotation_block_offset_adjustment; }; + struct LineDataPtr { + LineDataPtr() = default; + LineDataPtr(const LineDataPtr& other) { + line_data = std::make_unique<LineData>(*other.line_data); + } + + std::unique_ptr<LineData> line_data = std::make_unique<LineData>(); + }; + struct MathData { // See https://w3c.github.io/mathml-core/#box-model LayoutUnit italic_correction; @@ -744,6 +775,9 @@ } return address; } + bool HasData(DataUnionType data_type) const { + return data_union_type() == data_type; + } template <typename DataType> const DataType* GetData(const DataType* address, DataUnionType data_type) const { @@ -768,11 +802,25 @@ const GridData* GetGridData() const { return GetData<GridData>(&grid_data, kGridData); } + // When both `EnsureLineData()` and `EnsureLineSmallData()` are needed, + // `EnsureLineData()` must be done first. Upgrading `kLineSmallData` to + // `kLineData` isn't supported due to the lack of the needs. LineData* EnsureLineData() { - return EnsureData<LineData>(&line_data, kLineData); + return EnsureData(&line_data, kLineData)->line_data.get(); } const LineData* GetLineData() const { - return GetData<LineData>(&line_data, kLineData); + const LineDataPtr* data = GetData(&line_data, kLineData); + return data ? data->line_data.get() : nullptr; + } + LineSmallData* EnsureLineSmallData() { + return UNLIKELY(HasData(kLineData)) + ? EnsureLineData() + : EnsureData(&line_small_data, kLineSmallData); + } + const LineSmallData* GetLineSmallData() const { + return UNLIKELY(HasData(kLineData)) + ? GetLineData() + : GetData(&line_small_data, kLineSmallData); } MathData* EnsureMathData() { return EnsureData<MathData>(&math_data, kMathData); @@ -818,8 +866,11 @@ case kGridData: new (&grid_data) GridData(rare_data.grid_data); break; + case kLineSmallData: + new (&line_small_data) LineSmallData(rare_data.line_small_data); + break; case kLineData: - new (&line_data) LineData(rare_data.line_data); + new (&line_data) LineDataPtr(rare_data.line_data); break; case kMathData: new (&math_data) MathData(rare_data.math_data); @@ -845,8 +896,11 @@ case kGridData: grid_data.~GridData(); break; + case kLineSmallData: + line_small_data.~LineSmallData(); + break; case kLineData: - line_data.~LineData(); + line_data.~LineDataPtr(); break; case kMathData: math_data.~MathData(); @@ -869,6 +923,11 @@ return line_box_bfc_block_offset; } + std::optional<LayoutUnit> TrimBlockEndBy() const { + const RareData::LineSmallData* data = GetLineSmallData(); + return data ? data->TrimBlockEndBy() : std::nullopt; + } + void SetNonOverflowingScrollRanges( const HeapVector<NonOverflowingScrollRange>& non_overflowing_ranges) { non_overflowing_scroll_ranges = non_overflowing_ranges; @@ -930,7 +989,8 @@ BlockData block_data; FlexData flex_data; GridData grid_data; - LineData line_data; + LineSmallData line_small_data; + LineDataPtr line_data; MathData math_data; TableData table_data; };
diff --git a/third_party/blink/renderer/core/layout/text_autosizer_test.cc b/third_party/blink/renderer/core/layout/text_autosizer_test.cc index cc9207c..03f184c 100644 --- a/third_party/blink/renderer/core/layout/text_autosizer_test.cc +++ b/third_party/blink/renderer/core/layout/text_autosizer_test.cc
@@ -1111,7 +1111,7 @@ Element* target = GetElementById("target"); EXPECT_FLOAT_EQ(20.0f * device_scale, target->GetLayoutObject()->StyleRef().ComputedFontSize()); - GetDocument().GetFrame()->StartPrinting(print_size, 1.0); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(print_size)); EXPECT_FLOAT_EQ(8.0f, target->GetLayoutObject()->StyleRef().ComputedFontSize()); GetDocument().GetFrame()->EndPrinting();
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc index 1c493b5..e6e78da 100644 --- a/third_party/blink/renderer/core/page/print_context.cc +++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -223,10 +223,6 @@ visitor->Trace(linked_destinations_); } -bool PrintContext::use_printing_layout() const { - return use_printing_layout_; -} - ScopedPrintContext::ScopedPrintContext(LocalFrame* frame) : context_(MakeGarbageCollected<PrintContext>(frame)) {}
diff --git a/third_party/blink/renderer/core/page/print_context.h b/third_party/blink/renderer/core/page/print_context.h index ef5ddf1..3334ca7 100644 --- a/third_party/blink/renderer/core/page/print_context.h +++ b/third_party/blink/renderer/core/page/print_context.h
@@ -71,8 +71,6 @@ virtual void Trace(Visitor*) const; - bool use_printing_layout() const; - protected: friend class PrintContextTest;
diff --git a/third_party/blink/renderer/core/page/print_context_test.cc b/third_party/blink/renderer/core/page/print_context_test.cc index 2116349a..0af27d04 100644 --- a/third_party/blink/renderer/core/page/print_context_test.cc +++ b/third_party/blink/renderer/core/page/print_context_test.cc
@@ -858,7 +858,8 @@ float maximum_shrink_ratio = 1.1; auto* node = GetDocument().documentElement(); - GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_EQ(node->OffsetWidth(), 400); GetDocument().GetFrame()->EndPrinting(); EXPECT_EQ(node->OffsetWidth(), 800); @@ -866,7 +867,8 @@ SetBodyInnerHTML(R"HTML( <div style='border: 0px; margin: 0px; background-color: #0000FF; width:800px; height:400px'></div>)HTML"); - GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_EQ(node->OffsetWidth(), 440); GetDocument().GetFrame()->EndPrinting(); EXPECT_EQ(node->OffsetWidth(), 800); @@ -1228,7 +1230,8 @@ // The iframe element in the document. auto* target = GetDocument().getElementById(AtomicString("target")); - GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + GetDocument().GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_EQ(parent->OffsetWidth(), 440); EXPECT_EQ(child->OffsetWidth(), 800); EXPECT_EQ(target->OffsetWidth(), 440); @@ -1237,7 +1240,7 @@ EXPECT_EQ(child->OffsetWidth(), 800); EXPECT_EQ(target->OffsetWidth(), 800); - GetDocument().GetFrame()->StartPrinting(); + GetDocument().GetFrame()->StartPrinting(WebPrintParams()); EXPECT_EQ(parent->OffsetWidth(), 800); EXPECT_EQ(child->OffsetWidth(), 800); EXPECT_EQ(target->OffsetWidth(), 800); @@ -1247,7 +1250,8 @@ EXPECT_EQ(target->OffsetWidth(), 800); ASSERT_TRUE(ChildDocument() != GetDocument()); - ChildDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio); + ChildDocument().GetFrame()->StartPrinting(WebPrintParams(page_size), + maximum_shrink_ratio); EXPECT_EQ(parent->OffsetWidth(), 800); EXPECT_EQ(child->OffsetWidth(), 400); EXPECT_EQ(target->OffsetWidth(), 800);
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc index b85f2db6..65efecd 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -3319,7 +3319,7 @@ ASSERT_TRUE(image_layer); EXPECT_EQ(gfx::Vector2dF(0.25f, 0.0625f), image_layer->GetRecordingSourceForTesting() - ->directly_composited_image_info() + .directly_composited_image_info() ->default_raster_scale); } @@ -3335,7 +3335,7 @@ ASSERT_TRUE(image_layer); EXPECT_EQ(gfx::Vector2dF(0.0625f, 0.25f), image_layer->GetRecordingSourceForTesting() - ->directly_composited_image_info() + .directly_composited_image_info() ->default_raster_scale); } @@ -3367,15 +3367,15 @@ if (RuntimeEnabledFeatures::FillScrollingContentsLayerEnabled()) { EXPECT_EQ(gfx::Size(2000, 16000), layer->bounds()); EXPECT_EQ(gfx::Rect(0, 0, 2000, 16000), - layer->GetRecordingSourceForTesting()->recorded_bounds()); + layer->GetRecordingSourceForTesting().recorded_bounds()); } else if (RuntimeEnabledFeatures::HitTestOpaquenessEnabled()) { EXPECT_EQ(gfx::Size(2000, 16000), layer->bounds()); EXPECT_EQ(gfx::Rect(0, 2000, 2000, 2000), - layer->GetRecordingSourceForTesting()->recorded_bounds()); + layer->GetRecordingSourceForTesting().recorded_bounds()); } else { EXPECT_EQ(gfx::Size(2000, 2000), layer->bounds()); EXPECT_EQ(gfx::Rect(0, 0, 2000, 2000), - layer->GetRecordingSourceForTesting()->recorded_bounds()); + layer->GetRecordingSourceForTesting().recorded_bounds()); } }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 05029646..a8e8f25 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -5474,7 +5474,7 @@ // When the main frame is printing, it should not have content clip. gfx::SizeF page_size(100, 100); - GetFrame().StartPrinting(page_size, 1); + GetFrame().StartPrinting(WebPrintParams(page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); EXPECT_EQ(nullptr, DocContentClip(main_frame_doc)); EXPECT_CLIP_RECT(gfx::RectF(0, 0, 300, 150), DocContentClip(child_frame_doc)); @@ -5484,7 +5484,7 @@ // When only the child frame is printing, it should not have content clip but // the main frame still have (which doesn't matter though). - ChildFrame().StartPrinting(page_size, 1); + ChildFrame().StartPrinting(WebPrintParams(page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); ASSERT_NE(nullptr, DocContentClip(main_frame_doc)); EXPECT_CLIP_RECT(gfx::RectF(0, 0, 800, 600), DocContentClip(main_frame_doc)); @@ -5851,7 +5851,7 @@ EXPECT_EQ(1u, NumFragments(normal)); gfx::SizeF page_size(300, 400); - GetFrame().StartPrinting(page_size, 1); + GetFrame().StartPrinting(WebPrintParams(page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); fixed = GetLayoutObjectByElementId("fixed"); fixed_child = GetLayoutObjectByElementId("fixed-child"); @@ -5907,7 +5907,7 @@ EXPECT_EQ(1u, NumFragments(fixed_child)); gfx::SizeF page_size(300, 400); - GetFrame().StartPrinting(page_size, 1); + GetFrame().StartPrinting(WebPrintParams(page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); fixed = GetLayoutObjectByElementId("fixed"); fixed_child = GetLayoutObjectByElementId("fixed-child");
diff --git a/third_party/blink/renderer/core/paint/text_painter_test.cc b/third_party/blink/renderer/core/paint/text_painter_test.cc index d8c2fc6..a864e02 100644 --- a/third_party/blink/renderer/core/paint/text_painter_test.cc +++ b/third_party/blink/renderer/core/paint/text_painter_test.cc
@@ -144,7 +144,7 @@ CSSPropertyID::kWebkitPrintColorAdjust, CSSValueID::kEconomy); GetDocument().GetSettings()->SetShouldPrintBackgrounds(false); gfx::SizeF page_size(500, 800); - GetFrame().StartPrinting(page_size, 1); + GetFrame().StartPrinting(WebPrintParams(page_size)); UpdateAllLifecyclePhasesForTest(); // In LayoutNG, printing currently forces layout tree reattachment, // so we need to re-get layout_text_. @@ -170,7 +170,7 @@ CSSPropertyID::kWebkitPrintColorAdjust, CSSValueID::kEconomy); GetDocument().GetSettings()->SetShouldPrintBackgrounds(false); gfx::SizeF page_size(500, 800); - GetFrame().StartPrinting(page_size, 1); + GetFrame().StartPrinting(WebPrintParams(page_size)); GetDocument().View()->UpdateLifecyclePhasesForPrinting(); // In LayoutNG, printing currently forces layout tree reattachment, // so we need to re-get layout_text_.
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 2db97f20..5e9e0bd 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2247,7 +2247,7 @@ bool ComputedStyle::HasVariables() const { return InheritedVariables() || NonInheritedVariables() || - HasInitialVariables(InitialData().get()); + HasInitialVariables(InitialData()); } wtf_size_t ComputedStyle::GetVariableNamesCount() const { @@ -2265,7 +2265,7 @@ Vector<AtomicString>& cache = EnsureVariableNamesCache(); HashSet<AtomicString> names; - if (auto* initial_data = InitialData().get()) { + if (auto* initial_data = InitialData()) { initial_data->CollectVariableNames(names); } if (auto* inherited_variables = InheritedVariables()) { @@ -2280,11 +2280,11 @@ } const StyleInheritedVariables* ComputedStyle::InheritedVariables() const { - return InheritedVariablesInternal().get(); + return InheritedVariablesInternal().Get(); } const StyleNonInheritedVariables* ComputedStyle::NonInheritedVariables() const { - return NonInheritedVariablesInternal().get(); + return NonInheritedVariablesInternal().Get(); } namespace { @@ -2305,7 +2305,7 @@ return *data; } } - if (StyleInitialData* initial_data = style_or_builder.InitialData().get()) { + if (StyleInitialData* initial_data = style_or_builder.InitialData()) { return initial_data->GetVariableData(name); } return nullptr; @@ -2327,7 +2327,7 @@ return *data; } } - if (StyleInitialData* initial_data = style_or_builder.InitialData().get()) { + if (StyleInitialData* initial_data = style_or_builder.InitialData()) { return initial_data->GetVariableValue(name); } return nullptr; @@ -2923,6 +2923,8 @@ const ComputedStyle* ComputedStyleBuilder::CloneStyle() const { ResetAccess(); + has_own_inherited_variables_ = false; + has_own_non_inherited_variables_ = false; return MakeGarbageCollected<ComputedStyle>(ComputedStyle::BuilderPassKey(), *this); } @@ -2932,8 +2934,9 @@ ComputedStyleBuilderBase::PropagateIndependentInheritedProperties( parent_style); if (!HasVariableReference() && !HasVariableDeclaration() && - (InheritedVariablesInternal().get() != + (InheritedVariablesInternal().Get() != parent_style.InheritedVariables())) { + has_own_inherited_variables_ = false; MutableInheritedVariablesInternal() = parent_style.InheritedVariablesInternal(); } @@ -3082,29 +3085,36 @@ } StyleInheritedVariables& ComputedStyleBuilder::MutableInheritedVariables() { - scoped_refptr<StyleInheritedVariables>& variables = + Member<StyleInheritedVariables>& variables = MutableInheritedVariablesInternal(); - if (!variables) { - variables = StyleInheritedVariables::Create(); - } else if (!variables->HasOneRef()) { - variables = variables->Copy(); + if (!has_own_inherited_variables_) { + variables = variables + ? MakeGarbageCollected<StyleInheritedVariables>(*variables) + : MakeGarbageCollected<StyleInheritedVariables>(); } + has_own_inherited_variables_ = true; + DCHECK(variables); return *variables; } StyleNonInheritedVariables& ComputedStyleBuilder::MutableNonInheritedVariables() { - std::unique_ptr<StyleNonInheritedVariables>& variables = + Member<StyleNonInheritedVariables>& variables = MutableNonInheritedVariablesInternal(); - if (!variables) { - variables = std::make_unique<StyleNonInheritedVariables>(); + if (!has_own_non_inherited_variables_) { + variables = + variables ? MakeGarbageCollected<StyleNonInheritedVariables>(*variables) + : MakeGarbageCollected<StyleNonInheritedVariables>(); } + has_own_non_inherited_variables_ = true; + DCHECK(variables); return *variables; } void ComputedStyleBuilder::CopyInheritedVariablesFrom( const ComputedStyle* style) { if (style->InheritedVariablesInternal()) { + has_own_inherited_variables_ = false; MutableInheritedVariablesInternal() = style->InheritedVariablesInternal(); } } @@ -3112,8 +3122,9 @@ void ComputedStyleBuilder::CopyNonInheritedVariablesFrom( const ComputedStyle* style) { if (style->NonInheritedVariablesInternal()) { + has_own_non_inherited_variables_ = false; MutableNonInheritedVariablesInternal() = - style->NonInheritedVariablesInternal()->Clone(); + style->NonInheritedVariablesInternal(); } }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index 4e4f4aa..23f3bb4 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -106,7 +106,6 @@ class StyleDifference; class StyleImage; class StyleInheritedVariables; -class StyleInitialData; class StyleRay; class StyleResolver; class StyleResolverState; @@ -3221,10 +3220,10 @@ // Variables const StyleInheritedVariables* InheritedVariables() const { - return InheritedVariablesInternal().get(); + return InheritedVariablesInternal().Get(); } const StyleNonInheritedVariables* NonInheritedVariables() const { - return NonInheritedVariablesInternal().get(); + return NonInheritedVariablesInternal().Get(); } CSSVariableData* GetVariableData(const AtomicString&, bool is_inherited_property) const; @@ -3233,12 +3232,12 @@ void CopyInheritedVariablesFrom(const ComputedStyle*); void CopyNonInheritedVariablesFrom(const ComputedStyle*); CORE_EXPORT void SetVariableData(const AtomicString& name, - scoped_refptr<CSSVariableData> value, + CSSVariableData* value, bool is_inherited_property) { if (is_inherited_property) { - MutableInheritedVariables().SetData(name, std::move(value)); + MutableInheritedVariables().SetData(name, value); } else { - MutableNonInheritedVariables().SetData(name, std::move(value)); + MutableNonInheritedVariables().SetData(name, value); } } CORE_EXPORT void SetVariableValue(const AtomicString& name, @@ -3250,9 +3249,6 @@ MutableNonInheritedVariables().SetValue(name, value); } } - CORE_EXPORT void SetInitialData(scoped_refptr<StyleInitialData> data) { - MutableInitialDataInternal() = std::move(data); - } EWhiteSpace WhiteSpace() const { return ToWhiteSpace(GetWhiteSpaceCollapse(), GetTextWrap()); @@ -3287,6 +3283,9 @@ SetContainIntrinsicHeight(height); } + private: + mutable bool has_own_inherited_variables_ = false; + mutable bool has_own_non_inherited_variables_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 index 591e921..6068d2a 100644 --- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 +++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -505,7 +505,7 @@ type_name: "StyleInheritedVariables", include_paths: ["third_party/blink/renderer/core/style/style_inherited_variables.h"], default_value: "nullptr", - wrapper_pointer_name: "scoped_refptr", + wrapper_pointer_name: "Member", field_group: "inherited", computed_style_custom_functions: ["getter", "setter"], }, @@ -522,13 +522,12 @@ { name: "InitialData", inherited: true, - field_template: "external", + field_template: "pointer", type_name: "StyleInitialData", include_paths: ["third_party/blink/renderer/core/style/style_initial_data.h"], default_value: "nullptr", - wrapper_pointer_name: "scoped_refptr", + wrapper_pointer_name: "Member", field_group: "*", - computed_style_custom_functions: ["setter"], }, { name: "Mask", @@ -635,7 +634,7 @@ type_name: "StyleNonInheritedVariables", field_group: "*", default_value: "nullptr", - wrapper_pointer_name: "std::unique_ptr", + wrapper_pointer_name: "Member", include_paths: ["third_party/blink/renderer/core/style/style_non_inherited_variables.h"], computed_style_custom_functions: ["getter", "setter"], },
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc index 39a9b415..cfc8353 100644 --- a/third_party/blink/renderer/core/style/computed_style_test.cc +++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -624,9 +624,9 @@ const ComputedStyle* style1; const ComputedStyle* style2; - auto value1 = css_test_helpers::CreateVariableData("foo"); - auto value2 = css_test_helpers::CreateVariableData("bar"); - auto value3 = css_test_helpers::CreateVariableData("foo"); + auto* value1 = css_test_helpers::CreateVariableData("foo"); + auto* value2 = css_test_helpers::CreateVariableData("bar"); + auto* value3 = css_test_helpers::CreateVariableData("foo"); Vector<AtomicString> properties; properties.push_back("--x"); @@ -966,7 +966,8 @@ *CreateLengthRegistration("--y", 2)); ComputedStyleBuilder builder = CreateComputedStyleBuilder(); - builder.SetInitialData(StyleInitialData::Create(GetDocument(), *registry)); + builder.SetInitialData( + MakeGarbageCollected<StyleInitialData>(GetDocument(), *registry)); const ComputedStyle* style = builder.TakeStyle(); EXPECT_EQ(2u, style->GetVariableNames().size()); @@ -1039,7 +1040,8 @@ *CreateLengthRegistration("--e", 2)); ComputedStyleBuilder builder = CreateComputedStyleBuilder(); - builder.SetInitialData(StyleInitialData::Create(GetDocument(), *registry)); + builder.SetInitialData( + MakeGarbageCollected<StyleInitialData>(GetDocument(), *registry)); const bool inherited = true; builder.SetVariableData(AtomicString("--a"), CreateVariableData("foo"), @@ -1064,7 +1066,7 @@ const ComputedStyle* style = InitialComputedStyle(); EXPECT_EQ(style->GetVariableNamesCount(), 0u); - auto data = css_test_helpers::CreateVariableData("foo"); + auto* data = css_test_helpers::CreateVariableData("foo"); ComputedStyleBuilder builder(*style); builder.SetVariableData(AtomicString("--x"), data, false); style = builder.TakeStyle(); @@ -1084,7 +1086,7 @@ TEST_F(ComputedStyleTest, GetVariableNames_Invalidation) { const ComputedStyle* style; - auto data = css_test_helpers::CreateVariableData("foo"); + auto* data = css_test_helpers::CreateVariableData("foo"); ComputedStyleBuilder builder = CreateComputedStyleBuilder(); builder.SetVariableData(AtomicString("--x"), data, false); style = builder.TakeStyle(); @@ -1117,7 +1119,8 @@ PropertyRegistry* registry = MakeGarbageCollected<PropertyRegistry>(); registry->RegisterProperty(AtomicString("--x"), *CreateLengthRegistration("--x", 1)); - builder.SetInitialData(StyleInitialData::Create(GetDocument(), *registry)); + builder.SetInitialData( + MakeGarbageCollected<StyleInitialData>(GetDocument(), *registry)); style = builder.TakeStyle(); } EXPECT_EQ(style->GetVariableNames().size(), 1u); @@ -1131,7 +1134,8 @@ *CreateLengthRegistration("--y", 2)); registry->RegisterProperty(AtomicString("--z"), *CreateLengthRegistration("--z", 3)); - builder.SetInitialData(StyleInitialData::Create(GetDocument(), *registry)); + builder.SetInitialData( + MakeGarbageCollected<StyleInitialData>(GetDocument(), *registry)); style = builder.TakeStyle(); } EXPECT_EQ(style->GetVariableNames().size(), 2u);
diff --git a/third_party/blink/renderer/core/style/style_inherited_variables.h b/third_party/blink/renderer/core/style/style_inherited_variables.h index b3f0a84..3ff597b 100644 --- a/third_party/blink/renderer/core/style/style_inherited_variables.h +++ b/third_party/blink/renderer/core/style/style_inherited_variables.h
@@ -19,14 +19,14 @@ namespace blink { class CORE_EXPORT StyleInheritedVariables - : public RefCounted<StyleInheritedVariables> { + : public GarbageCollected<StyleInheritedVariables> { public: - static scoped_refptr<StyleInheritedVariables> Create() { - return base::AdoptRef(new StyleInheritedVariables()); - } + StyleInheritedVariables(); + StyleInheritedVariables(StyleInheritedVariables& other); - scoped_refptr<StyleInheritedVariables> Copy() { - return base::AdoptRef(new StyleInheritedVariables(*this)); + void Trace(Visitor* visitor) const { + visitor->Trace(variables_); + visitor->Trace(root_); } bool operator==(const StyleInheritedVariables& other) const; @@ -34,9 +34,9 @@ return !(*this == other); } - void SetData(const AtomicString& name, scoped_refptr<CSSVariableData> value) { + void SetData(const AtomicString& name, CSSVariableData* value) { DCHECK(!value || !value->NeedsVariableResolution()); - variables_.SetData(name, std::move(value)); + variables_.SetData(name, value); } StyleVariables::OptionalData GetData(const AtomicString&) const; @@ -54,13 +54,10 @@ const StyleVariables::ValueMap& Values() const { return variables_.Values(); } private: - StyleInheritedVariables(); - StyleInheritedVariables(StyleInheritedVariables& other); - bool HasEquivalentRoots(const StyleInheritedVariables& other) const; StyleVariables variables_; - scoped_refptr<StyleInheritedVariables> root_; + Member<StyleInheritedVariables> root_; friend CORE_EXPORT std::ostream& operator<<( std::ostream& stream,
diff --git a/third_party/blink/renderer/core/style/style_initial_data.cc b/third_party/blink/renderer/core/style/style_initial_data.cc index 3199e41..61f34b7e 100644 --- a/third_party/blink/renderer/core/style/style_initial_data.cc +++ b/third_party/blink/renderer/core/style/style_initial_data.cc
@@ -20,11 +20,11 @@ const CSSValue* computed_initial_value = &StyleBuilderConverter::ConvertRegisteredPropertyInitialValue( document, *specified_initial_value); - scoped_refptr<CSSVariableData> computed_initial_data = + CSSVariableData* computed_initial_data = StyleBuilderConverter::ConvertRegisteredPropertyVariableData( *computed_initial_value, false /* is_animation_tainted */); - variables_.SetData(entry.key, std::move(computed_initial_data)); + variables_.SetData(entry.key, computed_initial_data); variables_.SetValue(entry.key, computed_initial_value); }
diff --git a/third_party/blink/renderer/core/style/style_initial_data.h b/third_party/blink/renderer/core/style/style_initial_data.h index afa9e2c..30cb570 100644 --- a/third_party/blink/renderer/core/style/style_initial_data.h +++ b/third_party/blink/renderer/core/style/style_initial_data.h
@@ -22,13 +22,11 @@ // // An instance of this class is created once, and then shared between all the // ComputedStyles that inherit (directly or indirectly) from the initial style. -class CORE_EXPORT StyleInitialData : public RefCounted<StyleInitialData> { +class CORE_EXPORT StyleInitialData : public GarbageCollected<StyleInitialData> { public: - static scoped_refptr<StyleInitialData> Create( - Document& document, - const PropertyRegistry& registry) { - return base::AdoptRef(new StyleInitialData(document, registry)); - } + StyleInitialData(Document&, const PropertyRegistry&); + + void Trace(Visitor* visitor) const { visitor->Trace(variables_); } bool operator==(const StyleInitialData& other) const; bool operator!=(const StyleInitialData& other) const { @@ -52,7 +50,6 @@ unsigned GetViewportUnitFlags() const { return viewport_unit_flags_; } private: - StyleInitialData(Document&, const PropertyRegistry&); // Initial values for all registered properties. This is set on // the initial style, and then shared with all other styles that directly or
diff --git a/third_party/blink/renderer/core/style/style_non_inherited_variables.h b/third_party/blink/renderer/core/style/style_non_inherited_variables.h index b86d783..11e4106b 100644 --- a/third_party/blink/renderer/core/style/style_non_inherited_variables.h +++ b/third_party/blink/renderer/core/style/style_non_inherited_variables.h
@@ -20,13 +20,10 @@ namespace blink { -class CORE_EXPORT StyleNonInheritedVariables { - USING_FAST_MALLOC(StyleNonInheritedVariables); - +class CORE_EXPORT StyleNonInheritedVariables + : public GarbageCollected<StyleNonInheritedVariables> { public: - std::unique_ptr<StyleNonInheritedVariables> Clone() { - return base::WrapUnique(new StyleNonInheritedVariables(*this)); - } + void Trace(Visitor* visitor) const { visitor->Trace(variables_); } bool operator==(const StyleNonInheritedVariables& other) const { return variables_ == other.variables_; @@ -36,9 +33,9 @@ return !(*this == other); } - void SetData(const AtomicString& name, scoped_refptr<CSSVariableData> value) { + void SetData(const AtomicString& name, CSSVariableData* value) { DCHECK(!value || !value->NeedsVariableResolution()); - variables_.SetData(name, std::move(value)); + variables_.SetData(name, value); } StyleVariables::OptionalData GetData(const AtomicString& name) const { return variables_.GetData(name);
diff --git a/third_party/blink/renderer/core/style/style_variables.cc b/third_party/blink/renderer/core/style/style_variables.cc index e247f53..1163b883 100644 --- a/third_party/blink/renderer/core/style/style_variables.cc +++ b/third_party/blink/renderer/core/style/style_variables.cc
@@ -35,21 +35,9 @@ } // namespace -StyleVariables::StyleVariables() : values_(MakeGarbageCollected<ValueMap>()) {} - -StyleVariables::StyleVariables(const StyleVariables& other) - : data_(other.data_), - values_(MakeGarbageCollected<ValueMap>(*other.values_)) {} - -StyleVariables& StyleVariables::operator=(const StyleVariables& other) { - data_ = other.data_; - values_ = MakeGarbageCollected<ValueMap>(*other.values_); - return *this; -} - bool StyleVariables::operator==(const StyleVariables& other) const { if (data_.size() != other.data_.size() || - values_->size() != other.values_->size()) { + values_.size() != other.values_.size()) { return false; } @@ -69,7 +57,7 @@ } } - for (const auto& pair : *values_) { + for (const auto& pair : values_) { if (!IsEqual(GetValue(pair.key), other.GetValue(pair.key))) { equality_cached_result_ = other.equality_cached_result_ = false; return false; @@ -84,33 +72,32 @@ const AtomicString& name) const { auto i = data_.find(name); if (i != data_.end()) { - return i->value.get(); + return i->value.Get(); } return std::nullopt; } StyleVariables::OptionalValue StyleVariables::GetValue( const AtomicString& name) const { - auto i = values_->find(name); - if (i != values_->end()) { + auto i = values_.find(name); + if (i != values_.end()) { return i->value.Get(); } return std::nullopt; } -void StyleVariables::SetData(const AtomicString& name, - scoped_refptr<CSSVariableData> data) { - data_.Set(name, std::move(data)); +void StyleVariables::SetData(const AtomicString& name, CSSVariableData* data) { + data_.Set(name, data); equality_cache_partner_ = nullptr; } void StyleVariables::SetValue(const AtomicString& name, const CSSValue* value) { - values_->Set(name, value); + values_.Set(name, value); equality_cache_partner_ = nullptr; } bool StyleVariables::IsEmpty() const { - return data_.empty() && values_->empty(); + return data_.empty() && values_.empty(); } void StyleVariables::CollectNames(HashSet<AtomicString>& names) const { @@ -126,7 +113,7 @@ stream << key << ": " << value->Serialize() << ", "; } stream << "]["; - for (const auto& [key, value] : *variables.values_) { + for (const auto& [key, value] : variables.values_) { stream << key << ": " << value->CssText() << ", "; } return stream << "]";
diff --git a/third_party/blink/renderer/core/style/style_variables.h b/third_party/blink/renderer/core/style/style_variables.h index 5e206b0..06a1f0c 100644 --- a/third_party/blink/renderer/core/style/style_variables.h +++ b/third_party/blink/renderer/core/style/style_variables.h
@@ -44,15 +44,22 @@ // // [1] https://drafts.csswg.org/css-variables/#invalid-at-computed-value-time class CORE_EXPORT StyleVariables { - USING_FAST_MALLOC(StyleVariables); + DISALLOW_NEW(); public: - using DataMap = HashMap<AtomicString, scoped_refptr<CSSVariableData>>; + using DataMap = HeapHashMap<AtomicString, Member<CSSVariableData>>; using ValueMap = HeapHashMap<AtomicString, Member<const CSSValue>>; - StyleVariables(); - StyleVariables(const StyleVariables&); - StyleVariables& operator=(const StyleVariables&); + StyleVariables() = default; + StyleVariables(const StyleVariables&) = default; + StyleVariables(StyleVariables&&) = default; + StyleVariables& operator=(const StyleVariables&) = default; + StyleVariables& operator=(StyleVariables&&) = default; + + void Trace(Visitor* visitor) const { + visitor->Trace(data_); + visitor->Trace(values_); + } bool operator==(const StyleVariables& other) const; bool operator!=(const StyleVariables& other) const { @@ -64,18 +71,18 @@ OptionalValue GetValue(const AtomicString&) const; OptionalData GetData(const AtomicString&) const; - void SetData(const AtomicString&, scoped_refptr<CSSVariableData>); + void SetData(const AtomicString&, CSSVariableData*); void SetValue(const AtomicString&, const CSSValue*); bool IsEmpty() const; void CollectNames(HashSet<AtomicString>&) const; const DataMap& Data() const { return data_; } - const ValueMap& Values() const { return *values_; } + const ValueMap& Values() const { return values_; } private: DataMap data_; - Persistent<ValueMap> values_; + ValueMap values_; // Cache for speeding up operator==. Some pages tend to set large numbers // of custom properties on elements high up in the DOM, and the sets of
diff --git a/third_party/blink/renderer/core/style/style_variables_test.cc b/third_party/blink/renderer/core/style/style_variables_test.cc index 77ffa595..bf67a2aa 100644 --- a/third_party/blink/renderer/core/style/style_variables_test.cc +++ b/third_party/blink/renderer/core/style/style_variables_test.cc
@@ -23,7 +23,7 @@ } TEST_F(StyleVariablesTest, Copy) { - auto foo_data = css_test_helpers::CreateVariableData("foo"); + auto* foo_data = css_test_helpers::CreateVariableData("foo"); const CSSValue* foo_value = css_test_helpers::CreateCustomIdent("foo"); AtomicString x_string("--x"); @@ -38,7 +38,7 @@ } TEST_F(StyleVariablesTest, Assignment) { - auto foo_data = css_test_helpers::CreateVariableData("foo"); + auto* foo_data = css_test_helpers::CreateVariableData("foo"); const CSSValue* foo_value = css_test_helpers::CreateCustomIdent("foo"); AtomicString x_string("--x"); AtomicString y_string("--y"); @@ -106,8 +106,8 @@ AtomicString x_string("--x"); StyleVariables vars; - auto foo = css_test_helpers::CreateVariableData("foo"); - auto bar = css_test_helpers::CreateVariableData("bar"); + auto* foo = css_test_helpers::CreateVariableData("foo"); + auto* bar = css_test_helpers::CreateVariableData("bar"); EXPECT_FALSE(vars.GetData(x_string).has_value()); @@ -130,7 +130,7 @@ TEST_F(StyleVariablesTest, SingleDataSamePointer) { AtomicString x_string("--x"); - auto data = css_test_helpers::CreateVariableData("foo"); + auto* data = css_test_helpers::CreateVariableData("foo"); StyleVariables vars1; StyleVariables vars2; vars1.SetData(x_string, data);
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc index 048c0f2..db3f075 100644 --- a/third_party/blink/renderer/core/testing/internals.cc +++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -3413,6 +3413,13 @@ settings->SetPreferredColorScheme(mojom::blink::PreferredColorScheme::kDark); } +void Internals::setDarkPreferredRootScrollbarColorScheme(Document* document) { + DCHECK(document); + Settings* settings = document->GetSettings(); + settings->SetPreferredRootScrollbarColorScheme( + mojom::blink::PreferredColorScheme::kDark); +} + void Internals::setShouldRevealPassword(Element* element, bool reveal, ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h index 8903c76..dbc15bf 100644 --- a/third_party/blink/renderer/core/testing/internals.h +++ b/third_party/blink/renderer/core/testing/internals.h
@@ -470,6 +470,7 @@ void forceCompositingUpdate(Document*, ExceptionState&); void setDarkPreferredColorScheme(Document* document); + void setDarkPreferredRootScrollbarColorScheme(Document* document); void setForcedColorsAndDarkPreferredColorScheme(Document* document); void setShouldRevealPassword(Element*, bool, ExceptionState&);
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl index 6fe8a23..96322278 100644 --- a/third_party/blink/renderer/core/testing/internals.idl +++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -302,6 +302,7 @@ [RaisesException] void forceCompositingUpdate(Document document); void setDarkPreferredColorScheme(Document document); + void setDarkPreferredRootScrollbarColorScheme(Document document); void setForcedColorsAndDarkPreferredColorScheme(Document document); [RaisesException] void setShouldRevealPassword(Element element, boolean reveal);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 508d524..6f17016c 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -2970,12 +2970,11 @@ } } - // For form controls that act as triggering elements for popovers of type - // kAuto, then set aria-expanded=false when the popover is hidden, and - // aria-expanded=true when it is showing. + // For form controls that act as triggering elements for popovers, then set + // aria-expanded=false when the popover is hidden, and aria-expanded=true when + // it is showing. if (auto* form_control = DynamicTo<HTMLFormControlElement>(element)) { - if (auto popover = form_control->popoverTargetElement().popover; - popover && popover->PopoverType() == PopoverValueType::kAuto) { + if (auto popover = form_control->popoverTargetElement().popover) { return popover->popoverOpen() ? kExpandedExpanded : kExpandedCollapsed; } }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index da3116a7..f162f7a 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1350,11 +1350,10 @@ } } - if (accessibility_mode.has_mode(ui::AXMode::kHTML)) - SerializeHTMLTagAndClass(node_data); // Used for test readability. - - if (accessibility_mode.has_mode(ui::AXMode::kScreenReader)) + if (accessibility_mode.has_mode(ui::AXMode::kScreenReader)) { SerializeColorAttributes(node_data); // Blends using all nodes' values. + SerializeHTMLIdTagAndClass(node_data); + } if (accessibility_mode.has_mode(ui::AXMode::kScreenReader) || accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) { @@ -1566,7 +1565,7 @@ node_data, ax::mojom::blink::StringAttribute::kRole, role_str); } -void AXObject::SerializeHTMLTagAndClass(ui::AXNodeData* node_data) const { +void AXObject::SerializeHTMLIdTagAndClass(ui::AXNodeData* node_data) const { Element* element = GetElement(); if (!element) { if (IsA<Document>(GetNode())) { @@ -1577,6 +1576,10 @@ } TruncateAndAddStringAttribute(node_data, + ax::mojom::blink::StringAttribute::kHtmlId, + element->GetIdAttribute()); + + TruncateAndAddStringAttribute(node_data, ax::mojom::blink::StringAttribute::kHtmlTag, element->tagName().LowerASCII()); @@ -1591,7 +1594,8 @@ DCHECK(element); for (const Attribute& attr : element->Attributes()) { std::string name = attr.LocalName().LowerASCII().Utf8(); - if (name == "class") { // class already in kClassName + if (name == "id" || name == "class") { + // Attribute already in kHtmlId or kClassName. continue; } std::string value = attr.Value().Utf8();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index 14a251b..c2fce51 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -1540,7 +1540,7 @@ void SerializeChooserPopupAttributes(ui::AXNodeData* node_data) const; void SerializeColorAttributes(ui::AXNodeData* node_data) const; void SerializeElementAttributes(ui::AXNodeData* node_data) const; - void SerializeHTMLTagAndClass(ui::AXNodeData* node_data) const; + void SerializeHTMLIdTagAndClass(ui::AXNodeData* node_data) const; void SerializeHTMLAttributes(ui::AXNodeData* node_data) const; void SerializeInlineTextBoxAttributes(ui::AXNodeData* node_data) const; void SerializeLangAttribute(ui::AXNodeData* node_data) const;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 122ce89..84eebaa8c 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -4975,6 +4975,10 @@ AXObject* child = Get(child_node); if (child) { ChildrenChangedOnAncestorOf(child); + // The previous call can cause child to become detached. + if (child->IsDetached()) { + child = nullptr; + } } AXObject* parent = child ? child->ComputeParentOrNull()
diff --git a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc index df9eb25..f3c0f8ad 100644 --- a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc +++ b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
@@ -21,7 +21,6 @@ #include "base/unguessable_token.h" #include "base/uuid.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "mojo/public/cpp/bindings/map_traits_wtf_hash_map.h" #include "third_party/abseil-cpp/absl/numeric/int128.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" @@ -1010,13 +1009,6 @@ return true; } - if (!base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { - // Ignore the specified aggregation coordinator unless the feature is - // enabled. - return true; - } - scoped_refptr<const SecurityOrigin> aggregation_coordinator_origin = ParseOrigin(config.aggregationCoordinatorOrigin()); if (!aggregation_coordinator_origin) {
diff --git a/third_party/blink/renderer/modules/buckets/storage_bucket.cc b/third_party/blink/renderer/modules/buckets/storage_bucket.cc index 95778937..b85f8bf 100644 --- a/third_party/blink/renderer/modules/buckets/storage_bucket.cc +++ b/third_party/blink/renderer/modules/buckets/storage_bucket.cc
@@ -198,7 +198,7 @@ ScriptPromise<FileSystemDirectoryHandle> StorageBucket::getDirectory( ScriptState* script_state, ExceptionState& exception_state) { - return StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed( + return StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( script_state, exception_state, WTF::BindOnce(&StorageBucket::GetSandboxedFileSystem, WrapWeakPersistent(this))); @@ -208,7 +208,7 @@ ExecutionContext* context, base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr, FileSystemDirectoryHandle*)> callback) { - StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed( + StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( context, WTF::BindOnce(&StorageBucket::GetSandboxedFileSystemForDevtools, WrapWeakPersistent(this), WrapWeakPersistent(context), std::move(callback)));
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 0d6ce317..f2e8c73 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -29,7 +29,7 @@ #include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_object_objectarray_string.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_begin_layer_options.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_webgpu_access_option.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_2d_webgpu_transfer_option.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_format.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_union_canvasfilter_string.h" #include "third_party/blink/renderer/core/css/cssom/css_color_value.h" @@ -3470,8 +3470,8 @@ return *format; } -GPUTexture* BaseRenderingContext2D::beginWebGPUAccess( - const CanvasWebGPUAccessOption* access_options, +GPUTexture* BaseRenderingContext2D::transferToWebGPU( + const Canvas2dWebGPUTransferOption* access_options, ExceptionState& exception_state) { if (!OriginClean()) { exception_state.ThrowSecurityError( @@ -3486,12 +3486,12 @@ return nullptr; } - // Prevent unbalanced calls to beginWebGPUAccess without a later call to - // endWebGPUAccess. + // Prevent unbalanced calls to `transferToWebGPU` without a later call to + // `transferFromWebGPU`. if (webgpu_access_texture_) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "This canvas is already in use by WebGPU."); + "This canvas has already been transferred to WebGPU."); return nullptr; } @@ -3609,8 +3609,9 @@ return true; } -void BaseRenderingContext2D::endWebGPUAccess(blink::GPUTexture* tex, - ExceptionState& exception_state) { +void BaseRenderingContext2D::transferFromWebGPU( + blink::GPUTexture* tex, + ExceptionState& exception_state) { // If the context is lost or doesn't exist, this call should be a no-op. // We don't want to throw an exception or attempt any changes if // `endWebGPUAccess` is called during teardown. @@ -3645,7 +3646,7 @@ } // Destroy the WebGPU texture to prevent it from being used after - // endWebGPUAccess. + // `transferFromWebGPU`. webgpu_access_texture_->destroy(); // We are finished with the WebGPU texture and its associated device.
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index 95c97f01..312c638 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -43,7 +43,7 @@ class BeginLayerOptions; class CanvasImageSource; -class CanvasWebGPUAccessOption; +class Canvas2dWebGPUTransferOption; class Color; class Image; class Mesh2DVertexBuffer; @@ -279,17 +279,18 @@ // Transfers a canvas' existing back-buffer to a GPUTexture for use in a // WebGPU pipeline. The canvas' image can be used as a texture, or the texture - // can be bound as a color attachment and modified. After beginWebGPUAccess is - // called, the Canvas2D context will become unavailable until endWebGPUAccess - // is called. - GPUTexture* beginWebGPUAccess(const CanvasWebGPUAccessOption*, - ExceptionState& exception_state); + // can be bound as a color attachment and modified. After its texture is + // transferred, the canvas will be reset into an empty, freshly-initialized + // state. + GPUTexture* transferToWebGPU(const Canvas2dWebGPUTransferOption*, + ExceptionState& exception_state); // Replaces the canvas' back-buffer texture with the passed-in GPUTexture. // The GPUTexture immediately becomes inaccessible to WebGPU. // A GPUValidationError will occur if the GPUTexture is used after // endWebGPUAccess is called. - void endWebGPUAccess(blink::GPUTexture* tex, ExceptionState& exception_state); + void transferFromWebGPU(blink::GPUTexture* tex, + ExceptionState& exception_state); // Returns the format of the GPUTexture that beginWebGPUAccess will return. // This is useful if you need to create the WebGPU render pipeline before
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer.idl new file mode 100644 index 0000000..c477a0e --- /dev/null +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer.idl
@@ -0,0 +1,14 @@ +// 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. + +// https://github.com/fserb/canvas2D/blob/master/spec/webgpu.md +[ + RuntimeEnabled=Canvas2dWebGPUTransfer, + Exposed=(Window,Worker), + SecureContext +] interface mixin Canvas2dWebGPUTransfer { + [RaisesException] GPUTexture transferToWebGPU(Canvas2dWebGPUTransferOption options); + [RaisesException] undefined transferFromWebGPU(GPUTexture tex); + GPUTextureFormat getTextureFormat(); +};
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer_option.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer_option.idl new file mode 100644 index 0000000..b1121ac --- /dev/null +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_webgpu_transfer_option.idl
@@ -0,0 +1,17 @@ +// 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. + +// Used by method `transferToWebGPU` as defined in canvas_2d_webgpu_transfer.idl +dictionary Canvas2dWebGPUTransferOption { + // This GPUDevice will be given access to the canvas' texture. + GPUDevice device; + + // This label will be assigned to the GPUTexture returned by transferToWebGPU. + DOMString? label; + + // This controls the GPUTextureUsage flags of the GPUTexture returned by + // transferToWebGPU. The default value will return a canvas texture that is + // usable as a render attachment, and bindable as a 2D texture. + GPUTextureUsageFlags usage = 0x14; // TEXTURE_BINDING | RENDER_ATTACHMENT +};
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl index ee02d822..e41d864 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
@@ -186,4 +186,4 @@ }; CanvasRenderingContext2D includes CanvasPath; -CanvasRenderingContext2D includes CanvasWebGPUAccess; +CanvasRenderingContext2D includes Canvas2dWebGPUTransfer;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access.idl deleted file mode 100644 index 1679e41..0000000 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access.idl +++ /dev/null
@@ -1,14 +0,0 @@ -// 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. - -// https://github.com/fserb/canvas2D/blob/master/spec/webgpu.md -[ - RuntimeEnabled=CanvasWebGPUAccess, - Exposed=(Window,Worker), - SecureContext -] interface mixin CanvasWebGPUAccess { - [RaisesException] GPUTexture beginWebGPUAccess(CanvasWebGPUAccessOption options); - [RaisesException] undefined endWebGPUAccess(GPUTexture tex); - GPUTextureFormat getTextureFormat(); -};
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access_option.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access_option.idl deleted file mode 100644 index 6bff3cd..0000000 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_web_gpu_access_option.idl +++ /dev/null
@@ -1,19 +0,0 @@ -// 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. - -// Used by method `beginWebGPUAccess` as defined in canvas_web_gpu_access.idl -dictionary CanvasWebGPUAccessOption { - // This GPUDevice will be given access to the canvas' texture. - GPUDevice device; - - // This label will be assigned to the GPUTexture returned by beginWebGPUAccess. - DOMString? label; - - // This controls the GPUTextureUsage flags of the GPUTexture returned by - // beginWebGPUAccess. (The returned texture might actually have additional - // texture usage flags beyond the requested flags.) - // The default value will return a canvas texture that is usable as a render - // attachment, and bindable as a 2D texture. - GPUTextureUsageFlags usage = 0x14; // TEXTURE_BINDING | RENDER_ATTACHMENT -};
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl index aeb999e..f24d0f4c 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
@@ -125,4 +125,4 @@ }; OffscreenCanvasRenderingContext2D includes CanvasPath; -OffscreenCanvasRenderingContext2D includes CanvasWebGPUAccess; +OffscreenCanvasRenderingContext2D includes Canvas2dWebGPUTransfer;
diff --git a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc index 3bcb459..d262f46 100644 --- a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc +++ b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc
@@ -355,6 +355,21 @@ return document_picture_in_picture_window_; } +LocalDOMWindow* +PictureInPictureControllerImpl::GetDocumentPictureInPictureOwner() const { + return document_picture_in_picture_owner_; +} + +void PictureInPictureControllerImpl::SetDocumentPictureInPictureOwner( + LocalDOMWindow* owner) { + CHECK(owner); + + document_picture_in_picture_owner_ = owner; + document_pip_context_observer_ = + MakeGarbageCollected<DocumentPictureInPictureObserver>(this); + document_pip_context_observer_->SetContextLifecycleNotifier(owner); +} + void PictureInPictureControllerImpl::CreateDocumentPictureInPictureWindow( ScriptState* script_state, LocalDOMWindow& opener, @@ -440,6 +455,11 @@ document_picture_in_picture_window_ = local_dom_window; + // Give the pip document's PictureInPictureControllerImpl a pointer to our + // window as its owner/opener. + From(*pip_document) + .SetDocumentPictureInPictureOwner(GetSupplementable()->domWindow()); + // There should not be an unresolved ScriptPromiseResolverBase at this point. // Leaving one unresolved and letting it get garbage collected will crash the // renderer. @@ -487,6 +507,21 @@ void PictureInPictureControllerImpl:: OnDocumentPictureInPictureContextDestroyed() { + // If we have an owner, then we are contained in a picture-in-picture window + // and our owner's context has been destroyed. + if (document_picture_in_picture_owner_) { + CHECK(!document_picture_in_picture_window_); + OnDocumentPictureInPictureOwnerWindowContextDestroyed(); + return; + } + + // Otherwise, our owned picture-in-picture window's context has been + // destroyed. + OnOwnedDocumentPictureInPictureWindowContextDestroyed(); +} + +void PictureInPictureControllerImpl:: + OnOwnedDocumentPictureInPictureWindowContextDestroyed() { // The document PIP window has been destroyed, so the opener is no longer // associated with it. Allow throttling again. SetMayThrottleIfUndrawnFrames(true); @@ -501,6 +536,11 @@ open_document_pip_resolver_ = nullptr; } } + +void PictureInPictureControllerImpl:: + OnDocumentPictureInPictureOwnerWindowContextDestroyed() { + document_picture_in_picture_owner_ = nullptr; +} #endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) void PictureInPictureControllerImpl::OnPictureInPictureStateChange() { @@ -553,6 +593,7 @@ void PictureInPictureControllerImpl::Trace(Visitor* visitor) const { #if !BUILDFLAG(TARGET_OS_IS_ANDROID) visitor->Trace(document_picture_in_picture_window_); + visitor->Trace(document_picture_in_picture_owner_); visitor->Trace(document_pip_context_observer_); visitor->Trace(open_document_pip_resolver_); #endif // !BUILDFLAG(TARGET_OS_IS_ANDROID)
diff --git a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.h index 7cd47b8..ec53835 100644 --- a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.h +++ b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.h
@@ -88,6 +88,9 @@ bool report_failure) const override; #if !BUILDFLAG(TARGET_OS_IS_ANDROID) LocalDOMWindow* GetDocumentPictureInPictureWindow() const override; + LocalDOMWindow* GetDocumentPictureInPictureOwner() const override; + + void SetDocumentPictureInPictureOwner(LocalDOMWindow* owner); #endif // !BUILDFLAG(TARGET_OS_IS_ANDROID) // Implementation of PictureInPictureSessionObserver. @@ -162,12 +165,23 @@ // Called by DocumentPictureInPictureObserver. void OnDocumentPictureInPictureContextDestroyed(); + void OnOwnedDocumentPictureInPictureWindowContextDestroyed(); + void OnDocumentPictureInPictureOwnerWindowContextDestroyed(); // The Document Picture-in-Picture window, if any. It shouldn't be confused // with `picture_in_picture_session_`, which is for video-only PiP. Member<LocalDOMWindow> document_picture_in_picture_window_; - // Nullable observer for Document Picture in Picture. + // The window that opened this document picture-in-picture window. Only set on + // PictureInPictureControllerImpls that are owned by a document + // picture-in-picture window. + Member<LocalDOMWindow> document_picture_in_picture_owner_; + + // Observes for destruction for either our owned + // `document_picture_in_picture_window_` (if this controller's Document has + // opened a document picture-in-picture window) or our owner + // `document_picture_in_picture_owner_` (if this controller's Document is + // attached to a document picture-in-picture window). Member<DocumentPictureInPictureObserver> document_pip_context_observer_; // Used to force |CreateDocumentPictureInPictureWindow()| to be asynchronous.
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc index 65b7bc8..a1d0658 100644 --- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc +++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
@@ -15,11 +15,11 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writable_options.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" -#include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_access_error.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_access_file_delegate.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h" +#include "third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" @@ -28,10 +28,6 @@ namespace blink { -namespace { -const char kSecurityErrorMessage[] = "File System access is denied."; -} // namespace - using mojom::blink::FileSystemAccessErrorPtr; FileSystemFileHandle::FileSystemFileHandle( @@ -154,11 +150,22 @@ WrapWeakPersistent(this), WrapPersistent(options), WrapPersistent(resolver)); - CheckFileSystemStorageAccessIsAllowed( - ExecutionContext::From(script_state), + auto on_got_storage_access_status_cb = WTF::BindOnce(&FileSystemFileHandle::OnGotFileSystemStorageAccessStatus, WrapWeakPersistent(this), WrapPersistent(resolver), - std::move(on_allowed_callback))); + std::move(on_allowed_callback)); + + if (storage_access_status_.has_value()) { + std::move(on_got_storage_access_status_cb) + .Run(mojom::blink::FileSystemAccessError::New( + /*status=*/get<0>(storage_access_status_.value()), + /*file_error=*/get<1>(storage_access_status_.value()), + /*message=*/get<2>(storage_access_status_.value()))); + } else { + StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( + ExecutionContext::From(script_state), + std::move(on_got_storage_access_status_cb)); + } return promise; } @@ -373,59 +380,32 @@ mojo_ptr_->GetCloudIdentifiers(std::move(callback)); } -void FileSystemFileHandle::CheckFileSystemStorageAccessIsAllowed( - ExecutionContext* context, - base::OnceCallback<void(bool)> callback) { - SECURITY_DCHECK(context->IsWindow() || context->IsWorkerGlobalScope()); - - if (file_system_storage_access_allowed_.has_value()) { - std::move(callback).Run(file_system_storage_access_allowed_.value()); - return; - } - - WebContentSettingsClient* content_settings_client = nullptr; - if (auto* window = DynamicTo<LocalDOMWindow>(context)) { - LocalFrame* frame = window->GetFrame(); - if (!frame) { - std::move(callback).Run(false); - return; - } - - content_settings_client = frame->GetContentSettingsClient(); - } else { - content_settings_client = - To<WorkerGlobalScope>(context)->ContentSettingsClient(); - } - - if (!content_settings_client) { - std::move(callback).Run(true); - return; - } - - content_settings_client->AllowStorageAccess( - WebContentSettingsClient::StorageType::kFileSystem, std::move(callback)); -} - void FileSystemFileHandle::OnGotFileSystemStorageAccessStatus( ScriptPromiseResolver<FileSystemSyncAccessHandle>* resolver, base::OnceClosure on_allowed_callback, - bool allow_access) { + mojom::blink::FileSystemAccessErrorPtr result) { if (!resolver->GetExecutionContext() || !resolver->GetScriptState()->ContextIsValid()) { return; } - if (file_system_storage_access_allowed_.has_value()) { - DCHECK_EQ(file_system_storage_access_allowed_.value(), allow_access); + CHECK(result); + if (storage_access_status_.has_value()) { + CHECK_EQ(/*status=*/get<0>(storage_access_status_.value()), result->status); + CHECK_EQ(/*file_error=*/get<1>(storage_access_status_.value()), + result->file_error); + CHECK_EQ(/*message=*/get<2>(storage_access_status_.value()), + result->message); } else { - file_system_storage_access_allowed_ = allow_access; + storage_access_status_ = + std::make_tuple(result->status, result->file_error, result->message); } - if (!allow_access) { + if (result->status != mojom::blink::FileSystemAccessStatus::kOk) { auto* const isolate = resolver->GetScriptState()->GetIsolate(); ScriptState::Scope scope(resolver->GetScriptState()); resolver->Reject(V8ThrowDOMException::CreateOrEmpty( - isolate, DOMExceptionCode::kSecurityError, kSecurityErrorMessage)); + isolate, DOMExceptionCode::kSecurityError, result->message)); return; }
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h index 1a65ba6..5c382db7e 100644 --- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h +++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
@@ -88,19 +88,17 @@ const FileSystemCreateSyncAccessHandleOptions* options, ScriptPromiseResolver<FileSystemSyncAccessHandle>* resolver); - // Checks if the File System Storage Access is allowed for the current - // frame. - void CheckFileSystemStorageAccessIsAllowed( - ExecutionContext* context, - base::OnceCallback<void(bool)> callback); + // Callback for StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed. void OnGotFileSystemStorageAccessStatus( ScriptPromiseResolver<FileSystemSyncAccessHandle>* resolver, base::OnceClosure on_allowed_callback, - bool allow_access); + mojom::blink::FileSystemAccessErrorPtr result); HeapMojoRemote<mojom::blink::FileSystemAccessFileHandle> mojo_ptr_; - - std::optional<bool> file_system_storage_access_allowed_; + std::optional<std::tuple</*status=*/mojom::blink::FileSystemAccessStatus, + /*file_error=*/::base::File::Error, + /*message=*/WTF::String>> + storage_access_status_; }; template <>
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_observer.cc b/third_party/blink/renderer/modules/file_system_access/file_system_observer.cc index 325b755..a4743ee4 100644 --- a/third_party/blink/renderer/modules/file_system_access/file_system_observer.cc +++ b/third_party/blink/renderer/modules/file_system_access/file_system_observer.cc
@@ -4,11 +4,10 @@ #include "third_party/blink/renderer/modules/file_system_access/file_system_observer.h" -#include "base/feature_list.h" -#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_observer_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_observer_observe_options.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -17,6 +16,7 @@ #include "third_party/blink/renderer/modules/file_system_access/file_system_access_manager.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_change_record.h" #include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h" +#include "third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -78,17 +78,66 @@ ExceptionState& exception_state) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(https://crbug.com/321980226): Add AllowStorageAccess checks. - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>( script_state, exception_state.GetContext()); auto result = resolver->Promise(); + auto on_got_storage_access_status_cb = + WTF::BindOnce(&FileSystemObserver::OnGotStorageAccessStatus, + WrapWeakPersistent(this), WrapPersistent(resolver), + WrapPersistent(handle), WrapPersistent(options)); + + if (storage_access_status_.has_value()) { + std::move(on_got_storage_access_status_cb) + .Run(mojom::blink::FileSystemAccessError::New( + /*status=*/get<0>(storage_access_status_.value()), + /*file_error=*/get<1>(storage_access_status_.value()), + /*message=*/get<2>(storage_access_status_.value()))); + } else { + StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( + ExecutionContext::From(script_state), + std::move(on_got_storage_access_status_cb)); + } + + return result; +} + +void FileSystemObserver::OnGotStorageAccessStatus( + ScriptPromiseResolver<IDLUndefined>* resolver, + FileSystemHandle* handle, + FileSystemObserverObserveOptions* options, + mojom::blink::FileSystemAccessErrorPtr result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!resolver->GetExecutionContext() || + !resolver->GetScriptState()->ContextIsValid()) { + return; + } + + CHECK(result); + if (storage_access_status_.has_value()) { + CHECK_EQ(/*status=*/get<0>(storage_access_status_.value()), result->status); + CHECK_EQ(/*file_error=*/get<1>(storage_access_status_.value()), + result->file_error); + CHECK_EQ(/*message=*/get<2>(storage_access_status_.value()), + result->message); + } else { + storage_access_status_ = + std::make_tuple(result->status, result->file_error, result->message); + } + + if (result->status != mojom::blink::FileSystemAccessStatus::kOk) { + auto* const isolate = resolver->GetScriptState()->GetIsolate(); + ScriptState::Scope scope(resolver->GetScriptState()); + resolver->Reject(V8ThrowDOMException::CreateOrEmpty( + isolate, DOMExceptionCode::kSecurityError, result->message)); + return; + } + host_remote_->Observe( handle->Transfer(), options->recursive(), WTF::BindOnce(&FileSystemObserver::DidObserve, WrapPersistent(this), WrapPersistent(resolver))); - return result; } void FileSystemObserver::DidObserve(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_observer.h b/third_party/blink/renderer/modules/file_system_access/file_system_observer.h index 57ca85d..588a111 100644 --- a/third_party/blink/renderer/modules/file_system_access/file_system_observer.h +++ b/third_party/blink/renderer/modules/file_system_access/file_system_observer.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_OBSERVER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_OBSERVER_H_ -#include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink-forward.h" +#include "base/files/file.h" #include "third_party/blink/public/mojom/file_system_access/file_system_access_observer.mojom-blink.h" #include "third_party/blink/public/mojom/file_system_access/file_system_access_observer_host.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" @@ -55,8 +55,18 @@ mojo::PendingReceiver<mojom::blink::FileSystemAccessObserver> observer_receiver); + // Callback for StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed. + void OnGotStorageAccessStatus(ScriptPromiseResolver<IDLUndefined>* resolver, + FileSystemHandle* handle, + FileSystemObserverObserveOptions* options, + mojom::blink::FileSystemAccessErrorPtr result); + SEQUENCE_CHECKER(sequence_checker_); + std::optional<std::tuple</*status=*/mojom::blink::FileSystemAccessStatus, + /*file_error=*/::base::File::Error, + /*message=*/WTF::String>> + storage_access_status_; Member<ExecutionContext> execution_context_; Member<V8FileSystemObserverCallback> callback_;
diff --git a/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc b/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc index 04ac53c6..1841113 100644 --- a/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc +++ b/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc
@@ -58,7 +58,7 @@ StorageManagerFileSystemAccess::getDirectory(ScriptState* script_state, const StorageManager& storage, ExceptionState& exception_state) { - return CheckGetDirectoryIsAllowed( + return CheckStorageAccessIsAllowed( script_state, exception_state, WTF::BindOnce([](ScriptPromiseResolver<FileSystemDirectoryHandle>* resolver) { @@ -71,7 +71,7 @@ // static ScriptPromise<FileSystemDirectoryHandle> -StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed( +StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( ScriptState* script_state, ExceptionState& exception_state, base::OnceCallback<void(ScriptPromiseResolver<FileSystemDirectoryHandle>*)> @@ -81,7 +81,7 @@ script_state, exception_state.GetContext()); auto result = resolver->Promise(); - CheckGetDirectoryIsAllowed( + CheckStorageAccessIsAllowed( ExecutionContext::From(script_state), WTF::BindOnce(&OnGotAccessAllowed, WrapPersistent(resolver), std::move(on_allowed))); @@ -90,7 +90,7 @@ } // static -void StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed( +void StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( ExecutionContext* context, base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)> callback) { if (!context->GetSecurityOrigin()->CanAccessFileSystem()) {
diff --git a/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h b/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h index a707ceaf..cda1d2b 100644 --- a/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h +++ b/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h
@@ -29,12 +29,12 @@ // Called to execute checks, both renderer side and browser side, that OPFS is // allowed. Will execute `on_allowed` with the result of browser side checks // if it gets that far. - static ScriptPromise<FileSystemDirectoryHandle> CheckGetDirectoryIsAllowed( + static ScriptPromise<FileSystemDirectoryHandle> CheckStorageAccessIsAllowed( ScriptState* script_state, ExceptionState& exception_state, base::OnceCallback< void(ScriptPromiseResolver<FileSystemDirectoryHandle>*)> on_allowed); - static void CheckGetDirectoryIsAllowed( + static void CheckStorageAccessIsAllowed( ExecutionContext* context, base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)> callback);
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc index 83fc002..005db87 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -306,16 +306,25 @@ #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_FUCHSIA) -// Checks if the above flag is enabled, but gates it on the preview UI also -// being enabled. -bool ShouldDeferDeviceSettingsSelection() { +// Returns true if `kGetUserMediaDeferredDeviceSettingsSelection` is enabled, +// but gates it on `kCameraMicPreview` also being being enabled. This only +// applies to user media requests. +bool ShouldDeferDeviceSettingsSelection(UserMediaRequestType request_type) { + // The new behavior shouldn't be applied for anything except for user media + // requests. + // TODO(crbug.com/341136036): Find a better long-term solution for keeping + // both code paths happy. + if (request_type != UserMediaRequestType::kUserMedia) { + return false; + } + // Enables camera preview in permission bubble and site settings. return base::FeatureList::IsEnabled(features::kCameraMicPreview) && base::FeatureList::IsEnabled( features::kGetUserMediaDeferredDeviceSettingsSelection); } #else -bool ShouldDeferDeviceSettingsSelection() { +bool ShouldDeferDeviceSettingsSelection(UserMediaRequestType request_type) { return false; } #endif @@ -749,7 +758,8 @@ DCHECK(current_request_info_->stream_controls()->audio.requested()); SendLogMessage(base::StringPrintf("SelectAudioSettings({request_id=%d})", current_request_info_->request_id())); - if (ShouldDeferDeviceSettingsSelection()) { + if (ShouldDeferDeviceSettingsSelection( + user_media_request->MediaRequestType())) { base::expected<Vector<blink::AudioCaptureSettings>, std::string> eligible_settings = SelectEligibleSettingsAudioCapture( capabilities, user_media_request->AudioConstraints(), @@ -966,7 +976,8 @@ capabilities.noise_reduction_capabilities = {std::optional<bool>(), std::optional<bool>(true), std::optional<bool>(false)}; - if (ShouldDeferDeviceSettingsSelection()) { + if (ShouldDeferDeviceSettingsSelection( + user_media_request->MediaRequestType())) { auto eligible_settings = SelectEligibleSettingsVideoDeviceCapture( std::move(capabilities), user_media_request->VideoConstraints(), blink::MediaStreamVideoSource::kDefaultWidth, @@ -1177,7 +1188,8 @@ return; } - if (ShouldDeferDeviceSettingsSelection()) { + if (ShouldDeferDeviceSettingsSelection( + current_request_info_->request()->MediaRequestType())) { if (!current_request_info_->eligible_audio_settings().empty()) { const std::string selected_id = stream_devices_set->stream_devices.front()->audio_device->id;
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc index a23f3d8..567fd85 100644 --- a/third_party/blink/renderer/modules/ml/ml_context.cc +++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -202,7 +202,7 @@ if (result->is_error()) { const auto& create_context_error = result->get_error(); resolver->RejectWithDOMException( - ConvertWebNNErrorCodeToDOMExceptionCode(create_context_error->code), + WebNNErrorCodeToDOMExceptionCode(create_context_error->code), create_context_error->message); return; }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_buffer_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_buffer_mojo.cc index e9f24ec..a6617db 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_buffer_mojo.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_buffer_mojo.cc
@@ -87,7 +87,7 @@ if (result->is_error()) { const webnn::mojom::blink::Error& read_buffer_error = *result->get_error(); resolver->RejectWithDOMException( - ConvertWebNNErrorCodeToDOMExceptionCode(read_buffer_error.code), + WebNNErrorCodeToDOMExceptionCode(read_buffer_error.code), read_buffer_error.message); return; }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.cc index ea9c8d5..fe173e51 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.cc
@@ -11,7 +11,7 @@ return DOMExceptionCode::error_code; \ } -DOMExceptionCode ConvertWebNNErrorCodeToDOMExceptionCode( +DOMExceptionCode WebNNErrorCodeToDOMExceptionCode( webnn::mojom::blink::Error::Code error_code) { switch (error_code) { DEFINE_WEBNN_ERROR_CODE_MAPPING(kUnknownError)
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.h b/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.h index a8dc6d1..7a1a743c 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_error_mojo.h
@@ -11,7 +11,7 @@ namespace blink { -DOMExceptionCode ConvertWebNNErrorCodeToDOMExceptionCode( +DOMExceptionCode WebNNErrorCodeToDOMExceptionCode( webnn::mojom::blink::Error::Code error_code); template <typename MojoResultType>
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 3e4512b..9bf80c58 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
@@ -113,7 +113,7 @@ NOTREACHED_NORETURN(); } -webnn::Operand ConvertToComponentOperand(const blink::MLOperand* ml_operand) { +webnn::Operand BlinkOperandToComponent(const blink::MLOperand* ml_operand) { return webnn::Operand(BlinkOperandTypeToComponent(ml_operand->DataType()), ml_operand->Dimensions()); } @@ -213,10 +213,10 @@ CHECK(options); webnn::BatchNormalizationAttributes attributes; if (options->hasScale()) { - attributes.scale = ConvertToComponentOperand(options->scale()); + attributes.scale = BlinkOperandToComponent(options->scale()); } if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } attributes.axis = options->axis(); return attributes; @@ -259,7 +259,7 @@ attributes.input_layout = BlinkInputOperandLayoutToComponent(options->inputLayout().AsEnum()); if (options->hasBias()) { - attributes.bias_operand = ConvertToComponentOperand(options->bias()); + attributes.bias_operand = BlinkOperandToComponent(options->bias()); } return std::move(attributes); @@ -374,7 +374,7 @@ CHECK(options); webnn::GemmAttributes attributes; if (options->hasC()) { - attributes.c_operand = ConvertToComponentOperand(options->c()); + attributes.c_operand = BlinkOperandToComponent(options->c()); } attributes.alpha = options->alpha(); attributes.beta = options->beta(); @@ -389,15 +389,15 @@ webnn::GruAttributes attributes; if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } if (options->hasRecurrentBias()) { attributes.recurrent_bias = - ConvertToComponentOperand(options->recurrentBias()); + BlinkOperandToComponent(options->recurrentBias()); } if (options->hasInitialHiddenState()) { attributes.initial_hidden_state = - ConvertToComponentOperand(options->initialHiddenState()); + BlinkOperandToComponent(options->initialHiddenState()); } attributes.return_sequence = options->returnSequence(); attributes.direction = @@ -423,11 +423,11 @@ webnn::GruCellAttributes attributes; if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } if (options->hasRecurrentBias()) { attributes.recurrent_bias = - ConvertToComponentOperand(options->recurrentBias()); + BlinkOperandToComponent(options->recurrentBias()); } // If the activations are not specified, create a default activation sequence // [sigmoid, tanh] as defined in the spec. @@ -448,10 +448,10 @@ CHECK(options); webnn::InstanceNormalizationAttributes attributes; if (options->hasScale()) { - attributes.scale = ConvertToComponentOperand(options->scale()); + attributes.scale = BlinkOperandToComponent(options->scale()); } if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } attributes.layout = BlinkInputOperandLayoutToComponent(options->layout().AsEnum()); @@ -463,10 +463,10 @@ CHECK(options); webnn::LayerNormalizationAttributes attributes; if (options->hasScale()) { - attributes.scale = ConvertToComponentOperand(options->scale()); + attributes.scale = BlinkOperandToComponent(options->scale()); } if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } return attributes; } @@ -477,23 +477,23 @@ webnn::LstmAttributes attributes; if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } if (options->hasRecurrentBias()) { attributes.recurrent_bias = - ConvertToComponentOperand(options->recurrentBias()); + BlinkOperandToComponent(options->recurrentBias()); } if (options->hasPeepholeWeight()) { attributes.peephole_weight = - ConvertToComponentOperand(options->peepholeWeight()); + BlinkOperandToComponent(options->peepholeWeight()); } if (options->hasInitialHiddenState()) { attributes.initial_hidden_state = - ConvertToComponentOperand(options->initialHiddenState()); + BlinkOperandToComponent(options->initialHiddenState()); } if (options->hasInitialCellState()) { attributes.initial_cell_state = - ConvertToComponentOperand(options->initialCellState()); + BlinkOperandToComponent(options->initialCellState()); } attributes.activation_count = options->activations().size(); attributes.return_sequence = options->returnSequence(); @@ -509,15 +509,15 @@ webnn::LstmCellAttributes attributes; if (options->hasBias()) { - attributes.bias = ConvertToComponentOperand(options->bias()); + attributes.bias = BlinkOperandToComponent(options->bias()); } if (options->hasRecurrentBias()) { attributes.recurrent_bias = - ConvertToComponentOperand(options->recurrentBias()); + BlinkOperandToComponent(options->recurrentBias()); } if (options->hasPeepholeWeight()) { attributes.peephole_weight = - ConvertToComponentOperand(options->peepholeWeight()); + BlinkOperandToComponent(options->peepholeWeight()); } attributes.activation_count = options->activations().size(); @@ -581,7 +581,7 @@ const auto input_rank = input->Dimensions().size(); const auto axes = options->getAxesOr(CreateAllAxes(input_rank)); const auto validated_output = webnn::ValidateArgMinMaxAndInferOutput( - ConvertToComponentOperand(input), axes, options->keepDimensions()); + BlinkOperandToComponent(input), axes, options->keepDimensions()); if (!validated_output.has_value()) { exception_state.ThrowDOMException( DOMExceptionCode::kDataError, @@ -708,7 +708,7 @@ const auto input_rank = input->Dimensions().size(); const auto axes = options->getAxesOr(CreateAllAxes(input_rank)); auto validated_output = webnn::ValidateReduceAndInferOutput( - MojoReduceKindToComponent(kind), ConvertToComponentOperand(input), axes, + MojoReduceKindToComponent(kind), BlinkOperandToComponent(input), axes, options->keepDimensions()); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -744,7 +744,7 @@ } auto validated_output = webnn::ValidatePool2dAndInferOutput( - ConvertToComponentOperand(input), std::move(pool2d_attributes.value())); + BlinkOperandToComponent(input), std::move(pool2d_attributes.value())); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -849,8 +849,8 @@ } const auto validated_output = webnn::ValidateBatchNormalizationAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(mean), - ConvertToComponentOperand(variance), + BlinkOperandToComponent(input), BlinkOperandToComponent(mean), + BlinkOperandToComponent(variance), ConvertToBatchNormalizationAttributes(options)); if (!validated_output.has_value()) { exception_state.ThrowDOMException( @@ -887,7 +887,7 @@ input_component_operands.reserve(inputs.size()); base::ranges::transform( inputs, std::back_inserter(input_component_operands), - [](const auto& input) { return ConvertToComponentOperand(input); }); + [](const auto& input) { return BlinkOperandToComponent(input); }); auto validated_output = webnn::ValidateConcatAndInferOutput(input_component_operands, axis); @@ -957,7 +957,7 @@ } auto validated_output = webnn::ValidateConv2dAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(filter), + BlinkOperandToComponent(input), BlinkOperandToComponent(filter), std::move(conv2d_attributes.value())); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1002,7 +1002,7 @@ } auto validated_output = webnn::ValidateConvTranspose2dAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(filter), + BlinkOperandToComponent(input), BlinkOperandToComponent(filter), std::move(convTranspose2d_attributes.value())); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1192,7 +1192,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr); auto validated_output = webnn::ValidateGatherAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(indices), + BlinkOperandToComponent(input), BlinkOperandToComponent(indices), options->axis()); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1244,7 +1244,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr); auto validated_output = webnn::ValidateGemmAndInferOutput( - ConvertToComponentOperand(a), ConvertToComponentOperand(b), + BlinkOperandToComponent(a), BlinkOperandToComponent(b), ConvertToGemmAttributes(options)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1292,8 +1292,8 @@ } auto validated_outputs = webnn::ValidateGruAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), steps, hidden_size, + BlinkOperandToComponent(input), BlinkOperandToComponent(weight), + BlinkOperandToComponent(recurrent_weight), steps, hidden_size, ConvertToGruAttributes(this, options)); if (!validated_outputs.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_outputs.error())); @@ -1341,9 +1341,9 @@ } auto validated_output = webnn::ValidateGruCellAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), - ConvertToComponentOperand(hidden_state), hidden_size, + BlinkOperandToComponent(input), BlinkOperandToComponent(weight), + BlinkOperandToComponent(recurrent_weight), + BlinkOperandToComponent(hidden_state), hidden_size, ConvertToGruCellAttributes(this, options)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1429,7 +1429,7 @@ const auto validated_output = webnn::ValidateInstanceNormalizationAndInferOutput( - ConvertToComponentOperand(input), + BlinkOperandToComponent(input), ConvertToInstanceNormalizationAttributes(options)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1474,7 +1474,7 @@ CreateLayerNormalizationDefaultAxes(input->Dimensions().size())); const auto validated_output = webnn::ValidateLayerNormalizationAndInferOutput( - ConvertToComponentOperand(input), axes, + BlinkOperandToComponent(input), axes, ConvertToLayerNormalizationAttributes(options)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1592,8 +1592,8 @@ } auto validated_outputs = webnn::ValidateLstmAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), steps, hidden_size, + BlinkOperandToComponent(input), BlinkOperandToComponent(weight), + BlinkOperandToComponent(recurrent_weight), steps, hidden_size, ConvertToLstmAttributes(options)); if (!validated_outputs.has_value()) { exception_state.ThrowDOMException( @@ -1662,10 +1662,10 @@ } auto validated_outputs = webnn::ValidateLstmCellAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(weight), - ConvertToComponentOperand(recurrent_weight), - ConvertToComponentOperand(hidden_state), - ConvertToComponentOperand(cell_state), hidden_size, + BlinkOperandToComponent(input), BlinkOperandToComponent(weight), + BlinkOperandToComponent(recurrent_weight), + BlinkOperandToComponent(hidden_state), + BlinkOperandToComponent(cell_state), hidden_size, ConvertToLstmCellAttributes(options)); if (!validated_outputs.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_outputs.error())); @@ -1700,7 +1700,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr); auto validated_output = webnn::ValidateMatmulAndInferOutput( - ConvertToComponentOperand(a), ConvertToComponentOperand(b)); + BlinkOperandToComponent(a), BlinkOperandToComponent(b)); if (!validated_output.has_value()) { exception_state.ThrowTypeError( WTF::String::FromUTF8(validated_output.error())); @@ -1729,7 +1729,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInput(input), nullptr); auto validated_output = webnn::ValidatePadAndInferOutput( - ConvertToComponentOperand(input), beginning_padding, ending_padding); + BlinkOperandToComponent(input), beginning_padding, ending_padding); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -1806,7 +1806,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr); auto validated_output = webnn::ValidatePreluAndInferOutput( - ConvertToComponentOperand(input), ConvertToComponentOperand(slope)); + BlinkOperandToComponent(input), BlinkOperandToComponent(slope)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -1911,7 +1911,7 @@ } auto validated_output = webnn::ValidateResample2dAndInferOutput( - ConvertToComponentOperand(input), scales_or_sizes, + BlinkOperandToComponent(input), scales_or_sizes, options->getAxesOr({2, 3})); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); @@ -1962,7 +1962,7 @@ attributes.sizes.assign(sizes.begin(), sizes.end()); attributes.starts.assign(starts.begin(), starts.end()); auto validated_output = webnn::ValidateSliceAndInferOutput( - ConvertToComponentOperand(input), attributes); + BlinkOperandToComponent(input), attributes); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -1985,7 +1985,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInput(input), nullptr); auto validated_output = - webnn::ValidateSoftmaxAndInferOutput(ConvertToComponentOperand(input)); + webnn::ValidateSoftmaxAndInferOutput(BlinkOperandToComponent(input)); if (!validated_output.has_value()) { exception_state.ThrowDOMException( DOMExceptionCode::kDataError, @@ -2066,10 +2066,10 @@ HeapVector<Member<const MLOperand>>()); auto validated_outputs = webnn::ValidateSplitAndInferOutput( - ConvertToComponentOperand(input), { - .splits = splits, - .axis = options->axis(), - }); + BlinkOperandToComponent(input), { + .splits = splits, + .axis = options->axis(), + }); if (!validated_outputs.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_outputs.error())); return {}; @@ -2103,10 +2103,10 @@ HeapVector<Member<const MLOperand>>()); auto validated_outputs = webnn::ValidateSplitAndInferOutput( - ConvertToComponentOperand(input), { - .splits = splits, - .axis = options->axis(), - }); + BlinkOperandToComponent(input), { + .splits = splits, + .axis = options->axis(), + }); if (!validated_outputs.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_outputs.error())); return {}; @@ -2164,7 +2164,7 @@ const Vector<uint32_t> permutation = options->getPermutationOr(CreateDefaultPermutation(input_rank)); auto validated_output = webnn::ValidateTransposeAndInferOutput( - ConvertToComponentOperand(input), permutation); + BlinkOperandToComponent(input), permutation); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -2193,7 +2193,7 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInput(input), nullptr); const base::expected<webnn::Operand, std::string> validated_output = - webnn::ValidateTriangularAndInferOutput(ConvertToComponentOperand(input)); + webnn::ValidateTriangularAndInferOutput(BlinkOperandToComponent(input)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr; @@ -2223,9 +2223,8 @@ THROW_AND_RETURN_TYPE_IF_ERROR(ValidateInputs(inputs), nullptr); const auto validated_output = webnn::ValidateWhereAndInferOutput( - ConvertToComponentOperand(condition), - ConvertToComponentOperand(true_value), - ConvertToComponentOperand(false_value)); + BlinkOperandToComponent(condition), BlinkOperandToComponent(true_value), + BlinkOperandToComponent(false_value)); if (!validated_output.has_value()) { exception_state.ThrowTypeError(String::FromUTF8(validated_output.error())); return nullptr;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc index d9b5d4b0..195b47c 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc
@@ -252,7 +252,7 @@ if (mojo_result->is_error()) { const auto& compute_error = mojo_result->get_error(); resolver->RejectWithDOMException( - ConvertWebNNErrorCodeToDOMExceptionCode(compute_error->code), + WebNNErrorCodeToDOMExceptionCode(compute_error->code), compute_error->message); return; } @@ -306,7 +306,7 @@ if (result->is_error()) { const auto& create_graph_error = result->get_error(); resolver->RejectWithDOMException( - ConvertWebNNErrorCodeToDOMExceptionCode(create_graph_error->code), + WebNNErrorCodeToDOMExceptionCode(create_graph_error->code), create_graph_error->message); return; }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc index 34366bc9..7fe9e03 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc
@@ -82,7 +82,7 @@ case ESErrorType::kTypeError: return "TypeError"; default: - NOTREACHED(); + NOTREACHED_IN_MIGRATION(); return "UnknownError"; } }
diff --git a/third_party/blink/renderer/modules/shared_storage/util.cc b/third_party/blink/renderer/modules/shared_storage/util.cc index 3977b21..2e4084e 100644 --- a/third_party/blink/renderer/modules/shared_storage/util.cc +++ b/third_party/blink/renderer/modules/shared_storage/util.cc
@@ -7,7 +7,6 @@ #include "base/feature_list.h" #include "base/memory/scoped_refptr.h" #include "components/aggregation_service/aggregation_coordinator_utils.h" -#include "components/aggregation_service/features.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h" @@ -118,9 +117,7 @@ out_context_id = options.privateAggregationConfig()->contextId(); } - if (options.privateAggregationConfig()->hasAggregationCoordinatorOrigin() && - base::FeatureList::IsEnabled( - aggregation_service::kAggregationServiceMultipleCloudProviders)) { + if (options.privateAggregationConfig()->hasAggregationCoordinatorOrigin()) { scoped_refptr<SecurityOrigin> parsed_coordinator = SecurityOrigin::CreateFromString( options.privateAggregationConfig()->aggregationCoordinatorOrigin());
diff --git a/third_party/blink/renderer/modules/shared_storage/util.h b/third_party/blink/renderer/modules/shared_storage/util.h index 9e251afd..bd966f8 100644 --- a/third_party/blink/renderer/modules/shared_storage/util.h +++ b/third_party/blink/renderer/modules/shared_storage/util.h
@@ -42,15 +42,14 @@ // Returns true if a valid privateAggregationConfig is provided or if no config // is provided. A config is invalid if an invalid (i.e. too long) context_id // string is provided or an invalid (i.e. not on the allowlist) -// aggregationCoordinatorOrigin is provided. Note that the -// aggregationCoordinatorOrigin is only evaluated if the relevant features are -// enabled. If the config is invalid, returns false and rejects the `resolver` -// with an error. Always populates `out_private_aggregation_config` with a new -// config object. If a valid context_id string was provided, -// `out_private_aggregation_config->context_id` is populated with it; otherwise, -// it's left default (a null String). If a valid aggregation coordinator is -// provided, `out_private_aggregation_config->aggregation_coodinator_origin` is -// populated with it; otherwise, it's left default (nullptr). If a valid +// aggregationCoordinatorOrigin is provided. If the config is invalid, returns +// false and rejects the `resolver` with an error. Always populates +// `out_private_aggregation_config` with a new config object. If a valid +// context_id string was provided, `out_private_aggregation_config->context_id` +// is populated with it; otherwise, it's left default (a null String). If a +// valid aggregation coordinator is provided, +// `out_private_aggregation_config->aggregation_coodinator_origin` is populated +// with it; otherwise, it's left default (nullptr). If a valid // filteringIdMaxBytes is provided, `out_filtering_id_max_bytes` is populated // with it; otherwise, it's populated with the default of 1. bool CheckPrivateAggregationConfig(
diff --git a/third_party/blink/renderer/modules/storage_access/storage_access_handle.cc b/third_party/blink/renderer/modules/storage_access/storage_access_handle.cc index e0180fc..c19decd9 100644 --- a/third_party/blink/renderer/modules/storage_access/storage_access_handle.cc +++ b/third_party/blink/renderer/modules/storage_access/storage_access_handle.cc
@@ -324,7 +324,7 @@ GetSupplementable()->CountUse( WebFeature:: kStorageAccessAPI_requestStorageAccess_BeyondCookies_getDirectory_Use); - return StorageManagerFileSystemAccess::CheckGetDirectoryIsAllowed( + return StorageManagerFileSystemAccess::CheckStorageAccessIsAllowed( script_state, exception_state, WTF::BindOnce(&StorageAccessHandle::GetDirectoryImpl, WrapWeakPersistent(this)));
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 94e4bf2..85f2356 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -559,6 +559,10 @@ status: "experimental", }, { + name: "Canvas2dWebGPUTransfer", + status: "experimental", + }, + { name: "CanvasFloatingPoint", status: "experimental", }, @@ -576,10 +580,6 @@ status: "stable", }, { - name: "CanvasWebGPUAccess", - status: "experimental", - }, - { name: "CapabilityDelegationDisplayCaptureRequest", status: "experimental", }, @@ -672,7 +672,7 @@ { name: "CompressionDictionaryTransport", base_feature: "none", - origin_trial_feature_name: "CompressionDictionaryTransportV2", + origin_trial_feature_name: "CompressionDictionaryTransportForTest", origin_trial_allows_third_party: true, public: true, }, @@ -1328,6 +1328,15 @@ "default": "stable", }, }, + // Enables propagating user activation from a document picture-in-picture + // window up to its opener window and vice versa. + { + name: "DocumentPictureInPictureUserActivation", + status: { + "Android": "", + "default": "stable", + }, + }, // Enables the ability to use Document Policy header to control feature // DocumentDomain. { @@ -3415,6 +3424,11 @@ depends_on: ["RubyLineBreakable"], }, { + // crbug.com/324111880 + name: "RubyShortHeuristics", + status: "test", + }, + { // Runs a microtask checkpoint before creating custom elements in // XMLDocumentParser. Should be safe to remove after M125 name: "RunMicrotaskBeforeXmlCustomElement",
diff --git a/third_party/blink/renderer/platform/wtf/hash_table.h b/third_party/blink/renderer/platform/wtf/hash_table.h index 596531ac..52aece34 100644 --- a/third_party/blink/renderer/platform/wtf/hash_table.h +++ b/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -1801,13 +1801,27 @@ stats_(HashTableStatsPtr<Allocator>::copy(other.stats_)) #endif { - if (other.size()) - ReserveCapacityForSize(other.size()); - // Copy the hash table the dumb way, by adding each element to the new - // table. It might be more efficient to copy the table slots, but it's not - // clear that efficiency is needed. - for (const auto& element : other) - insert(element); + DCHECK(!other.AccessForbidden()); + table_size_ = other.table_size_; + if (table_size_ == 0) { + return; + } + table_ = AllocateTable(table_size_); + key_count_ = other.key_count_; + deleted_count_ = other.deleted_count_; + + for (unsigned i = 0; i < table_size_; i++) { + if (other.IsEmptyBucket(other.table_[i])) { + // Do nothing. All entries are initially empty by AllocateTable(). + } else if (other.IsDeletedBucket(other.table_[i])) { + ConstructHashTraitsDeletedValue<KeyTraits>( + Extractor::ExtractKey(table_[i])); + } else { + new (&table_[i]) ValueType(other.table_[i]); + ConstructTraits<ValueType, Traits, Allocator>::NotifyNewElement( + &table_[i]); + } + } } template <typename Key,
diff --git a/third_party/blink/tools/blinkpy/w3c/test_exporter.py b/third_party/blink/tools/blinkpy/w3c/test_exporter.py index 8f8f8097..183c123 100644 --- a/third_party/blink/tools/blinkpy/w3c/test_exporter.py +++ b/third_party/blink/tools/blinkpy/w3c/test_exporter.py
@@ -99,19 +99,8 @@ self.local_repo.fetch() pr_events = collections.defaultdict(set) - _log.info('Searching for exportable in-flight CLs.') - # The Gerrit search API is slow and easy to fail, so we wrap it in a try - # statement to continue exporting landed commits when it fails. - try: - open_gerrit_cls = self.gerrit.query_exportable_cls() - except GerritError as e: - _log.info( - 'In-flight CLs cannot be exported due to the following error:') - _log.error(str(e)) - gerrit_error = True - else: - self.process_gerrit_cls(open_gerrit_cls, pr_events) - gerrit_error = False + + gerrit_error = self.export_in_flight_changes(pr_events) _log.info('Searching for exportable Chromium commits.') exportable_commits, git_errors = self.get_exportable_commits() @@ -197,6 +186,25 @@ help='Write a summary of PR updates to this markdown file.') return parser.parse_args(argv) + def export_in_flight_changes(self, pr_events: PREventsByType) -> bool: + """ Search and export in-flight changes from Gerrit. + Returns: + A boolean: True if there was an error, False otherwise. + """ + _log.info('Searching for exportable in-flight CLs.') + # The Gerrit search API is slow and easy to fail, so we wrap it in a try + # statement to continue exporting landed commits when it fails. + try: + open_gerrit_cls = self.gerrit.query_exportable_cls() + except GerritError as e: + _log.info( + 'In-flight CLs cannot be exported due to the following error:') + _log.error(str(e)) + return True + else: + self.process_gerrit_cls(open_gerrit_cls, pr_events) + return False + def process_gerrit_cls(self, gerrit_cls, pr_events: PREventType): for cl in gerrit_cls: maybe_event = self.process_gerrit_cl(cl)
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 0e592dc..d4b2649 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2960,6 +2960,18 @@ ] }, { + "prefix": "document-picture-in-picture-user-activation", + "platforms": ["Linux", "Mac", "Win"], + "bases": [ + "external/wpt/document-picture-in-picture/propagate-user-activation-from-opener.https.html", + "external/wpt/document-picture-in-picture/propagate-user-activation-to-opener.https.html" + ], + "exclusive_tests": "ALL", + "args": ["--enable-blink-features=DocumentPictureInPictureUserActivation"], + "expires": "Dec 1, 2024", + "owners": ["steimel@chromium.org", "liberato@chromium.org"] + }, + { "prefix": "font-variant-emoji", "platforms": ["Linux"], "bases": [
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index 32a1014..4d2823d8c 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -24,16 +24,16 @@ # Mac gets invalid texture errors in SwiftShader. # Also, with a native GPU, sometimes R & B channels are incorrectly swapped in # texture readback. (Canvas readback does not exhibit this issue.) -crbug.com/40823053 [ Mac ] wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.html [ Skip ] -crbug.com/40823053 [ Mac ] wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.worker.html [ Skip ] +crbug.com/40823053 [ Mac ] wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.html [ Skip ] +crbug.com/40823053 [ Mac ] wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.worker.html [ Skip ] # Linux does not yet properly support readback on shared images. -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.html [ Skip ] -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.worker.html [ Skip ] -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.html [ Skip ] -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.worker.html [ Skip ] -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.html [ Skip ] -crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.worker.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.worker.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.worker.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.html [ Skip ] +crbug.com/40218893 [ Linux ] wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.worker.html [ Skip ] # Test fails due to scaling precision issues crbug.com/1515185 wpt_internal/webgpu/web_platform/reftests/canvas_image_rendering.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print-ref.html b/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print-ref.html new file mode 100644 index 0000000..c3e5d8d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print-ref.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<p> + Should print a green rectangle but not display it on screen. +</p> +<img src="/images/green.png" alt="A green rectangle">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print.html b/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print.html new file mode 100644 index 0000000..f100f7e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/background-image-only-for-print.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Test print result of background-image not displayed on screen</title> + +<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#background-image"> +<link rel="help" href="https://crbug.com/40262871"> + +<link rel="match" href="background-image-only-for-print-ref.html"> + +<style> + @media not print { + .print-only { + display: none; + } + } + + #target { + background-image: url("/images/green.png"); + height: 50px; + width: 100px; + } +</style> + +<p> + Should print a green rectangle but not display it on screen. +</p> + +<div id="target" class="print-only"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-after-layout-change.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-after-layout-change.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-after-layout-change.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-after-layout-change.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-interrupted-scroll.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-interrupted-scroll.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-interrupted-scroll.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-interrupted-scroll.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-root-scroll.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-programmatic-root-scroll.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-root-scroll.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-programmatic-root-scroll.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-scroll.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-programmatic-scroll.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-scroll.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-programmatic-scroll.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-root-scroll.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-user-root-scroll.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-root-scroll.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-user-root-scroll.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-scroll.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-user-scroll.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-scroll.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-on-user-scroll.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-same-targets-after-layout-changed.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-same-targets-after-layout-changed.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-same-targets-after-layout-changed.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-same-targets-after-layout-changed.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-scrolling-non-snapping-axis.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-scrolling-non-snapping-axis.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-scrolling-non-snapping-axis.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-scrolling-non-snapping-axis.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-with-proximity-strictness.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-with-proximity-strictness.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/snapchanged/snapchanged-with-proximity-strictness.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-scroll-snap-2/scrollsnapchange/scrollsnapchange-with-proximity-strictness.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-from-opener.https.html b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-from-opener.https.html new file mode 100644 index 0000000..7d8b55b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-from-opener.https.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Test that a user activation in window that owns a document picture-in-picture window is usable in the + document picture-in-picture window</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<body> +<script> +promise_test(async (t) => { + await test_driver.bless('request PiP window'); + const pipWindow = await documentPictureInPicture.requestWindow(); + + assert_false(navigator.userActivation.isActive, 'the opener should initially not have user activation'); + assert_false(pipWindow.navigator.userActivation.isActive, 'the PiP window should initially not have user activation'); + + // Activating this window should also activate the picture-in-picture window. + await test_driver.bless('activate opener window'); + assert_true(navigator.userActivation.isActive, 'the opener should be activated when the PiP window is activated'); + assert_true(pipWindow.navigator.userActivation.isActive, 'the PiP window should be activated'); + + // Consuming activation in the opener should also consume it in the picture-in-picture window. + window.open(); + assert_false(navigator.userActivation.isActive, 'the opener should no longer be active once it consumes activation'); + assert_false(pipWindow.navigator.userActivation.isActive, 'the PiP window should no longer be active once the opener consumes activation'); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-to-opener.https.html b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-to-opener.https.html new file mode 100644 index 0000000..1f25328a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/propagate-user-activation-to-opener.https.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Test that a user activation in a document picture-in-picture window is usable in its opener window</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<body> +<script> +promise_test(async (t) => { + await test_driver.bless('request PiP window'); + const pipWindow = await documentPictureInPicture.requestWindow(); + + assert_false(navigator.userActivation.isActive, 'the opener should initially not have user activation'); + assert_false(pipWindow.navigator.userActivation.isActive, 'the PiP window should initially not have user activation'); + + // Activating the picture-in-picture window should also activate the opener. + await test_driver.bless('activate pip window', null, pipWindow); + assert_true(navigator.userActivation.isActive, 'the opener should be activated when the PiP window is activated'); + assert_true(pipWindow.navigator.userActivation.isActive, 'the PiP window should be activated'); + + // Consuming activation in the picture-in-picture window should also consume it in the opener. + pipWindow.open(); + assert_false(navigator.userActivation.isActive, 'the opener should no longer be active once the PiP window consumes activation'); + assert_false(pipWindow.navigator.userActivation.isActive, 'the PiP window should no longer be active once it consumes activation'); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/pointer-event-document-move.html b/third_party/blink/web_tests/external/wpt/dom/events/pointer-event-document-move.html new file mode 100644 index 0000000..91e7c368 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/pointer-event-document-move.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<link rel="help" href="https://crbug.com/341104769"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<template> + <p>TEST</p> +</template> + +<body> +<script> + const clone = document.querySelector("template").content.cloneNode(true); + const p = clone.querySelector("p"); + + let gotEvent = false; + p.addEventListener("pointerup", () => { + gotEvent = true; + }); + + document.body.append(clone); + + promise_test(async () => { + await test_driver.click(document.querySelector("p")); + assert_true(gotEvent); + }, "Moving a node to new document should move the registered event listeners together"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html index c7b3b7c..33aeb44 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html
@@ -20,7 +20,7 @@ // Check if the data compressed using Brotli with the dictionary can be // decompressed. - const data_url = `${kCompressedDataPath}?content_encoding=br-d`; + const data_url = `${kCompressedDataPath}?content_encoding=dcb`; assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Decompresion using Brotli with the dictionary works as expected'); @@ -34,7 +34,7 @@ // Check if the data compressed using Zstandard with the dictionary can be // decompressed. - const data_url = `${kCompressedDataPath}?content_encoding=zstd-d`; + const data_url = `${kCompressedDataPath}?content_encoding=dcz`; assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Decompresion using Zstandard with the dictionary works as expected'); @@ -50,7 +50,7 @@ // Check if the data compressed using Brotli with the dictionary can be // decompressed. const data_url = - getRemoteHostUrl(`${kCompressedDataPath}?content_encoding=br-d`); + getRemoteHostUrl(`${kCompressedDataPath}?content_encoding=dcb`); assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Decompresion of a cross origin resource works as expected');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html index 2480104..d465ceb3 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html
@@ -41,7 +41,7 @@ kDefaultDictionaryHashBase64); // Check if the data compressed using Brotli with the dictionary can be // decompressed. - const data_url = `${kCompressedDataPath}?content_encoding=br-d`; + const data_url = `${kCompressedDataPath}?content_encoding=dcb`; assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Fetch same origin dictionary using link element'); @@ -64,7 +64,7 @@ // Check if the data compressed using Brotli with the dictionary can be // decompressed. const data_url = - getRemoteHostUrl(`${kCompressedDataPath}?content_encoding=br-d`); + getRemoteHostUrl(`${kCompressedDataPath}?content_encoding=dcb`); assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Fetch cross origin dictionary using link element');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-header.tentative.https.html b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-header.tentative.https.html index a9d96a6..007067d 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-header.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-header.tentative.https.html
@@ -46,7 +46,7 @@ kDefaultDictionaryHashBase64); // Check if the data compressed using Brotli with the dictionary can be // decompressed. - const data_url = `${kCompressedDataPath}?content_encoding=br-d`; + const data_url = `${kCompressedDataPath}?content_encoding=dcb`; assert_equals(await (await fetch(data_url)).text(), kExpectedCompressedData); }, 'Fetch same origin dictionary using link header');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/resources/compressed-data.py b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/resources/compressed-data.py index 4be4b55..bb9d7fe8 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/resources/compressed-data.py +++ b/third_party/blink/web_tests/external/wpt/fetch/compression-dictionary/resources/compressed-data.py
@@ -1,28 +1,31 @@ def main(request, response): response.headers.set(b"Access-Control-Allow-Origin", b"*") response.headers.set(b"Content-Type", b"text/plain") - response.headers.set( - b"Content-Dictionary", - b":U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:") - # `br_d_data` and `zstd_d_data` are generated using the following commands: + # `dcb_data` and `dcz_data` are generated using the following commands: # # $ echo "This is a test dictionary." > /tmp/dict # $ echo -n "This is compressed test data using a test dictionary" \ # > /tmp/data - # $ brotli -o /tmp/out.brd -D /tmp/dict /tmp/data - # $ xxd -p /tmp/out.brd | tr -d '\n' | sed 's/\(..\)/\\x\1/g' - br_d_data = b"\xa1\x98\x01\x80\x62\xa4\x4c\x1d\xdf\x12\x84\x8c\xae\xc2\xca\x60\x22\x07\x6e\x81\x05\x14\xc9\xb7\xc3\x44\x8e\xbc\x16\xe0\x15\x0e\xec\xc1\xee\x34\x33\x3e\x0d" - # $ zstd -o /tmp/out.zstdd -D /tmp/dict /tmp/data - # $ xxd -p /tmp/out.zstdd | tr -d '\n' | sed 's/\(..\)/\\x\1/g' - zstd_d_data = b"\x28\xb5\x2f\xfd\x24\x34\xf5\x00\x00\x98\x63\x6f\x6d\x70\x72\x65\x73\x73\x65\x64\x61\x74\x61\x20\x75\x73\x69\x6e\x67\x03\x00\x59\xf9\x73\x54\x46\x27\x26\x10\x9e\x99\xf2\xbc" + # + # $ echo -en '\xffDCB' > /tmp/out.dcb + # $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb + # $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb + # $ xxd -p /tmp/out.dcb | tr -d '\n' | sed 's/\(..\)/\\x\1/g' + dcb_data = b"\xff\x44\x43\x42\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\xa1\x98\x01\x80\x62\xa4\x4c\x1d\xdf\x12\x84\x8c\xae\xc2\xca\x60\x22\x07\x6e\x81\x05\x14\xc9\xb7\xc3\x44\x8e\xbc\x16\xe0\x15\x0e\xec\xc1\xee\x34\x33\x3e\x0d" + # $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz + # $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz + # $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data + # $ cat /tmp/tmp.zstd >> /tmp/out.dcz + # $ xxd -p /tmp/out.dcz | tr -d '\n' | sed 's/\(..\)/\\x\1/g' + dcz_data = b"\x5e\x2a\x4d\x18\x20\x00\x00\x00\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\x28\xb5\x2f\xfd\x24\x34\xf5\x00\x00\x98\x63\x6f\x6d\x70\x72\x65\x73\x73\x65\x64\x61\x74\x61\x20\x75\x73\x69\x6e\x67\x03\x00\x59\xf9\x73\x54\x46\x27\x26\x10\x9e\x99\xf2\xbc" if b'content_encoding' in request.GET: content_encoding = request.GET.first(b"content_encoding") response.headers.set(b"Content-Encoding", content_encoding) - if content_encoding == b"br-d": + if content_encoding == b"dcb": # Send the pre compressed file - response.content = br_d_data - if content_encoding == b"zstd-d": + response.content = dcb_data + if content_encoding == b"dcz": # Send the pre compressed file - response.content = zstd_d_data + response.content = dcz_data
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-baselines.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-baselines.tentative.html index d66e23d..6c634b9 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-baselines.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-baselines.tentative.html
@@ -40,17 +40,17 @@ for (const baseline of kBaselines) { const tm = ctx.measureText(text); // First character. - for (const r of tm.getSelectionRects(0, 0)) { + for (const r of tm.getSelectionRects(0, 1)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Last character. - for (const r of tm.getSelectionRects(text.length - 1, text.length - 1)) { + for (const r of tm.getSelectionRects(text.length - 1, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Whole string. - for (const r of tm.getSelectionRects(0, text.length - 1)) { + for (const r of tm.getSelectionRects(0, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } @@ -60,7 +60,11 @@ assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Invalid start > end string. Creates 0 width rectangle. - for (const r of tm.getSelectionRects(2, 1)) { + for (const r of tm.getSelectionRects(3, 2)) { + assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); + assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); + } + for (const r of tm.getSelectionRects(1, 0)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); }
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-exceptions.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-exceptions.tentative.html index f5b4cd75..dd213d3 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-exceptions.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects-exceptions.tentative.html
@@ -33,11 +33,11 @@ assert_throws_js(TypeError, () => tm.getSelectionRects(-1, -1) ); // Thrown in TextMetrics. assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, 0) ); + () => tm.getSelectionRects(text.length + 1, 0) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(0, text.length) ); + () => tm.getSelectionRects(0, text.length + 1) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, text.length) ); + () => tm.getSelectionRects(text.length + 1, text.length + 1) ); } });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects.tentative.html index 7d31b59..e724586 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/text/2d.text.measure.selection-rects.tentative.html
@@ -32,7 +32,7 @@ const parent = range.getClientRects()[0]; range.setStart(el.childNodes[0], from); - range.setEnd(el.childNodes[0], to+1); + range.setEnd(el.childNodes[0], to); let sel = window.getSelection(); sel.removeAllRanges(); @@ -73,28 +73,32 @@ const tm = ctx.measureText(text); // First character. checkRectListsMatch( - tm.getSelectionRects(0, 0), - placeAndSelectTextInDOM(text, 0, 0) + tm.getSelectionRects(0, 1), + placeAndSelectTextInDOM(text, 0, 1) ); // Last character. checkRectListsMatch( - tm.getSelectionRects(text.length - 1, text.length - 1), - placeAndSelectTextInDOM(text, text.length - 1, text.length - 1) + tm.getSelectionRects(text.length - 1, text.length), + placeAndSelectTextInDOM(text, text.length - 1, text.length) ); // Whole string. checkRectListsMatch( - tm.getSelectionRects(0, text.length - 1), - placeAndSelectTextInDOM(text, 0, text.length - 1) + tm.getSelectionRects(0, text.length), + placeAndSelectTextInDOM(text, 0, text.length) ); // Intermediate string. checkRectListsMatch( - tm.getSelectionRects(1, text.length - 2), - placeAndSelectTextInDOM(text, 1, text.length - 2) + tm.getSelectionRects(1, text.length - 1), + placeAndSelectTextInDOM(text, 1, text.length - 1) ); // Invalid start > end string. Creates 0 width rectangle. checkRectListsMatch( - tm.getSelectionRects(2, 1), - placeAndSelectTextInDOM(text, 2, 1) + tm.getSelectionRects(3, 2), + placeAndSelectTextInDOM(text, 3, 2) + ); + checkRectListsMatch( + tm.getSelectionRects(1, 0), + placeAndSelectTextInDOM(text, 1, 0) ); }
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.html index 9460d32..818a63ef 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.html
@@ -41,17 +41,17 @@ for (const baseline of kBaselines) { const tm = ctx.measureText(text); // First character. - for (const r of tm.getSelectionRects(0, 0)) { + for (const r of tm.getSelectionRects(0, 1)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Last character. - for (const r of tm.getSelectionRects(text.length - 1, text.length - 1)) { + for (const r of tm.getSelectionRects(text.length - 1, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Whole string. - for (const r of tm.getSelectionRects(0, text.length - 1)) { + for (const r of tm.getSelectionRects(0, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } @@ -61,7 +61,11 @@ assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Invalid start > end string. Creates 0 width rectangle. - for (const r of tm.getSelectionRects(2, 1)) { + for (const r of tm.getSelectionRects(3, 2)) { + assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); + assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); + } + for (const r of tm.getSelectionRects(1, 0)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); }
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.worker.js index c1e8c9c..56a8d27 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.worker.js +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-baselines.tentative.worker.js
@@ -37,17 +37,17 @@ for (const baseline of kBaselines) { const tm = ctx.measureText(text); // First character. - for (const r of tm.getSelectionRects(0, 0)) { + for (const r of tm.getSelectionRects(0, 1)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Last character. - for (const r of tm.getSelectionRects(text.length - 1, text.length - 1)) { + for (const r of tm.getSelectionRects(text.length - 1, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Whole string. - for (const r of tm.getSelectionRects(0, text.length - 1)) { + for (const r of tm.getSelectionRects(0, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } @@ -57,7 +57,11 @@ assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Invalid start > end string. Creates 0 width rectangle. - for (const r of tm.getSelectionRects(2, 1)) { + for (const r of tm.getSelectionRects(3, 2)) { + assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); + assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); + } + for (const r of tm.getSelectionRects(1, 0)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); }
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.html index ef2d2aa..06ffeac 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.html
@@ -34,11 +34,11 @@ assert_throws_js(TypeError, () => tm.getSelectionRects(-1, -1) ); // Thrown in TextMetrics. assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, 0) ); + () => tm.getSelectionRects(text.length + 1, 0) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(0, text.length) ); + () => tm.getSelectionRects(0, text.length + 1) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, text.length) ); + () => tm.getSelectionRects(text.length + 1, text.length + 1) ); } t.done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.worker.js index 4102c4a6..1ec8bc4 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.worker.js +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects-exceptions.tentative.worker.js
@@ -30,11 +30,11 @@ assert_throws_js(TypeError, () => tm.getSelectionRects(-1, -1) ); // Thrown in TextMetrics. assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, 0) ); + () => tm.getSelectionRects(text.length + 1, 0) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(0, text.length) ); + () => tm.getSelectionRects(0, text.length + 1) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, text.length) ); + () => tm.getSelectionRects(text.length + 1, text.length + 1) ); } t.done(); });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects.tentative.html index 32a758e..e857485 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.measure.selection-rects.tentative.html
@@ -33,7 +33,7 @@ const parent = range.getClientRects()[0]; range.setStart(el.childNodes[0], from); - range.setEnd(el.childNodes[0], to+1); + range.setEnd(el.childNodes[0], to); let sel = window.getSelection(); sel.removeAllRanges(); @@ -74,28 +74,32 @@ const tm = ctx.measureText(text); // First character. checkRectListsMatch( - tm.getSelectionRects(0, 0), - placeAndSelectTextInDOM(text, 0, 0) + tm.getSelectionRects(0, 1), + placeAndSelectTextInDOM(text, 0, 1) ); // Last character. checkRectListsMatch( - tm.getSelectionRects(text.length - 1, text.length - 1), - placeAndSelectTextInDOM(text, text.length - 1, text.length - 1) + tm.getSelectionRects(text.length - 1, text.length), + placeAndSelectTextInDOM(text, text.length - 1, text.length) ); // Whole string. checkRectListsMatch( - tm.getSelectionRects(0, text.length - 1), - placeAndSelectTextInDOM(text, 0, text.length - 1) + tm.getSelectionRects(0, text.length), + placeAndSelectTextInDOM(text, 0, text.length) ); // Intermediate string. checkRectListsMatch( - tm.getSelectionRects(1, text.length - 2), - placeAndSelectTextInDOM(text, 1, text.length - 2) + tm.getSelectionRects(1, text.length - 1), + placeAndSelectTextInDOM(text, 1, text.length - 1) ); // Invalid start > end string. Creates 0 width rectangle. checkRectListsMatch( - tm.getSelectionRects(2, 1), - placeAndSelectTextInDOM(text, 2, 1) + tm.getSelectionRects(3, 2), + placeAndSelectTextInDOM(text, 3, 2) + ); + checkRectListsMatch( + tm.getSelectionRects(1, 0), + placeAndSelectTextInDOM(text, 1, 0) ); } t.done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/text.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/text.yaml index 53680704..4aa1a55f 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/text.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/text.yaml
@@ -1199,7 +1199,7 @@ const parent = range.getClientRects()[0]; range.setStart(el.childNodes[0], from); - range.setEnd(el.childNodes[0], to+1); + range.setEnd(el.childNodes[0], to); let sel = window.getSelection(); sel.removeAllRanges(); @@ -1240,28 +1240,32 @@ const tm = ctx.measureText(text); // First character. checkRectListsMatch( - tm.getSelectionRects(0, 0), - placeAndSelectTextInDOM(text, 0, 0) + tm.getSelectionRects(0, 1), + placeAndSelectTextInDOM(text, 0, 1) ); // Last character. checkRectListsMatch( - tm.getSelectionRects(text.length - 1, text.length - 1), - placeAndSelectTextInDOM(text, text.length - 1, text.length - 1) + tm.getSelectionRects(text.length - 1, text.length), + placeAndSelectTextInDOM(text, text.length - 1, text.length) ); // Whole string. checkRectListsMatch( - tm.getSelectionRects(0, text.length - 1), - placeAndSelectTextInDOM(text, 0, text.length - 1) + tm.getSelectionRects(0, text.length), + placeAndSelectTextInDOM(text, 0, text.length) ); // Intermediate string. checkRectListsMatch( - tm.getSelectionRects(1, text.length - 2), - placeAndSelectTextInDOM(text, 1, text.length - 2) + tm.getSelectionRects(1, text.length - 1), + placeAndSelectTextInDOM(text, 1, text.length - 1) ); // Invalid start > end string. Creates 0 width rectangle. checkRectListsMatch( - tm.getSelectionRects(2, 1), - placeAndSelectTextInDOM(text, 2, 1) + tm.getSelectionRects(3, 2), + placeAndSelectTextInDOM(text, 3, 2) + ); + checkRectListsMatch( + tm.getSelectionRects(1, 0), + placeAndSelectTextInDOM(text, 1, 0) ); } @@ -1291,17 +1295,17 @@ for (const baseline of kBaselines) { const tm = ctx.measureText(text); // First character. - for (const r of tm.getSelectionRects(0, 0)) { + for (const r of tm.getSelectionRects(0, 1)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Last character. - for (const r of tm.getSelectionRects(text.length - 1, text.length - 1)) { + for (const r of tm.getSelectionRects(text.length - 1, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Whole string. - for (const r of tm.getSelectionRects(0, text.length - 1)) { + for (const r of tm.getSelectionRects(0, text.length)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } @@ -1311,7 +1315,11 @@ assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } // Invalid start > end string. Creates 0 width rectangle. - for (const r of tm.getSelectionRects(2, 1)) { + for (const r of tm.getSelectionRects(3, 2)) { + assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); + assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); + } + for (const r of tm.getSelectionRects(1, 0)) { assert_approx_equals(r.top, -tm.fontBoundingBoxAscent, 1.0); assert_approx_equals(r.bottom, tm.fontBoundingBoxDescent, 1.0); } @@ -1337,11 +1345,11 @@ assert_throws_js(TypeError, () => tm.getSelectionRects(-1, -1) ); // Thrown in TextMetrics. assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, 0) ); + () => tm.getSelectionRects(text.length + 1, 0) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(0, text.length) ); + () => tm.getSelectionRects(0, text.length + 1) ); assert_throws_dom("IndexSizeError", - () => tm.getSelectionRects(text.length, text.length) ); + () => tm.getSelectionRects(text.length + 1, text.length + 1) ); } - name: 2d.text.drawing.style.absolute.spacing
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print-ref.html index bee4a57..c3e5d8d 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print-ref.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print-ref.html
@@ -1,5 +1,5 @@ <!DOCTYPE html> <p> - Should print a green rectangle rectangle but not display it on screen. + Should print a green rectangle but not display it on screen. </p> <img src="/images/green.png" alt="A green rectangle">
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print.html index 938ebdc..b51a1bb 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-image-only-for-print.html
@@ -15,7 +15,7 @@ </style> <p> - Should print a green rectangle rectangle but not display it on screen. + Should print a green rectangle but not display it on screen. </p> <div>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-svg-only-for-print.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-svg-only-for-print.html index bede084..7bb804c2 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-svg-only-for-print.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-svg-only-for-print.html
@@ -15,7 +15,7 @@ </style> <p> - Should print a green rectangle rectangle but not display it on screen. + Should print a green rectangle but not display it on screen. </p> <div>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.tentative.html rename to third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index 9d846b35..df9b2f87 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -827,7 +827,3 @@ TESTDRIVER-IN-UNSUPPORTED-TYPE: payment-handler/payment-request-event-manual.https.html TESTDRIVER-IN-UNSUPPORTED-TYPE: payment-handler/supports-shipping-contact-delegation-manual.https.html TESTDRIVER-IN-UNSUPPORTED-TYPE: shadow-dom/crashtests/move-to-new-tree-1343016.html - -# Pre compressed data using Shared Brotli and Shared Zstandard. -TRAILING WHITESPACE, INDENT TABS, CR AT EOL: fetch/compression-dictionary/resources/compressed.br-d.data -TRAILING WHITESPACE, INDENT TABS, CR AT EOL: fetch/compression-dictionary/resources/compressed.zstd-d.data
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html b/third_party/blink/web_tests/external/wpt/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html index 87dbe81a..cd1ed285 100644 --- a/third_party/blink/web_tests/external/wpt/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html
@@ -11,17 +11,17 @@ const sameOrigin = new URL("", location.href).origin; const [outerKey] = parseKeylist(); let {expectedKey, expectedValue} = parseExpectedKeyAndValueData(); - const promise = navigateSharedStorageIframe({ + + await navigateSharedStorageIframe({ hasSharedStorageWritableAttribute: true, rawWriteHeader: `set;key=${expectedKey};value=${expectedValue}`, isSameOrigin: true, expectSharedStorageWritableHeader: true, }); - promise.then(() => { - verifyKeyValueForOrigin(expectedKey, expectedValue, sameOrigin); - deleteKeyForOrigin(expectedKey, sameOrigin); - writeValueToServer(outerKey, "writable_iframe_in_fenced_inner_loaded"); - }); + + await verifyKeyValueForOrigin(expectedKey, expectedValue, sameOrigin); + await deleteKeyForOrigin(expectedKey, sameOrigin); + await writeValueToServer(outerKey, "writable_iframe_in_fenced_inner_loaded"); } init();
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/resources/util.sub.js b/third_party/blink/web_tests/external/wpt/shared-storage/resources/util.sub.js index f147209d..37b440d 100644 --- a/third_party/blink/web_tests/external/wpt/shared-storage/resources/util.sub.js +++ b/third_party/blink/web_tests/external/wpt/shared-storage/resources/util.sub.js
@@ -1,7 +1,9 @@ function loadSharedStorageImage(data) { let {key, value, hasSharedStorageWritableAttribute, isSameOrigin} = data; + const encodedKey = encodeURIComponent(key); + const encodedValue = encodeURIComponent(value); const sameOriginSrc = `/shared-storage/resources/` + - `shared-storage-writable-pixel.png?key=${key}&value=${value}`; + `shared-storage-writable-pixel.png?key=${encodedKey}&value=${encodedValue}`; const crossOriginSrc = 'https://{{domains[www]}}:{{ports[https][0]}}' + sameOriginSrc;
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html index b358e87..154cd5b 100644 --- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html
@@ -11,29 +11,29 @@ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}'; promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: ':8J+YgA==:', value: ':4p2k:', hasSharedStorageWritableAttribute: true, isSameOrigin: true, }); - promise.then((img) => { - verifyKeyValueForOrigin('😀', '❤', sameOrigin); - deleteKeyForOrigin('😀', sameOrigin); - t.done(); - }); + + await verifyKeyValueForOrigin(String.fromCharCode(0xD83D, 0xDE00), + String.fromCharCode(0x2764), + sameOrigin); + await deleteKeyForOrigin(String.fromCharCode(0xD83D, 0xDE00), sameOrigin); }, 'test <img sharedstoragewritable src=[url]> via JS for same origin img with bytestring'); promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: ':8J+MjQ==:', value: ':8J+PgQ==:', hasSharedStorageWritableAttribute: true, isSameOrigin: false, }); - promise.then((img) => { - verifyKeyValueForOrigin('🌍', '🏁', crossOrigin); - deleteKeyForOrigin('🌍', crossOrigin); - t.done(); - }); + + await verifyKeyValueForOrigin(String.fromCharCode(0xD83C, 0xDF0D), + String.fromCharCode(0xD83C, 0xDFC1), + crossOrigin); + await deleteKeyForOrigin(String.fromCharCode(0xD83C, 0xDF0D), crossOrigin); }, 'test <img sharedstoragewritable src=[url]> via JS for cross origin img with bytestring'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html index 3e05414..65d8ee22 100644 --- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html
@@ -11,29 +11,25 @@ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}'; promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: 'a', value: 'b', hasSharedStorageWritableAttribute: true, isSameOrigin: true, }); - promise.then((img) => { - verifyKeyValueForOrigin('a', 'b', sameOrigin); - deleteKeyForOrigin('a', sameOrigin); - t.done(); - }); + + await verifyKeyValueForOrigin('a', 'b', sameOrigin); + await deleteKeyForOrigin('a', sameOrigin); }, 'test <img sharedstoragewritable src=[url]> via JS for same origin img'); promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: 'c', value: 'd', hasSharedStorageWritableAttribute: true, isSameOrigin: false, }); - promise.then((img) => { - verifyKeyValueForOrigin('c', 'd', crossOrigin); - deleteKeyForOrigin('d', crossOrigin); - t.done(); - }); + + await verifyKeyValueForOrigin('c', 'd', crossOrigin); + await deleteKeyForOrigin('d', crossOrigin); }, 'test <img sharedstoragewritable src=[url]> via JS for cross origin img'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html index 56badca..c35a29f 100644 --- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html
@@ -11,27 +11,23 @@ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}'; promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: 'f', value: 'g', hasSharedStorageWritableAttribute: false, isSameOrigin: true, }); - promise.then((img) => { - verifyKeyNotFoundForOrigin('f', sameOrigin); - t.done(); - }); + + await verifyKeyNotFoundForOrigin('f', sameOrigin); }, 'test <img src=[url]> via JS for same origin img'); promise_test(async t => { - const promise = loadSharedStorageImage({ + await loadSharedStorageImage({ key: 'h', value: 'i', hasSharedStorageWritableAttribute: false, isSameOrigin: false, }); - promise.then((img) => { - verifyKeyNotFoundForOrigin('h', crossOrigin); - t.done(); - }); + + await verifyKeyNotFoundForOrigin('h', crossOrigin); }, 'test <img src=[url]> via JS for cross origin img'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js index 668112c..4a2ab21 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js
@@ -19,6 +19,20 @@ output: {dataType: 'float32', dimensions: [1, 2, 5, 6, 4]} }, { + name: '[gather] Test gather with indices\'s dataType = uint32', + input: {dataType: 'float32', dimensions: [1, 2, 3, 4]}, + indices: {dataType: 'uint32', dimensions: [5, 6]}, + axis: 2, + output: {dataType: 'float32', dimensions: [1, 2, 5, 6, 4]} + }, + { + name: '[gather] Test gather with indices\'s dataType = int32', + input: {dataType: 'float32', dimensions: [1, 2, 3, 4]}, + indices: {dataType: 'int32', dimensions: [5, 6]}, + axis: 2, + output: {dataType: 'float32', dimensions: [1, 2, 5, 6, 4]} + }, + { name: '[gather] TypeError is expected if the input is a scalar', input: {dataType: 'float16', dimensions: []}, indices: {dataType: 'int64', dimensions: [1]} @@ -32,9 +46,15 @@ }, { name: - '[gather] TypeError is expected if the data type of indices is invalid', + '[gather] TypeError is expected if the data type of indices is float32 which is invalid', input: {dataType: 'float16', dimensions: [1, 2, 3, 4]}, indices: {dataType: 'float32', dimensions: [5, 6]} + }, + { + name: + '[gather] TypeError is expected if the data type of indices is uint64 which is invalid', + input: {dataType: 'float16', dimensions: [1, 2, 3, 4]}, + indices: {dataType: 'uint64', dimensions: [5, 6]} } ];
diff --git a/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html b/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html new file mode 100644 index 0000000..9ad7c8a6 --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<meta name="color-scheme" content="dark"> +<style> + :root { + background-color: green; + height: 5000px; + width: 5000px; + } +</style>
diff --git a/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change.html b/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change.html new file mode 100644 index 0000000..9d3d9af --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<!-- Verifies root scrollbars are painted dark when both preferred color scheme + and preferred root scrollbar color scheme are dark. --> +<link rel="match" href="dynamic-preferred-root-scrollbar-color-scheme-change-expected.html"> +<script src="../../../../resources/run-after-layout-and-paint.js"></script> + +<style> + :root { + background-color: green; + height: 5000px; + width: 5000px; + } +</style> + +<script> + runAfterLayoutAndPaint(() => { + window.internals.setDarkPreferredColorScheme(document); + window.internals.setDarkPreferredRootScrollbarColorScheme(document); + }, true); +</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource-expected.txt new file mode 100644 index 0000000..431d15b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource-expected.txt
@@ -0,0 +1,9 @@ +Verifies that the request head has static routing information on the main resource. +{ + actualSourceType : cache + matchedSourceType : cache + ruleIdMatched : 1 +} +workerRouterEvaluationStart exists: true +workerCacheLookupStart exists: true +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource.js new file mode 100644 index 0000000..420f68596 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/cache-router-info-mainresource.js
@@ -0,0 +1,30 @@ +(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { + var {page, session, dp} = await testRunner.startURL( + 'resources/cache.txt', + 'Verifies that the request head has static routing information on the main resource.'); + const swHelper = + (await testRunner.loadScript('../../resources/service-worker-helper.js'))( + dp, session); + + await Promise.all([ + dp.Network.enable(), + dp.Page.enable(), + ]); + + await swHelper.installSWAndWaitForActivated( + 'service-worker-router-to-cache.js'); + + const responseReceivedPromise = dp.Network.onceResponseReceived(); + + await dp.Page.reload(); + + const responseReceived = await responseReceivedPromise; + testRunner.log(responseReceived.params.response.serviceWorkerRouterInfo); + + const router_evaluation_start = responseReceived.params.response.timing.workerRouterEvaluationStart !== undefined; + testRunner.log("workerRouterEvaluationStart exists: " + router_evaluation_start); + + const cache_lookup_start = responseReceived.params.response.timing.workerCacheLookupStart !== undefined; + testRunner.log("workerCacheLookupStart exists: " + cache_lookup_start); + testRunner.completeTest(); +});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-expected.txt index d81aae7..e4c418da 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-expected.txt +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-expected.txt
@@ -1,6 +1,8 @@ Verifies that the request head has static routing information on the main resource. { + actualSourceType : fetch-event matchedSourceType : fetch-event ruleIdMatched : 1 } +workerRouterEvaluationStart exists: true
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-network-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-network-expected.txt index a37847f..299acfc2 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-network-expected.txt +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource-network-expected.txt
@@ -1,5 +1,6 @@ Verifies that the request head has static routing information on the main resource when the request fallbacks to the network. { + actualSourceType : network matchedSourceType : network ruleIdMatched : 1 }
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource.js index 83b5c96..52a8045 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-mainresource.js
@@ -21,5 +21,8 @@ const responseReceived = await responseReceivedPromise; testRunner.log(responseReceived.params.response.serviceWorkerRouterInfo); + const router_evaluation_start = responseReceived.params.response.timing.workerRouterEvaluationStart !== undefined; + testRunner.log("workerRouterEvaluationStart exists: " + router_evaluation_start); + testRunner.completeTest(); });
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource-expected.txt index 9cc8143c..9a7ea614 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource-expected.txt +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource-expected.txt
@@ -1,6 +1,8 @@ Verifies that the request head has static routing information on sub resources. { + actualSourceType : fetch-event matchedSourceType : fetch-event ruleIdMatched : 1 } +workerRouterEvaluationStart exists: true
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource.js index 53128c77..5ea8f60a 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/network-router-info-subresource.js
@@ -22,5 +22,8 @@ const responseReceived = await responseReceivedPromise; testRunner.log(responseReceived.params.response.serviceWorkerRouterInfo); + const router_evaluation_start = responseReceived.params.response.timing.workerRouterEvaluationStart !== undefined; + testRunner.log("workerRouterEvaluationStart exists: " + router_evaluation_start); + testRunner.completeTest(); });
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/resources/service-worker-router-to-cache.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/resources/service-worker-router-to-cache.js new file mode 100644 index 0000000..7c5c14f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/resources/service-worker-router-to-cache.js
@@ -0,0 +1,19 @@ +'use strict'; + +const TEST_CACHE_NAME = 'v1'; +self.addEventListener('install', async e => { + e.waitUntil(caches.open(TEST_CACHE_NAME).then( + cache => {cache.put('cache.txt', new Response('From cache'))})); + + await e.addRoutes( + [{condition: {urlPattern: new URLPattern({})}, source: 'cache'}]); + self.skipWaiting(); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', e => { + e.respondWith(new Response('fake handler')); +});
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index b0bfedb..75a7d7c01 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1339,7 +1339,6 @@ method arcTo method beginLayer method beginPath - method beginWebGPUAccess method bezierCurveTo method clearRect method clip @@ -1358,7 +1357,6 @@ method drawMesh method ellipse method endLayer - method endWebGPUAccess method fill method fillRect method fillText @@ -1387,6 +1385,8 @@ method stroke method strokeRect method strokeText + method transferFromWebGPU + method transferToWebGPU method transform method translate setter direction
diff --git a/third_party/blink/web_tests/virtual/controls-refresh-hc/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html b/third_party/blink/web_tests/virtual/controls-refresh-hc/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html new file mode 100644 index 0000000..e22d15a --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh-hc/fast/forms/color-scheme/scrollbar/dynamic-preferred-root-scrollbar-color-scheme-change-expected.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta name="color-scheme" content="dark"> +<script src="../../../../../../resources/run-after-layout-and-paint.js"></script> + +<style> + :root { + background-color: green; + height: 5000px; + width: 5000px; + } +</style> + +<script> + runAfterLayoutAndPaint(() => { + window.internals.setDarkPreferredColorScheme(document); + }, true); +</script>
diff --git a/third_party/blink/web_tests/virtual/document-picture-in-picture-user-activation/README.md b/third_party/blink/web_tests/virtual/document-picture-in-picture-user-activation/README.md new file mode 100644 index 0000000..7766dff --- /dev/null +++ b/third_party/blink/web_tests/virtual/document-picture-in-picture-user-activation/README.md
@@ -0,0 +1,5 @@ +This suite runs some tests in `external/wpt/document-picture-in-picture/` with +`--enable-blink-features=DocumentPictureInPictureUserActivation`. + +TODO(https://crbug.com/331246719): This should be removed when the feature flag +is removed.
diff --git a/third_party/blink/web_tests/virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.tentative-expected.txt b/third_party/blink/web_tests/virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative.tentative-expected.txt rename to third_party/blink/web_tests/virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-light-dismiss-with-anchor.tentative-expected.txt
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any.worker_cpu-expected.txt index 2115f41..d2490db 100644 --- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any.worker_cpu-expected.txt +++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any.worker_cpu-expected.txt
@@ -1,17 +1,3 @@ This is a testharness.js-based test. -[FAIL] instanceNormalization float32 4D tensor default options - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.scale - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.bias - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.epsilon - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor explict options.layout='nchw' - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.layout='nhwc' - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor all options - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any_cpu-expected.txt index 2115f41..d2490db 100644 --- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/instance_normalization.https.any_cpu-expected.txt
@@ -1,17 +1,3 @@ This is a testharness.js-based test. -[FAIL] instanceNormalization float32 4D tensor default options - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.scale - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.bias - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.epsilon - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor explict options.layout='nchw' - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor options.layout='nhwc' - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." -[FAIL] instanceNormalization float32 4D tensor all options - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator instanceNormalization." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index f8e529c..cca5c01 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1522,7 +1522,6 @@ [Worker] method arcTo [Worker] method beginLayer [Worker] method beginPath -[Worker] method beginWebGPUAccess [Worker] method bezierCurveTo [Worker] method clearRect [Worker] method clip @@ -1541,7 +1540,6 @@ [Worker] method drawMesh [Worker] method ellipse [Worker] method endLayer -[Worker] method endWebGPUAccess [Worker] method fill [Worker] method fillRect [Worker] method fillText @@ -1570,6 +1568,8 @@ [Worker] method stroke [Worker] method strokeRect [Worker] method strokeText +[Worker] method transferFromWebGPU +[Worker] method transferToWebGPU [Worker] method transform [Worker] method translate [Worker] setter direction
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index eeec5cb..4e6a14b 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1276,7 +1276,6 @@ method arcTo method beginLayer method beginPath - method beginWebGPUAccess method bezierCurveTo method clearRect method clip @@ -1296,7 +1295,6 @@ method drawMesh method ellipse method endLayer - method endWebGPUAccess method fill method fillRect method fillText @@ -1327,6 +1325,8 @@ method stroke method strokeRect method strokeText + method transferFromWebGPU + method transferToWebGPU method transform method translate setter direction @@ -7082,7 +7082,6 @@ method arcTo method beginLayer method beginPath - method beginWebGPUAccess method bezierCurveTo method clearRect method clip @@ -7101,7 +7100,6 @@ method drawMesh method ellipse method endLayer - method endWebGPUAccess method fill method fillRect method fillText @@ -7130,6 +7128,8 @@ method stroke method strokeRect method strokeText + method transferFromWebGPU + method transferToWebGPU method transform method translate setter direction
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index e197ae4..76ba7e8 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1279,7 +1279,6 @@ [Worker] method arcTo [Worker] method beginLayer [Worker] method beginPath -[Worker] method beginWebGPUAccess [Worker] method bezierCurveTo [Worker] method clearRect [Worker] method clip @@ -1298,7 +1297,6 @@ [Worker] method drawMesh [Worker] method ellipse [Worker] method endLayer -[Worker] method endWebGPUAccess [Worker] method fill [Worker] method fillRect [Worker] method fillText @@ -1327,6 +1325,8 @@ [Worker] method stroke [Worker] method strokeRect [Worker] method strokeText +[Worker] method transferFromWebGPU +[Worker] method transferToWebGPU [Worker] method transform [Worker] method translate [Worker] setter direction
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.html deleted file mode 100644 index 8f527d2b..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.html +++ /dev/null
@@ -1,39 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="./webgpu-helpers.js"></script> -</head> - -<h1>Canvas WebGPU Access: beginWebGPUAccess-balanced-access</h1> - -<p>beginWebGPUAccess() allows repeated calls after a call to endWebGPUAccess(). -</p> - -<canvas id="c" width="50" height="50"></canvas> - -<script> - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_balanced_access( - device, - document.getElementById('c')); - }); - }, - 'beginWebGPUAccess() allows repeated calls after a call to endWebGPUAccess().' -); - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_balanced_access( - device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() on an offscreen context allows repeated calls after a ' + - 'call to endWebGPUAccess().' -); - -</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.worker.js deleted file mode 100644 index 172fac9..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-balanced-access.https.worker.js +++ /dev/null
@@ -1,20 +0,0 @@ -// META: global=worker - -// ============================================================================ - -importScripts("/resources/testharness.js"); -importScripts("./webgpu-helpers.js"); - -// This test parallels beginWebGPUAccess-balanced-access.https.html. -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_balanced_access( - device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() in a worker allows repeated calls after a call to ' + - 'endWebGPUAccess().' -); - -done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.html deleted file mode 100644 index a9d157c..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="./webgpu-helpers.js"></script> -</head> - -<h1>Canvas WebGPU Access: beginWebGPUAccess-initialized-canvas</h1> - -<p>beginWebGPUAccess() creates a texture from an initialized canvas.</p> - -<canvas id="c" width="50" height="50"></canvas> - -<script> - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_initialized_canvas( - device, - document.getElementById('c')); - }); - }, 'beginWebGPUAccess() should create a texture from an initialized canvas.' -); - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_initialized_canvas( - device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() should create a texture from an initialized ' + - 'offscreen canvas.' -); - -</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.html deleted file mode 100644 index 7804136..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.html +++ /dev/null
@@ -1,40 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="./webgpu-helpers.js"></script> -</head> - -<h1>Canvas WebGPU Access: beginWebGPUAccess-unbalanced-access</h1> - -<p>beginWebGPUAccess() disallows repeated calls without a call to -endWebGPUAccess().</p> - -<canvas id="c" width="50" height="50"></canvas> - -<script> - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_unbalanced_access( - device, - document.getElementById('c')); - }); - }, - 'beginWebGPUAccess() disallows repeated calls without a call to ' + - 'endWebGPUAccess().' -); - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_unbalanced_access( - device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() on an offscreen context disallows repeated calls ' + - 'without a call to endWebGPUAccess().' -); - -</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.worker.js deleted file mode 100644 index 0e0e0be..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-unbalanced-access.https.worker.js +++ /dev/null
@@ -1,20 +0,0 @@ -// META: global=worker - -// ============================================================================ - -importScripts("/resources/testharness.js"); -importScripts("./webgpu-helpers.js"); - -// This test parallels beginWebGPUAccess-unbalanced-access.https.html. -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_unbalanced_access( - device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() in a worker disallows repeated calls without a call ' + - 'to endWebGPUAccess().' -); - -done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.html deleted file mode 100644 index ca85b2d..0000000 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="./webgpu-helpers.js"></script> -</head> - -<h1>Canvas WebGPU Access: beginWebGPUAccess-usage-flags</h1> - -<p>beginWebGPUAccess() creates a texture honoring the requested usage flags.</p> - -<canvas id="c" width="50" height="50"></canvas> - -<script> - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - return test_beginWebGPUAccess_usage_flags(adapter, adapterInfo, device, - document.getElementById('c')); - }); - }, - 'beginWebGPUAccess() should create a texture which honors the requested ' + - 'usage flags.' -); - -promise_test(() => { - return with_webgpu((adapter, adapterInfo, device) => { - return test_beginWebGPUAccess_usage_flags(adapter, adapterInfo, device, - new OffscreenCanvas(50, 50)); - }); - }, - 'beginWebGPUAccess() on an offscreen canvas should create a texture which ' + - 'honors the requested usage flags.' -); - -</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/README.md b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/README.md similarity index 83% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/README.md rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/README.md index 615b354..51d0a662 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/README.md +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/README.md
@@ -1,4 +1,4 @@ -# WebGPU access tests for Chromium +# WebGPU transfer tests for Chromium Explainer: https://github.com/fserb/canvas2D/blob/master/spec/webgpu.md
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-reset-orphans-texture.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-reset-orphans-texture.https.html similarity index 93% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-reset-orphans-texture.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-reset-orphans-texture.https.html index 50f19fbd..b58e59f2 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-reset-orphans-texture.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-reset-orphans-texture.https.html
@@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> -<title>Canvas WebGPU Access: canvas-reset-orphans-texture</title> +<title>Canvas2D WebGPU Transfer: canvas-reset-orphans-texture</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: canvas-reset-orphans-texture</h1> +<h1>Canvas2D WebGPU Transfer: canvas-reset-orphans-texture</h1> <p>Resetting a canvas during WebGPU access should orphan the GPUTexture.</p>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-reset-orphans-texture.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-reset-orphans-texture.https.worker.js similarity index 100% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-reset-orphans-texture.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-reset-orphans-texture.https.worker.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-works-after-cpu-downgrade.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-works-after-cpu-downgrade.https.html similarity index 86% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-works-after-cpu-downgrade.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-works-after-cpu-downgrade.https.html index 7da87ee9..4245289 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/canvas-works-after-cpu-downgrade.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/canvas-works-after-cpu-downgrade.https.html
@@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> -<title>Canvas WebGPU Access: canvas-works-after-cpu-downgrade</title> +<title>Canvas2D WebGPU Transfer: canvas-works-after-cpu-downgrade</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: canvas-works-after-cpu-downgrade</h1> +<h1>Canvas2D WebGPU Transfer: canvas-works-after-cpu-downgrade</h1> <p>WebGPU access should work normally on a canvas which has been downgraded to CPU, transparently bringing it back to the GPU.</p>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba16f.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba16f.https.html similarity index 85% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba16f.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba16f.https.html index d4d9124..b41007f3 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba16f.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba16f.https.html
@@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> -<title>Canvas WebGPU Access: getTextureFormat-rgba16float</title> +<title>Canvas2D WebGPU Transfer: getTextureFormat-rgba16float</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: getTextureFormat-rgba16f</h1> +<h1>Canvas2D WebGPU Transfer: getTextureFormat-rgba16f</h1> <p>getTextureFormat() returns RGBA16F for a float16 context</p>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba8.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba8.https.html similarity index 86% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba8.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba8.https.html index 1134095..71cdff7 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat-rgba8.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat-rgba8.https.html
@@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> -<title>Canvas WebGPU Access: getTextureFormat-rgba8</title> +<title>Canvas2D WebGPU Transfer: getTextureFormat-rgba8</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: getTextureFormat-rgba8</h1> +<h1>Canvas2D WebGPU Transfer: getTextureFormat-rgba8</h1> <p>getTextureFormat() returns RGBA8 or BGRA8 for a typical context</p>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat.https.worker.js similarity index 100% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/getTextureFormat.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/getTextureFormat.https.worker.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.html similarity index 64% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.html index 1bd528ac..5b4ef0c 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: endWebGPUAccess-canvas-readback</h1> +<h1>Canvas2D WebGPU Transfer: transferFromWebGPU-canvas-readback</h1> -<p>endWebGPUAccess() should preserve texture changes on the 2D canvas.</p> +<p>transferFromWebGPU() should preserve texture changes on the 2D canvas.</p> <canvas id="c" width="50" height="50"></canvas> @@ -16,27 +16,27 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, document.getElementById('c'), {colorSpace: 'srgb', pixelFormat: 'float16'}); }); }, - 'endWebGPUAccess() should preserve texture changes on an RGB16F canvas.' + 'transferFromWebGPU() should preserve texture changes on an RGB16F canvas.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, new OffscreenCanvas(50, 50), {colorSpace: 'srgb', pixelFormat: 'float16'}); }); }, - 'endWebGPUAccess() should preserve texture changes on an RGB16F offscreen ' + - 'canvas.' + 'transferFromWebGPU() should preserve texture changes on an RGB16F ' + + 'offscreen canvas.' ); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.worker.js similarity index 69% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.worker.js index 7b99f19..7afe635 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba16f.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba16f.https.worker.js
@@ -5,17 +5,17 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels endWebGPUAccess-canvas-readback.https.html. +// This test parallels transferFromWebGPU-canvas-readback.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, new OffscreenCanvas(50, 50), {colorSpace: 'srgb', pixelFormat: 'float16'}); }); }, - 'endWebGPUAccess() should preserve texture changes on an RGBA16F canvas ' + + 'transferFromWebGPU() should preserve texture changes on an RGBA16F canvas ' + 'when called from a worker.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.html similarity index 62% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.html index 3bc4a12..92a60b8e 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: endWebGPUAccess-canvas-readback</h1> +<h1>Canvas2D WebGPU Transfer: transferFromWebGPU-canvas-readback</h1> -<p>endWebGPUAccess() should preserve texture changes on the 2D canvas.</p> +<p>transferFromWebGPU() should preserve texture changes on the 2D canvas.</p> <canvas id="c" width="50" height="50"></canvas> @@ -16,26 +16,27 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, document.getElementById('c'), {}); }); }, - 'endWebGPUAccess() should preserve texture changes on the 2D canvas.' + 'transferFromWebGPU() should preserve texture changes on the 2D canvas.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, new OffscreenCanvas(50, 50), {}); }); }, - 'endWebGPUAccess() should preserve texture changes on a 2D offscreen canvas.' + 'transferFromWebGPU() should preserve texture changes on a 2D offscreen ' + + 'canvas.' ); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.worker.js similarity index 64% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.worker.js index deac7f2..2abf443 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-canvas-readback-rgba8.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-canvas-readback-rgba8.https.worker.js
@@ -5,17 +5,18 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels endWebGPUAccess-canvas-readback.https.html. +// This test parallels transferFromWebGPU-canvas-readback.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_canvas_readback( + return test_transferFromWebGPU_canvas_readback( adapterInfo, device, new OffscreenCanvas(50, 50), {}); }); }, - 'endWebGPUAccess() should preserve texture changes when called from a worker.' + 'transferFromWebGPU() should preserve texture changes when called from a ' + + 'worker.' ); done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-context-lost.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-context-lost.https.html similarity index 61% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-context-lost.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-context-lost.https.html index 995a03b..79fff3db 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-context-lost.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-context-lost.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: endWebGPUAccess-context-lost</h1> +<h1>Canvas2D WebGPU Transfer: transferFromWebGPU-context-lost</h1> -<p>endWebGPUAccess() should be a no-op if the canvas context is lost.</p> +<p>transferFromWebGPU() should be a no-op if the canvas context is lost.</p> <canvas id="c" width="50" height="50"></canvas> @@ -16,24 +16,24 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_context_lost( + return test_transferFromWebGPU_context_lost( device, document.getElementById('c'), {}); }); }, - 'endWebGPUAccess() should be a no-op if the 2D context is lost.' + 'transferFromWebGPU() should be a no-op if the 2D context is lost.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_context_lost( + return test_transferFromWebGPU_context_lost( device, new OffscreenCanvas(50, 50), {}); }); }, - 'endWebGPUAccess() should be a no-op if the offscreen context is lost.' + 'transferFromWebGPU() should be a no-op if the offscreen context is lost.' ); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.html similarity index 61% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.html index 643cdc5..ded55f5d 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: endWebGPUAccess-destroys-texture</h1> +<h1>Canvas2D WebGPU Transfer: transferFromWebGPU-destroys-texture</h1> -<p>endWebGPUAccess() causes the GPUTexture returned by beginWebGPUAccess() to +<p>transferFromWebGPU() causes the GPUTexture returned by transferToWebGPU() to enter a destroyed state.</p> <canvas id="c" width="50" height="50"></canvas> @@ -17,22 +17,22 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_destroys_texture( + return test_transferFromWebGPU_destroys_texture( device, document.getElementById('c')); }); }, - 'endWebGPUAccess() should destroy the associated GPUTexture.' + 'transferFromWebGPU() should destroy the associated GPUTexture.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_destroys_texture( + return test_transferFromWebGPU_destroys_texture( device, new OffscreenCanvas(50, 50)); }); }, - 'endWebGPUAccess() on an offscreen canvas should destroy the associated ' + + 'transferFromWebGPU() on an offscreen canvas should destroy the associated ' + 'GPUTexture.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.worker.js similarity index 63% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.worker.js index d5b3e433..ff9aea2 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-destroys-texture.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-destroys-texture.https.worker.js
@@ -5,16 +5,16 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels endWebGPUAccess-destroys-texture.https.html. +// This test parallels transferFromWebGPU-destroys-texture.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_destroys_texture( + return test_transferFromWebGPU_destroys_texture( device, new OffscreenCanvas(50, 50), {}); }); }, - 'endWebGPUAccess() on a worker should destroy the associated GPUTexture.' + 'transferFromWebGPU() on a worker should destroy the associated GPUTexture.' ); done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.html similarity index 64% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.html index 51fa104..0d30014 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.html
@@ -6,9 +6,10 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: endWebGPUAccess-exchanges-texture</h1> +<h1>Canvas2D WebGPU Transfer: transferFromWebGPU-exchanges-texture</h1> -<p>endWebGPUAccess() should allow two canvases to exchange their textures.</p> +<p>transferFromWebGPU() should allow two canvases to exchange their +textures.</p> <!-- Each canvas has a different size. --> <canvas id="c1" width="50" height="50"></canvas> @@ -19,36 +20,36 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_exchanges_texture( + return test_transferFromWebGPU_exchanges_texture( device, document.getElementById('c1'), document.getElementById('c2')); }); }, - 'endWebGPUAccess() should allow canvases to exchange textures.' + 'transferFromWebGPU() should allow canvases to exchange textures.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_exchanges_texture( + return test_transferFromWebGPU_exchanges_texture( device, new OffscreenCanvas(50, 50), new OffscreenCanvas(60, 60)); }); }, - 'endWebGPUAccess() should allow offscreen canvases to exchange textures.' + 'transferFromWebGPU() should allow offscreen canvases to exchange textures.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_exchanges_texture( + return test_transferFromWebGPU_exchanges_texture( device, document.getElementById('c3'), new OffscreenCanvas(50, 50)); }); }, - 'endWebGPUAccess() with a mix of canvas types should allow the exchange of ' + - 'textures.' + 'transferFromWebGPU() with a mix of canvas types should allow the exchange ' + + 'of textures.' ); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.worker.js similarity index 66% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.worker.js index 348cd52..a68087ff 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/endWebGPUAccess-exchanges-texture.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferFromWebGPU-exchanges-texture.https.worker.js
@@ -5,16 +5,16 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels endWebGPUAccess-exchanges-texture.https.html. +// This test parallels transferFromWebGPU-exchanges-texture.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_endWebGPUAccess_exchanges_texture( + return test_transferFromWebGPU_exchanges_texture( device, new OffscreenCanvas(50, 50), new OffscreenCanvas(50, 50)); }); }, - 'endWebGPUAccess() on a worker should allow canvases to exchange textures.' + 'transferFromWebGPU() on a worker should allow canvases to exchange textures.' ); done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.html new file mode 100644 index 0000000..9148772 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./webgpu-helpers.js"></script> +</head> + +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-balanced-access</h1> + +<p>transferToWebGPU() allows repeated calls after a call to +transferFromWebGPU().</p> + +<canvas id="c" width="50" height="50"></canvas> + +<script> + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + test_transferToWebGPU_balanced_access( + device, + document.getElementById('c')); + }); + }, + 'transferToWebGPU() allows repeated calls after a call to ' + + 'transferFromWebGPU().' +); + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + test_transferToWebGPU_balanced_access( + device, + new OffscreenCanvas(50, 50)); + }); + }, + 'transferToWebGPU() on an offscreen context allows repeated calls after a ' + + 'call to transferFromWebGPU().' +); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.worker.js similarity index 61% copy from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js copy to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.worker.js index eca2c78..ce00bc4 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-balanced-access.https.worker.js
@@ -5,16 +5,16 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-untouched-canvas.https.html. +// This test parallels transferToWebGPU-balanced-access.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_balanced_access( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() in a worker should create a texture from an ' + - 'uninitialized canvas.' + 'transferToWebGPU() in a worker allows repeated calls after a call to ' + + 'transferFromWebGPU().' ); done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.html similarity index 60% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.html index f8f3476f9..ad2f9934 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: beginWebGPUAccess-untouched-canvas</h1> +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-initialized-canvas</h1> -<p>beginWebGPUAccess() creates a texture from an uninitialized canvas.</p> +<p>transferToWebGPU() creates a texture from an initialized canvas.</p> <canvas id="c" width="50" height="50"></canvas> @@ -16,21 +16,21 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_initialized_canvas( device, document.getElementById('c')); }); - }, 'beginWebGPUAccess() should create a texture from an uninitialized canvas.' + }, 'transferToWebGPU() should create a texture from an initialized canvas.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_initialized_canvas( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() should create a texture from an uninitialized ' + + 'transferToWebGPU() should create a texture from an initialized ' + 'offscreen canvas.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.worker.js similarity index 66% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.worker.js index 1ad3d78..bbddb4d 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-initialized-canvas.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-initialized-canvas.https.worker.js
@@ -5,15 +5,15 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-initialized-canvas.https.html. +// This test parallels transferToWebGPU-initialized-canvas.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_initialized_canvas( + test_transferToWebGPU_initialized_canvas( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() in a worker should create a texture from an ' + + 'transferToWebGPU() in a worker should create a texture from an ' + 'initialized offscreen canvas.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.html similarity index 61% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.html rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.html index 4acb864..9be25eb 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: beginWebGPUAccess-texture-readback</h1> +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-texture-readback</h1> -<p>beginWebGPUAccess() texture retains the contents of the canvas, and readback +<p>transferToWebGPU() texture retains the contents of the canvas, and readback works.</p> <canvas id="c" width="50" height="50"></canvas> @@ -17,23 +17,23 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_beginWebGPUAccess_texture_readback( + return test_transferToWebGPU_texture_readback( device, document.getElementById('c')); }); }, - 'beginWebGPUAccess() texture retains the contents of the canvas, ' + + 'transferToWebGPU() texture retains the contents of the canvas, ' + 'and readback works.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_beginWebGPUAccess_texture_readback( + return test_transferToWebGPU_texture_readback( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() texture retains the contents of the offscreen canvas, ' + + 'transferToWebGPU() texture retains the contents of the offscreen canvas, ' + 'and readback works.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.worker.js similarity index 65% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.worker.js index d49f715..2c5e241 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-texture-readback.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-texture-readback.https.worker.js
@@ -5,15 +5,15 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-texture-readback.https.html. +// This test parallels transferToWebGPU-texture-readback.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - return test_beginWebGPUAccess_texture_readback( + return test_transferToWebGPU_texture_readback( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() texture retains the contents of the offscreen canvas, ' + + 'transferToWebGPU() texture retains the contents of the offscreen canvas, ' + 'and readback works, from a worker.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.html new file mode 100644 index 0000000..64a4a30c --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./webgpu-helpers.js"></script> +</head> + +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-unbalanced-access</h1> + +<p>transferToWebGPU() disallows repeated calls without a call to +transferFromWebGPU().</p> + +<canvas id="c" width="50" height="50"></canvas> + +<script> + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + test_transferToWebGPU_unbalanced_access( + device, + document.getElementById('c')); + }); + }, + 'transferToWebGPU() disallows repeated calls without a call to ' + + 'transferFromWebGPU().' +); + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + test_transferToWebGPU_unbalanced_access( + device, + new OffscreenCanvas(50, 50)); + }); + }, + 'transferToWebGPU() on an offscreen context disallows repeated calls ' + + 'without a call to transferFromWebGPU().' +); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.worker.js similarity index 61% copy from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js copy to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.worker.js index eca2c78..7441895 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-unbalanced-access.https.worker.js
@@ -5,16 +5,16 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-untouched-canvas.https.html. +// This test parallels transferToWebGPU-unbalanced-access.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_unbalanced_access( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() in a worker should create a texture from an ' + - 'uninitialized canvas.' + 'transferToWebGPU() in a worker disallows repeated calls without a call ' + + 'to transferFromWebGPU().' ); done();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.html similarity index 60% copy from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html copy to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.html index f8f3476f9..9869b7ed 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.html
@@ -6,9 +6,9 @@ <script src="./webgpu-helpers.js"></script> </head> -<h1>Canvas WebGPU Access: beginWebGPUAccess-untouched-canvas</h1> +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-untouched-canvas</h1> -<p>beginWebGPUAccess() creates a texture from an uninitialized canvas.</p> +<p>transferToWebGPU() creates a texture from an uninitialized canvas.</p> <canvas id="c" width="50" height="50"></canvas> @@ -16,21 +16,21 @@ promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_untouched_canvas( device, document.getElementById('c')); }); - }, 'beginWebGPUAccess() should create a texture from an uninitialized canvas.' + }, 'transferToWebGPU() should create a texture from an uninitialized canvas.' ); promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_untouched_canvas( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() should create a texture from an uninitialized ' + + 'transferToWebGPU() should create a texture from an uninitialized ' + 'offscreen canvas.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.worker.js similarity index 66% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.worker.js index eca2c78..637c0b4 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-untouched-canvas.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-untouched-canvas.https.worker.js
@@ -5,15 +5,15 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-untouched-canvas.https.html. +// This test parallels transferToWebGPU-untouched-canvas.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_untouched_canvas( + test_transferToWebGPU_untouched_canvas( device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() in a worker should create a texture from an ' + + 'transferToWebGPU() in a worker should create a texture from an ' + 'uninitialized canvas.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.html new file mode 100644 index 0000000..da714f0 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./webgpu-helpers.js"></script> +</head> + +<h1>Canvas2D WebGPU Transfer: transferToWebGPU-usage-flags</h1> + +<p>transferToWebGPU() creates a texture honoring the requested usage flags.</p> + +<canvas id="c" width="50" height="50"></canvas> + +<script> + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + return test_transferToWebGPU_usage_flags(adapter, adapterInfo, device, + document.getElementById('c')); + }); + }, + 'transferToWebGPU() should create a texture which honors the requested ' + + 'usage flags.' +); + +promise_test(() => { + return with_webgpu((adapter, adapterInfo, device) => { + return test_transferToWebGPU_usage_flags(adapter, adapterInfo, device, + new OffscreenCanvas(50, 50)); + }); + }, + 'transferToWebGPU() on an offscreen canvas should create a texture which ' + + 'honors the requested usage flags.' +); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.worker.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.worker.js similarity index 64% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.worker.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.worker.js index 63b4081..9bbda9d 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/beginWebGPUAccess-usage-flags.https.worker.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/transferToWebGPU-usage-flags.https.worker.js
@@ -5,14 +5,14 @@ importScripts("/resources/testharness.js"); importScripts("./webgpu-helpers.js"); -// This test parallels beginWebGPUAccess-usage-flags.https.html. +// This test parallels transferToWebGPU-usage-flags.https.html. promise_test(() => { return with_webgpu((adapter, adapterInfo, device) => { - test_beginWebGPUAccess_usage_flags(adapter, adapterInfo, device, + test_transferToWebGPU_usage_flags(adapter, adapterInfo, device, new OffscreenCanvas(50, 50)); }); }, - 'beginWebGPUAccess() on a worker should create a texture which honors the ' + + 'transferToWebGPU() on a worker should create a texture which honors the ' + 'requested usage flags.' );
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/webgpu-helpers.js b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/webgpu-helpers.js similarity index 82% rename from third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/webgpu-helpers.js rename to third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/webgpu-helpers.js index ecd3b06d..d8089eae 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_access/webgpu-helpers.js +++ b/third_party/blink/web_tests/wpt_internal/webgpu/canvas_webgpu_transfer/webgpu-helpers.js
@@ -136,13 +136,13 @@ assert_equals(ctx.getTextureFormat(), 'rgba16float'); } -/** beginWebGPUAccess() should create a texture from an uninitialized canvas. */ -function test_beginWebGPUAccess_untouched_canvas(device, canvas) { +/** transferToWebGPU() should create a texture from an uninitialized canvas. */ +function test_transferToWebGPU_untouched_canvas(device, canvas) { // Leave the canvas untouched; it won't have a Canvas2DLayerBridge yet. - // Next, call beginWebGPUAccess. + // Next, call transferToWebGPU. const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device, label: "hello, webgpu!"}); + const tex = ctx.transferToWebGPU({device: device, label: "hello, webgpu!"}); // Confirm that we now have a GPU texture that matches our request. assert_true(tex instanceof GPUTexture, 'not a GPUTexture'); @@ -151,15 +151,15 @@ assert_equals(tex.height, canvas.height); } -/** beginWebGPUAccess() should create a texture from an initialized canvas. */ -function test_beginWebGPUAccess_initialized_canvas(device, canvas) { +/** transferToWebGPU() should create a texture from an initialized canvas. */ +function test_transferToWebGPU_initialized_canvas(device, canvas) { // Paint into the canvas to ensure it has a valid Canvas2DLayerBridge. const ctx = canvas.getContext('2d'); ctx.fillStyle = "#FFFFFF"; ctx.fillRect(0, 0, 100, 50); - // Next, call beginWebGPUAccess. - const tex = ctx.beginWebGPUAccess({device: device, label: "hello, webgpu!"}); + // Next, call transferToWebGPU. + const tex = ctx.transferToWebGPU({device: device, label: "hello, webgpu!"}); // Confirm that we now have a GPU texture that matches our request. assert_true(tex instanceof GPUTexture, 'not a GPUTexture'); @@ -169,17 +169,17 @@ } /** - * beginWebGPUAccess() texture should retain the contents of the canvas, and + * transferToWebGPU() texture should retain the contents of the canvas, and * readback works. Returns a promise. */ -function test_beginWebGPUAccess_texture_readback(device, canvas) { +function test_transferToWebGPU_texture_readback(device, canvas) { // Fill the canvas with a color containing distinct values in each channel. const ctx = canvas.getContext('2d'); ctx.fillStyle = "#4080C0"; ctx.fillRect(0, 0, 50, 50); // Convert the canvas to a texture. - const tex = ctx.beginWebGPUAccess({device: device, + const tex = ctx.transferToWebGPU({device: device, usage: GPUTextureUsage.COPY_SRC}); // Copy the top-left pixel from the texture into a buffer. @@ -199,17 +199,17 @@ }; /** - * beginWebGPUAccess() disallows repeated calls without a call to - * endWebGPUAccess(). + * transferToWebGPU() disallows repeated calls without a call to + * transferFromWebGPU(). */ -function test_beginWebGPUAccess_unbalanced_access(device, canvas) { +function test_transferToWebGPU_unbalanced_access(device, canvas) { // Begin a WebGPU access session. const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device}); + const tex = ctx.transferToWebGPU({device: device}); try { // Try to start a second WebGPU access session. - tex = ctx.beginWebGPUAccess({device: device}); + tex = ctx.transferToWebGPU({device: device}); assert_unreached('InvalidStateError should have been thrown.'); } catch (ex) { assert_true(ex instanceof DOMException); @@ -218,21 +218,21 @@ } /** - * beginWebGPUAccess() should allow repeated calls after a call to - * endWebGPUAccess(). + * transferToWebGPU() should allow repeated calls after a call to + * transferFromWebGPU(). */ -function test_beginWebGPUAccess_balanced_access(device, canvas) { +function test_transferToWebGPU_balanced_access(device, canvas) { const ctx = canvas.getContext('2d'); // Begin and end a WebGPU access session several times. for (let count = 0; count < 10; ++count) { - const tex = ctx.beginWebGPUAccess({device: device}); - ctx.endWebGPUAccess(tex); + const tex = ctx.transferToWebGPU({device: device}); + ctx.transferFromWebGPU(tex); } } -/** endWebGPUAccess() should preserve texture changes on the 2D canvas. */ -function test_endWebGPUAccess_canvas_readback(adapterInfo, device, +/** transferFromWebGPU() should preserve texture changes on the 2D canvas. */ +function test_transferFromWebGPU_canvas_readback(adapterInfo, device, canvas, canvasFormat) { // Skip this test on Mac Swiftshader due to "Invalid Texture" errors. if (isMacSwiftShader(adapterInfo)) { @@ -241,24 +241,24 @@ // Convert the canvas to a texture. const ctx = canvas.getContext('2d', canvasFormat); - const tex = ctx.beginWebGPUAccess({device: device}); + const tex = ctx.transferToWebGPU({device: device}); // Fill the texture with a color containing distinct values in each channel. clearTextureToColor(device, tex, { r: 64 / 255, g: 128 / 255, b: 192 / 255, a: 1.0 }); // Finish our WebGPU pass and restore the canvas. - ctx.endWebGPUAccess(tex); + ctx.transferFromWebGPU(tex); // Verify that the canvas contains our chosen color across every pixel. checkCanvasColor(ctx, [0x40, 0x80, 0xC0, 0xFF]); } -/** endWebGPUAccess() should be a no-op if the canvas context is lost. */ -function test_endWebGPUAccess_context_lost(device, canvas) { +/** transferFromWebGPU() should be a no-op if the canvas context is lost. */ +function test_transferFromWebGPU_context_lost(device, canvas) { // Begin a WebGPU access session. const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device}); + const tex = ctx.transferToWebGPU({device: device}); // Forcibly lose the canvas context. assert_true(!!window.internals, 'Internal APIs unavailable.'); @@ -266,21 +266,21 @@ // End the WebGPU access session. Nothing should be thrown. try { - ctx.endWebGPUAccess(tex); + ctx.transferFromWebGPU(tex); } catch { - assert_unreached('endWebGPUAccess should be safe when context is lost.'); + assert_unreached('transferFromWebGPU should be safe when context is lost.'); } } /** - * endWebGPUAccess() should cause the GPUTexture returned by beginWebGPUAccess() - * to enter a destroyed state. + * transferFromWebGPU() should cause the GPUTexture returned by + * transferToWebGPU() to enter a destroyed state. */ -function test_endWebGPUAccess_destroys_texture(device, canvas) { +function test_transferFromWebGPU_destroys_texture(device, canvas) { // Briefly begin a WebGPU access session. const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device}); - ctx.endWebGPUAccess(tex); + const tex = ctx.transferToWebGPU({device: device}); + ctx.transferFromWebGPU(tex); // `tex` should be in a destroyed state. Unfortunately, there isn't a // foolproof way to test for this state in WebGPU. The best we can do is try @@ -310,7 +310,7 @@ // Begin a WebGPU access session. const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device, + const tex = ctx.transferToWebGPU({device: device, usage: GPUTextureUsage.COPY_SRC}); // Reset the canvas. This should abort the WebGPU access session. The canvas' @@ -323,10 +323,10 @@ } // Verify that the WebGPU access was terminated by starting a new WebGPU - // access session. This would throw if the initial beginWebGPUAccess session + // access session. This would throw if the initial transferToWebGPU session // were still active. - const anotherTex = ctx.beginWebGPUAccess({device: device}); - ctx.endWebGPUAccess(anotherTex); + const anotherTex = ctx.transferToWebGPU({device: device}); + ctx.transferFromWebGPU(anotherTex); // Verify that the texture from the initial WebGPU access session is still // usable by accessing its contents. This would cause a GPUValidationError if @@ -340,10 +340,10 @@ } /** - * beginWebGPUAccess() should create a texture which honors the requested usage + * transferToWebGPU() should create a texture which honors the requested usage * flags. */ -function test_beginWebGPUAccess_usage_flags(adapter, adapterInfo, device, +function test_transferToWebGPU_usage_flags(adapter, adapterInfo, device, canvas) { // Create a base-case promise that just resolves immediately. let promise = new Promise((resolve, reject) => { resolve(true); }); @@ -357,7 +357,7 @@ const testOneUsageFlag = function(device, canvas, usageToEnable, usageToTest) { const ctx = canvas.getContext('2d'); - const tex = ctx.beginWebGPUAccess({device: device, usage: usageToEnable}); + const tex = ctx.transferToWebGPU({device: device, usage: usageToEnable}); // Check that the GPUTexture's usage flags match our requested flags. assert_equals(tex.usage, usageToEnable); @@ -387,7 +387,7 @@ assert_not_equals(errors, null, 'enabled ' + usageToEnable + ', tested ' + usageToTest); } - ctx.endWebGPUAccess(tex); + ctx.transferFromWebGPU(tex); }); }; @@ -411,9 +411,9 @@ } /** - * endWebGPUAccess() should allow two canvases to exchange their textures. + * transferFromWebGPU() should allow two canvases to exchange their textures. */ -function test_endWebGPUAccess_exchanges_texture(device, canvasA, canvasB) { +function test_transferFromWebGPU_exchanges_texture(device, canvasA, canvasB) { const ctxA = canvasA.getContext('2d'); const ctxB = canvasB.getContext('2d'); @@ -424,18 +424,18 @@ ctxB.fillRect(0, 0, canvasB.width, canvasB.height); // First, we start a WebGPU access session on both contexts at once. - const texA = ctxA.beginWebGPUAccess({device: device}); - const texB = ctxB.beginWebGPUAccess({device: device}); + const texA = ctxA.transferToWebGPU({device: device}); + const texB = ctxB.transferToWebGPU({device: device}); // We should be able to return context A's texture to context B. // TODO(crbug.com/339846593): we do not yet honor the passed-in GPUTexture, so // we can only return a texture to its own context for now. - ctxB.endWebGPUAccess(texB); + ctxB.transferFromWebGPU(texB); // Likewise for the opposite pairing. // TODO(crbug.com/339846593): we do not yet honor the passed-in GPUTexture, so // we can only return a texture to its own context for now. - ctxA.endWebGPUAccess(texA); + ctxA.transferFromWebGPU(texA); // Confirm that the canvases' colors reflect the texture transfers. checkCanvasColor(ctxA, [0xFF, 0x00, 0x00, 0xFF]); @@ -444,7 +444,7 @@ // Passing a texture that has already been transferred to a canvas should not // be allowed; that GPUTexture is in a destroyed state already. try { - ctxA.endWebGPUAccess(texA); + ctxA.transferFromWebGPU(texA); assert_unreached('InvalidStateError should have been thrown.'); } catch (ex) { assert_true(ex instanceof DOMException); @@ -452,7 +452,7 @@ } try { - ctxB.endWebGPUAccess(texB); + ctxB.transferFromWebGPU(texB); assert_unreached('InvalidStateError should have been thrown.'); } catch (ex) { assert_true(ex instanceof DOMException); @@ -471,9 +471,9 @@ internals.disableCanvasAcceleration(canvas); // Perform a GPU clear to demonstrate that the canvas still works in WebGPU. - const tex = ctx.beginWebGPUAccess({device: device}); + const tex = ctx.transferToWebGPU({device: device}); clearTextureToColor(device, tex, { r: 0.0, g: 1.0, b: 0.0, a: 1.0 }); - ctx.endWebGPUAccess(tex); + ctx.transferFromWebGPU(tex); // Verify that WebGPU did its job; every pixel on the canvas should be green. // TODO(crbug.com/40218893): Linux with an Intel GPU returns the wrong color.
diff --git a/third_party/chromium-variations b/third_party/chromium-variations index 2ae5d11..f870ca9 160000 --- a/third_party/chromium-variations +++ b/third_party/chromium-variations
@@ -1 +1 @@ -Subproject commit 2ae5d111a8fed78bb687ca076f7a030518aca354 +Subproject commit f870ca90e89acf3414674cd9cbf3a78724703953
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js index b48c2701..ab978700e 100644 --- a/third_party/closure_compiler/externs/automation.js +++ b/third_party/closure_compiler/externs/automation.js
@@ -1329,6 +1329,13 @@ chrome.automation.AutomationNode.prototype.value; /** + * The HTML id for this element, if this node is an HTML element. + * @type {(string|undefined)} + * @see https://developer.chrome.com/extensions/automation#type-htmlId + */ +chrome.automation.AutomationNode.prototype.htmlId; + +/** * The HTML tag for this element, if this node is an HTML element. * @type {(string|undefined)} * @see https://developer.chrome.com/extensions/automation#type-htmlTag
diff --git a/third_party/dawn b/third_party/dawn index 45d8537..7f081d8 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 45d8537d934741a7a9c55b3fe05af3bd5c83cbba +Subproject commit 7f081d88a6c1faa8753e3305ba0a0822de3fea7e
diff --git a/third_party/depot_tools b/third_party/depot_tools index 0c55798..062ecac 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 0c557985c77daa1a809f5a6c2e04e69b792142e9 +Subproject commit 062ecac69f7149d88a467eef91f707f441d62b1d
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index 83c9067..c036b5a 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit 83c9067bf25af9a9d508ca2e7d52b383f27e64c2 +Subproject commit c036b5ae55b11a90127727a310ffac94515f82e3
diff --git a/third_party/flatbuffers/README.chromium b/third_party/flatbuffers/README.chromium index 47669af..7f7f4c87 100644 --- a/third_party/flatbuffers/README.chromium +++ b/third_party/flatbuffers/README.chromium
@@ -1,8 +1,8 @@ Name: FlatBuffers Short Name: flatbuffers URL: https://github.com/google/flatbuffers -Version: c696275eaffec33796b5ca8755614fd9fec0a6a7 -Date: 2024-05-09 +Version: 150644d7f4d030a0629c564fd90dc3becab77636 +Date: 2024-05-20 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/flatbuffers/src b/third_party/flatbuffers/src index c696275..150644d 160000 --- a/third_party/flatbuffers/src +++ b/third_party/flatbuffers/src
@@ -1 +1 @@ -Subproject commit c696275eaffec33796b5ca8755614fd9fec0a6a7 +Subproject commit 150644d7f4d030a0629c564fd90dc3becab77636
diff --git a/third_party/libaom/cmake_update.sh b/third_party/libaom/cmake_update.sh index e362f56b..97373fb 100755 --- a/third_party/libaom/cmake_update.sh +++ b/third_party/libaom/cmake_update.sh
@@ -34,6 +34,7 @@ BASE=$(pwd) SRC="${BASE}/source/libaom" CFG="${BASE}/source/config" +TMP="$(mktemp -d "${BASE}/build.XXXX")" function cleanup() { rm -rf "${TMP}" @@ -112,7 +113,6 @@ # Scope 'trap' error reporting to configuration generation. ( -TMP=$(mktemp -d "${BASE}/build.XXXX") cd "${TMP}" trap '{
diff --git a/third_party/libavif/src b/third_party/libavif/src index 5d97130..d369ffb 160000 --- a/third_party/libavif/src +++ b/third_party/libavif/src
@@ -1 +1 @@ -Subproject commit 5d97130f0820dbc97738f5480e2dd00865a35744 +Subproject commit d369ffb6a21646395df9c57ae7c0545bf6846101
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src index 5067b87..ba37085 160000 --- a/third_party/libc++abi/src +++ b/third_party/libc++abi/src
@@ -1 +1 @@ -Subproject commit 5067b87e93fc1ffbe3ba332dda932a605307538e +Subproject commit ba370858669b1e905db5ded82c8887095b61dc14
diff --git a/third_party/libunwind/src b/third_party/libunwind/src index c6e0c05..0906c4a 160000 --- a/third_party/libunwind/src +++ b/third_party/libunwind/src
@@ -1 +1 @@ -Subproject commit c6e0c0519bc3f2c7854cdef30bdd5699b475464c +Subproject commit 0906c4a31502cc7a46b5cf1794e21664ffa23be1
diff --git a/third_party/libvpx/testdata/.gitignore b/third_party/libvpx/testdata/.gitignore new file mode 100644 index 0000000..5db0562 --- /dev/null +++ b/third_party/libvpx/testdata/.gitignore
@@ -0,0 +1,4 @@ +# Test files for test_libvpx can be placed in this directory. +# Set download_libvpx_testdata to True in your gclient config +# and run "gclient runhooks" to download the test files. +*
diff --git a/third_party/libwebm/OWNERS b/third_party/libwebm/OWNERS index e4e65437..7c5ba3c 100644 --- a/third_party/libwebm/OWNERS +++ b/third_party/libwebm/OWNERS
@@ -2,7 +2,8 @@ niklase@chromium.org # The following OWNER refer to libwebm content. -tomfinegan@chromium.org +jzern@chromium.org +jzern@google.com # Original (legacy) owner. emircan@chromium.org
diff --git a/third_party/lit/v3_0/BUILD.gn b/third_party/lit/v3_0/BUILD.gn index 1c9e891..b15ac88 100644 --- a/third_party/lit/v3_0/BUILD.gn +++ b/third_party/lit/v3_0/BUILD.gn
@@ -18,6 +18,9 @@ # - tests that need to refer to CrLitElement. # - a few chrome/browser/resources/ folders that hold small UIs. # Update when the migration enters its next phase. + + "//chrome/browser/resources/about_sys:build_ts", + "//chrome/browser/resources/key_value_pair_viewer_shared:build_ts", "//chrome/browser/resources/side_panel/customize_chrome:build_ts", "//chrome/browser/resources/side_panel/history_clusters:build_ts", "//chrome/browser/resources/side_panel/reading_list:build_ts",
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index bec09b4..ad6d09f 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: bf9b5ccb915b301909530db50e6a1b11adbb4d59 +Version: 76a99ec941961c46f685d2a8e777f58427ea77f2 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/nearby/src b/third_party/nearby/src index bf9b5cc..76a99ec 160000 --- a/third_party/nearby/src +++ b/third_party/nearby/src
@@ -1 +1 @@ -Subproject commit bf9b5ccb915b301909530db50e6a1b11adbb4d59 +Subproject commit 76a99ec941961c46f685d2a8e777f58427ea77f2
diff --git a/third_party/openscreen/src b/third_party/openscreen/src index f90b21d..2fdf9fc 160000 --- a/third_party/openscreen/src +++ b/third_party/openscreen/src
@@ -1 +1 @@ -Subproject commit f90b21d85c04e51f0477042d0071db520e152593 +Subproject commit 2fdf9fc760444fa335a6750a85d2fa5b6d5db215
diff --git a/third_party/pdfium b/third_party/pdfium index 8007d6e..d4b014a 160000 --- a/third_party/pdfium +++ b/third_party/pdfium
@@ -1 +1 @@ -Subproject commit 8007d6ed5cd165d13c5655f9a230b58cf10195f0 +Subproject commit d4b014a1b48e326ac526877cd8697da283aaa479
diff --git a/third_party/perfetto b/third_party/perfetto index fe95ade..f235f50 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit fe95ade50a871086b1cfeab9e8374a916bc12b71 +Subproject commit f235f50590e878113c2fc6eec85ebb5ac47b98dd
diff --git a/third_party/polymer/v3_0/BUILD.gn b/third_party/polymer/v3_0/BUILD.gn index b6d6d2e..8c5cab1 100644 --- a/third_party/polymer/v3_0/BUILD.gn +++ b/third_party/polymer/v3_0/BUILD.gn
@@ -100,7 +100,6 @@ # Note that Lit will be required for any new WebUI development soon # (targeting end of Q2 2024). - "//chrome/browser/resources/about_sys:build_ts", "//chrome/browser/resources/access_code_cast:build_ts", "//chrome/browser/resources/app_home:build_ts", "//chrome/browser/resources/app_service_internals:build_ts", @@ -117,7 +116,6 @@ "//chrome/browser/resources/inline_login:build_ts", "//chrome/browser/resources/internals/user_education:build_ts", "//chrome/browser/resources/intro:build_ts", - "//chrome/browser/resources/key_value_pair_viewer_shared:build_ts", "//chrome/browser/resources/lens/overlay:build_ts", "//chrome/browser/resources/lens/overlay/search_bubble:build_ts", "//chrome/browser/resources/management:build_ts", @@ -149,7 +147,6 @@ "//chrome/browser/resources/webui_gallery:build_ts", "//chrome/test/data/pdf:build_ts", "//chrome/test/data/webui:build_ts", - "//chrome/test/data/webui/about_sys:build_ts", "//chrome/test/data/webui/app_home:build_ts", "//chrome/test/data/webui/app_settings:build_ts", "//chrome/test/data/webui/bookmarks:build_ts", @@ -160,7 +157,6 @@ "//chrome/test/data/webui/history:build_ts", "//chrome/test/data/webui/inline_login:build_ts", "//chrome/test/data/webui/js:build_ts", - "//chrome/test/data/webui/key_value_pair_viewer:build_ts", "//chrome/test/data/webui/new_tab_page:build_ts", "//chrome/test/data/webui/password_manager:build_ts", "//chrome/test/data/webui/print_preview:build_ts",
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 bbd958f..d0929c58 100644 --- a/third_party/rust/chromium_crates_io/supply-chain/config.toml +++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -341,19 +341,18 @@ later if maybe we can just import their audit). """ -[[exemptions.rand_chacha]] -version = "0.3.1" -criteria = "does-not-implement-crypto" -notes = "Grandparented-in when setting up `cargo vet` in Jan 2024" - [[exemptions.rand_core]] version = "0.6.4" -criteria = "does-not-implement-crypto" -notes = "Grandparented-in when setting up `cargo vet` in Jan 2024" +criteria = "crypto-safe" +notes = """ +Grandparented-in when setting up `cargo vet` in Jan 2024 + +TODO(b/341950532): Remove this exemption. +""" [[exemptions.ryu]] version = "1.0.18" -criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"] +criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"] notes = """ Grandparented-in when setting up `cargo vet` in Jan 2024. @@ -366,7 +365,7 @@ [[exemptions.syn]] version = "2.0.63" -criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"] +criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"] notes = """ Grandparented-in when setting up `cargo vet` in Jan 2024
diff --git a/third_party/rust/chromium_crates_io/vet_config.toml.hbs b/third_party/rust/chromium_crates_io/vet_config.toml.hbs index 911862a..f370e03 100644 --- a/third_party/rust/chromium_crates_io/vet_config.toml.hbs +++ b/third_party/rust/chromium_crates_io/vet_config.toml.hbs
@@ -118,19 +118,18 @@ later if maybe we can just import their audit). """ -[[exemptions.rand_chacha]] -version = "0.3.1" -criteria = "does-not-implement-crypto" -notes = "Grandparented-in when setting up `cargo vet` in Jan 2024" - [[exemptions.rand_core]] version = "0.6.4" -criteria = "does-not-implement-crypto" -notes = "Grandparented-in when setting up `cargo vet` in Jan 2024" +criteria = "crypto-safe" +notes = """ +Grandparented-in when setting up `cargo vet` in Jan 2024 + +TODO(b/341950532): Remove this exemption. +""" [[exemptions.ryu]] version = "1.0.18" -criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"] +criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"] notes = """ Grandparented-in when setting up `cargo vet` in Jan 2024. @@ -143,7 +142,7 @@ [[exemptions.syn]] version = "2.0.63" -criteria = ["safe-to-deploy", "does-not-implement-crypto", "ub-risk-2"] +criteria = ["safe-to-deploy", "crypto-safe", "ub-risk-2"] notes = """ Grandparented-in when setting up `cargo vet` in Jan 2024
diff --git a/third_party/skia b/third_party/skia index 93ed643d..371f52a 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 93ed643df6d12cfaa553e0734e2828ef916a6b32 +Subproject commit 371f52a008fa5a40ba0ae5592560bc3732a53691
diff --git a/third_party/swiftshader b/third_party/swiftshader index da33485..bf0c5d6 160000 --- a/third_party/swiftshader +++ b/third_party/swiftshader
@@ -1 +1 @@ -Subproject commit da334852e70510d259bfa8cbaa7c5412966b2f41 +Subproject commit bf0c5d6b9d00babdc2bef77dc383f9c2efed56ea
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium index c255a247..3d7685d 100644 --- a/third_party/tflite/README.chromium +++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@ Name: TensorFlow Lite Short Name: tflite URL: https://github.com/tensorflow/tensorflow -Version: 6b9a25f438944132acc54ecf2c59af53c10fd6a1 -Date: 2024-05-14 +Version: d0e577447a11533887249e87e0f9b701d00d527c +Date: 2024-05-20 License: Apache 2.0 License File: LICENSE Security Critical: Yes
diff --git a/third_party/tflite/features.gni b/third_party/tflite/features.gni index 5789d3a4..24665775 100644 --- a/third_party/tflite/features.gni +++ b/third_party/tflite/features.gni
@@ -6,10 +6,10 @@ declare_args() { # This enables building TFLite with XNNPACK. Currently only available for - # Linux, macOS and Windows arm64/x64/x86 targets. + # Linux, macOS and Windows arm64/x64/x86 targets and ChromeOS non-ARM targets. build_tflite_with_xnnpack = - (is_chromeos || is_linux || is_mac || is_win) && - (current_cpu == "arm64" || current_cpu == "x64" || current_cpu == "x86") + is_win || is_mac || is_linux || + (is_chromeos && target_cpu != "arm64" && target_cpu != "arm") # Turns on TFLITE_WITH_RUY, using ruy as the gemm backend instead of gemmlowp. build_tflite_with_ruy = true
diff --git a/third_party/tflite/src b/third_party/tflite/src index 6b9a25f..d0e5774 160000 --- a/third_party/tflite/src +++ b/third_party/tflite/src
@@ -1 +1 @@ -Subproject commit 6b9a25f438944132acc54ecf2c59af53c10fd6a1 +Subproject commit d0e577447a11533887249e87e0f9b701d00d527c
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src index 6e29c73..9af84b8 160000 --- a/third_party/webgpu-cts/src +++ b/third_party/webgpu-cts/src
@@ -1 +1 @@ -Subproject commit 6e29c73079d25269c5d21890f75e08755472b964 +Subproject commit 9af84b8d4827c98cd914ebcdacdc6500a846d19a
diff --git a/third_party/webrtc b/third_party/webrtc index 3ffa0e8..c78f25b 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 3ffa0e8b6fe73b4a8da9728961d66b17be7b3ec5 +Subproject commit c78f25b7f075d81a2fa17d2b95174be66d51e7cb
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium index 8062029..14b5d91 100644 --- a/third_party/xnnpack/README.chromium +++ b/third_party/xnnpack/README.chromium
@@ -1,8 +1,8 @@ Name: XNNPACK Short Name: xnnpack URL: https://github.com/google/xnnpack -Version: c9f0470750e7c3c71974cdb997aeb2990d2e2137 -Date: 2024-05-14 +Version: fcb36699c67201ceff7358df42730809e8f2c9cc +Date: 2024-05-20 License: BSD License File: src/LICENSE Security Critical: Yes
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src index c9f0470..fcb3669 160000 --- a/third_party/xnnpack/src +++ b/third_party/xnnpack/src
@@ -1 +1 @@ -Subproject commit c9f0470750e7c3c71974cdb997aeb2990d2e2137 +Subproject commit fcb36699c67201ceff7358df42730809e8f2c9cc
diff --git a/tools/android/avd/proto/creation/android_v_google_apis_x64.textpb b/tools/android/avd/proto/creation/android_v_google_apis_x64.textpb index 1d01faf4..24800bb 100644 --- a/tools/android/avd/proto/creation/android_v_google_apis_x64.textpb +++ b/tools/android/avd/proto/creation/android_v_google_apis_x64.textpb
@@ -6,7 +6,7 @@ emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" - version: "8go0I9U8zwjGFhFFulM3U9vc2dCFmS9m_v7AsPlKFmEC" # 34.2.13 + version: "97gAPeXJa7zT-JcddyV8fpQtsx6kJjwqfmLe8FhZD1kC" # 34.2.14 (Stable) dest_path: "android_v_google_apis_x64" }
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index 2db5ad40..f52f5bca 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -859,8 +859,11 @@ "ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd": { "includes": [6060], }, + "<(SHARED_INTERMEDIATE_DIR)/ash/webui/mall/resources/resources.grd": { + "META": {"join": 2, "sizes": {"includes": [10],}}, + "includes": [6070], + }, "ash/webui/media_app_ui/resources/media_app_resources.grd": { - "META": {"join": 2}, "includes": [6080], }, # Both media_app_bundle_resources.grd and media_app_bundle_mock_resources.grd
diff --git a/tools/metrics/BUILD.gn b/tools/metrics/BUILD.gn index 6a7b938..05ab5f4 100644 --- a/tools/metrics/BUILD.gn +++ b/tools/metrics/BUILD.gn
@@ -89,8 +89,8 @@ "//tools/metrics/histograms/extract_histograms_test.py", "//tools/metrics/histograms/generate_expired_histograms_array.py", "//tools/metrics/histograms/generate_expired_histograms_array_unittest.py", - "//tools/metrics/histograms/generate_histograms_variants_allowlist.py", - "//tools/metrics/histograms/generate_histograms_variants_allowlist_unittest.py", + "//tools/metrics/histograms/generate_allowlist_from_histograms_file.py", + "//tools/metrics/histograms/generate_allowlist_from_histograms_file_unittest.py", "//tools/metrics/histograms/generate_flag_enums.py", "//tools/metrics/histograms/generate_flag_enums_test.py", "//tools/metrics/histograms/histogram_ownership.py",
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index dbee82a..8ad54f56 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -31425,6 +31425,15 @@ <description>A download warning is shown.</description> </action> +<action name="SafeBrowsing.EsbDownloadRowPromo.Click"> + <owner>awado@google.com</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <description> + User clicks on the Enhanced Safe Browsing (ESB) download row promotion on + chrome://downloads. + </description> +</action> + <action name="SafeBrowsing.Settings.DisableSafeBrowsingClicked"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> @@ -43662,8 +43671,6 @@ <suffix name="PinnedNewIncognitoWindowButton" label="Pinned new incognito window button"/> <suffix name="PinnedPrintButton" label="Pinned print button"/> - <suffix name="PinnedQrCodeGeneratorButton" - label="Pinned QR code generator button"/> <suffix name="PinnedSendTabToSelfButton" label="Pinned send tab to self button"/> <suffix name="PinnedShowBookmarkSidePanelButton"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 8679f28e..50db25d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -17502,6 +17502,7 @@ <int value="-1646653199" label="WallpaperGooglePhotosIntegration:enabled"/> <int value="-1646196271" label="WebRtcStatsReportIdl:disabled"/> <int value="-1646016597" label="IsolatePrerenders:disabled"/> + <int value="-1645737335" label="AppInfoTabResumptionModule:enabled"/> <int value="-1645071473" label="ChromeColors:disabled"/> <int value="-1644308778" label="WASAPIRawAudioCapture:disabled"/> <int value="-1643933608" label="SyncAutofillWalletOfferData:enabled"/> @@ -20274,6 +20275,7 @@ <int value="-444867364" label="Metal:enabled"/> <int value="-444758854" label="CellularCarrierLock:disabled"/> <int value="-444307785" label="WebAppEnableAppTitle:disabled"/> + <int value="-442384327" label="RubyShortHeuristics:enabled"/> <int value="-442352394" label="IframeOneGoogleBar:disabled"/> <int value="-441972413" label="OobeJellyModal:disabled"/> <int value="-441840790" label="TailoredSecurityUpdatedMessages:disabled"/> @@ -21496,6 +21498,7 @@ <int value="92466801" label="UploadOfficeToCloud:disabled"/> <int value="93832899" label="NtpCustomizationMenuV2:enabled"/> <int value="94576028" label="LensEnableRegionSearchOnPdfViewer:disabled"/> + <int value="95820546" label="RubyShortHeuristics:disabled"/> <int value="96148142" label="SyncAndroidPromosWithAlternativeTitle:enabled"/> <int value="97091906" label="AutofillSaveCardShowNoThanks:enabled"/> <int value="97691440" label="SkipServiceWorkerForInstallPromot:disabled"/> @@ -24929,6 +24932,7 @@ <int value="1596843821" label="NtpRealboxCr23Theming:disabled"/> <int value="1597516564" label="kDiagnosticsAppJelly:enabled"/> <int value="1597880096" label="FocusMode:disabled"/> + <int value="1599380625" label="AppInfoTabResumptionModule:disabled"/> <int value="1599431665" label="WebRtcApmDownmixCaptureAudioMethod:enabled"/> <int value="1599757259" label="DrawWebEdgeToEdge:enabled"/> <int value="1600850069" label="MobileIdentityConsistency:disabled"/> @@ -32518,6 +32522,8 @@ <int value="6" label="TAB_GROUP"/> <int value="7" label="WEBAPP_NOTIFICATION"/> <int value="8" label="FEED"/> + <int value="9" label="PAGE_INSIGHTS"/> + <int value="10" label="GOOGLE_BOTTOM_BAR"/> </enum> <enum name="ShareSourceAndroid"> @@ -35628,6 +35634,7 @@ <int value="57900378" label="chrome://conch/"/> <int value="58807865" label="chrome://local-state/"/> <int value="84832110" label="chrome://fileicon/"/> + <int value="104579118" label="chrome://boca-app/"/> <int value="112165789" label="chrome://device-emulator/"/> <int value="114748825" label="chrome-devtools://devtools/"/> <int value="164517522" label="chrome://discards/"/> @@ -35764,6 +35771,7 @@ <int value="1780987498" label="chrome://eche-app/"/> <int value="1797107942" label="chrome://md-settings/"/> <int value="1834776370" label="chrome://password-change/"/> + <int value="1846714330" label="chrome://sanitize/"/> <int value="1887784693" label="chrome://policy/"/> <int value="1906728906" label="chrome://privacy-sandbox-internals/"/> <int value="1918190389" label="chrome-untrusted://projector-annotator/"/>
diff --git a/tools/metrics/histograms/generate_allowlist_from_histograms_file.py b/tools/metrics/histograms/generate_allowlist_from_histograms_file.py new file mode 100755 index 0000000..d00ab93 --- /dev/null +++ b/tools/metrics/histograms/generate_allowlist_from_histograms_file.py
@@ -0,0 +1,146 @@ +#!/usr/bin/env python +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import sys + +import extract_histograms +import xml.dom.minidom + +_SCRIPT_NAME = "generate_allowlist_from_histograms_file.py" +_FILE = """// Generated from {script_name}. Do not edit! + +#ifndef {include_guard} +#define {include_guard} + +#include <algorithm> +#include <string_view> + +namespace {namespace} {{ + +inline constexpr std::string_view k{allow_list_name}AllowList[] = {{ +{values} +}}; + +constexpr bool IsValid{allow_list_name}(std::string_view s) {{ + return std::binary_search( + std::cbegin(k{allow_list_name}AllowList), + std::cend(k{allow_list_name}AllowList), + s); +}} + +}} // namespace {namespace} + +#endif // {include_guard} +""" + + +class Error(Exception): + pass + + +def _GenerateStaticFile(file_path, namespace, values, allow_list_name): + """Generates a header file with constexpr facilities to check for the + existence of a variant or enum in a histograms.xml file. + + Args: + namespace: A namespace to contain generated array. + values(List[str|int]]): A list of variant or enum values. + allow_list_name: A name of the variant list for an allow list. + Returns: + String with the generated header file content. + """ + values = sorted(values, key=lambda d: str(d)) + include_guard = file_path.replace('\\', '_').replace('/', '_').replace( + '.', '_').upper() + "_" + + values_string = "\n".join( + [" \"{name}\",".format(name=value) for value in values]) + return _FILE.format(script_name=_SCRIPT_NAME, + include_guard=include_guard, + namespace=namespace, + values=values_string, + allow_list_name=allow_list_name) + + +def _GenerateValueList(histograms, tag, allow_list_name): + if tag == "variant": + values, had_errors = extract_histograms.ExtractVariantsFromXmlTree( + histograms) + elif tag == "enum": + values, had_errors = extract_histograms.ExtractEnumsFromXmlTree(histograms) + else: + raise Error("'tag' must be either 'variant' or 'enum'") + + if had_errors: + raise Error("Error parsing inputs.") + + if (allow_list_name not in values): + raise Error("AllowListName is missing in variants list") + + if tag == "variant": + return [value["name"] for value in values[allow_list_name]] + else: + return list(values[allow_list_name]["values"].keys()) + + +def _GenerateFile(arguments): + """Generates C++ header file containing values of a variant or enum from + a .xml file. + + Args: + arguments: An object with the following attributes: + arguments.input: An xml file with histogram descriptions. + arguments.file: A filename of the generated source file. + arguments.tag: A XML tag, can be "enum" or "variant". + arguments.namespace: A namespace to contain generated array. + arguments.output_dir: A directory to put the generated file. + arguments.allow_list_name: A name of the variant or enum list. + """ + histograms = xml.dom.minidom.parse(arguments.input) + values = _GenerateValueList(histograms, arguments.tag, + arguments.allow_list_name) + + static_check_header_file_content = _GenerateStaticFile( + arguments.file, arguments.namespace, values, arguments.allow_list_name) + with open(os.path.join(arguments.output_dir, arguments.file), + "w") as generated_file: + generated_file.write(static_check_header_file_content) + + +def _ParseArguments(): + """Defines and parses arguments from the command line.""" + arg_parser = argparse.ArgumentParser( + description="Generate an array of allowlist from a histograms.xml file." + ) + arg_parser.add_argument("--output_dir", + required=True, + help="Base directory to for generated files.") + arg_parser.add_argument("--file", + required=True, + help="File name of the generated file.") + arg_parser.add_argument( + "--allow_list_name", + required=True, + help="Name of the variant / enum list in the histograms.xml file.") + arg_parser.add_argument("--namespace", + required=True, + help="Namespace of the allow list array.") + arg_parser.add_argument("--tag", + required=True, + help="XML tag name of either 'enum' or 'variant'.") + arg_parser.add_argument("--input", + help="Path to .xml file with histogram descriptions.") + return arg_parser.parse_args() + + +def main(): + arguments = _ParseArguments() + _GenerateFile(arguments) + + +if __name__ == "__main__": + sys.exit(main())
diff --git a/tools/metrics/histograms/generate_allowlist_from_histograms_file_unittest.py b/tools/metrics/histograms/generate_allowlist_from_histograms_file_unittest.py new file mode 100755 index 0000000..bc17aa6 --- /dev/null +++ b/tools/metrics/histograms/generate_allowlist_from_histograms_file_unittest.py
@@ -0,0 +1,103 @@ +#!/usr/bin/env python +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest +import xml.dom.minidom + +import generate_allowlist_from_histograms_file + +_EXPECTED_FILE_CONTENT = ( + """// Generated from generate_allowlist_from_histograms_file.py. \ +Do not edit! + +#ifndef TEST_TEST_H_ +#define TEST_TEST_H_ + +#include <algorithm> +#include <string_view> + +namespace test_namespace { + +inline constexpr std::string_view kTestNameAllowList[] = { + "All", + "DownloadView", + "PageInfoView", +}; + +constexpr bool IsValidTestName(std::string_view s) { + return std::binary_search( + std::cbegin(kTestNameAllowList), + std::cend(kTestNameAllowList), + s); +} + +} // namespace test_namespace + +#endif // TEST_TEST_H_ +""") + +_EXPECTED_VARIANT_LIST = ["All", "DownloadView", "PageInfoView"] + +_TEST_VARIANT_INPUT = """ +<variants name="BubbleName"> + <variant name="All"/> + <variant name="DownloadView"/> + <variant name="PageInfoView"/> +</variants> +""" + +_EXPECTED_ENUM_LIST = [123, 456] + +_TEST_ENUM_INPUT = """ +<enum name="URLHashes"> + <int value="123" label="label1"/> + <int value="456" label="label2"/> +</enum> +""" + + +class VariantAllowListTest(unittest.TestCase): + + def testGenerateSourceFileContent(self): + namespace = "test_namespace" + + allow_list_name = "TestName" + + # Provide an unsorted list to ensure the list gets sorted since the check + # function relies on being sorted. + variant_list = ["DownloadView", "All", "PageInfoView"] + content = generate_allowlist_from_histograms_file._GenerateStaticFile( + "test/test.h", namespace, variant_list, allow_list_name) + self.assertEqual(_EXPECTED_FILE_CONTENT, content) + + def testGenerateListFromVariants(self): + histograms = xml.dom.minidom.parseString(_TEST_VARIANT_INPUT) + allow_list_name = "BubbleName" + variants = generate_allowlist_from_histograms_file._GenerateValueList( + histograms, "variant", allow_list_name) + self.assertEqual(_EXPECTED_VARIANT_LIST, variants) + + # Has incorrect allow list name. + allow_list_name = "MissingVariantsName" + with self.assertRaises(generate_allowlist_from_histograms_file.Error): + generate_allowlist_from_histograms_file._GenerateValueList( + histograms, "variant", allow_list_name) + + def testGenerateListFromEnums(self): + histograms = xml.dom.minidom.parseString(_TEST_ENUM_INPUT) + allow_list_name = "URLHashes" + variants = generate_allowlist_from_histograms_file._GenerateValueList( + histograms, "enum", allow_list_name) + self.assertEqual(_EXPECTED_ENUM_LIST, variants) + + # Has incorrect allow list name. + allow_list_name = "MissingVariantsName" + with self.assertRaises(generate_allowlist_from_histograms_file.Error): + generate_allowlist_from_histograms_file._GenerateValueList( + histograms, "enum", allow_list_name) + + +if __name__ == "__main__": + unittest.main()
diff --git a/tools/metrics/histograms/generate_histograms_variants_allowlist.py b/tools/metrics/histograms/generate_histograms_variants_allowlist.py deleted file mode 100755 index 5cf2cc2c..0000000 --- a/tools/metrics/histograms/generate_histograms_variants_allowlist.py +++ /dev/null
@@ -1,136 +0,0 @@ -#!/usr/bin/env python -# Copyright 2023 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import argparse -import os -import sys - -import extract_histograms -import xml.dom.minidom - -_SCRIPT_NAME = "generate_histograms_variants_allowlist.py" -_FILE = """// Generated from {script_name}. Do not edit! - -#ifndef {include_guard} -#define {include_guard} - -#include <algorithm> -#include <string_view> - -namespace {namespace} {{ - -inline constexpr std::string_view k{variant_name}VariantAllowList[] = {{ -{variants} -}}; - -constexpr bool IsValid{variant_name}Variant(std::string_view s) {{ - return std::binary_search( - std::cbegin(k{variant_name}VariantAllowList), - std::cend(k{variant_name}VariantAllowList), - s); -}} - -}} // namespace {namespace} - -#endif // {include_guard} -""" - - -class Error(Exception): - pass - - -def _GenerateStaticFile(file_path, namespace, variant_list, allow_list_name): - """Generates a header file with constexpr facilities to check for the - existence of a variant. - - Args: - namespace: A namespace to contain generated array. - variant_list(List[Dict]]): - A list of variant objects [{variant: {name, summary, ...}}] - allow_list_name: A name of the variant list for an allow list. - Returns: - String with the generated content. - """ - variant_list = sorted(variant_list, key=lambda d: d['name']) - include_guard = file_path.replace('\\', '_').replace('/', '_').replace( - '.', '_').upper() + "_" - - variants = "\n".join( - [" \"{name}\",".format(name=value['name']) for value in variant_list]) - return _FILE.format(script_name=_SCRIPT_NAME, - include_guard=include_guard, - namespace=namespace, - variants=variants, - variant_name=allow_list_name) - - -def _GenerateVariantList(histograms, allow_list_name): - all_variants, had_errors = extract_histograms.ExtractVariantsFromXmlTree( - histograms) - if had_errors: - raise Error("Error parsing inputs.") - - if (allow_list_name not in all_variants): - raise Error("AllowListName is missing in variants list") - - return all_variants[allow_list_name] - - -def _GenerateFile(arguments): - """Generates header file containing array with Variant names. - - Args: - arguments: An object with the following attributes: - arguments.input: An xml file with histogram descriptions. - arguments.file: A filename of the generated source file. - arguments.namespace: A namespace to contain generated array. - arguments.output_dir: A directory to put the generated file. - arguments.allow_list_name: A name of the variant list for an allow list. - """ - histograms = xml.dom.minidom.parse(arguments.input) - variants = _GenerateVariantList(histograms, arguments.allow_list_name) - - static_check_header_file_content = _GenerateStaticFile( - arguments.file, arguments.namespace, variants, arguments.allow_list_name) - with open(os.path.join(arguments.output_dir, arguments.file), - "w") as generated_file: - generated_file.write(static_check_header_file_content) - - -def _ParseArguments(): - """Defines and parses arguments from the command line.""" - arg_parser = argparse.ArgumentParser( - description="Generate an array of AllowList based on variants.") - arg_parser.add_argument("--output_dir", - "-o", - required=True, - help="Base directory to for generated files.") - arg_parser.add_argument("--file", - "-f", - required=True, - help="File name of the generated file.") - arg_parser.add_argument( - "--allow_list_name", - "-a", - required=True, - help="Name of variant list that should be part of the allow list.") - arg_parser.add_argument("--namespace", - "-n", - required=True, - help="Namespace of the allow list array.") - arg_parser.add_argument("--input", - "-i", - help="Path to .xml file with histogram descriptions.") - return arg_parser.parse_args() - - -def main(): - arguments = _ParseArguments() - _GenerateFile(arguments) - - -if __name__ == "__main__": - sys.exit(main())
diff --git a/tools/metrics/histograms/generate_histograms_variants_allowlist_unittest.py b/tools/metrics/histograms/generate_histograms_variants_allowlist_unittest.py deleted file mode 100755 index 05daebe..0000000 --- a/tools/metrics/histograms/generate_histograms_variants_allowlist_unittest.py +++ /dev/null
@@ -1,102 +0,0 @@ -#!/usr/bin/env python -# Copyright 2023 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import unittest -import xml.dom.minidom - -import generate_histograms_variants_allowlist - -_EXPECTED_FILE_CONTENT = ( - """// Generated from generate_histograms_variants_allowlist.py. Do not edit! - -#ifndef TEST_TEST_H_ -#define TEST_TEST_H_ - -#include <algorithm> -#include <string_view> - -namespace test_namespace { - -inline constexpr std::string_view kTestNameVariantAllowList[] = { - "All", - "DownloadView", - "PageInfoView", -}; - -constexpr bool IsValidTestNameVariant(std::string_view s) { - return std::binary_search( - std::cbegin(kTestNameVariantAllowList), - std::cend(kTestNameVariantAllowList), - s); -} - -} // namespace test_namespace - -#endif // TEST_TEST_H_ -""") - -_EXPECTED_VARIANT_LIST = [{ - 'name': 'All', - 'summary': 'All' -}, { - 'name': 'DownloadView', - 'summary': 'DownloadView' -}, { - 'name': 'PageInfoView', - 'summary': 'PageInfoView' -}] - - -class VariantAllowListTest(unittest.TestCase): - def testGenerateSourceFileContent(self): - namespace = "test_namespace" - - allow_list_name = "TestName" - - # Provide an unsorted list to ensure the list gets sorted since the check - # function relies on being sorted. - variant_list = [{ - 'name': 'DownloadView' - }, { - 'name': 'All' - }, { - 'name': 'PageInfoView' - }] - content = generate_histograms_variants_allowlist._GenerateStaticFile( - "test/test.h", namespace, variant_list, allow_list_name) - self.assertEqual(_EXPECTED_FILE_CONTENT, content) - - def testGenerateVariantList(self): - histograms = xml.dom.minidom.parseString(""" -<histogram-configuration> -<histograms> -<variants name="BubbleName"> - <variant name="All"/> - <variant name="DownloadView"/> - <variant name="PageInfoView"/> -</variants> - -<histogram name="Bubble.{BubbleName}.CloseReason" enum="WidgetClosedReason" - expires_after="2024-09-01"> - <summary>Records the reason a bubble was closed.</summary> - <token key="BubbleName" variants="BubbleName"/> -</histogram> -</histograms> -</histogram-configuration> -""") - allow_list_name = "BubbleName" - variants = generate_histograms_variants_allowlist._GenerateVariantList( - histograms, allow_list_name) - self.assertEqual(_EXPECTED_VARIANT_LIST, variants) - - # Has incorrect allow list name. - allow_list_name = "MissingVariantsName" - with self.assertRaises(generate_histograms_variants_allowlist.Error): - generate_histograms_variants_allowlist._GenerateVariantList( - histograms, allow_list_name) - - -if __name__ == "__main__": - unittest.main()
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 350a1b1..a3f2527 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -436,7 +436,7 @@ </histogram> <histogram name="Arc.AppInstall.PolicySuccessRate" units="%" - expires_after="2024-06-30"> + expires_after="2025-01-30"> <owner>batoon@google.com</owner> <owner>arc-commercial@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 3313e78..8e7530e 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -259,6 +259,7 @@ </variants> <variants name="MantaMetricType"> + <variant name="AnchovyProvider" summary="Request from Anchovy provider"/> <variant name="MahiProvider.Outline" summary="Request from Mahi provider for outline"/> <variant name="MahiProvider.QA" summary="Request from Mahi provider for QA"/>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index de399aa1..671917c 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -3184,6 +3184,36 @@ </summary> </histogram> +<histogram name="Blink.LCPP.PrewarmHttpDiskCache.{PrewarmMethod}.CacheExists" + enum="BooleanExists" expires_after="2024-08-22"> + <owner>chikamune@chromium.org</owner> + <owner> + src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS + </owner> + <summary> + Records whether prewarming HttpDiskCache successfully warmed up the disk or + not. If the cache entry does not exist, false will be recorded. This is + recorded on each HttpDiskCache prewarming attempt and only if the + {PrewarmMethod} prewarming method was used. + </summary> + <token key="PrewarmMethod"> + <variant name="DownloadBody"/> + <variant name="HeadersOnly"/> + </token> +</histogram> + +<histogram name="Blink.LCPP.PrewarmHttpDiskCacheURL.Count" units="count" + expires_after="2024-08-22"> + <owner>chikamune@chromium.org</owner> + <owner> + src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS + </owner> + <summary> + Records the predicted subresource URL count that is predicted by the + HttpDiskCachePrewarming feature. This is recorded on each navigation. + </summary> +</histogram> + <histogram name="Blink.LCPP.RecordedFontCount" units="count" expires_after="2024-11-17"> <owner>yyanagisawa@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/browser/enums.xml b/tools/metrics/histograms/metadata/browser/enums.xml index d28ada0..f2d0f238 100644 --- a/tools/metrics/histograms/metadata/browser/enums.xml +++ b/tools/metrics/histograms/metadata/browser/enums.xml
@@ -415,6 +415,28 @@ <int value="2" label="Tab shown twice without being hidden"/> </enum> +<enum name="UnavailableErrorReasonBrowser"> + <summary> + Defined as UnavailableErrorReason in + components/reporting/util/reporting_errors.h. + </summary> + <int value="0" label="CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_BROWSER"/> + <int value="1" label="CANNOT_GET_CLOUD_POLICY_MANAGER_FOR_PROFILE"/> + <int value="2" label="CLIENT_NOT_CONNECTED_TO_MISSIVE"/> + <int value="3" label="DEVICE_DM_TOKEN_NOT_SET"/> + <int value="4" label="FAILED_TO_CREATE_STORAGE_QUEUE_DIRECTORY"/> + <int value="5" label="FILE_NOT_OPEN"/> + <int value="6" label="FILE_UPLOAD_DELEGATE_IS_NULL"/> + <int value="7" label="FILE_UPLOAD_JOB_DELEGATE_IS_NULL"/> + <int value="8" label="REPORTING_CLIENT_IS_NULL"/> + <int value="9" label="REPORT_QUEUE_DESTRUCTED"/> + <int value="10" label="REPORT_QUEUE_IS_NULL"/> + <int value="11" label="REPORT_QUEUE_PROVIDER_DESTRUCTED"/> + <int value="12" label="STORAGE_QUEUE_SHUTDOWN"/> + <int value="13" label="UNABLE_TO_BUILD_REPORT_QUEUE"/> + <int value="14" label="UPLOAD_PROVIDER_IS_NULL"/> +</enum> + </enums> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml index 5d58114f..4978312 100644 --- a/tools/metrics/histograms/metadata/browser/histograms.xml +++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -391,6 +391,18 @@ </summary> </histogram> +<histogram name="Browser.ERP.UnavailableErrorReason" + enum="UnavailableErrorReasonBrowser" expires_after="2025-04-01"> + <owner>jrhilke@google.com</owner> + <owner>src/components/reporting/OWNERS</owner> + <summary> + Recorded once each time reporting::error::UNAVAILABLE is returned in the + browser. There is a 1:1 relationship between the UMA values and error + messages used with reporting::error::UNAVAILABLE so that we can understand + exactly which parts of the code are failing. + </summary> +</histogram> + <histogram name="Browser.ERP.UnuploadedCrashShouldNotReportReason" enum="EnterpriseReportingUnuploadedCrashShouldNotReportReason" expires_after="2024-10-18">
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml index 6fc3987..b6f00d8 100644 --- a/tools/metrics/histograms/metadata/enterprise/enums.xml +++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -2126,8 +2126,7 @@ <int value="1248" label="ShowAiIntroScreenEnabled"/> <int value="1249" label="ShowTunaScreenEnabled"/> <int value="1250" label="EnterpriseBadgingTemporarySetting"/> - <int value="1251" - label="GenAILocalFoundationalModelEnterprisePolicySettings"/> + <int value="1251" label="GenAILocalFoundationalModelSettings"/> <int value="1252" label="DeviceExtensionsSystemLogEnabled"/> <int value="1253" label="ChromeDataRegionSetting"/> <int value="1254" label="ContextualGoogleIntegrationsEnabled"/> @@ -2137,6 +2136,7 @@ <int value="1258" label="KeyboardFocusableScrollersEnabled"/> <int value="1259" label="ExtensibleEnterpriseSSOEnabled"/> <int value="1260" label="CSSCustomStateDeprecatedSyntaxEnabled"/> + <int value="1261" label="MemorySaverModeSavings"/> </enum> <enum name="EnterprisePoliciesSources">
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml index cf9ce68..acbdf90 100644 --- a/tools/metrics/histograms/metadata/file/histograms.xml +++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -1123,6 +1123,19 @@ <owner>src/ui/file_manager/OWNERS</owner> <summary> Chrome OS File Browser: HTTP response code of select Microsoft GraphAPI + calls. These histograms are deprecated in favour of the + "ResponseCodeSparse" variant. + </summary> + <token key="GraphAPIMethod" variants="GraphAPIMethod"/> +</histogram> + +<histogram + name="FileBrowser.OfficeFiles.ODFS.GraphAPI.ResponseCodeSparse.{GraphAPIMethod}" + enum="OfficeGraphAPIResult" expires_after="2025-05-01"> + <owner>simmonsjosh@google.com</owner> + <owner>src/ui/file_manager/OWNERS</owner> + <summary> + Chrome OS File Browser: HTTP response code of select Microsoft GraphAPI calls. </summary> <token key="GraphAPIMethod" variants="GraphAPIMethod"/>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml index 471b94b9d89..db0fc4cc 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -4551,6 +4551,7 @@ <suffix name="FaceML" label="Face ML (Deprecated)"/> <suffix name="FirmwareUpdate" label="FirmwareUpdate"/> <suffix name="Help" label="Help"/> + <suffix name="Mall" label="App Mall"/> <suffix name="Media" label="Media"/> <suffix name="OSFeedback" label="OSFeedback"/> <suffix name="OsFlags" label="OsFlags"/>
diff --git a/tools/metrics/histograms/metadata/magic_stack/histograms.xml b/tools/metrics/histograms/metadata/magic_stack/histograms.xml index 7f8d9a1..358250f 100644 --- a/tools/metrics/histograms/metadata/magic_stack/histograms.xml +++ b/tools/metrics/histograms/metadata/magic_stack/histograms.xml
@@ -70,6 +70,16 @@ <token key="ToggleState" variants="ToggleState"/> </histogram> +<histogram name="MagicStack.Clank.SingleTab.SeeMoreLinkClicked" enum="Boolean" + expires_after="2024-11-03"> + <owner>hanxi@google.com</owner> + <owner>huangs@google.com</owner> + <summary> + Records each time the Single Tab Card's "See more" link is + clicked, Android-only. + </summary> +</histogram> + <histogram name="MagicStack.Clank.TabResumption.ClickInfo" enum="MagicStack.Clank.TabResumption.ClickInfo" expires_after="2024-09-01"> <owner>huangs@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml index 49f85f21..75e184af 100644 --- a/tools/metrics/histograms/metadata/navigation/histograms.xml +++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1494,13 +1494,16 @@ </histogram> <histogram name="Navigation.QueueTime.{Method}.{FrameType}" units="ms" - expires_after="2023-07-28"> + expires_after="2024-11-20"> <owner>cduvall@chromium.org</owner> <owner>jam@chromium.org</owner> <summary> Measures the amount of time the task to run {Method} was queued before running. Logged every time {Method} is run for a {FrameType} in NavigationURLLoaderImpl with a valid queue time. + + Warning: this histogram was expired after 2023-07-28 and brought back + 2024-05-20; data may be missing. </summary> <token key="Method"> <variant name="OnReceiveRedirect"/>
diff --git a/tools/metrics/histograms/metadata/network/enums.xml b/tools/metrics/histograms/metadata/network/enums.xml index 68c2fb6e..7dc4eeb 100644 --- a/tools/metrics/histograms/metadata/network/enums.xml +++ b/tools/metrics/histograms/metadata/network/enums.xml
@@ -2595,6 +2595,11 @@ <int value="3" label="Both group owner and client are ready."/> </enum> +<enum name="WifiP2PDisconnectReason"> + <int value="0" label="Client Initiated."/> + <int value="1" label="Internal Error."/> +</enum> + <enum name="WifiP2POperationResult"> <int value="0" label="Success."/> <int value="1" label="Operation not allowed."/>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index b770de9..2989d87 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -747,6 +747,16 @@ </summary> </histogram> +<histogram name="Network.Ash.WiFiDirect.Connection.Duration" units="ms" + expires_after="2025-02-20"> + <owner>jiajunz@google.com</owner> + <owner>cros-connectivity@google.com</owner> + <summary> + Tracks the duration of each Wifi P2P connection. Emits when the connection + is torn down. + </summary> +</histogram> + <histogram name="Network.Ash.WiFiDirect.TagSocket.OperationResult" enum="BooleanSuccess" expires_after="2025-02-20"> <owner>jiajunz@google.com</owner> @@ -757,6 +767,20 @@ </summary> </histogram> +<histogram name="Network.Ash.WiFiDirect.{GroupType}.DisconnectReason" + enum="WifiP2PDisconnectReason" expires_after="2025-02-20"> + <owner>jiajunz@google.com</owner> + <owner>cros-connectivity@google.com</owner> + <summary> + Measures and tracks the disconnect reason of {GroupType} P2P connection. + Emitted when the {GroupType} P2P connection disconnects. + </summary> + <token key="GroupType"> + <variant name="GroupClient"/> + <variant name="GroupOwner"/> + </token> +</histogram> + <histogram name="Network.Ash.WiFiDirect.{Operation}.OperationResult" enum="WifiP2POperationResult" expires_after="2025-02-20"> <owner>jiajunz@google.com</owner> @@ -775,7 +799,7 @@ <histogram name="Network.Ash.{NetworkType}.ConnectionResult.NonUserInitiated" enum="ShillConnectResult" expires_after="2025-02-20"> - <owner>jiajunz@chromium.org</owner> + <owner>jiajunz@google.com</owner> <owner>cros-connectivity@google.com</owner> <summary> Tracks the result of automatic Network connection attempts. A success is @@ -3066,31 +3090,6 @@ </summary> </histogram> -<histogram name="Network.Shill.Vpn.Ikev2.EndReason" enum="NetworkServiceError" - expires_after="2024-12-31"> - <owner>jiejiang@chromium.org</owner> - <owner>cros-network-metrics@google.com</owner> - <summary> - ChromeOS network usage metric emitted on the end of each IKEv2 VPN - connection that tracks the reason that the connection is ended. This metric - will be emitted no matter if the connection is established successfully, - i.e., it will be emitted if an error happens during connecting. - </summary> -</histogram> - -<histogram name="Network.Shill.Vpn.L2tpIpsec.SwanctlEndReason" - enum="NetworkServiceError" expires_after="2024-12-31"> - <owner>jiejiang@chromium.org</owner> - <owner>cros-network-metrics@google.com</owner> - <summary> - ChromeOS network usage metric emitted on the end of each L2TP/IPsec VPN - connection initiated by the swanctl-based driver that tracks the reason that - the connection is ended. This metric will be emitted no matter if the - connection is established successfully, i.e., it will be emitted if an error - happens during connecting. - </summary> -</histogram> - <histogram name="Network.Shill.Vpn.L2tpIpsecTunnelGroupUsage" enum="VPNL2TPIPsecTunnelGroupUsage" expires_after="2024-12-31"> <owner>jiejiang@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/enums.xml b/tools/metrics/histograms/metadata/others/enums.xml index e5c2904..8cb67da 100644 --- a/tools/metrics/histograms/metadata/others/enums.xml +++ b/tools/metrics/histograms/metadata/others/enums.xml
@@ -58,6 +58,13 @@ <int value="14" label="Feedback Tool System Logs"/> </enum> +<enum name="SalientImageUrlFetchResult"> + <int value="0" label="Failed to fetch salient image url from network."/> + <int value="1" label="A previous network request failed."/> + <int value="2" label="Successfully fetched salient image url from network."/> + <int value="3" label="Succeessfully got salient image url from local cache."/> +</enum> + <enum name="SilentPushEvent"> <int value="0" label="New Silent Push request"/> <int value="1" label="Notification enforcement skipped"/>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 59c594e..36a8754 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -7396,6 +7396,17 @@ </summary> </histogram> +<histogram name="LoadingPredictor.SetLCPPNavigationHint.Time" units="ms" + expires_after="2024-08-22"> + <owner>chikamune@chromium.org</owner> + <owner>chrome-loading@google.com</owner> + <summary> + Measures the elapsed time it takes to read LCPPNavigationHint and attach it + to NavigationHandle. Recorded on DidStartNavigation or DidRedirectNavigation + only when there is hint information. + </summary> +</histogram> + <histogram name="Manifest.HasProperty" enum="Boolean" expires_after="2024-11-03"> <owner>mgiuca@chromium.org</owner> @@ -8590,6 +8601,19 @@ </summary> </histogram> +<histogram + name="PageImageService.Android.SalientImageUrlFetchResult.{ClientId}" + enum="SalientImageUrlFetchResult" expires_after="2025-01-20"> + <owner>hanxi@google.com</owner> + <owner>huangs@google.com</owner> + <owner>wylieb@google.com</owner> + <summary> + Records the fetching result of a salient image. The histogram is logged when + an salient image is fetched for the {ClientId}. Android-only. + </summary> + <token key="ClientId" variants="PageImageServiceClientId"/> +</histogram> + <histogram name="PageImageService.Backend.OptimizationGuide.Result{ClientId}" enum="PageImageServiceResult" expires_after="2024-11-03"> <owner>sophiechang@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml index 9259185..d0154e5 100644 --- a/tools/metrics/histograms/metadata/page/histograms.xml +++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -3367,6 +3367,21 @@ </histogram> <histogram + name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.SetSpeculationRulesPrerender" + units="ms" expires_after="2024-11-01"> + <owner>yoichio@chromium.org</owner> + <owner>loading-dev@chromium.org</owner> + <summary> + Similar to PaintTiming.NavigationToLargestContentfulPaint2, this measures + the time from navigation timing's navigation start to the time the largest + content (text or image) is first painted only for pages using Speculation + Rules API and calls Prerender2, across all frames. Excludes any content + painted after user input. Includes content that has been removed from the + page. See web.dev/lcp for more details. + </summary> +</histogram> + +<histogram name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.{Scheme}" units="ms" expires_after="2024-06-30"> <owner>iclelland@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/printing/enums.xml b/tools/metrics/histograms/metadata/printing/enums.xml index 8d022a8..6764b97 100644 --- a/tools/metrics/histograms/metadata/printing/enums.xml +++ b/tools/metrics/histograms/metadata/printing/enums.xml
@@ -69,7 +69,7 @@ <int value="0" label="Fatal Error"/> <int value="1" label="Success"/> <int value="2" label="Printer Unreachable"/> - <int value="3" label="Could not contact debugd over dbus"/> + <int value="3" label="Could not contact printscanmgr over dbus"/> <int value="4" label="Can't configure native printers due to policy"/> <int value="5" label="Invalid values are used to update printer"/> <int value="6" label="Could not install component"/> @@ -84,7 +84,7 @@ <int value="15" label="Memory allocation error in Cups"/> <int value="16" label="Printer's URI is incorrect"/> <int value="17" label="Manual setup required"/> - <int value="64" label="No reply from debugd over D-Bus"/> + <int value="64" label="No reply from printscanmgr over D-Bus"/> <int value="65" label="Generic D-Bus timeout"/> <int value="66" label="Printer removed during setup"/> </enum>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/enums.xml b/tools/metrics/histograms/metadata/safe_browsing/enums.xml index b51df58..d2d7d56 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/enums.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/enums.xml
@@ -324,6 +324,15 @@ <int value="3" label="WithoutToken"/> </enum> +<!-- LINT.IfChange(SafeBrowsingEsbDownloadRowPromoOutcome) --> + +<enum name="SafeBrowsingEsbDownloadRowPromoOutcome"> + <int value="0" label="Shown"/> + <int value="1" label="Clicked"/> +</enum> + +<!-- LINT.ThenChange(//chrome/browser/ui/webui/downloads/downloads_dom_handler.h:SafeBrowsingEsbDownloadRowPromoOutcome) --> + <enum name="SafeBrowsingHPRTOperationOutcome"> <int value="0" label="Success"/> <int value="1" label="Parse response error"/>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index 56e4227d..07aeb49 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -743,6 +743,19 @@ variants="MetricsCollectorTimesDisabledEnabledDuration"/> </histogram> +<histogram name="SafeBrowsing.EsbDownloadRowPromo.Outcome" + enum="SafeBrowsingEsbDownloadRowPromoOutcome" expires_after="2024-10-06"> + <owner>awado@google.com</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <summary> + Records the outcome of showing an ESB promotion on a download item on the + chrome://downloads page. Promotions are only shown on downloads that have + been determined to be dangerous and only when the user is able to enable + enhanced protection. The histogram outcome is recorded on display and on + every click on the promotion. + </summary> +</histogram> + <histogram name="SafeBrowsing.EsbPromotionFlow.IphShown" enum="SafeBrowsingReferralMethod" expires_after="2024-10-06"> <owner>awado@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/user_education/histograms.xml b/tools/metrics/histograms/metadata/user_education/histograms.xml index c6850105..c879a68 100644 --- a/tools/metrics/histograms/metadata/user_education/histograms.xml +++ b/tools/metrics/histograms/metadata/user_education/histograms.xml
@@ -23,6 +23,9 @@ <histograms> <variants name="NewBadgeFeature"> + <variant name="AutofillForUnclassifiedFieldsAvailable" + summary="For address and card field-by-field filling; shown in the + autofill section of the context menu."/> <variant name="Compose" summary="For Compose feature; shown in web context menu."/> <variant name="ComposeNudge"
diff --git a/tools/metrics/histograms/metadata/variations/enums.xml b/tools/metrics/histograms/metadata/variations/enums.xml index c3740e06..fa39657 100644 --- a/tools/metrics/histograms/metadata/variations/enums.xml +++ b/tools/metrics/histograms/metadata/variations/enums.xml
@@ -138,6 +138,7 @@ <int value="6" label="Unknown fields"/> <int value="7" label="Layer ID is not unique"/> <int value="8" label="Limited layer dropped"/> + <int value="9" label="Duplicated layer member ID"/> </enum> <enum name="VariationsInvalidStudyReason">
diff --git a/tools/metrics/metrics_python_tests.py b/tools/metrics/metrics_python_tests.py index ca171ac0..818e985 100755 --- a/tools/metrics/metrics_python_tests.py +++ b/tools/metrics/metrics_python_tests.py
@@ -40,7 +40,7 @@ 'histograms/expand_owners_unittest.py', 'histograms/extract_histograms_test.py', 'histograms/generate_expired_histograms_array_unittest.py', - 'histograms/generate_histograms_variants_allowlist_unittest.py', + 'histograms/generate_allowlist_from_histograms_file_unittest.py', 'histograms/merge_xml_test.py', 'histograms/pretty_print_test.py', 'histograms/validate_token_test.py',
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 1220a8a..e390384 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -658,7 +658,7 @@ 'pool': 'chrome.tests.perf', 'os': 'Android', 'device_type': 'oriole', - 'device_os': 'TP1A.220624.021', + # 'device_os': 'TP1A.220624.021', 'device_os_flavor': 'google', }, }, @@ -673,7 +673,7 @@ 'pool': 'chrome.tests.perf-pgo', 'os': 'Android', 'device_type': 'oriole', - 'device_os': 'TP1A.220624.021', + # 'device_os': 'TP1A.220624.021', 'device_os_flavor': 'google', }, }, @@ -688,7 +688,7 @@ 'pool': 'chrome.tests.perf', 'os': 'Android', 'device_type': 'raven', - 'device_os': 'TP1A.220624.021', + # 'device_os': 'TP1A.220624.021', 'device_os_flavor': 'google', }, }, @@ -703,7 +703,7 @@ 'pool': 'chrome.tests.perf', 'os': 'Android', 'device_type': 'raven', - 'device_os': 'TP1A.220624.021', + # 'device_os': 'TP1A.220624.021', 'device_os_flavor': 'google', }, },
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 36a13c4..3ed5a07 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/v45.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "4c1f529a84939695aa56aa72dfbf95ecbb94939b", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ce42344c728a5ae941621edfa394f5c8d1818a69/trace_processor_shell.exe" + "hash": "bac1402e6dc3b5bedb992265980364bc5092adc8", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/f235f50590e878113c2fc6eec85ebb5ac47b98dd/trace_processor_shell.exe" }, "linux_arm": { "hash": "f7cc2e856e9ee1260e9691c078f3771193eb4dea", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v45.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "b6e067f269854278e96e8d701a8182c1df029d4b", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fe95ade50a871086b1cfeab9e8374a916bc12b71/trace_processor_shell" + "hash": "0c820b958cb9369e8661f91d266576cd8a771b4f", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f235f50590e878113c2fc6eec85ebb5ac47b98dd/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/utr/recipe.py b/tools/utr/recipe.py index 1d41c27f..58e8b21 100644 --- a/tools/utr/recipe.py +++ b/tools/utr/recipe.py
@@ -96,7 +96,8 @@ skip_test, skip_prompts, build_dir=None, - additional_test_args=None): + additional_test_args=None, + reuse_task=None): """Constructor for LegacyRunner Args: @@ -112,6 +113,7 @@ build_dir: pathlib.Path to the build dir to build in. Will use the UTR's default otherwise if needed. additional_test_args: List of additional args to pass to the tests. + reuse_task: String of a swarming task to reuse. """ self._recipes_py = recipes_py self._skip_prompts = skip_prompts @@ -156,6 +158,9 @@ mode = 'RUN_TYPE_COMPILE' input_props['run_type'] = mode + if reuse_task: + input_props['reuse_swarming_task'] = reuse_task + # Need to pretend we're an actual build for various builder look-ups in # the recipe. input_props['$recipe_engine/buildbucket'] = {
diff --git a/tools/utr/run.py b/tools/utr/run.py index 2654671..08051f50 100755 --- a/tools/utr/run.py +++ b/tools/utr/run.py
@@ -77,6 +77,9 @@ 'a bundle locally, run `./recipes.py bundle` in your desired recipe ' 'checkout. This creates a dir called "bundle" that can be pointed to ' 'with this arg.') + parser.add_argument('--reuse-task', + type=str, + help='Ruse the cas digest of the provided swarming task') def add_compile_args(parser): @@ -137,6 +140,9 @@ if not args.run_mode: parser.print_help() parser.error('Please select a run_mode: compile,test,compile-and-test') + if args.reuse_task and args.run_mode != 'test': + parser.print_help() + parser.error('reuse-task is only compatible with "test"') return args @@ -186,6 +192,7 @@ args.force, args.build_dir, additional_test_args=None if skip_test else args.additional_test_args, + reuse_task=args.reuse_task, ) exit_code, error_msg = recipe_runner.run_recipe( filter_stdout=args.verbosity < 2)
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc index b3e702a..007221d3 100644 --- a/ui/accessibility/ax_enum_util.cc +++ b/ui/accessibility/ax_enum_util.cc
@@ -1297,6 +1297,8 @@ return "doDefaultLabel"; case ax::mojom::StringAttribute::kFontFamily: return "fontFamily"; + case ax::mojom::StringAttribute::kHtmlId: + return "htmlId"; case ax::mojom::StringAttribute::kHtmlTag: return "htmlTag"; case ax::mojom::StringAttribute::kImageAnnotation: @@ -1380,6 +1382,8 @@ return ax::mojom::StringAttribute::kDoDefaultLabel; } else if (string_attribute == "kFontFamily") { return ax::mojom::StringAttribute::kFontFamily; + } else if (string_attribute == "kHtmlId") { + return ax::mojom::StringAttribute::kHtmlId; } else if (string_attribute == "kHtmlTag") { return ax::mojom::StringAttribute::kHtmlTag; } else if (string_attribute == "kImageAnnotation") {
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom index e005cec..ece7e182 100644 --- a/ui/accessibility/ax_enums.mojom +++ b/ui/accessibility/ax_enums.mojom
@@ -572,8 +572,8 @@ kSubtreeUpdateEnd, }; -// Next version: 5 -// Next value: 38 +// Next version: 6 +// Next value: 39 [Extensible, Stable, Uuid="e5a4cd0c-3152-4427-93d5-35ff7d0f1ae8"] enum StringAttribute { [Default]kNone = 0, @@ -602,6 +602,7 @@ [MinVersion=1] kDoDefaultLabel = 31, // Only for ARC // Only present when different from parent. kFontFamily = 13, + [MinVersion=5] kHtmlId = 38, kHtmlTag = 14, // Stores an automatic image annotation if one is available. Only valid on // ax::mojom::Role::kImage. See kImageAnnotationStatus, too.
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc index 5289ce1..155b8ff1 100644 --- a/ui/accessibility/ax_node.cc +++ b/ui/accessibility/ax_node.cc
@@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "ui/accessibility/ax_computed_node_data.h" +#include "ui/accessibility/ax_enums.mojom-shared.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_hypertext.h" #include "ui/accessibility/ax_language_detection.h" @@ -2181,8 +2182,9 @@ // This requirement may need to be removed if ARIA element reflection is // implemented. HTML attribute serialization must currently be turned on in // order to pass this requirement. - if (!HasHtmlAttribute("id")) + if (!HasStringAttribute(ax::mojom::StringAttribute::kHtmlId)) { return false; + } // Finally, check for the required ancestor. for (AXNode* ancestor_node = GetUnignoredParent(); ancestor_node;
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc index feef863..a73c20d2 100644 --- a/ui/accessibility/ax_node_data.cc +++ b/ui/accessibility/ax_node_data.cc
@@ -1233,7 +1233,7 @@ GetStringAttribute(ax::mojom::StringAttribute::kClassName).c_str()); } std::string id_attr; - if (GetHtmlAttribute("id", &id_attr)) { + if (GetStringAttribute(ax::mojom::StringAttribute::kHtmlId, &id_attr)) { result += base::StringPrintf("#%s", id_attr.c_str()); } result += ">"; @@ -1791,6 +1791,7 @@ result += " virtual_content=" + value; break; case ax::mojom::StringAttribute::kClassName: + case ax::mojom::StringAttribute::kHtmlId: case ax::mojom::StringAttribute::kHtmlTag: case ax::mojom::StringAttribute::kRole: case ax::mojom::StringAttribute::kUrl:
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 2d2e2b2..945c1725 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -1550,9 +1550,8 @@ AddAttributeToList("datetime", datetime, attributes); } - // Expose id attribute. std::string id; - if (GetHtmlAttribute("id", &id)) { + if (delegate_->GetStringAttribute(ax::mojom::StringAttribute::kHtmlId, &id)) { AddAttributeToList("id", id, attributes); }
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm index 4e59e850..d3c5b1c 100644 --- a/ui/accessibility/platform/ax_platform_node_cocoa.mm +++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -1595,8 +1595,9 @@ return nil; std::string id; - if (_node->GetHtmlAttribute("id", &id)) + if (_node->GetStringAttribute(ax::mojom::StringAttribute::kHtmlId, &id)) { return base::SysUTF8ToNSString(id); + } return @""; }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.cc b/ui/accessibility/platform/ax_platform_node_delegate.cc index afc1eba8..87b28f4 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate.cc +++ b/ui/accessibility/platform/ax_platform_node_delegate.cc
@@ -581,7 +581,7 @@ std::u16string AXPlatformNodeDelegate::GetAuthorUniqueId() const { if (node_) - return node_->GetHtmlAttribute("id"); + return node_->GetString16Attribute(ax::mojom::StringAttribute::kHtmlId); return std::u16string(); }
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index f89a6ed..3aa60924 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -521,6 +521,7 @@ "//tools/typescript/definitions/webview_tag.d.ts", "//ui/file_manager/file_manager/definitions/file_manager_private.d.ts", "//ui/file_manager/image_loader/image_loader_private.d.ts", + "//ui/file_manager/image_loader/overrides.d.ts", ] generated_js_files = [
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn index 9b319e0..39e107b 100644 --- a/ui/file_manager/image_loader/BUILD.gn +++ b/ui/file_manager/image_loader/BUILD.gn
@@ -48,6 +48,7 @@ dts_files = [ "image_loader_private.d.ts", + "overrides.d.ts", "//tools/typescript/definitions/chrome_event.d.ts", "//tools/typescript/definitions/runtime.d.ts", ]
diff --git a/ui/file_manager/image_loader/image_request_task.ts b/ui/file_manager/image_loader/image_request_task.ts index 3e910c9..5caa1562 100644 --- a/ui/file_manager/image_loader/image_request_task.ts +++ b/ui/file_manager/image_loader/image_request_task.ts
@@ -29,7 +29,7 @@ * The maximum milliseconds to load video. If loading video exceeds the limit, * we give up generating video thumbnail and free the consumed memory. */ - static readonly MAX_MILLISECONDS_TO_LOAD_VIDEO: number = 3000; + static readonly MAX_MILLISECONDS_TO_LOAD_VIDEO: number = 10000; /** * The default width of a non-square thumbnail. The value is set to match the
diff --git a/ui/file_manager/image_loader/overrides.d.ts b/ui/file_manager/image_loader/overrides.d.ts new file mode 100644 index 0000000..40ecbd2c --- /dev/null +++ b/ui/file_manager/image_loader/overrides.d.ts
@@ -0,0 +1,7 @@ +// 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. + +interface Navigator { + readonly deviceMemory: number; +}
diff --git a/ui/file_manager/image_loader/scheduler.ts b/ui/file_manager/image_loader/scheduler.ts index d5a496f..39c7495 100644 --- a/ui/file_manager/image_loader/scheduler.ts +++ b/ui/file_manager/image_loader/scheduler.ts
@@ -4,8 +4,20 @@ import type {ImageRequestTask} from './image_request_task.js'; -/** Maximum download tasks to be run in parallel. */ -export const MAXIMUM_IN_PARALLEL = 5; + +// `deviceMemory` might be 0.5 or 0.25, so we normalize to minimum of 2. +const memory = Math.max(2, navigator.deviceMemory); +// For low end devices `hardwareCount` can be low like 4 some other devies are +// low in memory, it will have the value 4 as in 4GB. +const resourceCount = Math.min(navigator.hardwareConcurrency, memory, 10); + +/** + * Maximum download tasks to be run in parallel, for low end devices we expect + * the result to be 2, higher end devices we expect to be at least 4, but no + * more than 5. + */ +export const MAXIMUM_IN_PARALLEL = resourceCount / 2; +console.warn(`Image Loader maximum parallel tasks: ${MAXIMUM_IN_PARALLEL}`); /** * Scheduler for ImageRequestTask objects. Fetches tasks from a queue and
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index 83f201c..e2d6494 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc
@@ -1183,8 +1183,9 @@ // Note that |new_shape.glyph_to_char| is indexed from the beginning of // |range|, while |shape.glyph_to_char| is indexed from the beginning of // its embedding text. - for (size_t i = 0; i < shape.glyph_to_char.size(); ++i) - shape.glyph_to_char[i] += range.start(); + for (auto& glyph_to_char : shape.glyph_to_char) { + glyph_to_char += range.start(); + } } }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index a4bfc58..a14ebf3 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -8,7 +8,7 @@ import("//build/config/ozone.gni") import("//build/config/ui.gni") import("//build/nocompile.gni") -import("//components/metrics/generate_histograms_variants_allowlist.gni") +import("//components/metrics/generate_allowlist_from_histograms_file.gni") import("//components/vector_icons/vector_icons.gni") import("//skia/features.gni") import("//testing/test.gni") @@ -58,9 +58,10 @@ ] } -generate_histograms_variants_allowlist("bubble_histograms_variant") { +generate_allowlist_from_histograms_file("bubble_histograms_variant") { namespace = "views_metrics" input_xml_file = "//tools/metrics/histograms/metadata/views/histograms.xml" + tag = "variant" output_file = "bubble_histograms_variant.h" allow_list_name = "BubbleName" }
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index b71aa33..406b1c8 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -909,7 +909,7 @@ bubble_name.value())) { return; } - } else if (!views_metrics::IsValidBubbleNameVariant(bubble_name.value())) { + } else if (!views_metrics::IsValidBubbleName(bubble_name.value())) { return; }
diff --git a/ui/webui/resources/cr_components/commerce/browser_proxy.ts b/ui/webui/resources/cr_components/commerce/browser_proxy.ts index d9840ed..34edd193 100644 --- a/ui/webui/resources/cr_components/commerce/browser_proxy.ts +++ b/ui/webui/resources/cr_components/commerce/browser_proxy.ts
@@ -29,6 +29,7 @@ getPriceTrackingStatusForCurrentUrl(): Promise<{tracked: boolean}>; setPriceTrackingStatusForCurrentUrl(track: boolean): void; openUrlInNewTab(url: Url): void; + switchToOrOpenTab(url: Url): void; getParentBookmarkFolderNameForCurrentUrl(): Promise<{name: String16}>; showBookmarkEditorForCurrentUrl(): void; showFeedback(): void; @@ -128,6 +129,10 @@ this.handler.openUrlInNewTab(url); } + switchToOrOpenTab(url: Url) { + this.handler.switchToOrOpenTab(url); + } + getParentBookmarkFolderNameForCurrentUrl() { return this.handler.getParentBookmarkFolderNameForCurrentUrl(); }
diff --git a/ui/webui/resources/cr_components/commerce/shopping_service.mojom b/ui/webui/resources/cr_components/commerce/shopping_service.mojom index 5c13d93..24bd7f7 100644 --- a/ui/webui/resources/cr_components/commerce/shopping_service.mojom +++ b/ui/webui/resources/cr_components/commerce/shopping_service.mojom
@@ -199,9 +199,12 @@ // Sets the price tracking status of the current URL. SetPriceTrackingStatusForCurrentUrl(bool track); - // Open url in a new tab. + // Opens url in a new tab. OpenUrlInNewTab(url.mojom.Url url); + // Opens |url| in an existing or new tab. + SwitchToOrOpenTab(url.mojom.Url url); + // Returns the name of the parent bookmark folder of the current URL. This // will only be called when the current page is bookmarked. GetParentBookmarkFolderNameForCurrentUrl() => (mojo_base.mojom.String16 name);
diff --git a/v8 b/v8 index 5ce5de1..1d5b469 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 5ce5de190d00a6d32b6d15f89d169bcf7d70e3be +Subproject commit 1d5b4690a511c9a6c44ee270a11681a4d23c0eb9