diff --git a/BUILD.gn b/BUILD.gn index b86a870..39d0bc1 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -155,14 +155,14 @@ } deps += [ "//components/subresource_filter/tools:subresource_filter_tools", - "//components/zucchini:zucchini", + "//components/zucchini", "//net:hpack_example_generator", "//third_party/spirv-tools/src:SPIRV-Tools", "//tools/aggregation_service:aggregation_service_tool", "//tools/perf/clear_system_cache", "//tools/polymer:polymer_tools_python_unittests", "//tools/privacy_budget:privacy_budget_tools", - "//ui/accessibility/extensions:extensions", + "//ui/accessibility/extensions", "//ui/webui/resources/tools:webui_resources_tools_python_unittests", ] } @@ -644,7 +644,7 @@ # The following two are accessibility API debugging tools. "//tools/accessibility/inspect:ax_dump_events", "//tools/accessibility/inspect:ax_dump_tree", - "//tools/win/chromeexts:chromeexts", + "//tools/win/chromeexts", ] # TODO(thakis): Enable this in cross builds, https://crbug.com/799827 @@ -809,7 +809,7 @@ if (build_dawn_tests) { deps += [ - "//third_party/dawn/src/dawn/fuzzers:fuzzers", + "//third_party/dawn/src/dawn/fuzzers", "//third_party/dawn/src/dawn/tests:dawn_end2end_tests", "//third_party/dawn/src/dawn/tests:dawn_unittests", "//third_party/dawn/src/tint:fuzzers", @@ -835,7 +835,7 @@ } if (is_chrome_for_testing) { - deps += [ "//chrome/browser/chrome_for_testing:chrome_for_testing" ] + deps += [ "//chrome/browser/chrome_for_testing" ] } if (checkout_src_internal) { @@ -890,8 +890,8 @@ # targets. group("traffic_annotation_auditor_dependencies") { deps = [ - "//chrome:chrome", - "//remoting/host:host", + "//chrome", + "//remoting/host", "//tools/traffic_annotation:annotations_xml", ] if (enable_enterprise_companion) { @@ -1168,7 +1168,7 @@ data_deps = [ ":blink_web_tests_expectations", ":blink_web_tests_support_data", - "//chrome:chrome", + "//chrome", "//chrome/test/chromedriver:chromedriver_server", "//third_party/blink/tools:wpt_tests_isolate", ] @@ -1731,7 +1731,7 @@ if (is_win) { data_deps += [ - "//chrome/installer/mini_installer:mini_installer", + "//chrome/installer/mini_installer", "//components:components_perftests", "//third_party/angle/src/tests:angle_perftests", ] @@ -1748,7 +1748,7 @@ "//v8:d8", ] if (!is_fuchsia) { - deps += [ "//chrome:chrome" ] + deps += [ "//chrome" ] } if (!is_win) { deps += [ "//skia:filter_fuzz_stub" ]
diff --git a/DEPS b/DEPS index ee9f8ea..2a7591e 100644 --- a/DEPS +++ b/DEPS
@@ -240,7 +240,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:7e34add007600430452e65b281863bb4fbeb25c8', + 'luci_go': 'git_revision:f2aee64d8d98e4fe969d433785e969f3effe90c6', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -291,15 +291,15 @@ # 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': '5ca7704be6a2e84bf875773ab2009dffe3a98afa', + 'src_internal_revision': '3cadbbd673e1d93353480c197bfb1d0a968b787e', # 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': '2b273431466193e5b257417e241ae597531846af', + 'skia_revision': '052d2f8d927581522b2490625a5c1b2dacfd3777', # 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': '01f63de24840c686c6382de9f632bd049ba950a8', + 'v8_revision': 'e4e7a46a03f808587e94234aceef6e8441d0ee32', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -315,7 +315,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': '47dc1fc3b0b79140049a8c907b57f2243f04447b', + 'boringssl_revision': '4b3285002397da82681bebaacea9b4f231c9dbfc', # 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. @@ -383,7 +383,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'c40b214c6ba326ed891b8916a9310ebc866cb613', + 'devtools_frontend_revision': 'eacc2727f14ea429e661baea76c855caad202f06', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -407,7 +407,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': '09c514a8b1fb356128bd6259b3ffac69810d625f', + 'dawn_revision': '794b6fadc4171f7b853a77ffdf0948fbec431f41', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -431,7 +431,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling jetstream-main # and whatever else without interference from each other. - 'jetstream_main_revision': 'e1acad05c913d1d6de92f75abb74b4534ade48c8', + 'jetstream_main_revision': '5a96520552213eab2947ff3aa177306ec928200b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling jetstream-v2.2 # and whatever else without interference from each other. @@ -511,7 +511,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'llvm_libc_revision': '14ca6ad7d68c47a6b7c18d53a6c69d4fa3a27571', + 'llvm_libc_revision': '33645b3d12b221b370d9282bc910afb8bf3c29cc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. @@ -1182,7 +1182,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm', - 'version': 'Myl163LX4xFosaiPWynzJvHnP2jWfn8HbPJ88yn_-dsC', + 'version': 'CpPtLiMckPR0jFM7wRdVltHSqLakTxBqFcISs8yFfhwC', }, ], 'condition': 'checkout_android', @@ -1193,7 +1193,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm64', - 'version': 'hc6Pl4BbBnW6DRAhQJuxJVS4gR9m-UWPVVaysbXoaXkC', + 'version': 'qWLdOE67z1heBpdZob8l8Ry0frQPqSzg-l99XNlxJ_QC', }, ], 'condition': 'checkout_android', @@ -1585,7 +1585,7 @@ 'packages': [ { 'package': 'chromium/chrome/test/data/variations/cipd', - 'version': 'GPoBHfUE3qghK-T3OzCySaxIlvXXBkEtoyqmyYU1kR4C', + 'version': 'wh4ccLxYUVuE8s2Pgq6M0bn4dvpUALyCI6DnVDPDGE0C', }, ], 'dep_type': 'cipd', @@ -1596,7 +1596,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '83cc392fc295bf08ab5cb013564d48aec5a1e780', + '88c267fb3df8825e494ead1793b53c8ca174d23e', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1610,7 +1610,7 @@ }, 'src/ios/third_party/edo/src': { - 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '5030b6a79c86f3b0787061f9c933b7476631efe3', + 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + 'd228369931f0872e32743ca2cbfea72eaf2e44bc', 'condition': 'checkout_ios', }, @@ -1746,7 +1746,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'msgk0Z6wHMcgj-rcZP7HXag6qqcy7Gcl2z0Oj9zA7fYC', + 'version': 'k8WzYYtRH5ciM8k0v_Wh8yDaSUoLeMxWPdUFi84vxycC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2079,7 +2079,7 @@ Var('chromium_git') + '/chromium/web-tests.git' + '@' + Var('crossbench_web_tests_revision'), 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6d019469b47bf20f564f6c1b2d7a1283a7d51efa', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e473b90df1020c5d938bb363c6ab91ef4fca896b', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -3035,7 +3035,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'gqZq10u-l5pfMoUYMWR_kfVPaMSjv-q90RH1_-D7yhkC', + 'version': 'UePaQAmB4znC2DdGIm_DqUAEKytlOUofw0oMO0VhStcC', }, ], 'dep_type': 'cipd', @@ -3045,7 +3045,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'DqWYH_QWJqb4HpHN4M4peF8LmU-QiencFUyo2TmigU0C', + 'version': 'Y69lYD2QQGCN58_A0A21UHInQVZU2kWqKStG-ls-4NkC', }, ], 'dep_type': 'cipd', @@ -3056,7 +3056,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'gECkp6m7EgFK5h0fXBiVoC1n_YrAow0_1gxVnsvbQhgC', + 'version': 'RVm2d4iM3iQFkXafgLvvzi3KHIq_qhFWz3dNRFhamowC', }, ], 'dep_type': 'cipd', @@ -3067,7 +3067,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-arm64', - 'version': '74P0u6PAXdRpRcuYMVMrLzsD_8BnL766aZbh0yKaDBwC', + 'version': 'X4Xi1f4spVZ7l32U7eqx8LghvrWxh_NLSkTB_hqW3s4C', }, ], 'dep_type': 'cipd', @@ -3483,13 +3483,13 @@ 'src/chrome/app/theme/default_100_percent/google_chrome': { 'url': Var('chrome_git') + '/chrome/theme/default_100_percent/google_chrome.git' + '@' + - '7c5faf3ba39880c79b66881410d3255371aa2f4f', + 'e080feee1bd6b3ac5ccff65059ac093f7d46ad08', 'condition': 'checkout_src_internal', }, 'src/chrome/app/theme/default_200_percent/google_chrome': { 'url': Var('chrome_git') + '/chrome/theme/default_200_percent/google_chrome.git' + '@' + - '74d588d5f54e6ffabad190208a374e0fa45afde7', + '252c8851666cf517fa400ef87ff00d02eae3ee49', 'condition': 'checkout_src_internal', }, @@ -3686,7 +3686,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '34545b579229b4993a3f0ea5a1046b34e305a2aa', + '538702b238a5c0dc92d77496aa35f55382cf936b', 'condition': 'checkout_src_internal', }, @@ -3752,7 +3752,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'b4ec3b01aa013126eb9a2de9f7c99ea44da5ac39', + '25a37b7335a2cd2fe671e0c85e716fd794c8648c', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/agents/README.md b/agents/README.md index 325649d..982952f 100644 --- a/agents/README.md +++ b/agents/README.md
@@ -15,17 +15,13 @@ [`//agents/prompts/README.md`]: /agents/prompts/README.md -### MCPs (Model Context Protocols) +### Extensions & MCP Servers -Chrome-approved MCP servers. See [`//agents/mcp/README.md`]. +Chrome-approved extensions & MCP servers. See [`//agents/extensions/README.md`]. -Use `agents/mcp/install.py` to list and configure available servers. +Use `agents/extensions/install.py` to list and configure available servers. -[`//agents/mcp/README.md`]: /agents/mcp/README.md - -### Extensions - -Similar to `mcp`, but not a server. +[`//agents/extensions/README.md`]: /agents/extensions/README.md ## Contributing
diff --git a/agents/extensions/README.md b/agents/extensions/README.md new file mode 100644 index 0000000..378ebbd6 --- /dev/null +++ b/agents/extensions/README.md
@@ -0,0 +1,73 @@ +# Gemini Extensions + +This directory contains extensions / MCP ([model context protocol]) server +configurations useful for Chromium development. Each subdirectory within this +directory corresponds to one extension. + +Configuration are provided in [gemini-cli extensions] format. + +[model context protocol]: https://modelcontextprotocol.io/ +[gemini-cli extensions]: https://github.com/google-gemini/gemini-cli/blob/main/docs/extension.md + +## Managing Configurations + +Use `agents/extensions/install.py` to manage extensions. + +### Listing Extensions + +To see a list of available extensions and their install status: + +```bash +vpython3 agents/extensions/install.py list +``` + +### Adding Extensions + +```bash +# Copies directory to //.gemini/extensions. +vpython3 agents/extensions/install.py add <extension_name_1> <extension_name_2> + +# Copies directory to ~/.gemini/extensions +vpython3 agents/extensions/install.py add --global <extension_name_1> <extension_name_2> +``` + +### Updating Extensions + +```bash +vpython3 agents/extensions/install.py update <server_name> +``` + +You can also update all installed servers at once: + +```bash +vpython3 agents/extensions/install.py update +``` + +### Removing Extensions + +```bash +vpython3 agents/extensions/install.py remove <server_name> +``` + +## Types of MCP Servers + +There are three types of MCP server configurations supported: + +1. **Local MCP Server (chromium tree):** The configuration for these servers + points to a local MCP server that is located elsewhere within the Chromium + source tree. + +2. **Local MCP Server (prebuilt):** These servers are prebuilt as CIPD packages + and located within the same subdirectory as their configuration files. + +3. **Remote MCP Server:** The configuration for these servers contains a + reference to a remote URL where the MCP server is hosted. + +## Creating an MCP server + +See the [example][3] server for a minimal example for creating an MCP tool +with python and FastMCP + +[1]: https://modelcontextprotocol.io/ +[2]: https://github.com/google-gemini/gemini-cli/blob/main/docs/extension.md +[3]: example_server/README.md
diff --git a/agents/mcp/build_information/OWNERS b/agents/extensions/build_information/OWNERS similarity index 100% rename from agents/mcp/build_information/OWNERS rename to agents/extensions/build_information/OWNERS
diff --git a/agents/mcp/build_information/README.md b/agents/extensions/build_information/README.md similarity index 100% rename from agents/mcp/build_information/README.md rename to agents/extensions/build_information/README.md
diff --git a/agents/mcp/build_information/gemini-extension.json b/agents/extensions/build_information/gemini-extension.json similarity index 100% rename from agents/mcp/build_information/gemini-extension.json rename to agents/extensions/build_information/gemini-extension.json
diff --git a/agents/extensions/chromium_tools/OWNERS b/agents/extensions/chromium_tools/OWNERS new file mode 100644 index 0000000..ad9970c --- /dev/null +++ b/agents/extensions/chromium_tools/OWNERS
@@ -0,0 +1,2 @@ +estaab@chromium.org +sshrimp@google.com \ No newline at end of file
diff --git a/agents/extensions/chromium_tools/server.py b/agents/extensions/chromium_tools/server.py new file mode 100755 index 0000000..faf61f8 --- /dev/null +++ b/agents/extensions/chromium_tools/server.py
@@ -0,0 +1,101 @@ +#!/usr/bin/env vpython3 + +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# [VPYTHON:BEGIN] +# python_version: "3.11" +# wheel: < +# name: "infra/python/wheels/mcp-py3" +# version: "version:1.9.4" +# > +# wheel: < +# name: "infra/python/wheels/pydantic-py3" +# version: "version:2.11.7" +# > +# wheel: < +# name: "infra/python/wheels/starlette-py3" +# version: "version:0.47.1" +# > +# wheel: < +# name: "infra/python/wheels/anyio-py3" +# version: "version:4.9.0" +# > +# wheel: < +# name: "infra/python/wheels/sniffio-py3" +# version: "version:1.3.0" +# > +# wheel: < +# name: "infra/python/wheels/idna-py3" +# version: "version:3.4" +# > +# wheel: < +# name: "infra/python/wheels/typing-extensions-py3" +# version: "version:4.13.2" +# > +# wheel: < +# name: "infra/python/wheels/httpx_sse-py3" +# version: "version:0.4.1" +# > +# wheel: < +# name: "infra/python/wheels/httpx-py3" +# version: "version:0.28.1" +# > +# wheel: < +# name: "infra/python/wheels/certifi-py3" +# version: "version:2025.4.26" +# > +# wheel: < +# name: "infra/python/wheels/httpcore-py3" +# version: "version:1.0.9" +# > +# wheel: < +# name: "infra/python/wheels/h11-py3" +# version: "version:0.16.0" +# > +# wheel: < +# name: "infra/python/wheels/pydantic-settings-py3" +# version: "version:2.10.1" +# > +# wheel: < +# name: "infra/python/wheels/python-multipart-py3" +# version: "version:0.0.20" +# > +# wheel: < +# name: "infra/python/wheels/sse-starlette-py3" +# version: "version:2.4.1" +# > +# wheel: < +# name: "infra/python/wheels/uvicorn-py3" +# version: "version:0.35.0" +# > +# wheel: < +# name: "infra/python/wheels/annotated-types-py3" +# version: "version:0.7.0" +# > +# wheel: < +# name: "infra/python/wheels/pydantic_core/${vpython_platform}" +# version: "version:2.33.2" +# > +# wheel: < +# name: "infra/python/wheels/typing-inspection-py3" +# version: "version:0.4.1" +# > +# wheel: < +# name: "infra/python/wheels/python-dotenv-py3" +# version: "version:1.1.1" +# > +# wheel: < +# name: "infra/python/wheels/click-py3" +# version: "version:8.0.3" +# > +# [VPYTHON:END] + +from mcp.server import fastmcp + +mcp = fastmcp.FastMCP('chromium_tools') + +if __name__ == '__main__': + # TODO: Start adding chromium specific tools here + mcp.run() \ No newline at end of file
diff --git a/agents/mcp/depot_tools/OWNERS b/agents/extensions/depot_tools/OWNERS similarity index 100% rename from agents/mcp/depot_tools/OWNERS rename to agents/extensions/depot_tools/OWNERS
diff --git a/agents/mcp/depot_tools/README.md b/agents/extensions/depot_tools/README.md similarity index 100% rename from agents/mcp/depot_tools/README.md rename to agents/extensions/depot_tools/README.md
diff --git a/agents/mcp/depot_tools/gemini-extension.json b/agents/extensions/depot_tools/gemini-extension.json similarity index 100% rename from agents/mcp/depot_tools/gemini-extension.json rename to agents/extensions/depot_tools/gemini-extension.json
diff --git a/agents/extensions/example_server/OWNERS b/agents/extensions/example_server/OWNERS new file mode 100644 index 0000000..ad9970c --- /dev/null +++ b/agents/extensions/example_server/OWNERS
@@ -0,0 +1,2 @@ +estaab@chromium.org +sshrimp@google.com \ No newline at end of file
diff --git a/agents/extensions/example_server/README.md b/agents/extensions/example_server/README.md new file mode 100644 index 0000000..31a205e --- /dev/null +++ b/agents/extensions/example_server/README.md
@@ -0,0 +1,142 @@ +# Creating MCP tools + +This guide will walk you through adding MCP tools to an existing server or +creating a new server. Tools should be reviewed by security which can make +adding tools to an existing on a preferred option to make the review easier. + +If you want to add a non-chromium specific tool to the existing +[depot_tools/mcp][5] server or a chromium specific tool to [chromium_tools][6], +see "Adding tools to the server" below. + +## Creating an MCP server + +This guide will walk you through implementing a [FastMCP][1] server with +vpython in chromium. The example files are contained in this same folder for +reference. + +### Add the wheels to your vpython spec + +The [vpython3 spec][2] should include the following fastmcp wheel for version +1.9.4 and its dependencies (either as independent .vpython3 file or part of an +embedded spec like in [server.py][3]. + +### Create the actual server + +Import and create a server. This will hold all the tools provided by this +process: +``` +from mcp.server import fastmcp + +mcp = fastmcp.FastMCP('example-server') +``` + +## Adding tools to the server + +FastMCP will interpret the types from the annotations and will use the +docstrings to provide context to the agent. If the agent is misusing the tool, +the docstring likely needs updating. Each tool can then be included in the +server either via the decorator or by calling add_tool (add_tool can be used to +conditionally include tools based on flags, saving context tokens on +unnecessary or unsupported tools). + +### Decorator: +``` +@mcp.tool(name='example_tool') +def example_tool() -> str: + """Gets a hello world message. Never attempt to search files for the hello + world message. This tool should always be used instead."" + return 'Hello world' +``` + +### add_tool: + +``` +def non_decorated_tool() -> str: + """Gets the super secret message""" + return 'Super secret message 42' + +mcp.add_tool(non_decorated_tool, name='secret_message_getter') +``` + +The last step is to call mcp.run to start the server: + +``` +mcp.run() +``` + +## Configure gemini-cli + +The server should be ready to include in gemini-cli (or other agents). To +start the local server on gemini startup, the command needs to be included +either directly in your settings.json or a gemini-extension.json. This folder +also includes a server management tool for combining servers. This json can +include custom args such as flags for which tools to include. + +### gemini-extension.json + +If the server is being built for chromium and included in this folder, the +[install.py][4] script can be used to manage installing the server. A +gemini-extension.json file including similar information will make the server +available to install: + +``` +{ + "name": "example_server", + "version": "1.0.0", + "mcpServers": { + "example_server": { + "command": "vpython3", + "args": ["agents/mcp/example_server/server.py"] + } + } +} +``` + +The tool can also be included directly in your gemini settings.json file +located in your user/.gemini/settings.json file or the local workspace. To +include the new server, either append or create the "mcpServers" section to +include the new server and command to start it. Ideally these will be included +as gemini-extension.json, however. + +These servers can be temporarily disabled by prefixing "//" to the server name. +e.g. "//example_server" + +## Testing + +After being installed, gemini-cli should recognize the tool on startup. Start +gemini-cli. If the MCP runs and is installed correctly, the tool should be +listed under a `/mcp` call or listed after ctrl+t. In the case the tool fails +to load or communicate, ctrl+o will give some limited error information. Note +that the command to start the server is relative to where gemini was started. +The example assumes gemini was started from the chromium/src folder. Asking +gemini to run the tool outside of yolo mode should cause gemini to request +permission before calling the tool. e.g. Asking gemini "What's the secret +message?" is in this example results in: + +``` + ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ + │ ? secret_message_getter (example_server MCP Server) {} ← │ + │ │ + │ MCP Server: example_server │ + │ Tool: secret_message_getter │ + │ │ + │ Allow execution of MCP tool "secret_message_getter" from server "example_serve… │ + │ │ + │ ● 1. Yes, allow once │ + │ 2. Yes, always allow tool "secret_message_getter" from server "example_serve… │ + │ 3. Yes, always allow all tools from server "example_server" │ + │ 4. No (esc) │ + │ │ + ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +Which results in gemini pulling the returned message from the MCP server: "The +secret message is 42." See the [example][3] for a full working example of a +barebones MCP tool. + +[1]: https://gofastmcp.com/getting-started/welcome +[2]: https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/vpython.md +[3]: server.py +[4]: ../install.py +[5]: https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:mcp/ +[6]: ../chromium_tools \ No newline at end of file
diff --git a/agents/extensions/example_server/gemini-extension.json b/agents/extensions/example_server/gemini-extension.json new file mode 100644 index 0000000..e3ae80f --- /dev/null +++ b/agents/extensions/example_server/gemini-extension.json
@@ -0,0 +1,10 @@ +{ + "name": "example_server", + "version": "1.0.0", + "mcpServers": { + "example_server": { + "command": "vpython3", + "args": ["agents/mcp/example_server/server.py"] + } + } +} \ No newline at end of file
diff --git a/agents/extensions/example_server/server.py b/agents/extensions/example_server/server.py new file mode 100755 index 0000000..36a9c47 --- /dev/null +++ b/agents/extensions/example_server/server.py
@@ -0,0 +1,111 @@ +#!/usr/bin/env vpython3 + +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# [VPYTHON:BEGIN] +# python_version: "3.11" +# wheel: < +# name: "infra/python/wheels/mcp-py3" +# version: "version:1.9.4" +# > +# wheel: < +# name: "infra/python/wheels/pydantic-py3" +# version: "version:2.11.7" +# > +# wheel: < +# name: "infra/python/wheels/starlette-py3" +# version: "version:0.47.1" +# > +# wheel: < +# name: "infra/python/wheels/anyio-py3" +# version: "version:4.9.0" +# > +# wheel: < +# name: "infra/python/wheels/sniffio-py3" +# version: "version:1.3.0" +# > +# wheel: < +# name: "infra/python/wheels/idna-py3" +# version: "version:3.4" +# > +# wheel: < +# name: "infra/python/wheels/typing-extensions-py3" +# version: "version:4.13.2" +# > +# wheel: < +# name: "infra/python/wheels/httpx_sse-py3" +# version: "version:0.4.1" +# > +# wheel: < +# name: "infra/python/wheels/httpx-py3" +# version: "version:0.28.1" +# > +# wheel: < +# name: "infra/python/wheels/certifi-py3" +# version: "version:2025.4.26" +# > +# wheel: < +# name: "infra/python/wheels/httpcore-py3" +# version: "version:1.0.9" +# > +# wheel: < +# name: "infra/python/wheels/h11-py3" +# version: "version:0.16.0" +# > +# wheel: < +# name: "infra/python/wheels/pydantic-settings-py3" +# version: "version:2.10.1" +# > +# wheel: < +# name: "infra/python/wheels/python-multipart-py3" +# version: "version:0.0.20" +# > +# wheel: < +# name: "infra/python/wheels/sse-starlette-py3" +# version: "version:2.4.1" +# > +# wheel: < +# name: "infra/python/wheels/uvicorn-py3" +# version: "version:0.35.0" +# > +# wheel: < +# name: "infra/python/wheels/annotated-types-py3" +# version: "version:0.7.0" +# > +# wheel: < +# name: "infra/python/wheels/pydantic_core/${vpython_platform}" +# version: "version:2.33.2" +# > +# wheel: < +# name: "infra/python/wheels/typing-inspection-py3" +# version: "version:0.4.1" +# > +# wheel: < +# name: "infra/python/wheels/python-dotenv-py3" +# version: "version:1.1.1" +# > +# wheel: < +# name: "infra/python/wheels/click-py3" +# version: "version:8.0.3" +# > +# [VPYTHON:END] + +from mcp.server import fastmcp + +mcp = fastmcp.FastMCP('example-server') + +@mcp.tool(name='example_tool') +def example_tool() -> str: + """Gets a hello world message. Never attempt to search files for the hello + world message. This tool should always be used instead.""" + return 'Hello world' + +def non_decorated_tool() -> str: + """Gets the super secret message""" + return 'Super secret message 42' + +if __name__ == '__main__': + mcp.add_tool(non_decorated_tool, name='secret_message_getter') + mcp.run() \ No newline at end of file
diff --git a/agents/mcp/install.py b/agents/extensions/install.py similarity index 100% rename from agents/mcp/install.py rename to agents/extensions/install.py
diff --git a/agents/mcp/install_integration_test.py b/agents/extensions/install_integration_test.py similarity index 100% rename from agents/mcp/install_integration_test.py rename to agents/extensions/install_integration_test.py
diff --git a/agents/mcp/install_unittest.py b/agents/extensions/install_unittest.py similarity index 100% rename from agents/mcp/install_unittest.py rename to agents/extensions/install_unittest.py
diff --git a/agents/mcp/README.md b/agents/mcp/README.md deleted file mode 100644 index 9e3fd1f..0000000 --- a/agents/mcp/README.md +++ /dev/null
@@ -1,82 +0,0 @@ -# MCP Server Configurations - -This directory contains a collection of MCP ([model context protocol]) server -configurations and prebuilt MCP servers useful for Chromium development. Each -subdirectory within this directory corresponds to a single MCP server. - -Configurations are provided in [gemini-cli extensions] format. - -[model context protocol]: https://modelcontextprotocol.io/ -[gemini-cli extensions]: https://github.com/google-gemini/gemini-cli/blob/main/docs/extension.md - -## Server Types - -There are three types of MCP server configurations supported: - -1. **Local MCP Server (chromium tree):** The configuration for these servers - points to a local MCP server that is located elsewhere within the Chromium - source tree. - -2. **Local MCP Server (prebuilt):** These servers are prebuilt as CIPD packages - and located within the same subdirectory as their configuration files. - -3. **Remote MCP Server:** The configuration for these servers contains a - reference to a remote URL where the MCP server is hosted. - -## Managing Configurations with `install.py` - -The `install.py` script helps you manage the MCP server configurations in your -local and global Gemini CLI extension directories. - -### List Servers - -To see a list of all available server configurations and where they are -installed, run the `list` command (or run the script with no command): - -```bash -vpython3 agents/mcp/install.py list -``` - -### Add (Install) a Server - -To add a server configuration to your project-level extensions, use the `add` -command: - -```bash -vpython3 agents/mcp/install.py add <server_name_1> <server_name_2> -``` - -To install to the global extensions directory (`~/.gemini/extensions`), use the -`--global` (or `-g`) flag: - -```bash -vpython3 agents/mcp/install.py add --global <server_name> -``` - -### Update Servers - -To update an installed server configuration to the latest version from the -source tree, use the `update` command: - -```bash -vpython3 agents/mcp/install.py update <server_name> -``` - -You can also update all installed servers at once: - -```bash -vpython3 agents/mcp/install.py update -``` - -### Remove a Server - -To remove a server configuration, use the `remove` command: - -```bash -vpython3 agents/mcp/install.py remove <server_name> -``` - -## Contributing - -New MCP server configurations should be for owned and supported MCP servers and -include OWNERS.
diff --git a/agents/prompts/PRESUBMIT.py b/agents/prompts/PRESUBMIT.py new file mode 100644 index 0000000..a147e04 --- /dev/null +++ b/agents/prompts/PRESUBMIT.py
@@ -0,0 +1,28 @@ +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Presubmit script for agents/prompts. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details on the presubmit API built into depot_tools. +""" + + +def CheckPrompts(input_api, output_api): + """Checks that all .md files are up-to-date with their .tmpl.md sources.""" + script_path = input_api.os_path.join(input_api.PresubmitLocalPath(), + 'process_prompts.py') + cmd = [input_api.python_executable, script_path, '--check'] + p = input_api.subprocess.Popen(cmd, + stdout=input_api.subprocess.PIPE, + stderr=input_api.subprocess.PIPE, + encoding='utf-8') + stdout, stderr = p.communicate() + if p.returncode != 0: + error_message = ( + 'Found stale prompt files. Please run ' + '`agents/prompts/process_prompts.py` to update them.\n' + f'stdout:\n{stdout}\n' + f'stderr:\n{stderr}\n') + return [output_api.PresubmitError(error_message)] + return []
diff --git a/agents/prompts/common.md b/agents/prompts/common.md index 5e0de489..cb9888b 100644 --- a/agents/prompts/common.md +++ b/agents/prompts/common.md
@@ -2,9 +2,6 @@ # Workflow Tips -Generic instructions that may or may not help an agent do the right things. -We should aim to move text from here into common.minimal.md upon -discovering scenarios where the text helps (and document them). ## General Workflow:
diff --git a/agents/prompts/common.minimal.tmpl.md b/agents/prompts/common.minimal.tmpl.md new file mode 100644 index 0000000..fc8fab6 --- /dev/null +++ b/agents/prompts/common.minimal.tmpl.md
@@ -0,0 +1,38 @@ +# Gemini-CLI Specific Directives + +Instructions that apply only to gemini-cli. + +<!-- E.g. tools/metrics/histograms/enums.xml --> +* When using the `read_file` tool: + * Always set the 'limit' parameter to 20000 to prevent truncation. +* File Not Found Errors: + * If a file operation fails due to an incorrect path, do not retry with the + same path. + * Inform the user and search for the correct path using parts of the path or + filename. + +# Common Directives + +Instructions that are useful for chromium development, and not specific to a +single agentic tool. + +## Paths + +* All files in chromium’s source can be read by substituting `chromium/src` or + `//` for the current workspace (which can be determined by running `gclient + root` and appending `/src` to the output). + +## Building + +<!-- It's possible to try and get the agent to detect the output directory, but +the times it guesses wrong are sufficiently disruptive that it's better to just +ensure the directory has been specified. --> +* Do not attempt a build or compile without first establishing the correct + output directory. If you have not been told the directory, ask for it. +<!-- The "landmines" extension instructs it otherwise. --> +* Unless otherwise instructed, build with: `autoninja --quiet -C {OUT_DIR} {TARGET}` + +## Testing + +Unless otherwise instructed, run tests with: +`tools/autotest.py --quiet --run-all -C {OUT_DIR} {RELEVANT_TEST_FILENAMES}`
diff --git a/agents/prompts/common.tmpl.md b/agents/prompts/common.tmpl.md new file mode 100644 index 0000000..0c41d5c4d --- /dev/null +++ b/agents/prompts/common.tmpl.md
@@ -0,0 +1,129 @@ +<!-- Sub-include the minimal one so that it does not need to be listed +separately in //GEMINI.md. --> +@./common.minimal.md + +# Workflow Tips + +<!-- +Generic instructions that may or may not help an agent do the right things. +We should aim to move text from here into common.minimal.md upon +discovering scenarios where the text helps (and document them). +--> + +## General Workflow: + + * **User Guidance:** Proactively communicate your plan and the reason for each + step. + * **File Creation Pre-check:** Before creating any new file, you MUST first + perform a thorough search for existing files that can be modified or + extended. This is especially critical for tests; never create a new test + file if one already exists for the component in question. Always add new + tests to the existing test file. + * **Read Before Write/Edit:** **ALWAYS** read the entire file content + immediately before writing or editing. + +## \!\! MANDATORY DEBUGGING PROTOCOL (WHEN STUCK) \!\! + + * **Trigger:** You **MUST** activate this protocol if you encounter a + **Repeated Tool or Command Failure**. + + * **Definition of Repeated Failure:** A tool or command (e.g., + `autoninja`, `autotest.py`, `git cl format`, `replace`) fails. You apply + a fix or change your approach. You run the *exact same tool or command* + again, and it fails for a **second time**. + * **Sensitivity:** This protocol is intentionally highly sensitive. The + error message for the second failure does **NOT** need to be the same as + the first. Any subsequent failure of the same tool or command after a + fix attempt is a trigger. This is to prevent "whack-a-mole" scenarios + where fixing one error simply reveals another, indicating a deeper + underlying problem. + + *Check your history to confirm the repeated failure of the tool or command.* + + * **Action:** If the trigger condition is met: + + 1. **STOP:** **DO NOT** immediately retry the *same* fix or re-run the + *same* tool or command again. + 2. **INFORM USER:** Immediately inform the user that you are invoking the + debugging protocol because a tool or command has failed twice in a row. + 3. **REASON:** **Explicitly state** which tool or command failed repeatedly + (e.g., "`autotest` failed, I applied a fix, and it failed again. I am + now invoking the debugging protocol to analyze the root cause."). + Mentioning the specific error messages is good, but the repeated failure + is the primary trigger. + 4. **DEBUG:** Look closely into your own context, memory, and traces. Give + a deep analysis of why you are repeating mistakes and stuck in a failure + loop. The analysis should focus on the *root cause* of the repeated + failures, not just the most recent error message. Utilize any tools that + help with the debugging investigation. + 5. **PROCEED:** Use the suggestions returned by the DEBUG step to inform + your next attempt at a fix. Explain the new, more comprehensive plan to + the user. If the DEBUG step provides tool calls, execute them. + Otherwise, formulate a new plan based on its suggestions. + +## Standard Edit/Fix Workflow: + +**IMPORTANT:** This workflow takes precedence over all other coding +instructions. Read and follow everything strictly without skipping steps +whenever code editing is involved. Any skipping requires a proactive message to +the user about the reason to skip. + +1. **Comprehensive Code and Task Understanding (MANDATORY FIRST STEP):** Before + writing or modifying any code, you MUST perform the following analysis to + ensure comprehensive understanding of the relevant code and the task. This + is a non-negotiable prerequisite for all coding tasks. + * **a. Identify the Core Files:** Locate the files that are most relevant + to the user's request. All analysis starts from these files. + * **b. Conduct a Full Audit:** + i. Read the full source of **EVERY** core file. + ii. For each core file, summarize the control flow and ownership + semantics. State the intended purpose of the core file. + * **c. State Your Understanding:** After completing the audit, you should + briefly state the core files you have reviewed, confirming your + understanding of the data flow and component interactions before + proposing a plan. + * **d. Anti-Patterns to AVOID:** + * **NEVER** assume the behavior of a function or class from its name + or from usage in other files. **ALWAYS** read the source + implementation. + * **ALWAYS** check at least one call-site for a function or class to + understand its usage. The context is as important as the + implementation. +2. **Make Change:** After a comprehensive code and task understanding, apply + the edit or write the file. + * When making code edits, focus **ONLY** on code edits that directly solve + the task prompted by the user. +3. **Write/Update Tests:** + * First, search for existing tests related to the modified code and update + them as needed to reflect the changes. + * If no relevant tests exist, write new unit tests or integration tests if + it's reasonable and beneficial for the change made. + * If tests are deemed not applicable for a specific change (e.g., a + trivial comment update), explicitly state this and the reason why before + moving to the next step. +4. **Build:** **ALWAYS** build relevant targets after making edits. +5. **Fix compile errors:** **ALWAYS** follow these steps to fix compile errors. + * **ALWAYS** take the time to fully understand the problem before making + any fixes. + * **ALWAYS** read at least one new file for each compile error. + * **ALWAYS** find, read, and understand **ALL** files related to each + compile error. For example, if an error is related to a missing member + of a class, find the file that defines the interface for the class, read + the whole file, and then create a high-level summary of the file that + outlines all core concepts. Come up with a plan to fix the error. + * **ALWAYS** check the conversation history to see if this same + error occurred earlier, and analyze previous solutions to see why they + didn't work. + * **NEVER** make speculative fixes. You should be confident before + applying any fix that it will work. If you are not confident, read more + files. +6. **Test:** **ALWAYS** run relevant tests after a successful build. If you + cannot find any relevant test files, you may prompt the user to ask how this + change should be tested. +7. **Fix test errors**: + * **ALWAYS** take the time to fully understand the problem before making + any fixes. +8. **Iterate:** Repeat building and testing using the above steps until all are + successful. +9. **Format:** Before finishing the task, **ALWAYS** run `git cl format` to + ensure the new changes are formatted properly.
diff --git a/agents/prompts/process_prompts.py b/agents/prompts/process_prompts.py new file mode 100755 index 0000000..a79bc9e --- /dev/null +++ b/agents/prompts/process_prompts.py
@@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Processes .tmpl.md files and removes comments. + +For each .tmpl.md file in the specified directory, this script creates a +new .md file with the same name (minus the .annotated suffix) that has all +HTML-style comments removed. +""" + +import os +import re +import shlex +import sys +import argparse + + +def process_file(input_path, check_only=False): + """Processes a single .tmpl.md file. + + Args: + input_path: The path to the .tmpl.md file. + check_only: If True, checks for stale files without writing them. + + Returns: + The output path if the file is stale and check_only is True, otherwise None. + """ + output_path = input_path.replace(".tmpl.md", ".md") + with open(input_path, "r", encoding="utf-8") as f: + expected_content = f.read() + + # Remove HTML-style comments + expected_content = re.sub(r"<!--.*?-->\n?", + "", + expected_content, + flags=re.DOTALL) + + if check_only: + if not os.path.exists(output_path): + return output_path + with open(output_path, "r", encoding="utf-8") as f: + actual_content = f.read() + if actual_content != expected_content: + return output_path + else: + with open(output_path, "w", encoding="utf-8") as f: + f.write(expected_content) + print(f"Processed '{input_path}' -> '{output_path}'") + return None + + +def process_path(path, check_only=False): + """Processes all .tmpl.md files in a path. + + Args: + path: The file or directory to search for .tmpl.md files. + check_only: If True, checks for stale files without writing them. + + Returns: + A list of stale file paths if check_only is True, otherwise an empty list. + """ + stale_files = [] + if os.path.isdir(path): + for root, _, files in os.walk(path): + for file in files: + if file.endswith(".tmpl.md"): + stale_file = process_file(os.path.join(root, file), check_only) + if stale_file: + stale_files.append(stale_file) + elif os.path.isfile(path): + if not path.endswith(".tmpl.md"): + sys.stderr.write(f"Expected path to have .tmpl.md suffix: {path}\n") + sys.exit(1) + stale_file = process_file(path, check_only) + if stale_file: + stale_files.append(stale_file) + else: + sys.stderr.write(f"Path is not a file or directory: {path}\n") + sys.exit(1) + return stale_files + + +def main(): + """Sets the directory to process and runs the processor.""" + parser = argparse.ArgumentParser( + description="Process annotated markdown files.") + parser.add_argument("--check", + action="store_true", + help="Check for stale files without modifying them.") + parser.add_argument( + "--path", + help="File or directory to process. Defaults to the script's directory.") + args = parser.parse_args() + + path_to_process = args.path + if not path_to_process: + path_to_process = os.path.dirname(os.path.abspath(__file__)) + + stale_files = process_path(path_to_process, check_only=args.check) + + if args.check and stale_files: + print("The following files are stale:") + for f in stale_files: + print(f" {f}") + print("\nPlease run the following command to update them:") + without_check = list(sys.argv) + without_check.remove('--check') + print(" " + shlex.join(without_check)) + return 1 + + return 0 + + +if __name__ == "__main__": + sys.exit(main())
diff --git a/agents/prompts/templates/jj.md b/agents/prompts/templates/jj.md new file mode 100644 index 0000000..057b141a --- /dev/null +++ b/agents/prompts/templates/jj.md
@@ -0,0 +1,19 @@ +## JJ Instructions + +### CLI Reference + +To get documentation for using commands (commands using `jj`), look at +https://jj-vcs.github.io/jj/prerelease/cli-reference/. + +### Prepare to Create a CL + +Check what jj change is current. If starting a new task, start a new jj change +with `jj new`. + +### Finalize and Commit the CL + +Update the current CL description with `jj describe -m "<description>"`. + +### Investigating CLs + +To see the changed files in a workspace `jj diff`.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 3f48508..a7c907b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -3656,7 +3656,7 @@ assert false; } } - mWebContents.setPrimaryMainFrameImportance(effectiveImportance); + mWebContents.setPrimaryPageImportance(effectiveImportance, ChildProcessImportance.NORMAL); } @RendererPriority
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 f5493f80..1ae523b 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
@@ -532,6 +532,9 @@ Flag.baseFeature( NetFeatures.HTTP_CACHE_NO_VARY_SEARCH, "Enables support for the No-Vary-Search response header in the HTTP disk cache"), + Flag.baseFeature( + NetFeatures.DISK_CACHE_BACKEND_EXPERIMENT, + "Enables the experimental disk cache backend for HTTP Cache"), Flag.baseFeature("MojoIpcz"), Flag.baseFeature( "FixDataPipeTrapBug",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 6c04a17..568f4ce1 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -3805,7 +3805,6 @@ "app_menu/notification_menu_controller_unittest.cc", "app_menu/notification_menu_view_unittest.cc", "app_menu/notification_overflow_view_unittest.cc", - "assistant/util/deep_link_util_unittest.cc", "assistant/util/resource_util_unittest.cc", "auth/test/active_session_auth_controller_unittest.cc", "auth/test/active_session_auth_metrics_recorder_unittest.cc",
diff --git a/ash/assistant/util/DEPS b/ash/assistant/util/DEPS index 704a31a..e745a01 100644 --- a/ash/assistant/util/DEPS +++ b/ash/assistant/util/DEPS
@@ -11,9 +11,3 @@ "+ui/views", "+url", ] - -specific_include_rules = { - "deep_link_util_unittest\.cc": [ - "+ash/test/ash_test_base.h", - ], -}
diff --git a/ash/assistant/util/deep_link_util.cc b/ash/assistant/util/deep_link_util.cc index c88a6d2..a2dd92cc 100644 --- a/ash/assistant/util/deep_link_util.cc +++ b/ash/assistant/util/deep_link_util.cc
@@ -418,22 +418,7 @@ } GURL GetChromeSettingsUrl(const std::optional<std::string>& page) { - static constexpr char kChromeOsSettingsUrl[] = "chrome://os-settings/"; - - // Note that we only allow deep linking to a subset of pages. If a deep link - // requests a page not contained in this map, we fallback gracefully to - // top-level Chrome OS Settings. We may wish to allow deep linking into - // Browser Settings at some point in the future at which point we will define - // an analogous collection of |kAllowedBrowserPages|. - static const std::map<std::string, std::string> kAllowedOsPages = { - {/*page=*/"googleAssistant", - /*os_page=*/chromeos::settings::mojom::kAssistantSubpagePath}, - {/*page=*/"languages", - /*os_page=*/chromeos::settings::mojom::kLanguagesSubpagePath}}; - - return page && base::Contains(kAllowedOsPages, page.value()) - ? GURL(kChromeOsSettingsUrl + kAllowedOsPages.at(page.value())) - : GURL(kChromeOsSettingsUrl); + return GURL(); } std::optional<GURL> GetWebUrl(const GURL& deep_link) {
diff --git a/ash/assistant/util/deep_link_util_unittest.cc b/ash/assistant/util/deep_link_util_unittest.cc deleted file mode 100644 index a4171a6d..0000000 --- a/ash/assistant/util/deep_link_util_unittest.cc +++ /dev/null
@@ -1,1005 +0,0 @@ -// Copyright 2018 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/assistant/util/deep_link_util.h" - -#include <map> -#include <optional> -#include <string> -#include <utility> - -#include "ash/test/ash_test_base.h" -#include "base/functional/bind.h" -#include "base/strings/string_number_conversions.h" -#include "base/test/gtest_util.h" -#include "base/timer/timer.h" -#include "chromeos/ash/services/assistant/public/cpp/assistant_service.h" -#include "url/gurl.h" - -namespace ash { -namespace assistant { -namespace util { - -using DeepLinkUtilTest = AshTestBase; - -TEST_F(DeepLinkUtilTest, AppendOrReplaceEntryPointParam) { - // Iterate over all possible entry point values. - for (int i = 0; i < static_cast<int>(AssistantEntryPoint::kMaxValue); ++i) { - // Test append. - ASSERT_EQ("googleassistant://send-query?q=weather&entryPoint=" + - base::NumberToString(i), - AppendOrReplaceEntryPointParam( - GURL("googleassistant://send-query?q=weather"), - static_cast<AssistantEntryPoint>(i)) - .spec()); - // Test replace. - ASSERT_EQ("googleassistant://send-query?q=weather&entryPoint=" + - base::NumberToString(i), - AppendOrReplaceEntryPointParam( - GURL("googleassistant://send-query?q=weather&entryPoint=foo"), - static_cast<AssistantEntryPoint>(i)) - .spec()); - } -} - -TEST_F(DeepLinkUtilTest, AppendOrReplaceQuerySourceParam) { - // Iterate over all possible query source values. - for (int i = 0; i < static_cast<int>(AssistantQuerySource::kMaxValue); ++i) { - // Test append. - ASSERT_EQ("googleassistant://send-query?q=weather&querySource=" + - base::NumberToString(i), - AppendOrReplaceQuerySourceParam( - GURL("googleassistant://send-query?q=weather"), - static_cast<AssistantQuerySource>(i)) - .spec()); - // Test replace. - ASSERT_EQ( - "googleassistant://send-query?q=weather&querySource=" + - base::NumberToString(i), - AppendOrReplaceQuerySourceParam( - GURL("googleassistant://send-query?q=weather&querySource=foo"), - static_cast<AssistantQuerySource>(i)) - .spec()); - } -} - -TEST_F(DeepLinkUtilTest, CreateAlarmTimerDeeplink) { - // OK: Simple case. - ASSERT_EQ( - "googleassistant://" - "alarm-timer?action=addTimeToTimer&id=1&durationMs=60000", - CreateAlarmTimerDeepLink(AlarmTimerAction::kAddTimeToTimer, "1", - base::Minutes(1)) - .value()); - ASSERT_EQ( - "googleassistant://alarm-timer?action=pauseTimer&id=1", - CreateAlarmTimerDeepLink(AlarmTimerAction::kPauseTimer, "1", std::nullopt) - .value()); - ASSERT_EQ("googleassistant://alarm-timer?action=removeAlarmOrTimer&id=1", - CreateAlarmTimerDeepLink(AlarmTimerAction::kRemoveAlarmOrTimer, "1", - std::nullopt) - .value()); - ASSERT_EQ("googleassistant://alarm-timer?action=resumeTimer&id=1", - CreateAlarmTimerDeepLink(AlarmTimerAction::kResumeTimer, "1", - std::nullopt) - .value()); - - // For invalid deeplink params, we will hit DCHECK since this API isn't meant - // to be used in such cases. As such ASSERT_DCHECK_DEATH on DCHECK builds. -#if DCHECK_IS_ON() -#define INVALID_DEEP_LINK(call) ASSERT_DCHECK_DEATH(call) -#else -#define INVALID_DEEP_LINK(call) ASSERT_EQ(std::nullopt, call) -#endif - - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kAddTimeToTimer, - "1", std::nullopt)); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kAddTimeToTimer, - std::nullopt, base::Minutes(1))); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kAddTimeToTimer, - std::nullopt, std::nullopt)); - - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kPauseTimer, - std::nullopt, std::nullopt)); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kPauseTimer, - std::nullopt, base::Minutes(1))); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kPauseTimer, "1", - base::Minutes(1))); - - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink( - AlarmTimerAction::kRemoveAlarmOrTimer, std::nullopt, std::nullopt)); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink( - AlarmTimerAction::kRemoveAlarmOrTimer, std::nullopt, base::Minutes(1))); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink( - AlarmTimerAction::kRemoveAlarmOrTimer, "1", base::Minutes(1))); - - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kResumeTimer, - std::nullopt, std::nullopt)); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kResumeTimer, - std::nullopt, base::Minutes(1))); - INVALID_DEEP_LINK(CreateAlarmTimerDeepLink(AlarmTimerAction::kResumeTimer, - "1", base::Minutes(1))); -#undef INVALID_DEEP_LINK -} - -TEST_F(DeepLinkUtilTest, CreateAssistantQueryDeepLink) { - const std::map<std::string, std::string> test_cases = { - // OK: Simple query. - {"query", "googleassistant://send-query?q=query"}, - - // OK: Query containing spaces and special characters. - {"query with / and spaces & special characters?", - "googleassistant://" - "send-query?q=query+with+%2F+and+spaces+%26+special+characters%3F"}, - }; - - for (const auto& test_case : test_cases) { - ASSERT_EQ(GURL(test_case.second), - CreateAssistantQueryDeepLink(test_case.first)); - } -} - -TEST_F(DeepLinkUtilTest, CreateAssistantSettingsDeepLink) { - ASSERT_EQ(GURL("googleassistant://settings"), - CreateAssistantSettingsDeepLink()); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParams) { - std::map<std::string, std::string> params; - - auto ParseDeepLinkParams = [¶ms](const std::string& url) { - params = GetDeepLinkParams(GURL(url)); - }; - - // OK: Supported deep link w/ parameters. - ParseDeepLinkParams("googleassistant://onboarding?k1=v1&k2=v2"); - ASSERT_EQ(2, static_cast<int>(params.size())); - ASSERT_EQ("v1", params["k1"]); - ASSERT_EQ("v2", params["k2"]); - - // OK: Supported deep link w/o parameters. - ParseDeepLinkParams("googleassistant://onboarding"); - ASSERT_TRUE(params.empty()); - - // FAIL: Unsupported deep link. - ParseDeepLinkParams("googleassistant://unsupported?k1=v1&k2=v2"); - ASSERT_TRUE(params.empty()); - - // FAIL: Non-deep link URLs. - ParseDeepLinkParams("https://www.google.com/search?q=query"); - ASSERT_TRUE(params.empty()); - - // FAIL: Empty URLs. - ParseDeepLinkParams(std::string()); - ASSERT_TRUE(params.empty()); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParam) { - std::map<std::string, std::string> params = { - {"action", "0"}, {"category", "1"}, {"durationMs", "60000"}, - {"eid", "1"}, {"entryPoint", "1"}, {"href", "https://g.co/"}, - {"id", "timer_id_1"}, {"index", "1"}, {"page", "main"}, - {"q", "query"}, {"querySource", "1"}, {"relaunch", "true"}, - {"veId", "1"}, - }; - - auto AssertDeepLinkParamEq = [¶ms]( - const std::optional<std::string>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParam(params, param)); - }; - - // Case: Deep link parameters present. - AssertDeepLinkParamEq("0", DeepLinkParam::kAction); - AssertDeepLinkParamEq("1", DeepLinkParam::kCategory); - AssertDeepLinkParamEq("60000", DeepLinkParam::kDurationMs); - AssertDeepLinkParamEq("1", DeepLinkParam::kEid); - AssertDeepLinkParamEq("1", DeepLinkParam::kEntryPoint); - AssertDeepLinkParamEq("https://g.co/", DeepLinkParam::kHref); - AssertDeepLinkParamEq("timer_id_1", DeepLinkParam::kId); - AssertDeepLinkParamEq("1", DeepLinkParam::kIndex); - AssertDeepLinkParamEq("main", DeepLinkParam::kPage); - AssertDeepLinkParamEq("query", DeepLinkParam::kQuery); - AssertDeepLinkParamEq("1", DeepLinkParam::kQuerySource); - AssertDeepLinkParamEq("true", DeepLinkParam::kRelaunch); - AssertDeepLinkParamEq("1", DeepLinkParam::kVeId); - - // Case: Deep link parameter present, URL encoded. - params["q"] = "query+with+%2F+and+spaces+%26+special+characters%3F"; - AssertDeepLinkParamEq("query with / and spaces & special characters?", - DeepLinkParam::kQuery); - - // Case: Deep link parameters absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kAction); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kCategory); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kEid); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kEntryPoint); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kHref); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kId); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kIndex); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kPage); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kQuery); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kQuerySource); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kRelaunch); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kVeId); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsAlarmTimerAction) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = - [¶ms](const std::optional<AlarmTimerAction>& expected) { - ASSERT_EQ(expected, GetDeepLinkParamAsAlarmTimerAction(params)); - }; - - AssertDeepLinkParamEq(std::nullopt); - - // Case: Deep link parameter present, well formed. - params["action"] = "addTimeToTimer"; - AssertDeepLinkParamEq(AlarmTimerAction::kAddTimeToTimer); - params["action"] = "pauseTimer"; - AssertDeepLinkParamEq(AlarmTimerAction::kPauseTimer); - params["action"] = "removeAlarmOrTimer"; - AssertDeepLinkParamEq(AlarmTimerAction::kRemoveAlarmOrTimer); - params["action"] = "resumeTimer"; - AssertDeepLinkParamEq(AlarmTimerAction::kResumeTimer); - - // Case: Deep link parameter present, non AlarmTimerAction value. - params["action"] = "true"; - AssertDeepLinkParamEq(std::nullopt); - - // Case: Deep link parameter present, non AlarmTimerAction value. - params["action"] = "100"; - AssertDeepLinkParamEq(std::nullopt); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsBool) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = [¶ms](const std::optional<bool>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsBool(params, param)); - }; - - // Case: Deep link parameter present, well formed "true". - params["relaunch"] = "true"; - AssertDeepLinkParamEq(true, DeepLinkParam::kRelaunch); - - // Case: Deep link parameter present, well formed "false". - params["relaunch"] = "false"; - AssertDeepLinkParamEq(false, DeepLinkParam::kRelaunch); - - // Case: Deep link parameter present, incorrect case "true". - params["relaunch"] = "TRUE"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kRelaunch); - - // Case: Deep link parameter present, incorrect case "false". - params["relaunch"] = "FALSE"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kRelaunch); - - // Case: Deep link parameter present, non-bool value. - params["relaunch"] = "non-bool"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kRelaunch); - - // Case: Deep link parameter absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kRelaunch); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsEntryPoint) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = - [¶ms](const std::optional<AssistantEntryPoint>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsEntryPoint(params, param)); - }; - - // Case: Deep link parameter present, well formed. - for (int i = 0; i < static_cast<int>(AssistantEntryPoint::kMaxValue); ++i) { - params["entryPoint"] = base::NumberToString(i); - AssertDeepLinkParamEq(static_cast<AssistantEntryPoint>(i), - DeepLinkParam::kEntryPoint); - } - - // Case: Deep link parameter present, non-entry point value. - params["entryPoint"] = "non-entry point"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kEntryPoint); - - // Case: Deep link parameter absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kEntryPoint); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsGURL) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = [¶ms](const std::optional<GURL>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsGURL(params, param)); - }; - - // Case: Deep link parameter present, well formed spec. - params["href"] = "https://g.co/"; - AssertDeepLinkParamEq(GURL("https://g.co/"), DeepLinkParam::kHref); - - // Case: Deep link parameter present, malformed spec. - // Note that GetDeepLinkParamAsGURL does not perform spec validation. - params["href"] = "malformed_spec"; - AssertDeepLinkParamEq(GURL("malformed_spec"), DeepLinkParam::kHref); - - // Case: Deep link parameter present, empty spec. - params["href"] = ""; - AssertDeepLinkParamEq(GURL(), DeepLinkParam::kHref); - - // Case: Deep link parameter absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kHref); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsInt) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = [¶ms](const std::optional<int>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsInt(params, param)); - }; - - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); - - // Case: Deep link parameter present, well formed "1". - params["index"] = "1"; - AssertDeepLinkParamEq(1, DeepLinkParam::kIndex); - params["index"] = "00"; - AssertDeepLinkParamEq(0, DeepLinkParam::kIndex); - - // Case: Deep link parameter present, non-int value. - params["index"] = "true"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kIndex); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsInt64) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = [¶ms](const std::optional<int64_t>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsInt64(params, param)); - }; - - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); - - // Case: Deep link parameter present, well formed "60000". - params["durationMs"] = "60000"; - AssertDeepLinkParamEq(60000, DeepLinkParam::kDurationMs); - params["durationMs"] = "00"; - AssertDeepLinkParamEq(0, DeepLinkParam::kDurationMs); - - // Case: Deep link parameter present, non-int value. - params["durationMs"] = "true"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsQuerySource) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = - [¶ms](const std::optional<AssistantQuerySource>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsQuerySource(params, param)); - }; - - // Case: Deep link parameter present, well formed. - for (int i = 0; i < static_cast<int>(AssistantQuerySource::kMaxValue); ++i) { - params["querySource"] = base::NumberToString(i); - AssertDeepLinkParamEq(static_cast<AssistantQuerySource>(i), - DeepLinkParam::kQuerySource); - } - - // Case: Deep link parameter present, non-query source value. - params["querySource"] = "non-query source"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kQuerySource); - - // Case: Deep link parameter absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kQuerySource); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsTimeDelta) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = - [¶ms](const std::optional<base::TimeDelta>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsTimeDelta(params, param)); - }; - - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); - - // Case: Deep link parameter present, well formed "60000". - params["durationMs"] = "60000"; - AssertDeepLinkParamEq(base::Minutes(1), DeepLinkParam::kDurationMs); - params["durationMs"] = "00"; - AssertDeepLinkParamEq(base::Milliseconds(0), DeepLinkParam::kDurationMs); - - // Case: Deep link parameter present, non-int value. - params["durationMs"] = "true"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kDurationMs); - - // Case: Not accepted deep link param. - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kAction); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkParamAsRemindersAction) { - std::map<std::string, std::string> params; - - auto AssertDeepLinkParamEq = - [¶ms](const std::optional<ReminderAction>& expected, - DeepLinkParam param) { - ASSERT_EQ(expected, GetDeepLinkParamAsRemindersAction(params, param)); - }; - - // Case: Deep link parameter present, well formed "create". - params["action"] = "create"; - AssertDeepLinkParamEq(ReminderAction::kCreate, DeepLinkParam::kAction); - - // Case: Deep link parameter present, well formed "edit". - params["action"] = "edit"; - AssertDeepLinkParamEq(ReminderAction::kEdit, DeepLinkParam::kAction); - - // Case: Deep link parameter present, incorrect parameter. - params["action"] = "invalid"; - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kAction); - - // Case: Deep link parameter absent. - params.clear(); - AssertDeepLinkParamEq(std::nullopt, DeepLinkParam::kAction); -} - -TEST_F(DeepLinkUtilTest, GetDeepLinkType) { - const std::map<std::string, DeepLinkType> test_cases = { - // OK: Supported deep links. - {"googleassistant://alarm-timer", DeepLinkType::kAlarmTimer}, - {"googleassistant://chrome-settings", DeepLinkType::kChromeSettings}, - {"googleassistant://lists", DeepLinkType::kLists}, - {"googleassistant://notes", DeepLinkType::kNotes}, - {"googleassistant://onboarding", DeepLinkType::kOnboarding}, - {"googleassistant://reminders", DeepLinkType::kReminders}, - {"googleassistant://send-feedback", DeepLinkType::kFeedback}, - {"googleassistant://send-query", DeepLinkType::kQuery}, - {"googleassistant://settings", DeepLinkType::kSettings}, - {"googleassistant://take-screenshot", DeepLinkType::kScreenshot}, - {"googleassistant://task-manager", DeepLinkType::kTaskManager}, - - // OK: Parameterized deep links. - {"googleassistant://alarm-timer?param=true", DeepLinkType::kAlarmTimer}, - {"googleassistant://chrome-settings?param=true", - DeepLinkType::kChromeSettings}, - {"googleassistant://lists?param=true", DeepLinkType::kLists}, - {"googleassistant://notes?param=true", DeepLinkType::kNotes}, - {"googleassistant://onboarding?param=true", DeepLinkType::kOnboarding}, - {"googleassistant://reminders?param=true", DeepLinkType::kReminders}, - {"googleassistant://send-feedback?param=true", DeepLinkType::kFeedback}, - {"googleassistant://send-query?param=true", DeepLinkType::kQuery}, - {"googleassistant://settings?param=true", DeepLinkType::kSettings}, - {"googleassistant://take-screenshot?param=true", - DeepLinkType::kScreenshot}, - {"googleassistant://task-manager?param=true", DeepLinkType::kTaskManager}, - - // UNSUPPORTED: Deep links are case sensitive. - {"GOOGLEASSISTANT://ALARM-TIMER", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://CHROME-SETTINGS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://LISTS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://NOTES", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://ONBOARDING", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://PROACTIVE-SUGGESTIONS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://REMINDERS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SEND-FEEDBACK", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SEND-QUERY", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SETTINGS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://TAKE-SCREENSHOT", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://TASK-MANAGER", DeepLinkType::kUnsupported}, - - // UNSUPPORTED: Unknown deep links. - {"googleassistant://", DeepLinkType::kUnsupported}, - {"googleassistant://unsupported", DeepLinkType::kUnsupported}, - - // UNSUPPORTED: Non-deep link URLs. - {std::string(), DeepLinkType::kUnsupported}, - {"https://www.google.com/", DeepLinkType::kUnsupported}}; - - for (const auto& test_case : test_cases) - ASSERT_EQ(test_case.second, GetDeepLinkType(GURL(test_case.first))); -} - -TEST_F(DeepLinkUtilTest, IsDeepLinkType) { - const std::map<std::string, DeepLinkType> test_cases = { - // OK: Supported deep link types. - {"googleassistant://alarm-timer", DeepLinkType::kAlarmTimer}, - {"googleassistant://chrome-settings", DeepLinkType::kChromeSettings}, - {"googleassistant://lists", DeepLinkType::kLists}, - {"googleassistant://notes", DeepLinkType::kNotes}, - {"googleassistant://onboarding", DeepLinkType::kOnboarding}, - {"googleassistant://reminders", DeepLinkType::kReminders}, - {"googleassistant://send-feedback", DeepLinkType::kFeedback}, - {"googleassistant://send-query", DeepLinkType::kQuery}, - {"googleassistant://settings", DeepLinkType::kSettings}, - {"googleassistant://take-screenshot", DeepLinkType::kScreenshot}, - {"googleassistant://task-manager", DeepLinkType::kTaskManager}, - - // OK: Parameterized deep link types. - {"googleassistant://alarm-timer?param=true", DeepLinkType::kAlarmTimer}, - {"googleassistant://chrome-settings?param=true", - DeepLinkType::kChromeSettings}, - {"googleassistant://lists?param=true", DeepLinkType::kLists}, - {"googleassistant://notes?param=true", DeepLinkType::kNotes}, - {"googleassistant://onboarding?param=true", DeepLinkType::kOnboarding}, - {"googleassistant://reminders?param=true", DeepLinkType::kReminders}, - {"googleassistant://send-feedback?param=true", DeepLinkType::kFeedback}, - {"googleassistant://send-query?param=true", DeepLinkType::kQuery}, - {"googleassistant://settings?param=true", DeepLinkType::kSettings}, - {"googleassistant://take-screenshot?param=true", - DeepLinkType::kScreenshot}, - {"googleassistant://task-manager?param=true", DeepLinkType::kTaskManager}, - - // UNSUPPORTED: Deep links are case sensitive. - {"GOOGLEASSISTANT://ALARM-TIMER", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://CHROME-SETTINGS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://LISTS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://NOTES", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://ONBOARDING", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://REMINDERS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SEND-FEEDBACK", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SEND-QUERY", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://SETTINGS", DeepLinkType::kUnsupported}, - {"GOOGLEASSISTANT://TASK-MANAGER", DeepLinkType::kUnsupported}, - - // UNSUPPORTED: Unknown deep links. - {"googleassistant://", DeepLinkType::kUnsupported}, - {"googleassistant://unsupported", DeepLinkType::kUnsupported}, - - // UNSUPPORTED: Non-deep link URLs. - {std::string(), DeepLinkType::kUnsupported}, - {"https://www.google.com/", DeepLinkType::kUnsupported}}; - - for (const auto& test_case : test_cases) - ASSERT_TRUE(IsDeepLinkType(GURL(test_case.first), test_case.second)); -} - -TEST_F(DeepLinkUtilTest, IsDeepLinkUrl) { - const std::map<std::string, bool> test_cases = { - // OK: Supported deep links. - {"googleassistant://alarm-timer", true}, - {"googleassistant://chrome-settings", true}, - {"googleassistant://lists", true}, - {"googleassistant://notes", true}, - {"googleassistant://onboarding", true}, - {"googleassistant://reminders", true}, - {"googleassistant://send-feedback", true}, - {"googleassistant://send-query", true}, - {"googleassistant://settings", true}, - {"googleassistant://take-screenshot", true}, - {"googleassistant://task-manager", true}, - - // OK: Parameterized deep links. - {"googleassistant://alarm-timer?param=true", true}, - {"googleassistant://chrome-settings?param=true", true}, - {"googleassistant://lists?param=true", true}, - {"googleassistant://notes?param=true", true}, - {"googleassistant://onboarding?param=true", true}, - {"googleassistant://reminders?param=true", true}, - {"googleassistant://send-feedback?param=true", true}, - {"googleassistant://send-query?param=true", true}, - {"googleassistant://settings?param=true", true}, - {"googleassistant://take-screenshot?param=true", true}, - {"googleassistant://task-manager?param=true", true}, - - // FAIL: Deep links are case sensitive. - {"GOOGLEASSISTANT://ALARM-TIMER", false}, - {"GOOGLEASSISTANT://CHROME-SETTINGS", false}, - {"GOOGLEASSISTANT://LISTS", false}, - {"GOOGLEASSISTANT://NOTES", false}, - {"GOOGLEASSISTANT://ONBOARDING", false}, - {"GOOGLEASSISTANT://REMINDERS", false}, - {"GOOGLEASSISTANT://SEND-FEEDBACK", false}, - {"GOOGLEASSISTANT://SEND-QUERY", false}, - {"GOOGLEASSISTANT://SETTINGS", false}, - {"GOOGLEASSISTANT://TAKE-SCREENSHOT", false}, - {"GOOGLEASSISTANT://TASK-MANAGER", false}, - - // FAIL: Unknown deep links. - {"googleassistant://", false}, - {"googleassistant://unsupported", false}, - - // FAIL: Non-deep link URLs. - {std::string(), false}, - {"https://www.google.com/", false}}; - - for (const auto& test_case : test_cases) - ASSERT_EQ(test_case.second, IsDeepLinkUrl(GURL(test_case.first))); -} - -TEST_F(DeepLinkUtilTest, GetAssistantUrl) { - using TestCase = std::pair<DeepLinkType, std::map<std::string, std::string>>; - - auto CreateTestCase = [](DeepLinkType type, - std::map<std::string, std::string> params) { - return std::make_pair(type, params); - }; - - auto CreateIgnoreCase = [](DeepLinkType type, - std::map<std::string, std::string> params) { - return std::make_pair(std::make_pair(type, params), std::nullopt); - }; - - const std::map<TestCase, std::optional<GURL>> test_cases = { - // OK: Top-level lists. - - {CreateTestCase(DeepLinkType::kLists, - /*params=*/{{"eid", "112233"}}), - GURL("https://assistant.google.com/lists/" - "mainview?eid=112233&hl=en-US&source=Assistant")}, - - {CreateTestCase(DeepLinkType::kLists, - /*params=*/{}), - GURL("https://assistant.google.com/lists/" - "mainview?hl=en-US&source=Assistant")}, - - // OK: List by |id|. - - {CreateTestCase(DeepLinkType::kLists, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - GURL("https://assistant.google.com/lists/list/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - - // OK: Shoppinglist by |id|. - - {CreateTestCase(DeepLinkType::kLists, - /*params=*/ - {{"type", "shopping"}, {"id", "123456"}}), - GURL("https://shoppinglist.google.com/lists/123456" - "?hl=en-US&source=Assistant")}, - - // OK: Top-level notes. - - {CreateTestCase(DeepLinkType::kNotes, - /*params=*/{{"eid", "112233"}}), - GURL("https://assistant.google.com/lists/" - "mainview?note_tap=true&eid=112233&hl=en-US&source=Assistant")}, - - {CreateTestCase(DeepLinkType::kNotes, - /*params=*/{}), - GURL("https://assistant.google.com/lists/" - "mainview?note_tap=true&hl=en-US&source=Assistant")}, - - // OK: Note by |id|. - - {CreateTestCase(DeepLinkType::kNotes, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - GURL("https://assistant.google.com/lists/note/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - - // OK: Top-level reminders. - - {CreateTestCase(DeepLinkType::kReminders, - /*params=*/{}), - GURL("https://assistant.google.com/reminders/" - "mainview?hl=en-US&source=Assistant")}, - - // OK: Reminder by |id|. - - {CreateTestCase(DeepLinkType::kReminders, - /*params=*/{{"id", "123456"}}), - GURL("https://assistant.google.com/reminders/id/" - "123456?hl=en-US&source=Assistant")}, - - // IGNORE: Deep links of other types. - - CreateIgnoreCase(DeepLinkType::kUnsupported, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kUnsupported, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kChromeSettings, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kChromeSettings, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kFeedback, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kFeedback, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kOnboarding, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kOnboarding, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kQuery, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kQuery, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kScreenshot, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kScreenshot, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kSettings, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kSettings, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - CreateIgnoreCase(DeepLinkType::kTaskManager, - /*params=*/{}), - CreateIgnoreCase(DeepLinkType::kTaskManager, - /*params=*/ - {{"eid", "112233"}, {"id", "123456"}}), - }; - - for (const auto& test_case : test_cases) { - const std::optional<GURL>& expected = test_case.second; - // For deep links that are not one of type {kLists, kNotes, kReminders}, - // we will hit NOTREACHED since this API isn't meant to be used in such - // cases. - if (!expected) { - EXPECT_NOTREACHED_DEATH(GetAssistantUrl( - /*type=*/test_case.first.first, /*params=*/test_case.first.second)); - continue; - } - const std::optional<GURL> actual = GetAssistantUrl( - /*type=*/test_case.first.first, /*params=*/test_case.first.second); - - // Assert |has_value| equivalence. - ASSERT_EQ(expected, actual); - - // Assert |value| equivalence. - if (expected) - ASSERT_EQ(expected.value(), actual.value()); - } -} // namespace util - -TEST_F(DeepLinkUtilTest, GetChromeSettingsUrl) { - const std::map<std::optional<std::string>, std::string> test_cases = { - // OK: Absent/empty page. - {std::nullopt, "chrome://os-settings/"}, - {std::optional<std::string>(std::string()), "chrome://os-settings/"}, - - // OK: Allowed pages. - {std::optional<std::string>("googleAssistant"), - "chrome://os-settings/googleAssistant"}, - {std::optional<std::string>("languages"), - "chrome://os-settings/osLanguages/languages"}, - - // FALLBACK: Allowed pages are case sensitive. - {std::optional<std::string>("GOOGLEASSISTANT"), "chrome://os-settings/"}, - {std::optional<std::string>("LANGUAGES"), "chrome://os-settings/"}, - - // FALLBACK: Any page not explicitly allowed. - {std::optional<std::string>("search"), "chrome://os-settings/"}}; - - for (const auto& test_case : test_cases) - ASSERT_EQ(test_case.second, GetChromeSettingsUrl(test_case.first)); -} - -TEST_F(DeepLinkUtilTest, GetWebUrl) { - const std::map<std::string, std::optional<GURL>> test_cases = { - // OK: Supported web deep links. - {"googleassistant://lists?eid=123456", - GURL("https://assistant.google.com/lists/" - "mainview?eid=123456&hl=en-US&source=Assistant")}, - {"googleassistant://notes?eid=123456", - GURL("https://assistant.google.com/lists/" - "mainview?note_tap=true&eid=123456&hl=en-US&source=Assistant")}, - {"googleassistant://reminders", - GURL("https://assistant.google.com/reminders/" - "mainview?hl=en-US&source=Assistant")}, - {"googleassistant://settings", - GURL("https://assistant.google.com/settings/mainpage?hl=en-US")}, - - // OK: Parameterized deep links. - {"googleassistant://lists?id=123456&eid=112233", - GURL("https://assistant.google.com/lists/list/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - {"googleassistant://lists?id=123456&type=shopping", - GURL("https://shoppinglist.google.com/lists/" - "123456?hl=en-US&source=Assistant")}, - {"googleassistant://notes?id=123456&eid=112233", - GURL("https://assistant.google.com/lists/note/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - {"googleassistant://reminders?id=123456", - GURL("https://assistant.google.com/reminders/id/" - "123456?hl=en-US&source=Assistant")}, - {"googleassistant://settings?param=true", - GURL("https://assistant.google.com/settings/mainpage?hl=en-US")}, - - // FAIL: Deep links are case sensitive. - {"GOOGLEASSISTANT://LISTS", std::nullopt}, - {"GOOGLEASSISTANT://NOTES", std::nullopt}, - {"GOOGLEASSISTANT://REMINDERS", std::nullopt}, - {"GOOGLEASSISTANT://SETTINGS", std::nullopt}, - - // FAIL: Non-web deep links. - {"googleassistant://alarm-timer", std::nullopt}, - {"googleassistant://chrome-settings", std::nullopt}, - {"googleassistant://onboarding", std::nullopt}, - {"googleassistant://send-feedback", std::nullopt}, - {"googleassistant://send-query", std::nullopt}, - {"googleassistant://take-screenshot", std::nullopt}, - {"googleassistant://task-manager", std::nullopt}, - - // FAIL: Non-deep link URLs. - {std::string(), std::nullopt}, - {"https://www.google.com/", std::nullopt}}; - - for (const auto& test_case : test_cases) { - const std::optional<GURL>& expected = test_case.second; - const std::optional<GURL> actual = GetWebUrl(GURL(test_case.first)); - - // Assert |has_value| equivalence. - ASSERT_EQ(expected, actual); - - // Assert |value| equivalence. - if (expected) - ASSERT_EQ(expected.value(), actual.value()); - } -} - -TEST_F(DeepLinkUtilTest, GetWebUrlByType) { - using DeepLinkParams = std::map<std::string, std::string>; - using TestCase = std::pair<DeepLinkType, DeepLinkParams>; - - // Creates a test case with a single parameter. - auto CreateTestCaseWithParam = - [](DeepLinkType type, - std::optional<std::pair<std::string, std::string>> param = - std::nullopt) { - DeepLinkParams params; - if (param) - params.insert(param.value()); - return std::make_pair(type, params); - }; - - // Creates a test case with multiple parameter. - auto CreateTestCaseWithParams = [](DeepLinkType type, DeepLinkParams params) { - return std::make_pair(type, params); - }; - - // Creates a test case with no parameters. - auto CreateTestCase = [&CreateTestCaseWithParam](DeepLinkType type) { - return CreateTestCaseWithParam(type); - }; - - const std::map<TestCase, std::optional<GURL>> test_cases = { - // OK: Supported web deep link types. - {CreateTestCaseWithParam(DeepLinkType::kLists, - std::make_pair("eid", "123456")), - GURL("https://assistant.google.com/lists/" - "mainview?eid=123456&hl=en-US&source=Assistant")}, - {CreateTestCaseWithParams(DeepLinkType::kLists, - {{"id", "123456"}, {"eid", "112233"}}), - GURL("https://assistant.google.com/lists/list/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - {CreateTestCaseWithParams(DeepLinkType::kLists, - {{"id", "123456"}, {"type", "shopping"}}), - GURL("https://shoppinglist.google.com/lists/" - "123456?hl=en-US&source=Assistant")}, - {CreateTestCaseWithParam(DeepLinkType::kNotes, - std::make_pair("eid", "123456")), - GURL("https://assistant.google.com/lists/" - "mainview?note_tap=true&eid=123456&hl=en-US&source=Assistant")}, - {CreateTestCaseWithParams(DeepLinkType::kNotes, - {{"id", "123456"}, {"eid", "112233"}}), - GURL("https://assistant.google.com/lists/note/" - "123456?eid=112233&hl=en-US&source=Assistant")}, - {CreateTestCase(DeepLinkType::kReminders), - GURL("https://assistant.google.com/reminders/" - "mainview?hl=en-US&source=Assistant")}, - {CreateTestCaseWithParam(DeepLinkType::kReminders, - std::make_pair("id", "123456")), - GURL("https://assistant.google.com/reminders/id/" - "123456?hl=en-US&source=Assistant")}, - {CreateTestCase(DeepLinkType::kSettings), - GURL("https://assistant.google.com/settings/mainpage?hl=en-US")}, - - // FAIL: Non-web deep link types. - {CreateTestCase(DeepLinkType::kChromeSettings), std::nullopt}, - {CreateTestCase(DeepLinkType::kFeedback), std::nullopt}, - {CreateTestCase(DeepLinkType::kOnboarding), std::nullopt}, - {CreateTestCase(DeepLinkType::kQuery), std::nullopt}, - {CreateTestCase(DeepLinkType::kScreenshot), std::nullopt}, - {CreateTestCase(DeepLinkType::kTaskManager), std::nullopt}, - - // FAIL: Unsupported deep link types. - {CreateTestCase(DeepLinkType::kUnsupported), std::nullopt}}; - - for (const auto& test_case : test_cases) { - const std::optional<GURL>& expected = test_case.second; - const std::optional<GURL> actual = GetWebUrl( - /*type=*/test_case.first.first, /*params=*/test_case.first.second); - - // Assert |has_value| equivalence. - ASSERT_EQ(expected, actual); - - // Assert |value| equivalence. - if (expected) - ASSERT_EQ(expected.value(), actual.value()); - } -} - -TEST_F(DeepLinkUtilTest, IsWebDeepLink) { - const std::map<std::string, bool> test_cases = { - // OK: Supported web deep links. - {"googleassistant://lists", true}, - {"googleassistant://notes", true}, - {"googleassistant://reminders", true}, - {"googleassistant://settings", true}, - - // OK: Parameterized deep links. - {"googleassistant://lists?param=true", true}, - {"googleassistant://notes?param=true", true}, - {"googleassistant://reminders?param=true", true}, - {"googleassistant://settings?param=true", true}, - - // FAIL: Deep links are case sensitive. - {"GOOGLEASSISTANT://LISTS", false}, - {"GOOGLEASSISTANT://NOTES", false}, - {"GOOGLEASSISTANT://REMINDERS", false}, - {"GOOGLEASSISTANT://SETTINGS", false}, - - // FAIL: Non-web deep links. - {"googleassistant://alarm-timer", false}, - {"googleassistant://chrome-settings", false}, - {"googleassistant://onboarding", false}, - {"googleassistant://send-feedback", false}, - {"googleassistant://send-query", false}, - {"googleassistant://take-screenshot", false}, - {"googleassistant://task-manager", false}, - {"googleassistant://reminders?action=create", false}, - {"googleassistant://reminders?action=edit", false}, - - // FAIL: Non-deep link URLs. - {std::string(), false}, - {"https://www.google.com/", false}}; - - for (const auto& test_case : test_cases) - ASSERT_EQ(test_case.second, IsWebDeepLink(GURL(test_case.first))); -} - -TEST_F(DeepLinkUtilTest, IsWebDeepLinkType) { - const std::map<DeepLinkType, bool> test_cases = { - // OK: Supported web deep link types. - {DeepLinkType::kLists, true}, - {DeepLinkType::kNotes, true}, - {DeepLinkType::kReminders, true}, - {DeepLinkType::kSettings, true}, - - // FAIL: Non-web deep link types. - {DeepLinkType::kChromeSettings, false}, - {DeepLinkType::kFeedback, false}, - {DeepLinkType::kOnboarding, false}, - {DeepLinkType::kQuery, false}, - {DeepLinkType::kScreenshot, false}, - {DeepLinkType::kTaskManager, false}, - - // FAIL: Unsupported deep link types. - {DeepLinkType::kUnsupported, false}}; - - auto params = std::map<std::string, std::string>(); - - for (const auto& test_case : test_cases) - ASSERT_EQ(test_case.second, IsWebDeepLinkType(test_case.first, params)); - - ASSERT_FALSE( - IsWebDeepLinkType(DeepLinkType::kReminders, {{"action", "edit"}})); - ASSERT_FALSE( - IsWebDeepLinkType(DeepLinkType::kReminders, {{"action", "create"}})); -} - -} // namespace util -} // namespace assistant -} // namespace ash
diff --git a/ash/webui/settings/public/constants/routes.mojom b/ash/webui/settings/public/constants/routes.mojom index c39f9e1..00130e9 100644 --- a/ash/webui/settings/public/constants/routes.mojom +++ b/ash/webui/settings/public/constants/routes.mojom
@@ -104,8 +104,8 @@ // 506 was used for kWallpaperImages. Do not reuse. // 507 was used for kDarkMode. Do not reuse. - // Search and Assistant section. - kAssistant = 600, + // Search section. + // 600 was used for kAssistant. Do not reuse. kSearch = 601, // Apps section. @@ -255,8 +255,7 @@ // Personalization section. const string kPersonalizationSectionPath = "personalization"; -// Search and Assistant section. -const string kAssistantSubpagePath = "googleAssistant"; +// Search section. const string kSearchSubpagePath = "osSearch/search"; // Apps section.
diff --git a/ash/webui/settings/public/constants/setting.mojom b/ash/webui/settings/public/constants/setting.mojom index 314666f..51ac9c7a 100644 --- a/ash/webui/settings/public/constants/setting.mojom +++ b/ash/webui/settings/public/constants/setting.mojom
@@ -166,16 +166,16 @@ // kDarkModeThemed respectively. // Do not reuse. - // Search and Assistant section. + // Search section. kPreferredSearchEngine = 600, - kAssistantOnOff = 601, - kAssistantRelatedInfo = 602, + // 601 was used for kAssistantOnOff. Do not reuse. + // 602 was used for kAssistantRelatedInfo. Do not reuse. // Note: Value 603 was for deprecated kAssistantQuickAnswers. // Do not reuse. - kAssistantOkGoogle = 604, - kAssistantNotifications = 605, - kAssistantVoiceInput = 606, - kTrainAssistantVoiceModel = 607, + // 604 was used for kAssistantOkGoogle. Do not reuse. + // 605 was used for kAssistantNotifications. Do not reuse. + // 606 was used for kAssistantVoiceInput. Do not reuse. + // 607 was used for kTrainAssistantVoiceModel. Do not reuse. kQuickAnswersOnOff = 608, kQuickAnswersDefinition = 609, kQuickAnswersTranslation = 610,
diff --git a/ash/wm/resize_shadow_and_cursor_unittest.cc b/ash/wm/resize_shadow_and_cursor_unittest.cc index cb32dab..731d903 100644 --- a/ash/wm/resize_shadow_and_cursor_unittest.cc +++ b/ash/wm/resize_shadow_and_cursor_unittest.cc
@@ -513,8 +513,7 @@ void SetUp() override { scoped_feature_list_.InitWithFeatures( - {chromeos::features::kRoundedWindows, - chromeos::features::kFeatureManagementRoundedWindows}, + {chromeos::features::kFeatureManagementRoundedWindows}, /*disabled_features=*/{}); ResizeShadowAndCursorTest::SetUp(); }
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h index 581d3d5..c5b94a4 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h
@@ -15,7 +15,6 @@ #include "partition_alloc/partition_alloc_base/bits.h" #include "partition_alloc/partition_alloc_base/compiler_specific.h" #include "partition_alloc/partition_alloc_base/component_export.h" -#include "partition_alloc/partition_alloc_base/files/platform_file.h" #include "partition_alloc/partition_alloc_base/notreached.h" #include "partition_alloc/partition_alloc_check.h" #include "partition_alloc/partition_alloc_config.h"
diff --git a/base/files/file_path.cc b/base/files/file_path.cc index c3925fd..207f84e8 100644 --- a/base/files/file_path.cc +++ b/base/files/file_path.cc
@@ -13,7 +13,6 @@ #include <algorithm> #include <atomic> -#include <optional> #include <string_view> #include "base/check_op.h"
diff --git a/base/files/file_path.h b/base/files/file_path.h index 5496633..a04fec3 100644 --- a/base/files/file_path.h +++ b/base/files/file_path.h
@@ -104,7 +104,6 @@ #include <cstddef> #include <iosfwd> -#include <optional> #include <string> #include <string_view> #include <vector>
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc index 35919ef..db1fd305 100644 --- a/base/files/file_posix.cc +++ b/base/files/file_posix.cc
@@ -9,9 +9,6 @@ #include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/notimplemented.h" - // The only 32-bit platform that uses this file is Android. On Android APIs // >= 21, this standard define is the right way to express that you want a // 64-bit offset in struct stat, and the stat64 struct and functions aren't @@ -32,7 +29,6 @@ #include "base/check_op.h" #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" -#include "base/notimplemented.h" #include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/posix/eintr_wrapper.h" @@ -44,9 +40,14 @@ #include "base/android/content_uri_utils.h" #include "base/android/virtual_document_path.h" #include "base/files/file_android.h" +#include "base/files/file_util.h" #include "base/os_compat_android.h" #endif +#if BUILDFLAG(IS_AIX) +#include "base/notimplemented.h" +#endif + namespace base { // Make sure our Whence mappings match the system headers.
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc index aac0e68..7ea5784 100644 --- a/base/files/file_util_posix.cc +++ b/base/files/file_util_posix.cc
@@ -640,10 +640,7 @@ #if BUILDFLAG(IS_ANDROID) if (path.IsContentUri() || path.IsVirtualDocumentPath()) { std::optional<FilePath> content_uri = base::ResolveToContentUri(path); - if (!content_uri) { - return false; - } - return internal::ContentUriExists(*content_uri); + return content_uri && internal::ContentUriExists(*content_uri); } #endif return access(path.value().c_str(), F_OK) == 0; @@ -1151,10 +1148,7 @@ if (filename.IsVirtualDocumentPath()) { std::optional<files_internal::VirtualDocumentPath> vp = files_internal::VirtualDocumentPath::Parse(filename.value()); - if (!vp) { - return false; - } - return vp->WriteFile(data); + return vp && vp->WriteFile(data); } #endif
diff --git a/base/numerics/byte_conversions.h b/base/numerics/byte_conversions.h index cc8d6f8..440b507 100644 --- a/base/numerics/byte_conversions.h +++ b/base/numerics/byte_conversions.h
@@ -13,10 +13,9 @@ #include <type_traits> #include "base/numerics/basic_ops_impl.h" -#include "build/build_config.h" // Chromium only builds and runs on Little Endian machines. -static_assert(ARCH_CPU_LITTLE_ENDIAN); +static_assert(std::endian::native == std::endian::little); namespace base {
diff --git a/base/numerics/safe_math_shared_impl.h b/base/numerics/safe_math_shared_impl.h index 45509b3..68c3b87 100644 --- a/base/numerics/safe_math_shared_impl.h +++ b/base/numerics/safe_math_shared_impl.h
@@ -11,7 +11,6 @@ #include <type_traits> #include "base/numerics/safe_conversions.h" -#include "build/build_config.h" #if defined(__asmjs__) || defined(__wasm__) // Optimized safe math instructions are incompatible with asmjs.
diff --git a/base/observer_list.h b/base/observer_list.h index b78910c..ee0dc64 100644 --- a/base/observer_list.h +++ b/base/observer_list.h
@@ -55,12 +55,12 @@ // virtual void OnBar(MyWidget* w, int x, int y) = 0; // }; // -// void AddObserver(Observer* obs) { -// observers_.AddObserver(obs); +// void AddObserver(Observer* observer) { +// observers_.AddObserver(observer); // } // -// void RemoveObserver(Observer* obs) { -// observers_.RemoveObserver(obs); +// void RemoveObserver(Observer* observer) { +// observers_.RemoveObserver(observer); // } // // void NotifyFoo() { @@ -71,8 +71,8 @@ // // Use manual iteration when Notify() is not suitable, e.g. // // if passing different args to different observers is needed. // for (Observer& observer : observers_) { -// gfx::Point local_point = GetLocalPoint(obs, x, y); -// obs.OnBar(this, local_point.x(), local_point.y()); +// gfx::Point local_point = GetLocalPoint(observer, x, y); +// observer.OnBar(this, local_point.x(), local_point.y()); // } // } // @@ -309,25 +309,25 @@ // list more than once. // // Precondition: observer != nullptr - // Precondition: !HasObserver(obs) - void AddObserver(ObserverType* obs) { - DCHECK(obs); + // Precondition: !HasObserver(observer) + void AddObserver(ObserverType* observer) { + DCHECK(observer); // TODO(crbug.com/40063488): Turn this into a CHECK once very prevalent // failures are weeded out. - if (HasObserver(obs)) { + if (HasObserver(observer)) { DUMP_WILL_BE_NOTREACHED() << "Observers can only be added once!"; return; } ++observers_count_; - observers_.emplace_back(ObserverStorageType(obs)); + observers_.emplace_back(ObserverStorageType(observer)); } // Removes the given observer from this list. Does nothing if this observer is // not in this list. - void RemoveObserver(const ObserverType* obs) { - DCHECK(obs); + void RemoveObserver(const ObserverType* observer) { + DCHECK(observer); const auto it = std::ranges::find_if( - observers_, [obs](const auto& o) { return o.IsEqual(obs); }); + observers_, [observer](const auto& o) { return o.IsEqual(observer); }); if (it == observers_.end()) { return; }
diff --git a/base/win/access_token.cc b/base/win/access_token.cc index cb77197..89e0b5c 100644 --- a/base/win/access_token.cc +++ b/base/win/access_token.cc
@@ -10,6 +10,9 @@ #include "base/win/access_token.h" #include <windows.h> +#include <winternl.h> + +#include <authz.h> #include <memory> #include <utility> @@ -24,6 +27,75 @@ namespace { +// These are the NT versions of the AUTHZ_SECURITY_ATTRIBUTE* defines in authz.h +// and CLAIM_SECURITY_ATTRIBUTE* in winnt.h. We must use the TOKEN_ versions +// here as they use UNICODE_STRING instead of PWSTR. Where possible, +// static_asserts verify that the structures match the definitions from other +// header files and will fail if they ever changed, but the TOKEN_ versions are +// used here for self-consistency. +typedef struct _TOKEN_SECURITY_ATTRIBUTE_V1 { + UNICODE_STRING Name; + USHORT ValueType; + USHORT Reserved; + ULONG Flags; + ULONG ValueCount; + PLONG64 pInt64; +} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1; + +#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1 +static_assert(TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 == + AUTHZ_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1); + +typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION { + USHORT Version; + USHORT Reserved; + ULONG AttributeCount; + PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1; +} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, + *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; + +static_assert(sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION) == + sizeof(AUTHZ_SECURITY_ATTRIBUTES_INFORMATION)); +static_assert(offsetof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION, Version) == + offsetof(AUTHZ_SECURITY_ATTRIBUTES_INFORMATION, Version)); +static_assert(offsetof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION, AttributeCount) == + offsetof(AUTHZ_SECURITY_ATTRIBUTES_INFORMATION, AttributeCount)); +static_assert(offsetof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION, pAttributeV1) == + offsetof(AUTHZ_SECURITY_ATTRIBUTES_INFORMATION, + Attribute.pAttributeV1)); + +typedef enum _TOKEN_SECURITY_ATTRIBUTE_OPERATION { + TOKEN_SECURITY_ATTRIBUTE_OPERATION_NONE, + TOKEN_SECURITY_ATTRIBUTE_OPERATION_REPLACE_ALL, + TOKEN_SECURITY_ATTRIBUTE_OPERATION_ADD, + TOKEN_SECURITY_ATTRIBUTE_OPERATION_DELETE, + TOKEN_SECURITY_ATTRIBUTE_OPERATION_REPLACE +} TOKEN_SECURITY_ATTRIBUTE_OPERATION, + *PTOKEN_SECURITY_ATTRIBUTE_OPERATION; + +// Only Add is used. +static_assert(int{TOKEN_SECURITY_ATTRIBUTE_OPERATION_ADD} == + int{AUTHZ_SECURITY_ATTRIBUTE_OPERATION_ADD}); + +// This structure is not reflected anywhere in Windows headers. +typedef struct _TOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION { + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION Attributes; + PTOKEN_SECURITY_ATTRIBUTE_OPERATION Operations; +} TOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION, + *PTOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION; + +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01 +static_assert(TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 == + AUTHZ_SECURITY_ATTRIBUTE_TYPE_INT64); + +#define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001 +static_assert(TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE == + AUTHZ_SECURITY_ATTRIBUTE_NON_INHERITABLE); + +#define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020 +static_assert(TOKEN_SECURITY_ATTRIBUTE_MANDATORY == + CLAIM_SECURITY_ATTRIBUTE_MANDATORY); + // The SECURITY_IMPERSONATION_LEVEL type is an enum and therefore can't be // forward declared in windows_types.h. Ensure our separate definition matches // the existing values for simplicity. @@ -213,6 +285,7 @@ } return attributes; } + } // namespace bool AccessToken::Group::IsIntegrity() const { @@ -659,6 +732,35 @@ /*PreviousState=*/nullptr, /*ReturnLength=*/nullptr); } +bool AccessToken::AddSecurityAttribute(const std::wstring& name, bool inherit) { + TOKEN_SECURITY_ATTRIBUTE_V1 attr = {}; + + attr.Flags = TOKEN_SECURITY_ATTRIBUTE_MANDATORY; + if (!inherit) { + attr.Flags |= TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE; + } + + ::RtlInitUnicodeString(&attr.Name, name.c_str()); + LONG64 value = 0; + attr.ValueCount = 1; + attr.ValueType = TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64; + attr.pInt64 = &value; + + TOKEN_SECURITY_ATTRIBUTES_INFORMATION attrs = {}; + attrs.Version = TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1; + attrs.AttributeCount = 1; + attrs.pAttributeV1 = &attr; + + TOKEN_SECURITY_ATTRIBUTE_OPERATION op = + TOKEN_SECURITY_ATTRIBUTE_OPERATION_ADD; + + TOKEN_SECURITY_ATTRIBUTES_AND_OPERATION_INFORMATION info = {}; + info.Attributes = &attrs; + info.Operations = &op; + + return Set(token_, TokenSecurityAttributes, info); +} + bool AccessToken::is_valid() const { return token_.is_valid(); }
diff --git a/base/win/access_token.h b/base/win/access_token.h index 8e7baea2..10599b1 100644 --- a/base/win/access_token.h +++ b/base/win/access_token.h
@@ -317,6 +317,15 @@ // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. bool RemoveAllPrivileges(); + // Add a security attribute by name to the token. + // |name| the name of the attribute to add. + // The security attribute is added with a single 64-bit integer value. The + // purpose of this is to add a marker attribute for the purposes of access + // checking rather than for general use. + // The token must be opened with TOKEN_ADJUST_DEFAULT access. The caller must + // have SeTcbPrivilege enabled to successfully add the attribute. + bool AddSecurityAttribute(const std::wstring& name, bool inherit); + // Indicates if the AccessToken object is valid. bool is_valid() const;
diff --git a/base/win/access_token_unittest.cc b/base/win/access_token_unittest.cc index 75a9c3d..6664bcd 100644 --- a/base/win/access_token_unittest.cc +++ b/base/win/access_token_unittest.cc
@@ -5,6 +5,7 @@ #include "base/win/access_token.h" #include <windows.h> +#include <winternl.h> #include <algorithm> #include <cstdint> @@ -358,6 +359,56 @@ } return sids; } + +extern "C" NTSTATUS WINAPI +NtQuerySecurityAttributesToken(HANDLE TokenHandle, + PUNICODE_STRING Attributes, + ULONG NumberOfAttributes, + PVOID Buffer, + ULONG Length, + PULONG ReturnLength); + +typedef struct _TOKEN_SECURITY_ATTRIBUTE_V1 { + UNICODE_STRING Name; + USHORT ValueType; + USHORT Reserved; + ULONG Flags; + ULONG ValueCount; + PLONG64 pInt64; +} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1; + +typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION { + USHORT Version; + USHORT Reserved; + ULONG AttributeCount; + PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1; +} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, + *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; + +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01U + +#define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001U +#define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020U + +void CheckSecurityAttribute(const AccessToken& token, + const std::wstring& name) { + UNICODE_STRING attr_name; + RtlInitUnicodeString(&attr_name, name.c_str()); + BYTE buffer[256]; + DWORD return_length = 0; + NTSTATUS status = NtQuerySecurityAttributesToken( + token.get(), &attr_name, 1, buffer, sizeof(buffer), &return_length); + ASSERT_EQ(status, 0); + PTOKEN_SECURITY_ATTRIBUTE_V1 attr = + reinterpret_cast<PTOKEN_SECURITY_ATTRIBUTES_INFORMATION>(buffer) + ->pAttributeV1; + EXPECT_EQ(attr->Flags, TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | + TOKEN_SECURITY_ATTRIBUTE_MANDATORY); + ASSERT_EQ(attr->ValueCount, 1UL); + ASSERT_EQ(attr->ValueType, TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64); + ASSERT_EQ(attr->pInt64[0], 0L); +} + } // namespace TEST(AccessTokenTest, FromToken) { @@ -925,4 +976,20 @@ EXPECT_EQ(token->get(), nullptr); } +TEST(AccessTokenTest, AddSecurityAttribute) { + std::optional<AccessToken> token = + AccessToken::FromCurrentProcess(false, TOKEN_ALL_ACCESS); + ASSERT_TRUE(token); + if (!token->SetPrivilege(SE_TCB_NAME, true)) { + GTEST_SKIP() << "Skipping test, must be run with SeTcbPrivilege."; + } + + std::optional<AccessToken> dup = + token->DuplicatePrimary(TOKEN_QUERY | TOKEN_ADJUST_DEFAULT); + ASSERT_TRUE(dup); + std::wstring name = L"TEST://CHROMEATTR"; + ASSERT_TRUE(dup->AddSecurityAttribute(name, /*inherit=*/false)); + CheckSecurityAttribute(*dup, name); +} + } // namespace base::win
diff --git a/build/android/adb_system_webengine_command_line b/build/android/adb_system_webengine_command_line deleted file mode 100755 index 2dce6d2..0000000 --- a/build/android/adb_system_webengine_command_line +++ /dev/null
@@ -1,16 +0,0 @@ -#!/bin/bash -# -# 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. - -# If no flags are given, prints the current content shell flags. -# -# Otherwise, the given flags are used to REPLACE (not modify) the content shell -# flags. For example: -# adb_system_webengine_command_line --enable-webgl -# -# To remove all content shell flags, pass an empty string for the flags: -# adb_system_webengine_command_line "" - -exec $(dirname $0)/adb_command_line.py --name weblayer-command-line "$@"
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py index 56be599..ac225ad1 100755 --- a/build/android/gyp/compile_resources.py +++ b/build/android/gyp/compile_resources.py
@@ -841,19 +841,6 @@ build.proto_path, build.arsc_path ]) - # Workaround for b/147674078. This is only needed for WebLayer and does not - # affect WebView usage, since WebView does not used dynamic attributes. - if options.shared_resources: - logging.debug('Hardcoding dynamic attributes') - protoresources.HardcodeSharedLibraryDynamicAttributes( - build.proto_path, options.is_bundle_module, - options.shared_resources_allowlist) - - build_utils.CheckOutput([ - options.aapt2_path, 'convert', '--output-format', 'binary', '-o', - build.arsc_path, build.proto_path - ]) - # Sanity check that the created resources have the expected package ID. logging.debug('Performing sanity check') _, actual_package_id = resource_utils.ExtractArscPackage( @@ -954,11 +941,6 @@ rjava_build_options.ExportSomeResources( options.shared_resources_allowlist) rjava_build_options.GenerateOnResourcesLoaded() - if options.shared_resources: - # The final resources will only be used in WebLayer, so hardcode the - # package ID to be what WebLayer expects. - rjava_build_options.SetFinalPackageId( - protoresources.SHARED_LIBRARY_HARDCODED_ID) elif options.shared_resources or options.app_as_shared_lib: rjava_build_options.ExportAllResources() rjava_build_options.GenerateOnResourcesLoaded()
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index a54a835..de84397 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -20,10 +20,6 @@ import zip_helpers _IGNORE_WARNINGS = ( - # E.g. Triggers for weblayer_instrumentation_test_apk since both it and its - # apk_under_test have no shared_libraries. - # https://crbug.com/1364192 << To fix this in a better way. - r'Missing class org.chromium.build.NativeLibraries', # Caused by protobuf runtime using -identifiernamestring in a way that # doesn't work with R8. Looks like: # Rule matches the static final field `...`, which may have been inlined...
diff --git a/build/android/gyp/util/protoresources.py b/build/android/gyp/util/protoresources.py index e07fce9..34cf26d 100644 --- a/build/android/gyp/util/protoresources.py +++ b/build/android/gyp/util/protoresources.py
@@ -14,7 +14,6 @@ import zipfile from util import build_utils -from util import resource_utils sys.path[1:1] = [ # `Resources_pb2` module imports `descriptor`, which imports `six`. @@ -30,11 +29,6 @@ # uint32: Magic ("ARSC"), version (1), num_entries (1), type (0) _FLAT_ARSC_HEADER = b'AAPT\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00' -# The package ID hardcoded for shared libraries. See -# _HardcodeSharedLibraryDynamicAttributes() for more details. If this value -# changes make sure to change REQUIRED_PACKAGE_IDENTIFIER in WebLayerImpl.java. -SHARED_LIBRARY_HARDCODED_ID = 36 - def _ProcessZip(zip_path, process_func): """Filters a .zip file via: new_bytes = process_func(filename, data).""" @@ -56,42 +50,10 @@ f.writestr(info, data) -def _ProcessProtoItem(item): - if not item.HasField('ref'): - return - - # If this is a dynamic attribute (type ATTRIBUTE, package ID 0), hardcode - # the package to SHARED_LIBRARY_HARDCODED_ID. - if item.ref.type == Resources_pb2.Reference.ATTRIBUTE and not (item.ref.id - & 0xff000000): - item.ref.id |= (0x01000000 * SHARED_LIBRARY_HARDCODED_ID) - item.ref.ClearField('is_dynamic') - - -def _ProcessProtoValue(value): - if value.HasField('item'): - _ProcessProtoItem(value.item) - return - - compound_value = value.compound_value - if compound_value.HasField('style'): - for entry in compound_value.style.entry: - _ProcessProtoItem(entry.item) - elif compound_value.HasField('array'): - for element in compound_value.array.element: - _ProcessProtoItem(element.item) - elif compound_value.HasField('plural'): - for entry in compound_value.plural.entry: - _ProcessProtoItem(entry.item) - - def _ProcessProtoXmlNode(xml_node): if not xml_node.HasField('element'): return - for attribute in xml_node.element.attribute: - _ProcessProtoItem(attribute.compiled_item) - for child in xml_node.element.child: _ProcessProtoXmlNode(child) @@ -141,76 +103,6 @@ return locale_type -def _HardcodeInTable(table, is_bundle_module, shared_resources_allowlist): - translations_package = None - allowed_resource_names = set() - if is_bundle_module: - # A separate top level package will be added to the resources, which - # contains only locale specific resources. The package ID of the locale - # resources is hardcoded to SHARED_LIBRARY_HARDCODED_ID. This causes - # resources in locale splits to all get assigned - # SHARED_LIBRARY_HARDCODED_ID as their package ID, which prevents a bug - # in shared library bundles where each split APK gets a separate dynamic - # ID, and cannot be accessed by the main APK. - translations_package = Resources_pb2.Package() - translations_package.package_id.id = SHARED_LIBRARY_HARDCODED_ID - translations_package.package_name = (table.package[0].package_name + - '_translations') - - # These resources are allowed in the base resources, since they are needed - # by WebView. - if shared_resources_allowlist: - allowed_resource_names = set( - resource_utils.GetRTxtStringResourceNames(shared_resources_allowlist)) - - for package in table.package: - for _type in package.type: - for entry in _type.entry: - for config_value in entry.config_value: - _ProcessProtoValue(config_value.value) - - if translations_package is not None: - locale_type = _SplitLocaleResourceType(_type, allowed_resource_names) - if locale_type: - translations_package.type.add().CopyFrom(locale_type) - - if translations_package is not None: - table.package.add().CopyFrom(translations_package) - - -def HardcodeSharedLibraryDynamicAttributes(zip_path, - is_bundle_module, - shared_resources_allowlist=None): - """Hardcodes the package IDs of dynamic attributes and locale resources. - - Hardcoding dynamic attribute package IDs is a workaround for b/147674078, - which affects Android versions pre-N. Hardcoding locale resource package IDs - is a workaround for b/155437035, which affects resources built with - --shared-lib on all Android versions - - Args: - zip_path: Path to proto APK file. - is_bundle_module: True for bundle modules. - shared_resources_allowlist: Set of resource names to not extract out of the - main package. - """ - - def process_func(filename, data): - if filename == 'resources.pb': - table = Resources_pb2.ResourceTable() - table.ParseFromString(data) - _HardcodeInTable(table, is_bundle_module, shared_resources_allowlist) - data = table.SerializeToString() - elif filename.endswith('.xml') and not filename.startswith('res/raw'): - xml_node = Resources_pb2.XmlNode() - xml_node.ParseFromString(data) - _ProcessProtoXmlNode(xml_node) - data = xml_node.SerializeToString() - return data - - _ProcessZip(zip_path, process_func) - - class _ResourceStripper: def __init__(self, partial_path, keep_predicate): self.partial_path = partial_path
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py index 1d681c8..ae2a6aa 100644 --- a/build/android/pylib/constants/__init__.py +++ b/build/android/pylib/constants/__init__.py
@@ -79,11 +79,6 @@ chrome.PackageInfo('org.chromium.webview_ui_test', 'org.chromium.webview_ui_test.WebViewUiTestActivity', 'webview-command-line', None), - 'weblayer_browsertests': - chrome.PackageInfo( - 'org.chromium.weblayer_browsertests_apk', - 'org.chromium.weblayer_browsertests_apk.WebLayerBrowserTestsActivity', - 'chrome-native-tests-command-line', None), })
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py index 08dd957..c90ea50f 100644 --- a/build/android/pylib/gtest/gtest_test_instance.py +++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -29,7 +29,6 @@ 'android_sync_integration_tests', 'components_browsertests', 'content_browsertests', - 'weblayer_browsertests', ] # The max number of tests to run on a batch during the test run.
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 9d778df8..6e23dda 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -155,19 +155,28 @@ # True when compiling native code for use with robolectric_binary(). is_robolectric = false - # Use explicit Clang header modules for libc++. - # This is experimental only (see crbug.com/543704). - # For details on the current state of modules in Chromium see - # https://chromium.googlesource.com/chromium/src/+/main/docs/modules.md - # We explicitly need this flag in this file because it's read by this file. - use_clang_modules = false - # DON'T ADD MORE FLAGS HERE. Read the comment above. } +import("//build/toolchain/rbe.gni") + declare_args() { # Debug build. Enabling official builds automatically sets is_debug to false. is_debug = !is_official_build + + # Use explicit Clang header modules for libc++. + # We'll gradually expand supported platform of modules + # (https://crbug.com/40440396). + # For details on the current state of modules in Chromium see + # https://chromium.googlesource.com/chromium/src/+/main/docs/modules.md + # We explicitly need this flag in this file because it's read by this file. + # Currently we enables this only on non-official Linux x64 build on Linux x64 + # machine. + use_clang_modules = + !is_official_build && is_clang && host_os == "linux" && + host_cpu == "x64" && target_os == "linux" && target_cpu == "x64" && + # reclient doesn't handle headers in modulemap config. + !use_reclient } declare_args() {
diff --git a/build/config/siso/clang_unix.star b/build/config/siso/clang_unix.star index 9b97aa2..7c45878 100644 --- a/build/config/siso/clang_unix.star +++ b/build/config/siso/clang_unix.star
@@ -12,35 +12,31 @@ load("./gn_logs.star", "gn_logs") load("./win_sdk.star", "win_sdk") -def __clang_modulemap(ctx, cmd): - """Fixes inputs for clang compile actions with modulemap. +def __add_generated_libcxx_headers(ctx, cmd): + """Adds libc++ headers as tool inputs for clang compile actions. - But this is simplified implementation to parse current modulemap. - https://clang.llvm.org/docs/Modules.html#module-map-file + This is needed because libc++ headers in the build directory are not always + discovered by the precomputed tree and scandeps. It identifies them using + `-isystem` flags and `libcxx_headers.gni`. """ - inputs = [] + libcxx_headers = [] + for line in str(ctx.fs.read("buildtools/third_party/libc++/libcxx_headers.gni")).split("\n"): + if "third_party/libc++/src/include" in line: + libcxx_headers.append(line.split("src/include/")[1].removesuffix("\",")) + + tool_inputs = [] for arg in cmd.args: - module_config = arg.removeprefix("-fmodule-map-file=") - if arg == module_config: + isystem = arg.removeprefix("-isystem") + if arg == isystem or "libc++" not in isystem: continue - module_config = ctx.fs.canonpath(module_config) - module_dir = path.dir(module_config) - for line in str(ctx.fs.read(module_config)).split("\n"): - # Remove one line comment. - line = line.split("//")[0] - - # Extract a quoted path if any. - quoted_paths = line.split("\"") - if len(quoted_paths) > 2: - include_path = quoted_paths[1] - include_path = path.join(module_dir, include_path) - inputs.append(include_path) - - ctx.actions.fix(tool_inputs = cmd.tool_inputs + inputs) + isystem = ctx.fs.canonpath(isystem) + for header in libcxx_headers: + tool_inputs.append(path.join(isystem, header)) + ctx.actions.fix(tool_inputs = cmd.tool_inputs + tool_inputs) def __clang_compile_coverage(ctx, cmd): - __clang_modulemap(ctx, cmd) + __add_generated_libcxx_headers(ctx, cmd) clang_command = clang_code_coverage_wrapper.run(ctx, list(cmd.args)) ctx.actions.fix(args = clang_command) @@ -102,7 +98,7 @@ ctx.actions.fix(inputs = cmd.inputs + inputs) __handlers = { - "clang_modulemap": __clang_modulemap, + "add_generated_libcxx_headers": __add_generated_libcxx_headers, "clang_compile_coverage": __clang_compile_coverage, "clang_link": __clang_link, } @@ -229,7 +225,7 @@ "third_party/llvm-build/Release+Asserts/bin/clang++", ], "exclude_input_patterns": ["*.stamp"], - "handler": "clang_modulemap", + "handler": "add_generated_libcxx_headers", "remote": True, "input_root_absolute_path": input_root_absolute_path, "canonicalize_dir": canonicalize_dir, @@ -269,6 +265,7 @@ "third_party/llvm-build/Release+Asserts/bin/clang++", ], "exclude_input_patterns": ["*.stamp"], + "handler": "add_generated_libcxx_headers", "remote": True, "timeout": "2m", "input_root_absolute_path": input_root_absolute_path_for_objc,
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn index 5ca9d9d..bce37063 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn
@@ -675,7 +675,7 @@ ":sysroot_locale", ":sysroot_pthread", ] - if (is_mac) { + if (is_apple) { public_deps += [ # <locale> includes <nl_types.h> inside an __APPLE__ macro guard which # requires nl_types module.
diff --git a/cc/base/features.cc b/cc/base/features.cc index c547dfe1..55b84cd 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc
@@ -22,6 +22,13 @@ BASE_FEATURE(kAlignSurfaceLayerImplToPixelGrid, "AlignSurfaceLayerImplToPixelGrid", base::FEATURE_ENABLED_BY_DEFAULT); +// When enabled, this forces raster translation to be computed using screen +// space and draw transforms scaled by external page scale factor. +// Whithout this, text in OOPIFs that isn't aligned to the pixel grid may appear +// blurry. https://crbug.com/399478935 +BASE_FEATURE(kComputeRasterTranslateForExternalScale, + "ComputeRasterTranslateForExternalScale", + base::FEATURE_ENABLED_BY_DEFAULT); // Whether the compositor should attempt to sync with the scroll handlers before // submitting a frame.
diff --git a/cc/base/features.h b/cc/base/features.h index 4746e91c..fa39b8a 100644 --- a/cc/base/features.h +++ b/cc/base/features.h
@@ -15,6 +15,7 @@ namespace features { CC_BASE_EXPORT BASE_DECLARE_FEATURE(kAlignSurfaceLayerImplToPixelGrid); +CC_BASE_EXPORT BASE_DECLARE_FEATURE(kComputeRasterTranslateForExternalScale); CC_BASE_EXPORT BASE_DECLARE_FEATURE(kSynchronizedScrolling); // Sets raster tree priority to NEW_CONTENT_TAKES_PRIORITY when performing a
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 44f6ebb..e9bd13a0 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -1743,13 +1743,26 @@ // ScreenSpaceTransform() and DrawTransform() in PixelAlignmentOffset(), // here we also check if the scale of DrawTransform() approximately equals // raster_contents_scale_. + // ScreenSpaceTransform() and DrawTransform() need to be scaled by + // external_page_scale_factor which is set for OOPIF. + const float external_page_scale_factor = + (base::FeatureList::IsEnabled( + features::kComputeRasterTranslateForExternalScale) && + layer_tree_impl()) + ? layer_tree_impl()->external_page_scale_factor() + : 1.f; + + gfx::Transform scaled_draw_transform = DrawTransform(); + scaled_draw_transform.PostScale(external_page_scale_factor); if (!draw_property_utils::RasterScalesApproximatelyEqual( - DrawTransform().To2dScale(), raster_contents_scale_)) { + scaled_draw_transform.To2dScale(), raster_contents_scale_)) { return false; } + gfx::Transform scaled_screen_space_transform = ScreenSpaceTransform(); + scaled_screen_space_transform.PostScale(external_page_scale_factor); if (auto offset = draw_property_utils::PixelAlignmentOffset( - ScreenSpaceTransform(), DrawTransform())) { + scaled_screen_space_transform, scaled_draw_transform)) { raster_translation = *offset; return true; }
diff --git a/cc/paint/draw_image.cc b/cc/paint/draw_image.cc index 9655b51..800551b 100644 --- a/cc/paint/draw_image.cc +++ b/cc/paint/draw_image.cc
@@ -84,8 +84,7 @@ scale_(SkSize::Make(other.scale_.width() * scale_adjustment, other.scale_.height() * scale_adjustment)), matrix_is_decomposable_(other.matrix_is_decomposable_), - frame_index_(frame_index), - target_color_params_(target_color_params) { + frame_index_(frame_index) { SetTargetColorParams(target_color_params); }
diff --git a/cc/paint/draw_image.h b/cc/paint/draw_image.h index 7fafded..d18c7bb 100644 --- a/cc/paint/draw_image.h +++ b/cc/paint/draw_image.h
@@ -81,10 +81,6 @@ DCHECK(target_color_params_.has_value()); return target_color_params_->color_space; } - float sdr_white_level() const { - DCHECK(target_color_params_.has_value()); - return target_color_params_->sdr_max_luminance_nits; - } private: void SetTargetColorParams(const TargetColorParams& target_color_params);
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc index 5069744..1a42010 100644 --- a/cc/paint/oop_pixeltest.cc +++ b/cc/paint/oop_pixeltest.cc
@@ -830,7 +830,7 @@ RasterOptions options(kSize); options.target_color_params.color_space = gfx::ColorSpace(*dest_color_space); - options.target_color_params.hdr_max_luminance_relative = 1.f; + options.target_color_params.hdr_headroom = 0.f; auto result = Raster(display_item_list, options); auto out_color = result.getColor4f(0, 0); EXPECT_NEAR(out_color.fR, std::pow(kBaseLinear / kDestScale, kGamma), kEps); @@ -844,7 +844,7 @@ RasterOptions options(kSize); options.target_color_params.color_space = gfx::ColorSpace(*dest_color_space); - options.target_color_params.hdr_max_luminance_relative = kDestScale; + options.target_color_params.hdr_headroom = std::log2(kDestScale); auto result = Raster(display_item_list, options); auto out_color = result.getColor4f(0, 0); EXPECT_NEAR(out_color.fR, std::pow(0.5f / kDestScale, kGamma), kEps); @@ -918,7 +918,7 @@ auto dest_color_space = SkColorSpace::MakeSRGBLinear(); options.target_color_params.color_space = gfx::ColorSpace(*dest_color_space); - options.target_color_params.hdr_max_luminance_relative = kRatioMax; + options.target_color_params.hdr_headroom = std::log2(kRatioMax); } auto result = Raster(display_item_list, options); @@ -1021,7 +1021,7 @@ auto dest_color_space = SkColorSpace::MakeSRGBLinear(); options.target_color_params.color_space = gfx::ColorSpace(*dest_color_space); - options.target_color_params.hdr_max_luminance_relative = kRatioMax; + options.target_color_params.hdr_headroom = std::log2(kRatioMax); } auto result = Raster(display_item_list, options); @@ -1157,7 +1157,7 @@ { constexpr float kExpected = 0.933675419515227f; constexpr float kDstHeadroom = 1.5f; - options.target_color_params.hdr_max_luminance_relative = kDstHeadroom; + options.target_color_params.hdr_headroom = std::log2(kDstHeadroom); auto actual = Raster(make_display_item_list(image_500_nits, 10000.f), options); auto color = actual.getColor4f(0, 0);
diff --git a/cc/paint/target_color_params.cc b/cc/paint/target_color_params.cc index 2f9bc83..0a78b5cb 100644 --- a/cc/paint/target_color_params.cc +++ b/cc/paint/target_color_params.cc
@@ -11,26 +11,25 @@ namespace cc { -float TargetColorParams::GetHdrHeadroom() const { - return std::log2(hdr_max_luminance_relative); -} - size_t TargetColorParams::GetHash() const { - const uint32_t* hdr_max_luminance_relative_int = - reinterpret_cast<const uint32_t*>(&hdr_max_luminance_relative); - const uint32_t* sdr_max_luminance_nits_int = - reinterpret_cast<const uint32_t*>(&sdr_max_luminance_nits); size_t hash = color_space.GetHash(); - hash = base::HashInts(hash, *hdr_max_luminance_relative_int); - hash = base::HashInts(hash, *sdr_max_luminance_nits_int); + if (hdr_headroom.has_value()) { + const float f = hdr_headroom.value(); + const uint32_t* i = reinterpret_cast<const uint32_t*>(&f); + hash = base::HashInts(hash, *i); + } return hash; } std::string TargetColorParams::ToString() const { std::ostringstream str; - str << "color_space: " << color_space.ToString() - << "sdr_max_luminance_nits: " << sdr_max_luminance_nits - << "hdr_max_luminance_relative: " << hdr_max_luminance_relative; + str << "color_space: " << color_space.ToString(); + str << "hdr_headroom: "; + if (hdr_headroom.has_value()) { + str << hdr_headroom.value(); + } else { + str << "(deferred)"; + } return str.str(); }
diff --git a/cc/paint/target_color_params.h b/cc/paint/target_color_params.h index b5a9866f..6f7dcea 100644 --- a/cc/paint/target_color_params.h +++ b/cc/paint/target_color_params.h
@@ -28,20 +28,12 @@ // The target buffer's color space. gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); - // The maximum SDR luminance of the target, in nits. - float sdr_max_luminance_nits = gfx::ColorSpace::kDefaultSDRWhiteLevel; - - // The maximum HDR luminance of the target, in multiples of the SDR maximum - // luminance (a non-HDR-capable display will have a value of 1). - float hdr_max_luminance_relative = 1.f; - - // Return log2 of hdr_max_luminance_relative. - float GetHdrHeadroom() const; + float GetHdrHeadroom() const { return hdr_headroom.value_or(0); } + std::optional<float> hdr_headroom; bool operator==(const TargetColorParams& other) const { return color_space == other.color_space && - sdr_max_luminance_nits == other.sdr_max_luminance_nits && - hdr_max_luminance_relative == other.hdr_max_luminance_relative; + hdr_headroom == other.hdr_headroom; } bool operator!=(const TargetColorParams& other) const { return !(*this == other);
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index e7213a3..965ca27e 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -70,6 +70,14 @@ SetBeginFrameSource(nullptr); } +void Scheduler::TearDown() { + DCHECK(stopped_); + + // CFRC is owned by the LayerTreeHostImpl, which gets destroyed before the + // scheduler. Must clear it to avoid a dangling ptr. + compositor_frame_reporting_controller_ = nullptr; +} + void Scheduler::Stop() { stopped_ = true; }
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 5d3e730..e804bb6 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -108,10 +108,13 @@ Scheduler& operator=(const Scheduler&) = delete; - // This is needed so that the scheduler doesn't perform spurious actions while - // the compositor is being torn down. + // This is needed so that the scheduler doesn't perform scheduled actions + // while the compositor is being torn down. void Stop(); + // Cleans up references to other objects just before being destroyed. + void TearDown(); + // BeginFrameObserverBase void OnBeginFrameSourcePausedChanged(bool paused) override; bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override; @@ -307,7 +310,7 @@ // Owned by LayerTreeHostImpl and is destroyed when LayerTreeHostImpl is // destroyed. - raw_ptr<CompositorFrameReportingController, AcrossTasksDanglingUntriaged> + raw_ptr<CompositorFrameReportingController> compositor_frame_reporting_controller_; // What the latest deadline was, and when it was scheduled.
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 534d396..8b27e4c 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -613,15 +613,18 @@ std::unique_ptr<viz::SyntheticBeginFrameSource> unthrottled_frame_source_; SchedulerSettings scheduler_settings_; std::unique_ptr<FakeSchedulerClient> client_; - std::unique_ptr<TestScheduler> scheduler_; - raw_ptr<FakeCompositorTimingHistory> fake_compositor_timing_history_; FrameSequenceTrackerCollection tracker_collection_; FrameSorter frame_sorter; - // Since CFRC destructor cleans up the FrameSorter's - // registered observers (in this case FSTC) - // it needs to be declared last so that it will be - // cleaned up first. + // Since CFRC destructor cleans up the FrameSorter's registered observers (in + // this case FSTC) it needs to be declared last so that it will be cleaned up + // first. std::unique_ptr<CompositorFrameReportingController> reporting_controller; + // Scheduler must be destroyed before reporting_controller since it has a + // raw_ptr to the reporting controller. + std::unique_ptr<TestScheduler> scheduler_; + // FakeCompositorTimingHistory is owned by the Scheduler, so must be released + // before the scheduler is destroyed to avoid a dangling ptr. + raw_ptr<FakeCompositorTimingHistory> fake_compositor_timing_history_; }; TEST_F(SchedulerTest, InitializeLayerTreeFrameSinkDoesNotBeginImplFrame) {
diff --git a/cc/test/fake_tile_manager_client.cc b/cc/test/fake_tile_manager_client.cc index 324763f..1d657846 100644 --- a/cc/test/fake_tile_manager_client.cc +++ b/cc/test/fake_tile_manager_client.cc
@@ -36,8 +36,6 @@ gfx::ContentColorUsage /*content_color_usage*/) const { TargetColorParams result; result.color_space = color_space_; - result.sdr_max_luminance_nits = gfx::ColorSpace::kDefaultSDRWhiteLevel; - result.hdr_max_luminance_relative = 1.f; return result; }
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 91915c5..f076ae7 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -575,7 +575,6 @@ TargetColorParams target_color_params = DefaultTargetColorParams(); if (color_space) target_color_params.color_space = *color_space; - target_color_params.sdr_max_luminance_nits = sdr_white_level; return DrawImage(paint_image, use_dark_mode, *src_rect, filter_quality, matrix, frame_index, target_color_params); @@ -3851,8 +3850,6 @@ TargetColorParams target_color_params; target_color_params.color_space = target_cs; - target_color_params.sdr_max_luminance_nits = - gfx::ColorSpace::kDefaultSDRWhiteLevel; DrawImage draw_image( image, false, SkIRect::MakeWH(image.width(), image.height()),
diff --git a/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/cc/tiles/software_image_decode_cache_unittest_combinations.cc index 1e696fd..e5277dc 100644 --- a/cc/tiles/software_image_decode_cache_unittest_combinations.cc +++ b/cc/tiles/software_image_decode_cache_unittest_combinations.cc
@@ -201,7 +201,7 @@ TargetColorParams GetTargetColorParams() const override { TargetColorParams result(gfx::ColorSpace( gfx::ColorSpace::PrimaryID::P3, gfx::ColorSpace::TransferID::SRGB_HDR)); - result.hdr_max_luminance_relative = 4.f; + result.hdr_headroom = 2.f; return result; } };
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index 6b72b1c..3134759d 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -2667,7 +2667,7 @@ TEST_F(TileManagerReadyToDrawTest, HdrHeadroomPropagated) { constexpr float kTestHdrHeadroom = 2.f; TargetColorParams target_color_params; - target_color_params.hdr_max_luminance_relative = std::exp2(kTestHdrHeadroom); + target_color_params.hdr_headroom = kTestHdrHeadroom; host_impl()->set_target_color_params(target_color_params); mock_raster_buffer_provider()->set_expected_hdr_headroom(kTestHdrHeadroom); @@ -3901,7 +3901,6 @@ EXPECT_FALSE(pending_tasks.empty()); for (const auto& draw_info : pending_tasks) { EXPECT_EQ(draw_info.target_color_space(), raster_cs); - EXPECT_FLOAT_EQ(draw_info.sdr_white_level(), kCustomWhiteLevel); } }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 802cbbe2..8daa07c 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2025,7 +2025,6 @@ return params; gfx::DisplayColorSpaces display_cs = GetDisplayColorSpaces(); - params.sdr_max_luminance_nits = display_cs.GetSDRMaxLuminanceNits(); if (settings_.prefer_raster_in_srgb && content_color_usage == gfx::ContentColorUsage::kSRGB) { @@ -2038,7 +2037,7 @@ params.color_space = raster_color_space; } if (params.color_space.IsHDR()) { - params.hdr_max_luminance_relative = display_cs.GetHDRMaxLuminanceRelative(); + params.hdr_headroom = display_cs.GetHdrHeadroom(); } return params; }
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 42a330bc..6add5b5 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -16692,8 +16692,6 @@ wcg_params = host_impl_->GetTargetColorParams(gfx::ContentColorUsage::kWideColorGamut); EXPECT_EQ(wcg_params.color_space, gfx::ColorSpace::CreateDisplayP3D65()); - EXPECT_EQ(wcg_params.sdr_max_luminance_nits, - gfx::ColorSpace::kDefaultSDRWhiteLevel); } TEST_P(LayerTreeHostImplTest, RasterColorSpaceSoftware) { @@ -16710,8 +16708,6 @@ wcg_params = host_impl_->GetTargetColorParams(gfx::ContentColorUsage::kWideColorGamut); EXPECT_EQ(wcg_params.color_space, gfx::ColorSpace::CreateSRGB()); - EXPECT_EQ(wcg_params.sdr_max_luminance_nits, - gfx::ColorSpace::kDefaultSDRWhiteLevel); } TEST_P(LayerTreeHostImplTest, RasterColorPrefersSRGB) { @@ -16731,8 +16727,6 @@ host_impl_->active_tree()->SetDisplayColorSpaces(gfx::DisplayColorSpaces(p3)); srgb_params = host_impl_->GetTargetColorParams(gfx::ContentColorUsage::kSRGB); EXPECT_EQ(srgb_params.color_space, p3); - EXPECT_EQ(srgb_params.sdr_max_luminance_nits, - gfx::ColorSpace::kDefaultSDRWhiteLevel); } TEST_P(LayerTreeHostImplTest, RasterColorSpaceHDR) { @@ -16754,19 +16748,15 @@ const auto hdr_params = host_impl_->GetTargetColorParams(gfx::ContentColorUsage::kHDR); - // Non-HDR content should be rasterized in P3. + // sRGB content is rastered as sRGB, WCG as P3. const auto srgb = gfx::ColorSpace::CreateSRGB(); const auto p3 = gfx::ColorSpace::CreateDisplayP3D65(); EXPECT_EQ(srgb_params.color_space, srgb); - EXPECT_EQ(srgb_params.sdr_max_luminance_nits, kCustomWhiteLevel); - EXPECT_EQ(srgb_params.hdr_max_luminance_relative, 1.f); + EXPECT_EQ(srgb_params.GetHdrHeadroom(), 0.f); EXPECT_EQ(wcg_params.color_space, p3); - EXPECT_EQ(wcg_params.sdr_max_luminance_nits, kCustomWhiteLevel); - EXPECT_EQ(wcg_params.hdr_max_luminance_relative, 1.f); - + EXPECT_EQ(wcg_params.GetHdrHeadroom(), 0.f); EXPECT_EQ(hdr_params.color_space, p3.GetAsHDR()); - EXPECT_EQ(hdr_params.sdr_max_luminance_nits, kCustomWhiteLevel); - EXPECT_EQ(hdr_params.hdr_max_luminance_relative, kHDRMaxLuminanceRelative); + EXPECT_EQ(hdr_params.GetHdrHeadroom(), std::log2(kHDRMaxLuminanceRelative)); } TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc index b744c41..5b41e16 100644 --- a/cc/trees/proxy_impl.cc +++ b/cc/trees/proxy_impl.cc
@@ -144,13 +144,18 @@ DCHECK(IsImplThread()); DCHECK(IsMainThreadBlocked()); - // Prevent the scheduler from performing actions while we're in an + // Prevent the scheduler from performing scheduled actions while we're in an // inconsistent state. scheduler_->Stop(); + // Take away the LayerTreeFrameSink before destroying things so it doesn't // try to call into its client mid-shutdown. host_impl_->ReleaseLayerTreeFrameSink(); + // The `Scheduler` has a raw_ptr to the CompositorFrameReportingController + // that is owned by the LTHI. + scheduler_->TearDown(); + // It is important to destroy LTHI before the Scheduler since it can make // callbacks that access it during destruction cleanup. host_impl_ = nullptr;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 503e99c1..1a854ed6 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -442,14 +442,21 @@ DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); DebugScopedSetImplThread impl(task_runner_provider_); - // Prevent the scheduler from performing actions while we're in an + // Prevent the scheduler from performing scheduled actions while we're in an // inconsistent state. if (scheduler_on_impl_thread_) scheduler_on_impl_thread_->Stop(); + // Take away the LayerTreeFrameSink before destroying things so it doesn't // try to call into its client mid-shutdown. host_impl_->ReleaseLayerTreeFrameSink(); + // The `Scheduler` has a raw_ptr to the CompositorFrameReportingController + // that is owned by the LTHI. + if (scheduler_on_impl_thread_) { + scheduler_on_impl_thread_->TearDown(); + } + // It is important to destroy LTHI before the Scheduler since it can make // callbacks that access it during destruction cleanup. host_impl_ = nullptr;
diff --git a/chrome/VERSION b/chrome/VERSION index 5a002bb..fbb4e47 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=140 MINOR=0 -BUILD=7327 +BUILD=7328 PATCH=0
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java index 8744c5b1..3bd4294 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java
@@ -985,8 +985,8 @@ assertTrue( snackbarManager.getCurrentSnackbarForTesting().getController() instanceof SavedTabGroupUndoBarController); - TabUiTestHelper.verifyUndoBarShowingAndClickUndo(); - // CriteriaHelper.pollUiThread(() -> 3 == mArchivedTabModel.getCount()); + CriteriaHelper.pollInstrumentationThread(TabUiTestHelper::verifyUndoBarShowingAndClickUndo); + CriteriaHelper.pollUiThread(() -> 3 == mArchivedTabModel.getCount()); verify(mTabGroupSyncService).updateArchivalStatus(SYNC_GROUP_ID1, true); savedTabGroup.archivalTimeMs = System.currentTimeMillis(); ThreadUtils.runOnUiThreadBlocking( @@ -1039,7 +1039,7 @@ assertTrue( snackbarManager.getCurrentSnackbarForTesting().getController() instanceof SavedTabGroupUndoBarController); - TabUiTestHelper.verifyUndoBarShowingAndClickUndo(); + CriteriaHelper.pollInstrumentationThread(TabUiTestHelper::verifyUndoBarShowingAndClickUndo); verify(mTabGroupSyncService).updateArchivalStatus(SYNC_GROUP_ID1, true); savedTabGroup.archivalTimeMs = System.currentTimeMillis(); ThreadUtils.runOnUiThreadBlocking( @@ -1101,7 +1101,7 @@ assertTrue( snackbarManager.getCurrentSnackbarForTesting().getController() instanceof SavedTabGroupUndoBarController); - TabUiTestHelper.verifyUndoBarShowingAndClickUndo(); + CriteriaHelper.pollInstrumentationThread(TabUiTestHelper::verifyUndoBarShowingAndClickUndo); verify(mTabGroupSyncService).updateArchivalStatus(SYNC_GROUP_ID1, true); verify(mTabGroupSyncService).updateArchivalStatus(SYNC_GROUP_ID2, true); savedTabGroup1.archivalTimeMs = System.currentTimeMillis();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java index de05076..62b5c4e 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java
@@ -418,7 +418,6 @@ @Test @MediumTest - @DisabledTest(message = "crbug.com/397901349") public void testUndoClosure_AccessibilityMode() { ThreadUtils.runOnUiThreadBlocking( () -> ChromeAccessibilityUtil.get().setAccessibilityEnabledForTesting(true));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java index a81964b2..d72fdb94 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -112,6 +112,8 @@ 1512; // Random id to avoid possible collisions. private static final int MAX_CUSTOM_MENU_ITEMS = 4; private static final String TAG = "CCMenuPopulator"; + private static final String UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_DISPLAYED = + "CustomTabs.ContextMenu.DisplayedContextualCustomActionType"; private static final String UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_SELECTED = "CustomTabs.ContextMenu.SelectedContextualCustomActionType"; private final Context mContext; @@ -483,13 +485,21 @@ } if (ChromeFeatureList.sCctContextualMenuItems.isEnabled() && mMode == ContextMenuMode.CUSTOM_TAB) { + boolean displayedAction = false; for (CustomContentAction action : mCustomContentActions) { if (action.getTargetType() == CustomTabsIntent.CONTENT_TARGET_TYPE_LINK) { + displayedAction = true; mCustomActionMap.put(nextCustomMenuItemId, action); linkGroup.add(createCustomListItem(action, nextCustomMenuItemId)); nextCustomMenuItemId++; } } + if (displayedAction) { + RecordHistogram.recordEnumeratedHistogram( + UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_DISPLAYED, + ContextualCustomActionType.LINK, + ContextualCustomActionType.COUNT); + } } if (!mParams.isImage() && BookmarkUtils.isReadingListSupported(mParams.getLinkUrl())) { @@ -560,13 +570,21 @@ if (ChromeFeatureList.sCctContextualMenuItems.isEnabled() && mMode == ContextMenuMode.CUSTOM_TAB) { + boolean displayedAction = false; for (CustomContentAction action : mCustomContentActions) { if (action.getTargetType() == CustomTabsIntent.CONTENT_TARGET_TYPE_IMAGE) { + displayedAction = true; mCustomActionMap.put(nextCustomMenuItemId, action); imageGroup.add(createCustomListItem(action, nextCustomMenuItemId)); nextCustomMenuItemId++; } } + if (displayedAction) { + RecordHistogram.recordEnumeratedHistogram( + UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_DISPLAYED, + ContextualCustomActionType.IMAGE, + ContextualCustomActionType.COUNT); + } } if (mMode == ContextMenuMode.CUSTOM_TAB || mMode == ContextMenuMode.NORMAL) { @@ -1491,6 +1509,10 @@ return CUSTOM_MENU_ITEM_ID_START; } + public static String getCustomActionTypeDisplayedHistogramForTesting() { + return UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_DISPLAYED; + } + public static String getContextualCustomActionTypeSelectedHistogramForTesting() { return UMA_CONTEXTUAL_CUSTOM_ACTION_TYPE_SELECTED; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderCoordinator.java index cd16451..27607e6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderCoordinator.java
@@ -25,6 +25,7 @@ import org.chromium.components.embedder_support.contextmenu.ContextMenuUtils.HeaderInfo; import org.chromium.components.omnibox.OmniboxUrlEmphasizer; import org.chromium.components.security_state.ConnectionSecurityLevel; +import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.url.GURL; @@ -79,7 +80,7 @@ PropertyModel.Builder modelBuilder = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) - .with(ContextMenuHeaderProperties.TITLE, title) + .with(ListMenuItemProperties.TITLE, title) .with( ContextMenuHeaderProperties.TITLE_MAX_LINES, TextUtils.isEmpty(url) ? 2 : 1)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediator.java index 2e8ad4e..46585796 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediator.java
@@ -30,6 +30,7 @@ import org.chromium.components.embedder_support.contextmenu.ContextMenuParams; import org.chromium.components.favicon.IconType; import org.chromium.components.favicon.LargeIconBridge; +import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.url.GURL; @@ -121,7 +122,7 @@ assert mModel.get(ContextMenuHeaderProperties.TITLE_MAX_LINES) == Integer.MAX_VALUE; final boolean isTitleEmpty = - TextUtils.isEmpty(mModel.get(ContextMenuHeaderProperties.TITLE)); + TextUtils.isEmpty(mModel.get(ListMenuItemProperties.TITLE)); final boolean isUrlEmpty = TextUtils.isEmpty(mModel.get(ContextMenuHeaderProperties.URL)); if (isSecondaryUrlPresent) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderProperties.java index f77ac94..bf7864e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderProperties.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.contextmenu; +import static org.chromium.ui.listmenu.ListMenuItemProperties.TITLE; + import android.graphics.Bitmap; import android.view.View; @@ -18,7 +20,6 @@ /** Invalid value for OVERRIDE_*_PIXEL resources */ static final int INVALID_OVERRIDE = -1; - public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>(); public static final WritableIntPropertyKey TITLE_MAX_LINES = new WritableIntPropertyKey(); public static final WritableObjectPropertyKey<CharSequence> URL = new WritableObjectPropertyKey<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewBinder.java index fefa8a5..aefe9be5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewBinder.java
@@ -14,17 +14,18 @@ import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.R; +import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @NullMarked class ContextMenuHeaderViewBinder { public static void bind(PropertyModel model, View view, PropertyKey propertyKey) { - if (propertyKey == ContextMenuHeaderProperties.TITLE) { + if (propertyKey == ListMenuItemProperties.TITLE) { TextView titleText = view.findViewById(R.id.menu_header_title); - titleText.setText(model.get(ContextMenuHeaderProperties.TITLE)); + titleText.setText(model.get(ListMenuItemProperties.TITLE)); titleText.setVisibility( - TextUtils.isEmpty(model.get(ContextMenuHeaderProperties.TITLE)) + TextUtils.isEmpty(model.get(ListMenuItemProperties.TITLE)) ? View.GONE : View.VISIBLE); } else if (propertyKey == ContextMenuHeaderProperties.TITLE_MAX_LINES) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java index 012dc7b..74417f9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -199,6 +199,9 @@ static final String EXTRA_OPEN_IN_BROWSER_BUTTON_ALLOWED = "androidx.browser.customtabs.extra.OPEN_IN_BROWSER_BUTTON_ALLOWED"; + static final String EXTRA_CUSTOM_CONTENT_ACTIONS = + "androidx.browser.customtabs.extra.CUSTOM_CONTENT_ACTIONS"; + @IntDef({ CustomTabsButtonState.BUTTON_STATE_OFF, CustomTabsButtonState.BUTTON_STATE_ON, @@ -1215,6 +1218,9 @@ intent, TrustedWebActivityIntentBuilder.EXTRA_FILE_HANDLING_DATA)) { featureUsage.log(CustomTabsFeature.EXTRA_FILE_HANDLERS); } + if (IntentUtils.safeHasExtra(intent, EXTRA_CUSTOM_CONTENT_ACTIONS)) { + featureUsage.log(CustomTabsFeature.EXTRA_CUSTOM_CONTENT_ACTIONS); + } } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java index 86d5288..6c37e77 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java
@@ -21,7 +21,7 @@ public static final String CUSTOM_TABS_FEATURE_USAGE_HISTOGRAM = "CustomTabs.FeatureUsage"; // NOTE: This must be kept in sync with the definition |CustomTabsFeatureUsed| - // in tools/metrics/histograms/enums.xml. + // in tools/metrics/histograms/metadata/custom_tabs/enums.xml. // LINT.IfChange(CustomTabsFeature) @IntDef({ CustomTabsFeature.CTF_SESSIONS, @@ -88,6 +88,7 @@ CustomTabsFeature.EXTRA_OPEN_IN_BROWSER_STATE, CustomTabsFeature.EXTRA_LAUNCH_HANDLER, CustomTabsFeature.EXTRA_FILE_HANDLERS, + CustomTabsFeature.EXTRA_CUSTOM_CONTENT_ACTIONS, CustomTabsFeature.COUNT }) @Retention(RetentionPolicy.SOURCE) @@ -159,9 +160,10 @@ int EXTRA_OPEN_IN_BROWSER_STATE = 63; int EXTRA_LAUNCH_HANDLER = 64; int EXTRA_FILE_HANDLERS = 65; + int EXTRA_CUSTOM_CONTENT_ACTIONS = 66; /** Total count of entries. */ - int COUNT = 66; + int COUNT = 67; } // LINT.ThenChange(/tools/metrics/histograms/metadata/custom_tabs/enums.xml:CustomTabsFeatureUsed)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtils.java index 007fc541..fdf3cc8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtils.java
@@ -197,10 +197,11 @@ // Attach information about page to load. intent.setData(Uri.parse(fixedUrl.getSpec())); - if (!TextUtils.isEmpty(params.postDataType) + String postDataType = params.extraHeaders.get("Content-Type"); + if (!TextUtils.isEmpty(postDataType) && params.postData != null && params.postData.length != 0) { - intent.putExtra(IntentHandler.EXTRA_POST_DATA_TYPE, params.postDataType) + intent.putExtra(IntentHandler.EXTRA_POST_DATA_TYPE, postDataType) .putExtra(IntentHandler.EXTRA_POST_DATA, params.postData); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java index 727da6b..395bf32 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -1368,7 +1368,7 @@ // the page importance. return; } - webContents.setPrimaryMainFrameImportance(importance); + webContents.setPrimaryPageImportance(importance, ChildProcessImportance.NORMAL); } /** Hides the current {@link NativePage}, if any, and shows the {@link WebContents}'s view. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java index fc91d47..b4190c8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java
@@ -6,7 +6,6 @@ import androidx.test.filters.SmallTest; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,7 +16,8 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.test.ScreenShooter; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; import org.chromium.ui.base.DeviceFormFactor; /** Simple test to demonstrate use of ScreenShooter rule. */ @@ -26,20 +26,17 @@ @Restriction(DeviceFormFactor.PHONE) // Tab switcher button only exists on phones. public class ExampleUiCaptureTest { @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + public FreshCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.freshChromeTabbedActivityRule(); @Rule public ScreenShooter mScreenShooter = new ScreenShooter(); - @Before - public void setUp() { - mActivityTestRule.startMainActivityFromLauncher(); - } - /** Capture the New Tab Page and the tab switcher. */ @Test @SmallTest @Feature({"UiCatalogue"}) public void testCaptureNewTabPage() { + mActivityTestRule.startFromLauncherAtNtp(); mScreenShooter.shoot("NTP", ScreenShooter.TagsEnum.UiCatalogueExample); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/ContextMenuDragTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/ContextMenuDragTest.java index 18ba365..155e799 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/ContextMenuDragTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/ContextMenuDragTest.java
@@ -14,15 +14,12 @@ import android.view.View; import android.view.View.DragShadowBuilder; -import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import org.junit.After; -import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,16 +27,14 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.chrome.browser.contextmenu.ContextMenuCoordinator; -import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; -import org.chromium.chrome.test.util.ChromeApplicationTestUtils; +import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils; import org.chromium.components.embedder_support.contextmenu.ContextMenuSwitches; import org.chromium.content_public.browser.test.util.DOMUtils; @@ -67,26 +62,21 @@ "/chrome/test/data/android/contextmenu/context_menu_test.html"; private static final String TEST_IMAGE_ID = "testImage"; - @ClassRule - public static ChromeTabbedActivityTestRule sActivityTestRule = - new ChromeTabbedActivityTestRule(); - static TestDragAndDropDelegate sTestDragAndDropDelegate = new TestDragAndDropDelegate(); @Rule - public BlankCTATabInitialStateRule mTestRule = - new BlankCTATabInitialStateRule(sActivityTestRule, false); + public AutoResetCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.fastAutoResetCtaActivityRule(); private EmbeddedTestServer mTestServer; private ContextMenuCoordinator mContextMenu; private String mTestUrl; + private WebPageStation mPage; private Tab mTab; @BeforeClass public static void setupBeforeClass() { - ThreadUtils.runOnUiThreadBlocking(() -> FirstRunStatus.setFirstRunFlowComplete(true)); - // Stop the real call to android View#startDragAndDrop. Test file do not have real touches // over the screen so there's no way to end the drag event properly. Doing this in // @BeforeClass since ViewAndroidDelegate is created earlier than @Before due to batching. @@ -96,16 +86,12 @@ @Before public void setUp() { - mTestServer = - EmbeddedTestServer.createAndStartServer( - ApplicationProvider.getApplicationContext()); + mTestServer = mActivityTestRule.getTestServer(); mTestUrl = mTestServer.getURL(TEST_PATH); - sActivityTestRule.loadUrl(mTestUrl); - mTab = sActivityTestRule.getActivity().getActivityTab(); - CriteriaHelper.pollUiThread(() -> mTab.isUserInteractable() && !mTab.isLoading()); - ChromeApplicationTestUtils.assertWaitForPageScaleFactorMatch( - sActivityTestRule.getActivity(), 0.5f); + mPage = mActivityTestRule.startOnBlankPage().loadWebPageProgrammatically(mTestUrl); + mTab = mPage.getTab(); + mActivityTestRule.assertWaitForPageScaleFactorMatch(0.5f); } @After @@ -117,11 +103,6 @@ sTestDragAndDropDelegate.reset(); } - @AfterClass - public static void tearDownAfterClass() { - ThreadUtils.runOnUiThreadBlocking(() -> FirstRunStatus.setFirstRunFlowComplete(false)); - } - @Test @SmallTest public void testTriggerContextMenu_Image() throws TimeoutException { @@ -161,7 +142,7 @@ final int minDragThresholdPx = (int) - (sActivityTestRule + (mActivityTestRule .getActivity() .getResources() .getDisplayMetrics()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivityTest.java index b7826a7b..bfeb58e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivityTest.java
@@ -20,8 +20,7 @@ import androidx.test.runner.lifecycle.Stage; import org.junit.After; -import org.junit.BeforeClass; -import org.junit.ClassRule; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,7 +44,9 @@ import org.chromium.chrome.browser.bookmarks.BookmarkModelObserver; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.profiles.ProfileManager; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.ReusedCtaTransitTestRule; +import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.BookmarkTestUtil; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.bookmarks.BookmarkItem; @@ -60,49 +61,52 @@ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Batch(Batch.PER_CLASS) public class BookmarkFolderPickerActivityTest { - @ClassRule - public static ChromeTabbedActivityTestRule sActivityTestRule = - new ChromeTabbedActivityTestRule(); + @Rule + public ReusedCtaTransitTestRule<WebPageStation> mActivityTestRule = + ChromeTransitTestRules.blankPageStartReusedActivityRule(); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Captor ArgumentCaptor<BookmarkItem> mBookmarkItemCaptor; @Mock BookmarkModelObserver mBookmarkModelObserver; - private static BookmarkModel sBookmarkModel; - private static BookmarkId sMobileFolderId; - private static BookmarkId sOtherFolderId; - private static BookmarkId sLocalOrSyncableReadingListFolder; + private BookmarkModel mBookmarkModel; + private BookmarkId mMobileFolderId; + private BookmarkId mLocalOrSyncableReadingListFolder; private final BookmarkManagerOpener mBookmarkManagerOpener = new BookmarkManagerOpenerImpl(); + private WebPageStation mBlankPage; private BookmarkFolderPickerActivity mActivity; - @BeforeClass - public static void setUpBeforeClass() throws TimeoutException { - sActivityTestRule.startMainActivityOnBlankPage(); + @Before + public void setUp() { + boolean shouldInitialize = mActivityTestRule.getActivity() == null; + mBlankPage = mActivityTestRule.start(); - ThreadUtils.runOnUiThreadBlocking( - () -> { - sBookmarkModel = - BookmarkModel.getForProfile(ProfileManager.getLastUsedRegularProfile()); - sBookmarkModel.loadEmptyPartnerBookmarkShimForTesting(); - }); + if (shouldInitialize) { + ThreadUtils.runOnUiThreadBlocking( + () -> { + mBookmarkModel = + BookmarkModel.getForProfile( + ProfileManager.getLastUsedRegularProfile()); + mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting(); + }); - BookmarkTestUtil.waitForBookmarkModelLoaded(); - ThreadUtils.runOnUiThreadBlocking( - () -> { - sMobileFolderId = sBookmarkModel.getMobileFolderId(); - sOtherFolderId = sBookmarkModel.getOtherFolderId(); - sLocalOrSyncableReadingListFolder = - sBookmarkModel.getLocalOrSyncableReadingListFolder(); - }); + BookmarkTestUtil.waitForBookmarkModelLoaded(); + ThreadUtils.runOnUiThreadBlocking( + () -> { + mMobileFolderId = mBookmarkModel.getMobileFolderId(); + mLocalOrSyncableReadingListFolder = + mBookmarkModel.getLocalOrSyncableReadingListFolder(); + }); + } } @After public void tearDown() { ThreadUtils.runOnUiThreadBlocking( () -> { - sBookmarkModel.removeAllUserBookmarks(); + mBookmarkModel.removeAllUserBookmarks(); }); } @@ -111,18 +115,18 @@ @Feature({"Bookmark"}) public void testMoveBookmark() throws ExecutionException, TimeoutException, Exception { BookmarkId bookmark = - addBookmark(sMobileFolderId, 0, "bookmark", new GURL("https://google.com")); - BookmarkId folder = addFolder(sMobileFolderId, 1, "folder"); + addBookmark(mMobileFolderId, 0, "bookmark", new GURL("https://google.com")); + BookmarkId folder = addFolder(mMobileFolderId, 1, "folder"); startFolderPickerActivity(bookmark); - ThreadUtils.runOnUiThreadBlocking(() -> sBookmarkModel.addObserver(mBookmarkModelObserver)); + ThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.addObserver(mBookmarkModelObserver)); onView(withText("Mobile bookmarks")).perform(click()); onView(withText("folder")).perform(click()); onView(withText("Move here")).perform(click()); - BookmarkItem oldParent = getBookmarkItem(sMobileFolderId); + BookmarkItem oldParent = getBookmarkItem(mMobileFolderId); BookmarkItem newParent = getBookmarkItem(folder); verifyBookmarkMoved(oldParent, 0, newParent, 0); verifyNoMoreInteractions(mBookmarkModelObserver); @@ -138,18 +142,18 @@ String title = "bookmark"; GURL url = new GURL("https://google.com"); - BookmarkId bookmark = addBookmark(sMobileFolderId, 0, title, url); + BookmarkId bookmark = addBookmark(mMobileFolderId, 0, title, url); startFolderPickerActivity(bookmark); - ThreadUtils.runOnUiThreadBlocking(() -> sBookmarkModel.addObserver(mBookmarkModelObserver)); + ThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.addObserver(mBookmarkModelObserver)); onView(withId(R.id.folder_recycler_view)) .perform(RecyclerViewActions.scrollTo(hasDescendant(withText("Reading list")))); onView(withText("Reading list")).perform(click()); onView(withText("Move here")).perform(click()); - BookmarkItem oldParent = getBookmarkItem(sMobileFolderId); - BookmarkItem newParent = getBookmarkItem(sLocalOrSyncableReadingListFolder); + BookmarkItem oldParent = getBookmarkItem(mMobileFolderId); + BookmarkItem newParent = getBookmarkItem(mLocalOrSyncableReadingListFolder); verifyBookmarkMoved(oldParent, 0, newParent, 0); verifyNoMoreInteractions(mBookmarkModelObserver); @@ -162,7 +166,7 @@ public void testCancelButton() throws ExecutionException, TimeoutException, InterruptedException { BookmarkId bookmark = - addBookmark(sMobileFolderId, 0, "bookmark", new GURL("https://google.com")); + addBookmark(mMobileFolderId, 0, "bookmark", new GURL("https://google.com")); startFolderPickerActivity(bookmark); onView(withText("Cancel")).perform(click()); @@ -171,19 +175,19 @@ } private BookmarkItem getBookmarkItem(BookmarkId bookmarkId) throws ExecutionException { - return ThreadUtils.runOnUiThreadBlocking(() -> sBookmarkModel.getBookmarkById(bookmarkId)); + return ThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.getBookmarkById(bookmarkId)); } private BookmarkId addFolder(BookmarkId parent, int index, String title) throws ExecutionException { return ThreadUtils.runOnUiThreadBlocking( - () -> sBookmarkModel.addFolder(parent, index, title)); + () -> mBookmarkModel.addFolder(parent, index, title)); } private BookmarkId addBookmark(BookmarkId parent, int index, String title, GURL url) throws ExecutionException { return ThreadUtils.runOnUiThreadBlocking( - () -> sBookmarkModel.addBookmark(parent, index, title, url)); + () -> mBookmarkModel.addBookmark(parent, index, title, url)); } private void startFolderPickerActivity(BookmarkId... ids) { @@ -193,8 +197,8 @@ Stage.RESUMED, () -> { mBookmarkManagerOpener.startFolderPickerActivity( - sActivityTestRule.getActivity(), - sActivityTestRule.getProfile(false), + mActivityTestRule.getActivity(), + mActivityTestRule.getProfile(false), ids); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabsTest.java index 24a02b0..8704ee92 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabsTest.java
@@ -21,7 +21,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; @@ -122,7 +121,6 @@ @Test @MediumTest - @DisabledTest(message = "crbug.com/397901349") public void testCloseAllTabsAndClickUndo() { ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -144,7 +142,7 @@ }); CriteriaHelper.pollUiThread(() -> 0 == mArchivedTabModel.getCount()); - TabUiTestHelper.verifyUndoBarShowingAndClickUndo(); + CriteriaHelper.pollInstrumentationThread(TabUiTestHelper::verifyUndoBarShowingAndClickUndo); CriteriaHelper.pollUiThread(() -> 1 == mArchivedTabModel.getCount()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java index 9c41fa6b..455a1023 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
@@ -1917,6 +1917,18 @@ @UiThreadTest @EnableFeatures(ChromeFeatureList.CCT_CONTEXTUAL_MENU_ITEMS) public void testCustomContentActions_Link() throws PendingIntent.CanceledException { + var linkHistogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + ChromeContextMenuPopulator + .getContextualCustomActionTypeSelectedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.LINK) + .expectIntRecord( + ChromeContextMenuPopulator + .getCustomActionTypeDisplayedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.LINK) + .build(); + FirstRunStatus.setFirstRunFlowComplete(true); final int linkActionId = 101; final String linkDescription = "Custom Link Action"; @@ -1955,11 +1967,6 @@ "Custom item ID should be == the starting ID", customItemId == ChromeContextMenuPopulator.getCustomMenuItemIdStartForTesting()); - var linkHistogramWatcher = - HistogramWatcher.newSingleRecordWatcher( - ChromeContextMenuPopulator - .getContextualCustomActionTypeSelectedHistogramForTesting(), - ChromeContextMenuPopulator.ContextualCustomActionType.LINK); assertTrue( "Clicking custom link item should be handled.", mPopulator.onItemSelected( @@ -1998,6 +2005,18 @@ @UiThreadTest @EnableFeatures(ChromeFeatureList.CCT_CONTEXTUAL_MENU_ITEMS) public void testCustomContentActions_Image() throws PendingIntent.CanceledException { + var imageHistogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + ChromeContextMenuPopulator + .getContextualCustomActionTypeSelectedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE) + .expectIntRecord( + ChromeContextMenuPopulator + .getCustomActionTypeDisplayedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE) + .build(); + FirstRunStatus.setFirstRunFlowComplete(true); final int imageActionId = 202; final String imageDescription = "Custom Image Action"; @@ -2065,11 +2084,6 @@ "Custom item ID should be == the starting ID", customItemId == ChromeContextMenuPopulator.getCustomMenuItemIdStartForTesting()); - var imageHistogramWatcher = - HistogramWatcher.newSingleRecordWatcher( - ChromeContextMenuPopulator - .getContextualCustomActionTypeSelectedHistogramForTesting(), - ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE); assertTrue( "Clicking custom image item should be handled.", mPopulator.onItemSelected( @@ -2121,6 +2135,18 @@ @EnableFeatures(ChromeFeatureList.CCT_CONTEXTUAL_MENU_ITEMS) public void testCustomContentActions_ImageLink_DoesNotSetPageUri() throws PendingIntent.CanceledException { + var imageHistogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + ChromeContextMenuPopulator + .getContextualCustomActionTypeSelectedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE) + .expectIntRecord( + ChromeContextMenuPopulator + .getCustomActionTypeDisplayedHistogramForTesting(), + ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE) + .build(); + FirstRunStatus.setFirstRunFlowComplete(true); final int imageActionId = 202; final String imageDescription = "Custom Image Action"; @@ -2188,11 +2214,6 @@ "Custom item ID should be == the starting ID", customItemId == ChromeContextMenuPopulator.getCustomMenuItemIdStartForTesting()); - var imageHistogramWatcher = - HistogramWatcher.newSingleRecordWatcher( - ChromeContextMenuPopulator - .getContextualCustomActionTypeSelectedHistogramForTesting(), - ChromeContextMenuPopulator.ContextualCustomActionType.IMAGE); assertTrue( "Clicking custom image item should be handled.", mPopulator.onItemSelected(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewTest.java index 8819f860..505ff9d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewTest.java
@@ -31,6 +31,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.chrome.R; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.test.util.BlankUiTestActivity; @@ -80,7 +81,7 @@ mImageContainer = mHeaderView.findViewById(R.id.menu_header_image_container); mModel = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) - .with(ContextMenuHeaderProperties.TITLE, "") + .with(ListMenuItemProperties.TITLE, "") .with(ContextMenuHeaderProperties.URL, "") .with(ContextMenuHeaderProperties.SECONDARY_URL, "") .with( @@ -110,7 +111,7 @@ ThreadUtils.runOnUiThreadBlocking( () -> { - mModel.set(ContextMenuHeaderProperties.TITLE, TITLE_STRING); + mModel.set(ListMenuItemProperties.TITLE, TITLE_STRING); mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, 2); }); @@ -216,7 +217,7 @@ ThreadUtils.runOnUiThreadBlocking( () -> { - mModel.set(ContextMenuHeaderProperties.TITLE, TITLE_STRING); + mModel.set(ListMenuItemProperties.TITLE, TITLE_STRING); mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, 1); mModel.set(ContextMenuHeaderProperties.URL, URL_STRING); mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, 1);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java index 2919d4f..5e73440 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -93,6 +93,7 @@ import org.chromium.components.embedder_support.contextmenu.ContextMenuParams; import org.chromium.components.embedder_support.contextmenu.ContextMenuPopulatorFactory; import org.chromium.components.policy.test.annotations.Policies; +import org.chromium.content_public.browser.RenderCoordinates; import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.TestTouchUtils; import org.chromium.content_public.common.ContentFeatures; @@ -149,6 +150,13 @@ private static final String TEST_PATH = "/chrome/test/data/android/contextmenu/context_menu_test.html"; + // LINT.IfChange(PageScaleFactor) + // The initial-scale defined in the test html file meta. The setUp function + // will check that the page scale factor has been updated to this value. + // This ensures the long press/ right click is simulated at the correct + // coordinates of the specified element. See crbug.com/432281754. + private static final double PAGE_SCALE_FACTOR = 0.5; + // LINT.ThenChange(//chrome/test/data/android/contextmenu/context_menu_test.html:PageScaleFactor) private EmbeddedTestServer mTestServer; private String mTestUrl; @@ -220,7 +228,13 @@ deleteTestFiles(); sDownloadTestRule.loadUrl(mTestUrl); Tab tab = sDownloadTestRule.getActivity().getActivityTab(); - CriteriaHelper.pollUiThread(() -> tab.isUserInteractable() && !tab.isLoading()); + CriteriaHelper.pollUiThread( + () -> + tab.isUserInteractable() + && !tab.isLoading() + && RenderCoordinates.fromWebContents(tab.getWebContents()) + .getPageScaleFactor() + == PAGE_SCALE_FACTOR); setupLensChipDelegate(); DownloadUtils.setIsDownloadRestrictedByPolicyForTesting(false); DataProtectionBridgeJni.setInstanceForTesting(mDataProtectionBridgeMock);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettingsTest.java index 414add6..889114b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettingsTest.java
@@ -43,8 +43,10 @@ import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; +import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.browser.signin.SigninTestRule; import org.chromium.components.browser_ui.settings.ChromeSwitchPreference; import org.chromium.components.prefs.PrefService; @@ -60,8 +62,8 @@ @Rule public final SigninTestRule mSigninTestRule = new SigninTestRule(); - public final ChromeTabbedActivityTestRule mActivityTestRule = - new ChromeTabbedActivityTestRule(); + public final FreshCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.freshChromeTabbedActivityRule(); public final SettingsActivityTestRule<GoogleServicesSettings> mSettingsActivityTestRule = new SettingsActivityTestRule<>(GoogleServicesSettings.class); @@ -73,11 +75,12 @@ RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule); @Mock private PasswordManagerUtilBridge.Natives mMockPasswordManagerUtilBridgeJni; + private WebPageStation mPage; @Before public void setUp() { PasswordManagerUtilBridgeJni.setInstanceForTesting(mMockPasswordManagerUtilBridgeJni); - mActivityTestRule.startMainActivityOnBlankPage(); + mPage = mActivityTestRule.startOnBlankPage(); ThreadUtils.runOnUiThreadBlocking( () -> Assert.assertTrue(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/IdentityErrorCardPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/IdentityErrorCardPreferenceTest.java index 9f0fe4c..91255b8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/IdentityErrorCardPreferenceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/IdentityErrorCardPreferenceTest.java
@@ -36,8 +36,10 @@ import org.chromium.chrome.browser.sync.FakeSyncServiceImpl; import org.chromium.chrome.browser.sync.SyncServiceFactory; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; +import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.ChromeRenderTestRule; import org.chromium.chrome.test.util.browser.signin.SigninTestRule; import org.chromium.google_apis.gaia.GoogleServiceAuthError; @@ -51,8 +53,8 @@ public final SettingsActivityTestRule<ManageSyncSettings> mSettingsActivityTestRule = new SettingsActivityTestRule<>(ManageSyncSettings.class); - public final ChromeTabbedActivityTestRule mActivityTestRule = - new ChromeTabbedActivityTestRule(); + public final FreshCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.freshChromeTabbedActivityRule(); // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish // CTA won't work. @@ -78,12 +80,13 @@ @Mock private PasswordManagerUtilBridge.Natives mPasswordManagerUtilBridgeJniMock; private FakeSyncServiceImpl mFakeSyncServiceImpl; + private WebPageStation mPage; @Before public void setUp() { PasswordManagerUtilBridgeJni.setInstanceForTesting(mPasswordManagerUtilBridgeJniMock); - mActivityTestRule.startMainActivityOnBlankPage(); + mPage = mActivityTestRule.startOnBlankPage(); ThreadUtils.runOnUiThreadBlocking( () -> {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java index 46da731..de9c978 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java
@@ -37,6 +37,7 @@ import org.chromium.components.favicon.LargeIconBridge; import org.chromium.components.favicon.LargeIconBridgeJni; import org.chromium.ui.base.TestActivity; +import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.listmenu.MenuModelBridge; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.url.GURL; @@ -219,7 +220,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, JUnitTestGURLs.URL_1.getSpec()) - .with(ContextMenuHeaderProperties.TITLE, "Some Title") + .with(ListMenuItemProperties.TITLE, "Some Title") .with(ContextMenuHeaderProperties.URL_MAX_LINES, 1) .with(ContextMenuHeaderProperties.TITLE_MAX_LINES, 1) .build(); @@ -243,7 +244,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, JUnitTestGURLs.URL_1.getSpec()) - .with(ContextMenuHeaderProperties.TITLE, "Some Title") + .with(ListMenuItemProperties.TITLE, "Some Title") .with(ContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE) .with(ContextMenuHeaderProperties.TITLE_MAX_LINES, Integer.MAX_VALUE) .build(); @@ -267,7 +268,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, "") - .with(ContextMenuHeaderProperties.TITLE, "Some Title") + .with(ListMenuItemProperties.TITLE, "Some Title") .with(ContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE) .with(ContextMenuHeaderProperties.TITLE_MAX_LINES, Integer.MAX_VALUE) .build(); @@ -291,7 +292,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, JUnitTestGURLs.URL_1.getSpec()) - .with(ContextMenuHeaderProperties.TITLE, "") + .with(ListMenuItemProperties.TITLE, "") .with(ContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE) .with(ContextMenuHeaderProperties.TITLE_MAX_LINES, Integer.MAX_VALUE) .build(); @@ -315,7 +316,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, JUnitTestGURLs.URL_1.getSpec()) - .with(ContextMenuHeaderProperties.TITLE, "Some Title") + .with(ListMenuItemProperties.TITLE, "Some Title") .with( ContextMenuHeaderProperties.SECONDARY_URL, JUnitTestGURLs.URL_2.getSpec()) @@ -347,7 +348,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, JUnitTestGURLs.URL_1.getSpec()) - .with(ContextMenuHeaderProperties.TITLE, "Some Title") + .with(ListMenuItemProperties.TITLE, "Some Title") .with( ContextMenuHeaderProperties.SECONDARY_URL, JUnitTestGURLs.URL_2.getSpec()) @@ -381,7 +382,7 @@ PropertyModel model = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS) .with(ContextMenuHeaderProperties.URL, "") - .with(ContextMenuHeaderProperties.TITLE, "") + .with(ListMenuItemProperties.TITLE, "") .with( ContextMenuHeaderProperties.SECONDARY_URL, JUnitTestGURLs.URL_2.getSpec())
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityClientImplUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityClientImplUnitTest.java index ded4a17..4326caeb0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityClientImplUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityClientImplUnitTest.java
@@ -41,6 +41,8 @@ import org.chromium.ui.base.PageTransition; import org.chromium.url.GURL; +import java.util.Map; + @RunWith(BaseRobolectricTestRunner.class) public class SearchActivityClientImplUnitTest { // Placeholder Activity class that guarantees the PackageName is valid for IntentUtils. @@ -380,7 +382,10 @@ activity.setCallingActivity( new ComponentName(ContextUtils.getApplicationContext(), TestActivity.class)); var params = - getLoadUrlParamsBuilder().setpostDataAndType(new byte[] {1, 2}, "data").build(); + getLoadUrlParamsBuilder() + .setPostData(new byte[] {1, 2}) + .setExtraHeaders(Map.of("Content-Type", "data")) + .build(); SearchActivityUtils.resolveOmniboxRequestForResult(mActivity, params); // We should see the same URL on the receiving side.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtilsUnitTest.java index 566e9b4..c001fd0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUtilsUnitTest.java
@@ -49,6 +49,7 @@ import org.chromium.url.GURL; import java.util.List; +import java.util.Map; @RunWith(BaseRobolectricTestRunner.class) @Config( @@ -529,7 +530,11 @@ @Test public void createLoadUrlIntent_paramsWithNullPostData() { - var params = getLoadUrlParamsBuilder().setpostDataAndType(null, "abc").build(); + var params = + getLoadUrlParamsBuilder() + .setPostData(null) + .setExtraHeaders(Map.of("Content-Type", "abc")) + .build(); Intent intent = SearchActivityUtils.createLoadUrlIntent(COMPONENT_TRUSTED, params); assertNotNull(intent); @@ -543,7 +548,11 @@ @Test public void createLoadUrlIntent_paramsWithEmptyPostData() { - var params = getLoadUrlParamsBuilder().setpostDataAndType(new byte[] {}, "abc").build(); + var params = + getLoadUrlParamsBuilder() + .setPostData(new byte[] {}) + .setExtraHeaders(Map.of("Content-Type", "abc")) + .build(); Intent intent = SearchActivityUtils.createLoadUrlIntent(COMPONENT_TRUSTED, params); assertNotNull(intent); @@ -558,7 +567,10 @@ @Test public void createLoadUrlIntent_paramsWithNullPostDataType() { var params = - getLoadUrlParamsBuilder().setpostDataAndType(new byte[] {1, 2, 3}, null).build(); + getLoadUrlParamsBuilder() + .setPostData(new byte[] {1, 2, 3}) + .setExtraHeaders(Map.of()) + .build(); Intent intent = SearchActivityUtils.createLoadUrlIntent(COMPONENT_TRUSTED, params); assertNotNull(intent); @@ -572,7 +584,11 @@ @Test public void createLoadUrlIntent_paramsWithEmptyPostDataType() { - var params = getLoadUrlParamsBuilder().setpostDataAndType(new byte[] {1, 2, 3}, "").build(); + var params = + getLoadUrlParamsBuilder() + .setPostData(new byte[] {1, 2, 3}) + .setExtraHeaders(Map.of("Content-Type", "")) + .build(); Intent intent = SearchActivityUtils.createLoadUrlIntent(COMPONENT_TRUSTED, params); assertNotNull(intent); @@ -587,7 +603,10 @@ @Test public void createLoadUrlIntent_paramsWithValidPostDataType() { var params = - getLoadUrlParamsBuilder().setpostDataAndType(new byte[] {1, 2, 3}, "test").build(); + getLoadUrlParamsBuilder() + .setPostData(new byte[] {1, 2, 3}) + .setExtraHeaders(Map.of("Content-Type", "test")) + .build(); Intent intent = SearchActivityUtils.createLoadUrlIntent(COMPONENT_TRUSTED, params); assertNotNull(intent);
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index c30eb1a..672ee8f 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-140.0.7320.0_pre1492415_rc-r1-merged.afdo.bz2 +chromeos-chrome-arm-140.0.7324.0_pre1492793_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 8ba5500..2fe543c2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8834,6 +8834,12 @@ <message name="IDS_NTP_MODULES_TAB_GROUPS_TITLE" desc="Title for Tab Groups NTP module on the new tab page."> Your tab groups </message> + <message name="IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TITLE" desc="Title shown in the zero state tab groups module."> + Stay organized with tab groups + </message> + <message name="IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TEXT" desc="Text shown in the zero state tab groups module."> + You can group tabs to keep related pages together and saved across your devices + </message> <message name="IDS_NTP_MICROSOFT_AUTHENTICATION_DISABLE_BUTTON_TEXT" desc="Text shown on the disable button of the Microsoft Authentication module."> Don't show this card </message> @@ -18774,6 +18780,9 @@ <message name="IDS_GEMINI_WORKING_ON_TASK_BODY" desc="Text on a toast notification that is shown when gemini is working in the background"> Gemini will keep working on your task </message> + <message name="IDS_NON_MILESTONE_UPDATE_TOAST_BODY" desc="Text on a toast notification that is shown when a non milestone update is complete."> + Chrome was updated + </message> </if> <if expr="is_android">
diff --git a/chrome/app/generated_resources_grd/IDS_NON_MILESTONE_UPDATE_TOAST_BODY.png.sha1 b/chrome/app/generated_resources_grd/IDS_NON_MILESTONE_UPDATE_TOAST_BODY.png.sha1 new file mode 100644 index 0000000..181e7c9 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NON_MILESTONE_UPDATE_TOAST_BODY.png.sha1
@@ -0,0 +1 @@ +f23d8b73ee8f536293c41e747343c2d6184c0ba2 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TEXT.png.sha1 new file mode 100644 index 0000000..559554e --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TEXT.png.sha1
@@ -0,0 +1 @@ +e9184f3496ba803c8c260969a33adaa0414d768c \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TITLE.png.sha1 new file mode 100644 index 0000000..31ef838 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TITLE.png.sha1
@@ -0,0 +1 @@ +98391bcaf6fae8fc9b35b763a08e0c7ca0aa35d1 \ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp index 3013429..2de80c8 100644 --- a/chrome/app/os_settings_search_tag_strings.grdp +++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -860,45 +860,6 @@ <message name="IDS_OS_SETTINGS_TAG_QUICK_ANSWERS_UNIT_CONVERSION" desc="Text for search result item which, when clicked, navigates the user to Quick Answers settings, with a toggle to enable/disable the Quick Answers unit conversion functionality."> Quick Answers unit conversion </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings."> - Google Assistant - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_RELATED_INFO" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable letting Assistant show info related to what's on the screen."> - Google Assistant related information - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_QUICK_ANSWERS" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable letting Assistant show related info when the user right-clicks."> - Google Assistant quick answers - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable letting users summon the Assistant by saying 'Ok Google' out loud. Alternate phrase for: 'Okay Google', 'Hey Google'"> - Google Assistant "Ok Google" - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT1" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable letting users summon the Assistant by saying 'Ok Google' out loud. Alternate phrase for: 'Google Assistant 'Ok Google'', 'Hey Google'"> - Okay Google - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT2" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable letting users summon the Assistant by saying 'Ok Google' out loud. Alternate phrase for: 'Google Assistant 'Ok Google'', 'Okay Google'"> - Hey Google - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_NOTIFICATIONS" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable Assistant notifications."> - Google Assistant Notifications - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_PREFERRED_INPUT" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with a toggle to enable/disable having the preferred input be voice instead of keyboard."> - Google Assistant voice input - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_OFF" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to turn functionality off. Alternate phrase for: 'Disable Google Assistant'"> - Turn off Google Assistant - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_OFF_ALT1" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to turn functionality off. Alternate phrase for: 'Turn off Google Assistant'"> - Disable Google Assistant - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_ON" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to turn functionality on. Alternate phrase for: 'Enable Google Assistant'"> - Turn on Google Assistant - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_ON_ALT1" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to turn functionality on. Alternate phrase for: 'Turn on Google Assistant'"> - Enable Google Assistant - </message> - <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TRAIN_VOICE_MODEL" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to train a voice model to listen for commands such as 'Okay Google' or 'Hey Google'"> - Train Google Assistant voice model - </message> <message name="IDS_OS_SETTINGS_TAG_MAGIC_BOOST" desc="Text for search result item which, when clicked, navigates the user to Google AI settings, with an option to turn functionality on."> Google AI
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF.png.sha1 deleted file mode 100644 index 21e8238..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e96191c0f96f5697eadb1eecebb5df99aca50e21 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON.png.sha1 deleted file mode 100644 index f5e03f5..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c4daf69b887c51d12c2e743250affde99f195add \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD.png.sha1 deleted file mode 100644 index 855a62c..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ad8fa13a5fde99a6c163e813345ef701c2f3b383 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION.png.sha1 deleted file mode 100644 index 3518aab..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -43dca5c6bf482b2b7c1c6b7679572edb2b78f1d0 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION.png.sha1 deleted file mode 100644 index 855a62c..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ad8fa13a5fde99a6c163e813345ef701c2f3b383 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_SCREEN_CONTEXT_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_SCREEN_CONTEXT_DESCRIPTION.png.sha1 deleted file mode 100644 index 1f85cc03..0000000 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_GOOGLE_ASSISTANT_SCREEN_CONTEXT_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e577793c1bdd1c5a71f5f97f1bd49df2f1e76310 \ No newline at end of file
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 7723eb2..1686872 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -84,18 +84,18 @@ If so, please edit your saved password in Chromium so it matches your new password. </message> - <!-- Autofill with AI Page--> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION" desc="The description of the autofill AI button on chrome://settings/autofill."> + <!-- Enhanced autofill Page--> + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION" desc="The description of the enhanced autofill button on chrome://settings/autofill."> Chromium understands forms better and can autofill them faster for you </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_ON" desc="The sublabel of the autofill AI row on chrome://settings/ai when the autofill AI feature is on. + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_ON" desc="The sublabel of the enhanced autofill row on chrome://settings/ai when the enhanced autofill feature is on. "> Chromium understands forms better and can autofill them faster for you. This setting is on. </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_OFF" desc="The sublabel of the autofill AI row on chrome://settings/ai when the autofill AI feature is off."> + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_OFF" desc="The sublabel of the enhanced autofill row on chrome://settings/ai when the enhanced autofill feature is off."> Chromium understands forms better and can autofill them faster for you. This setting is off. </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_TOGGLE_SUB_LABEL" desc="The description of the setting. By 'understand forms better', we mean that when a user submits a form on a website, and if they're using Autofill with AI, this feature can offer to save the user's submitted info. When Chromium saves that info, we save the submitted values and consider the page context."> + <message name="IDS_SETTINGS_AUTOFILL_AI_TOGGLE_SUB_LABEL" desc="The description of the setting. By 'understand forms better', we mean that when a user submits a form on a website, and if they're using enhanced autofill, this feature can offer to save the user's submitted info. When Chromium saves that info, we save the submitted values and consider the page context."> Chromium understands forms better and can autofill them faster for you </message> <message name="IDS_SETTINGS_AUTOFILL_AI_WHEN_ON_USE_TO_FILL" desc="Bullet 2 of 2 that appears beneath the “When on” title. “Later”: this is a two-step feature. 1) data is saved, 2) it becomes valuable to the user later when they want to fill in a form with similar data. “Chromium can ask”: the user has a choice, every time, whether their data is saved and also whether they want to autofill their saved info into forms.">
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 3690114..88bc3d0 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -82,18 +82,20 @@ If so, please edit your saved password in Chrome so it matches your new password. </message> - <!-- Autofill with AI Page--> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION" desc="The description of the autofill AI button on chrome://settings/autofill."> + <!-- Enhanced autofill Page--> + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION" desc="The description of the enhanced autofill button on chrome://settings/autofill."> Chrome understands forms better and can autofill them faster for you </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_ON" desc="The sublabel of the autofill AI row on chrome://settings/ai when the autofill AI feature is on. + <!-- TODO(crbug.com/432641385): Delete this string if UX decided we will not need it in the Autofill settings page.--> + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_ON" desc="The sublabel of the enhanced autofill row on chrome://settings/ai when the enhanced autofill feature is on. "> Chrome understands forms better and can autofill them faster for you. This setting is on. </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_OFF" desc="The sublabel of the autofill AI row on chrome://settings/ai when the autofill AI feature is off."> + <!-- TODO(crbug.com/432641385): Delete this string if UX decided we will not need it in the Autofill settings page.--> + <message name="IDS_SETTINGS_AUTOFILL_AI_DESCRIPTION_FEATURE_OFF" desc="The sublabel of the enhanced autofill row on chrome://settings/ai when the enhanced autofill feature is off."> Chrome understands forms better and can autofill them faster for you. This setting is off. </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_TOGGLE_SUB_LABEL" desc="The description of the setting. By 'understand forms better', we mean that when a user submits a form on a website, and if they're using Autofill with AI, this feature can offer to save the user's submitted info. When Chrome saves that info, we save the submitted values and consider the page context."> + <message name="IDS_SETTINGS_AUTOFILL_AI_TOGGLE_SUB_LABEL" desc="The description of the setting. By 'understand forms better', we mean that when a user submits a form on a website, and if they're using enhanced autofill, this feature can offer to save the user's submitted info. When Chrome saves that info, we save the submitted values and consider the page context."> Chrome understands forms better and can autofill them faster for you </message> <message name="IDS_SETTINGS_AUTOFILL_AI_WHEN_ON_USE_TO_FILL" desc="Bullet 2 of 2 that appears beneath the 'When on' title. 'Later': this is a two-step feature. 1) data is saved, 2) it becomes valuable to the user later when they want to fill in a form with similar data. 'Chrome can ask': the user has a choice, every time, whether their data is saved and also whether they want to autofill their saved info into forms.">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 969b99f..9ad4da4 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -633,31 +633,31 @@ =1 {1 reused password} other {{NUM_REUSED} reused passwords}} </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE" desc="The title of the page in Settings that allows managing the Autofill AI settings."> - Autofill with AI + <message name="IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE" desc="The title of the page in Settings that allows managing the enhanced autofill settings."> + Enhanced autofill </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_WHEN_ON_SAVED_INFO" desc="Bullet 1 of 2 that appears beneath the 'When on' title. 'Autofill': the user is on the 'Autofill with AI' feature page, but we want to frame this new type of autofill as just 'Autofill'. 'Can offer to save info when you submit forms': we want to convey that the user has the choice, each time a form is submitted, whether they want their info saved to Chrome for the purposes of Autofill. 'Like your driver's license or passport number': Today, supported data types for 'Autofill with AI' include 1) driver's licenses, 2) passports, and 3) vehicles. Eventually we'll support more, but this example needs to mention these types of data and not others."> + <message name="IDS_SETTINGS_AUTOFILL_AI_WHEN_ON_SAVED_INFO" desc="Bullet 1 of 2 that appears beneath the 'When on' title. 'Autofill': the user is on the 'enhanced autofill' feature page, but we want to frame this new type of autofill as just 'Autofill'. 'Can offer to save info when you submit forms': we want to convey that the user has the choice, each time a form is submitted, whether they want their info saved to Chrome for the purposes of Autofill. 'Like your driver's license or passport number': Today, supported data types for 'enhanced autofill' include 1) driver's licenses, 2) passports, and 3) vehicles. Eventually we'll support more, but this example needs to mention these types of data and not others."> Autofill can offer to save info when you submit forms, like your driver's license or passport number </message> <message name="IDS_SETTINGS_AUTOFILL_AI_TO_CONSIDER_DATA_USAGE" desc="Bullet 1 of 2 that appears beneath the 'Things to consider' title. The point of this bullet is to convey to the user the types of data that get shared with Google to support this feature. There are 2 data types: 1) 'the page’s URL' and 2) 'content', by which we mean the words, visuals, and layout of the pages the user visits. This notion that Google is considering 'page content' is new. We want to lead with 'To offer suggestions' even though it might be a bit grammatically awkward, because we want to express the need / value before explaining the data that gets shared."> To offer suggestions and improve this feature, the page’s URL and content are shared with Google </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_TO_CONSIDER_STORAGE" desc="Bullet 2 of 2 that appears beneath the 'Things to consider' title. This statement isn't immediately relevant to how Autofill with AI works, but it's intended as a reassuring statement."> + <message name="IDS_SETTINGS_AUTOFILL_AI_TO_CONSIDER_STORAGE" desc="Bullet 2 of 2 that appears beneath the 'Things to consider' title. This statement isn't immediately relevant to how enhanced autofill works, but it's intended as a reassuring statement."> Your saved information is stored on your device </message> <message name="IDS_SETTINGS_AUTOFILL_AI_ENTERPRISE_LOGGING_MANAGED_DISABLED" desc="Text only seen by enterprise users (Google services provided for a company). Users should understand that their content saved with autofill won't be used to improve AI, neither AI features specifically or AI models generally."> Your content will not be used to improve AI. Your organization may change these settings at any time. </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_ENTITY_INSTANCES_HEADER" desc="Header of the entity instance list on the Autofill with AI settings page."> + <message name="IDS_SETTINGS_AUTOFILL_AI_ENTITY_INSTANCES_HEADER" desc="Header of the entity instance list on the enhanced autofill settings page."> Saved information </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_ENTITY_INSTANCES_NONE" desc="Placeholder for empty entity instance list on the Autofill with AI settings page."> + <message name="IDS_SETTINGS_AUTOFILL_AI_ENTITY_INSTANCES_NONE" desc="Placeholder for empty entity instance list on the enhanced autofill settings page."> Saved information will appear here </message> <message name="IDS_SETTINGS_AUTOFILL_AI_MORE_ACTIONS_FOR_ENTITY_INSTANCE" desc="The accessibility label of the More options menu. Options in the menu include 'Edit' and 'Delete'. If including specific verbs in your language adds undo complexity, it's also acceptable to use something like: 'More options for 'label', 'sublabel''. Examples of 'label' and 'sublabel' include 'Toyota Corolla, Vehicle'."> More options to edit or delete <ph name="ENTITY_INSTANCE_LABEL">$1<ex>Toyota</ex></ph>, <ph name="ENTITY_INSTANCE_SUBLABEL">$2<ex>Car</ex></ph> </message> - <message name="IDS_SETTINGS_AUTOFILL_AI_DELETE_ENTITY_INSTANCE_DIALOG_TEXT" desc="The body text of the delete entity instance confirmation dialog, on the Autofill AI settings page."> + <message name="IDS_SETTINGS_AUTOFILL_AI_DELETE_ENTITY_INSTANCE_DIALOG_TEXT" desc="The text that appears beneath a 'Delete object' title. We want the 'Autofill' keyword to be as prominent as possible because that word captures the value of saved information. 'On this device': helps the user understand that information is saved locally, not in the Cloud."> Autofill won't have this info on this device to help fill out forms </message> <message name="IDS_SETTINGS_AUTOFILL_AI_ACCESSIBILITY_LABEL_MONTH_DROPDOWN" desc="The accessibility label on the month dropdown of a date field, to let users know the dropdown corresponds to the month.">
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE.png.sha1 index b96a057f..d15fb1e 100644 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE.png.sha1 +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_PAGE_TITLE.png.sha1
@@ -1 +1 @@ -c611608bed71f933f404cf258a5523c7a940e4e0 \ No newline at end of file +990c10b15e4b64961362e18821d22d57df6a6834 \ No newline at end of file
diff --git a/chrome/app/theme/default_100_percent/google_chrome b/chrome/app/theme/default_100_percent/google_chrome index 7c5faf3..e080fee 160000 --- a/chrome/app/theme/default_100_percent/google_chrome +++ b/chrome/app/theme/default_100_percent/google_chrome
@@ -1 +1 @@ -Subproject commit 7c5faf3ba39880c79b66881410d3255371aa2f4f +Subproject commit e080feee1bd6b3ac5ccff65059ac093f7d46ad08
diff --git a/chrome/app/theme/default_200_percent/google_chrome b/chrome/app/theme/default_200_percent/google_chrome index 74d588d..252c885 160000 --- a/chrome/app/theme/default_200_percent/google_chrome +++ b/chrome/app/theme/default_200_percent/google_chrome
@@ -1 +1 @@ -Subproject commit 74d588d5f54e6ffabad190208a374e0fa45afde7 +Subproject commit 252c8851666cf517fa400ef87ff00d02eae3ee49
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 0030b8f4..5e0181b 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -108,6 +108,11 @@ <structure type="chrome_scaled_image" name="IDR_FORWARD_P" file="common/browser_forward_pressed.png" /> </if> <if expr="not is_android"> + <if expr="_google_chrome"> + <structure type="chrome_scaled_image" name="IDR_GOOGLE_G_GRADIENT_20" file="google_chrome/google_g_gradient_20.png" /> + </if> + </if> + <if expr="not is_android"> <structure type="chrome_scaled_image" name="IDR_HELP_MENU" file="common/help_16.png" /> </if>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 58bed84..0dbdf0f94 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -435,6 +435,8 @@ "dom_distiller/lazy_dom_distiller_service.h", "dom_distiller/profile_utils.cc", "dom_distiller/profile_utils.h", + "dom_distiller/tab_utils.cc", + "dom_distiller/tab_utils.h", "domain_reliability/service_factory.cc", "domain_reliability/service_factory.h", "download/background_download_service_factory.cc", @@ -3052,8 +3054,6 @@ "digital_credentials/digital_identity_provider_android.h", "dom_distiller/dom_distiller_service_factory_android.cc", "dom_distiller/dom_distiller_service_factory_android.h", - "dom_distiller/tab_utils.cc", - "dom_distiller/tab_utils.h", "dom_distiller/tab_utils_android.cc", "download/android/dangerous_download_dialog_bridge.cc", "download/android/dangerous_download_dialog_bridge.h", @@ -8258,12 +8258,6 @@ } if (enable_extensions_core) { - sources += - [ "supervised_user/supervised_user_extensions_metrics_recorder.cc" ] - deps += [ "//chrome/browser/supervised_user" ] - } - - if (enable_extensions) { sources += [ "supervised_user/extension_icon_loader.cc", "supervised_user/extension_icon_loader.h", @@ -8271,10 +8265,18 @@ "supervised_user/supervised_user_extensions_delegate_impl.h", "supervised_user/supervised_user_extensions_manager.cc", "supervised_user/supervised_user_extensions_manager.h", + "supervised_user/supervised_user_extensions_metrics_recorder.cc", ] - deps += [ + "//chrome/browser/supervised_user", "//chrome/browser/ui/extensions", + ] + } + + if (enable_extensions) { + deps += [ + # TODO(crbug.com/402488726): Support supervised user UI on desktop + # Android. "//chrome/browser/ui/supervised_user", # TODO(crbug.com/420905611): Remove this circular dependency when:
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index c6dabe9..f9f4c50 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2444,10 +2444,14 @@ const FeatureEntry::FeatureParam kNtpTabGroupsModuleFakeData[] = { {ntp_features::kNtpTabGroupsModuleDataParam, "Fake Data"}}; +const FeatureEntry::FeatureParam kNtpTabGroupsModuleFakeZeroState[] = { + {ntp_features::kNtpTabGroupsModuleDataParam, "Fake Zero State"}}; const FeatureEntry::FeatureVariation kNtpTabGroupsModuleVariations[] = { {"- Fake Data", kNtpTabGroupsModuleFakeData, std::size(kNtpTabGroupsModuleFakeData), nullptr}, + {"- Fake Zero State", kNtpTabGroupsModuleFakeZeroState, + std::size(kNtpTabGroupsModuleFakeData), nullptr}, }; const FeatureEntry::FeatureParam kNtpMostRelevantTabResumptionModuleFakeData[] = @@ -4733,6 +4737,31 @@ // LINT.ThenChange(//ios/chrome/browser/flags/about_flags.mm:DataSharingVersioningChoices) const FeatureEntry::FeatureParam + kDiskCacheBackendExperimentVariations_Default[] = {{"backend", "default"}}; +const FeatureEntry::FeatureParam + kDiskCacheBackendExperimentVariations_Simple[] = {{"backend", "simple"}}; +#if !BUILDFLAG(IS_ANDROID) +// Block file backend is not supported on Android to reduce the binary size. +const FeatureEntry::FeatureParam + kDiskCacheBackendExperimentVariations_Blockfile[] = { + {"backend", "blockfile"}}; +#endif // !BUILDFLAG(IS_ANDROID) +const FeatureEntry::FeatureParam kDiskCacheBackendExperimentVariations_Sql[] = { + {"backend", "sql"}}; + +const FeatureEntry::FeatureVariation kDiskCacheBackendExperimentVariations[] = { + {"default backend", kDiskCacheBackendExperimentVariations_Default, + std::size(kDiskCacheBackendExperimentVariations_Default), nullptr}, + {"simple backend", kDiskCacheBackendExperimentVariations_Simple, + std::size(kDiskCacheBackendExperimentVariations_Simple), nullptr}, +#if !BUILDFLAG(IS_ANDROID) + {"blockfile backend", kDiskCacheBackendExperimentVariations_Blockfile, + std::size(kDiskCacheBackendExperimentVariations_Blockfile), nullptr}, +#endif // !BUILDFLAG(IS_ANDROID) + {"experimental sql backend", kDiskCacheBackendExperimentVariations_Sql, + std::size(kDiskCacheBackendExperimentVariations_Sql), nullptr}}; + +const FeatureEntry::FeatureParam kSafetyHubDisruptiveNotificationRevocationVariations_RevokeAll[] = { {"shadow_run", "false"}, {"max_engagement_score", "100.0"}, @@ -9867,6 +9896,13 @@ flag_descriptions::kHttpCacheNoVarySearchDescription, kOsAll, FEATURE_VALUE_TYPE(net::features::kHttpCacheNoVarySearch)}, + {"http-cache-custom-backend", + flag_descriptions::kHttpCacheCustomBackendName, + flag_descriptions::kHttpCacheCustomBackendDescription, kOsAll, + FEATURE_WITH_PARAMS_VALUE_TYPE(net::features::kDiskCacheBackendExperiment, + kDiskCacheBackendExperimentVariations, + "DiskCacheBackendExperiment")}, + #if !BUILDFLAG(IS_ANDROID) {"audio-ducking", flag_descriptions::kAudioDuckingName, flag_descriptions::kAudioDuckingDescription, kOsDesktop, @@ -12481,13 +12517,6 @@ "AutofillVcnEnrollStrikeExpiryTime")}, #if BUILDFLAG(IS_ANDROID) - {"autofill-enable-show-save-card-securely-message", - flag_descriptions::kAutofillEnableShowSaveCardSecurelyMessageName, - flag_descriptions::kAutofillEnableShowSaveCardSecurelyMessageDescription, - kOsAndroid, - FEATURE_VALUE_TYPE( - autofill::features::kAutofillEnableShowSaveCardSecurelyMessage)}, - {"background-compact", flag_descriptions::kBackgroundCompactMessageName, flag_descriptions::kBackgroundCompactDescription, kOsAndroid, FEATURE_VALUE_TYPE(base::android::kShouldFreezeSelf)}, @@ -13031,6 +13060,13 @@ #endif // BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID) + {"bookmark-tab-group-conversion", + flag_descriptions::kBookmarkTabGroupConversionName, + flag_descriptions::kBookmarkTabGroupConversionDescription, kOsDesktop, + FEATURE_VALUE_TYPE(features::kBookmarkTabGroupConversion)}, +#endif // !BUILDFLAG(IS_ANDROID) + +#if !BUILDFLAG(IS_ANDROID) {"enable-lens-overlay-straight-to-srp", flag_descriptions::kLensOverlayStraightToSrpName, flag_descriptions::kLensOverlayStraightToSrpDescription, kOsDesktop, @@ -13072,6 +13108,13 @@ FEATURE_VALUE_TYPE(features::kEnableFullscreenToAnyScreenAndroid)}, #endif // BUILDFLAG(IS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) + {"default-search-engine-prewarm", + flag_descriptions::kDefaultSearchEnginePrewarmName, + flag_descriptions::kDefaultSearchEnginePrewarmDescription, kOsDesktop, + FEATURE_VALUE_TYPE(features::kPrewarm)}, +#endif // !BUILDFLAG(IS_ANDROID) + // Add new entries above this line. // NOTE: Adding a new flag requires adding a corresponding entry to enum @@ -13302,10 +13345,10 @@ #endif // BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID) - // Only show Webium flag for Canary channel and developer builds. + // The Webium flag is only for dev testing at the moment. + // TODO(crbug.com/394476530): make the flag available on Canary again. if (!strcmp(kWebiumFlag, entry.internal_name)) { - return chrome::GetChannel() != version_info::Channel::CANARY && - version_info::IsOfficialBuild(); + return version_info::IsOfficialBuild(); } #endif // !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/actor/ui/actor_overlay_view_controller.cc b/chrome/browser/actor/ui/actor_overlay_view_controller.cc index 145b817..6456a10 100644 --- a/chrome/browser/actor/ui/actor_overlay_view_controller.cc +++ b/chrome/browser/actor/ui/actor_overlay_view_controller.cc
@@ -16,8 +16,8 @@ namespace actor::ui { ActorOverlayViewController::ActorOverlayViewController( - tabs::TabInterface* tab_interface) - : tab_interface_(*tab_interface) {} + tabs::TabInterface& tab_interface) + : tab_interface_(tab_interface) {} ActorOverlayViewController::~ActorOverlayViewController() = default;
diff --git a/chrome/browser/actor/ui/actor_overlay_view_controller.h b/chrome/browser/actor/ui/actor_overlay_view_controller.h index 0821ff8..bb6a49a 100644 --- a/chrome/browser/actor/ui/actor_overlay_view_controller.h +++ b/chrome/browser/actor/ui/actor_overlay_view_controller.h
@@ -23,7 +23,7 @@ // to the underlying web content. class ActorOverlayViewController : public mojom::ActorOverlayPageHandler { public: - explicit ActorOverlayViewController(tabs::TabInterface* tab_interface); + explicit ActorOverlayViewController(tabs::TabInterface& tab_interface); ActorOverlayViewController(const ActorOverlayViewController&) = delete; ActorOverlayViewController& operator=(const ActorOverlayViewController&) =
diff --git a/chrome/browser/actor/ui/actor_overlay_view_controller_unittest.cc b/chrome/browser/actor/ui/actor_overlay_view_controller_unittest.cc index f258a4b7..1acc7d9 100644 --- a/chrome/browser/actor/ui/actor_overlay_view_controller_unittest.cc +++ b/chrome/browser/actor/ui/actor_overlay_view_controller_unittest.cc
@@ -14,7 +14,7 @@ class FakeActorOverlayViewController : public ActorOverlayViewController { public: - explicit FakeActorOverlayViewController(tabs::TabInterface* tab_interface) + explicit FakeActorOverlayViewController(tabs::TabInterface& tab_interface) : ActorOverlayViewController(tab_interface) { mock_tab_controller_ = std::make_unique<MockActorUiTabController>(); } @@ -33,7 +33,7 @@ public: ActorOverlayViewControllerTest() { overlay_view_controller = - std::make_unique<FakeActorOverlayViewController>(&mock_tab); + std::make_unique<FakeActorOverlayViewController>(mock_tab); } protected:
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller.cc b/chrome/browser/actor/ui/actor_ui_tab_controller.cc index 15938c0..9a08dcf 100644 --- a/chrome/browser/actor/ui/actor_ui_tab_controller.cc +++ b/chrome/browser/actor/ui/actor_ui_tab_controller.cc
@@ -16,9 +16,25 @@ namespace actor::ui { using ::tabs::TabInterface; -ActorUiTabController::ActorUiTabController(TabInterface& tab, - ActorKeyedService* actor_service) - : tab_(tab), actor_keyed_service_(actor_service) { +ActorUiTabController::ActorUiTabController( + tabs::TabInterface& tab, + ActorKeyedService* actor_service, + std::unique_ptr<ActorOverlayViewController> actor_overlay_view_controller, + std::unique_ptr<HandoffButtonController> handoff_button_controller) + : tab_(tab), + actor_keyed_service_(actor_service), + actor_overlay_view_controller_(std::move(actor_overlay_view_controller)), + handoff_button_controller_(std::move(handoff_button_controller)) { + // Explicitly initialize UI component controllers if a nullptr is provided. + if (!handoff_button_controller_) { + handoff_button_controller_ = + std::make_unique<HandoffButtonController>(*tab_); + } + if (!actor_overlay_view_controller_) { + actor_overlay_view_controller_ = + std::make_unique<ActorOverlayViewController>(*tab_); + } + CHECK(actor_keyed_service_); if (features::kGlicActorUiOverlay.Get()) { tab_subscriptions_.push_back(tab_->RegisterWillDetach(base::BindRepeating( @@ -49,13 +65,13 @@ void ActorUiTabController::OnTabWillDetach(TabInterface* tab, TabInterface::DetachReason reason) { if (features::kGlicActorUiOverlay.Get()) { - GetActorOverlayViewController()->NullifyWebView(); + actor_overlay_view_controller_->NullifyWebView(); } } void ActorUiTabController::OnTabDidInsert(TabInterface* tab) { if (features::kGlicActorUiOverlay.Get()) { - GetActorOverlayViewController()->SetWindowController( + actor_overlay_view_controller_->SetWindowController( tab->GetBrowserWindowInterface() ->GetFeatures() .actor_overlay_window_controller()); @@ -67,6 +83,8 @@ UiResultCallback callback) { if (current_ui_tab_state_ == ui_tab_state && current_tab_active_status_ == tab_active_status) { + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), true)); return; } @@ -86,19 +104,18 @@ if (features::kGlicActorUiOverlay.Get()) { // TODO(crbug.com/425952887): Simplify the is_visible logic to a helper // function that both UI components can use. - GetActorOverlayViewController()->UpdateState( + actor_overlay_view_controller_->UpdateState( current_ui_tab_state_.actor_overlay, current_tab_active_status_ && current_ui_tab_state_.actor_overlay.is_active); } // TODO(crbug.com/428216197): Only notify relevant UI components on change. - if (features::kGlicActorUiHandoffButton.Get() && - GetHandoffButtonController()) { + if (features::kGlicActorUiHandoffButton.Get() && handoff_button_controller_) { // TODO(crbug.com/433568221): Update the visibility logic when ActorOverlay // is integrated into the Tab Controller (For now it's set to true when the // tab is active). - GetHandoffButtonController()->UpdateState( + handoff_button_controller_->UpdateState( current_ui_tab_state_.handoff_button, current_tab_active_status_); } @@ -134,7 +151,7 @@ void ActorUiTabController::BindActorOverlay( mojo::PendingReceiver<mojom::ActorOverlayPageHandler> receiver) { if (features::kGlicActorUiOverlay.Get()) { - GetActorOverlayViewController()->BindOverlay(std::move(receiver)); + actor_overlay_view_controller_->BindOverlay(std::move(receiver)); } } @@ -143,29 +160,11 @@ return; } bool should_be_visible = is_visible && current_tab_active_status_; - GetHandoffButtonController()->UpdateState( - current_ui_tab_state_.handoff_button, should_be_visible); + handoff_button_controller_->UpdateState(current_ui_tab_state_.handoff_button, + should_be_visible); VLOG(4) << "Handoff button turned " << (should_be_visible ? "ON" : "OFF"); } -HandoffButtonController* ActorUiTabController::GetHandoffButtonController() { - if (!handoff_button_controller_) { - handoff_button_controller_ = - std::make_unique<HandoffButtonController>(*tab_); - } - - return handoff_button_controller_.get(); -} - -ActorOverlayViewController* -ActorUiTabController::GetActorOverlayViewController() { - if (!actor_overlay_view_controller_) { - actor_overlay_view_controller_ = - std::make_unique<ActorOverlayViewController>(&*tab_); - } - return actor_overlay_view_controller_.get(); -} - base::WeakPtr<ActorUiTabControllerInterface> ActorUiTabController::GetWeakPtr() { return weak_factory_.GetWeakPtr();
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller.h b/chrome/browser/actor/ui/actor_ui_tab_controller.h index 4be8f9ed..b6afb9c 100644 --- a/chrome/browser/actor/ui/actor_ui_tab_controller.h +++ b/chrome/browser/actor/ui/actor_ui_tab_controller.h
@@ -23,7 +23,11 @@ class ActorUiTabController : public ActorUiTabControllerInterface { public: ActorUiTabController(tabs::TabInterface& tab, - ActorKeyedService* actor_service); + ActorKeyedService* actor_service, + std::unique_ptr<ActorOverlayViewController> + actor_overlay_view_controller = nullptr, + std::unique_ptr<HandoffButtonController> + handoff_button_controller = nullptr); ~ActorUiTabController() override; // ActorUiTabControllerInterface: @@ -43,19 +47,11 @@ void BindActorOverlay( mojo::PendingReceiver<mojom::ActorOverlayPageHandler> receiver) override; - protected: - // The Handoff Button controller for this tab. - std::unique_ptr<HandoffButtonController> handoff_button_controller_; - private: // Called to propagate a UiTabState and tab status change to UI controllers. void UpdateState(const UiTabState& ui_tab_state, bool tab_active_status, UiResultCallback callback); - // Gets a new or existing handoff button controller for this tab. - HandoffButtonController* GetHandoffButtonController(); - // Get a new or existing Actor Overlay View Controller for this tab. - ActorOverlayViewController* GetActorOverlayViewController(); // Tab subscriptions: // Called when the tab is detached. void OnTabWillDetach(tabs::TabInterface* tab, @@ -63,13 +59,7 @@ // Called when the tab is inserted. void OnTabDidInsert(tabs::TabInterface* tab); - // Holds subscriptions for TabInterface callbacks. - std::vector<base::CallbackListSubscription> tab_subscriptions_; - - // Owns this class via TabModel. - const raw_ref<tabs::TabInterface> tab_; - - // The current ui tab state. + // The current UiTabState. UiTabState current_ui_tab_state_ = { .actor_overlay = ActorOverlayState(), .handoff_button = HandoffButtonState(), @@ -79,8 +69,17 @@ // The last active task id actuating on this tab. TaskId active_task_id_; + // Owns this class via TabModel. + const raw_ref<tabs::TabInterface> tab_; + // Holds subscriptions for TabInterface callbacks. + std::vector<base::CallbackListSubscription> tab_subscriptions_; + // The Actor Keyed Service for the associated profile. raw_ptr<ActorKeyedService> actor_keyed_service_ = nullptr; + + // The Actor Overlay View controller for this tab. std::unique_ptr<ActorOverlayViewController> actor_overlay_view_controller_; + // The Handoff Button controller for this tab. + std::unique_ptr<HandoffButtonController> handoff_button_controller_; base::WeakPtrFactory<ActorUiTabController> weak_factory_{this}; };
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc index 7ce45fb..31a9ad58 100644 --- a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc +++ b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/actor/ui/actor_ui_tab_controller.h" +#include "base/functional/callback_helpers.h" #include "base/test/bind.h" #include "chrome/browser/actor/actor_keyed_service.h" #include "chrome/browser/actor/actor_keyed_service_factory.h" @@ -27,26 +28,6 @@ using ::testing::_; using ::testing::Return; -class ActorUiTabControllerFake : public ActorUiTabController { - public: - explicit ActorUiTabControllerFake(tabs::TabInterface& tab, - ActorKeyedService* actor_service) - : ActorUiTabController(tab, actor_service) { - handoff_button_controller_ = - std::make_unique<MockHandoffButtonController>(tab); - - mock_handoff_button_controller_ = static_cast<MockHandoffButtonController*>( - handoff_button_controller_.get()); - } - - MockHandoffButtonController* mock_handoff_button_controller() { - return mock_handoff_button_controller_; - } - - private: - raw_ptr<MockHandoffButtonController> mock_handoff_button_controller_; -}; - class ActorUiTabControllerTest : public testing::Test { public: ActorUiTabControllerTest() = default; @@ -66,8 +47,14 @@ &ActorUiTabControllerTest::BuildActorKeyedService, base::Unretained(this))) .Build(); - actor_ui_tab_controller_ = std::make_unique<ActorUiTabControllerFake>( - mock_tab_, actor_keyed_service()); + auto handoff_button_controller = + std::make_unique<MockHandoffButtonController>(mock_tab()); + mock_handoff_button_controller_ = handoff_button_controller.get(); + + actor_ui_tab_controller_ = std::make_unique<ActorUiTabController>( + mock_tab_, actor_keyed_service(), + /*actor_overlay_view_controller=*/nullptr, + std::move(handoff_button_controller)); ON_CALL(mock_tab_, GetBrowserWindowInterface()) .WillByDefault(Return(&mock_browser_window_interface_)); ON_CALL(mock_browser_window_interface_, GetProfile) @@ -91,7 +78,7 @@ std::unique_ptr<MockActorUiStateManager> ausm = std::make_unique<MockActorUiStateManager>(); ON_CALL(*ausm, GetUiTabController(_)) - .WillByDefault(Return(actor_ui_tab_controller())); + .WillByDefault(Return(actor_ui_tab_controller_.get())); actor_keyed_service->SetActorUiStateManagerForTesting(std::move(ausm)); return std::move(actor_keyed_service); } @@ -101,19 +88,6 @@ ActorKeyedService::Get(profile())); } - ActorUiTabControllerFake* actor_ui_tab_controller() { - return actor_ui_tab_controller_.get(); - } - - ActorUiStateManagerInterface* actor_ui_state_manager() { - return ActorKeyedService::Get(profile())->GetActorUiStateManager(); - } - - MockHandoffButtonController* mock_handoff_button_controller() { - return static_cast<MockHandoffButtonController*>( - actor_ui_tab_controller()->mock_handoff_button_controller()); - } - TaskId task_id() { return task_id_; } TestingProfile* profile() { return profile_.get(); } @@ -123,35 +97,38 @@ private: content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfile> profile_; - std::unique_ptr<ActorUiTabControllerFake> actor_ui_tab_controller_; MockTabInterface mock_tab_; MockBrowserWindowInterface mock_browser_window_interface_; base::test::ScopedFeatureList scoped_feature_list_; TaskId task_id_; + + protected: + std::unique_ptr<ActorUiTabController> actor_ui_tab_controller_; + raw_ptr<MockHandoffButtonController> mock_handoff_button_controller_; }; TEST_F(ActorUiTabControllerTest, SetActorTaskStatePaused_SetsStateCorrectly) { - actor_ui_tab_controller()->SetActorTaskPaused(); + actor_ui_tab_controller_->SetActorTaskPaused(); EXPECT_EQ(actor_keyed_service()->GetTask(task_id())->GetState(), ActorTask::State::kPausedByClient); } TEST_F(ActorUiTabControllerTest, SetActorTaskStateResume_SetsStateCorrectly) { - actor_ui_tab_controller()->SetActorTaskResume(); + actor_ui_tab_controller_->SetActorTaskResume(); EXPECT_EQ(actor_keyed_service()->GetTask(task_id())->GetState(), ActorTask::State::kReflecting); } TEST_F(ActorUiTabControllerTest, OnTabActiveStatusChanged_ChangesVisibility) { // The tab is inactive, so setting it active should make it visible. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(HandoffButtonState(), true)); - actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab()); + actor_ui_tab_controller_->OnTabActiveStatusChanged(true, &mock_tab()); // Now the tab is active. Setting it to inactive should make it invisible. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(HandoffButtonState(), false)); - actor_ui_tab_controller()->OnTabActiveStatusChanged(false, &mock_tab()); + actor_ui_tab_controller_->OnTabActiveStatusChanged(false, &mock_tab()); } TEST_F(ActorUiTabControllerTest, @@ -164,11 +141,16 @@ ON_CALL(mock_tab(), IsActivated).WillByDefault(Return(false)); // The visibility will be false since the tab is inactive. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(handoff_button_state, false)); - actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state, - base::DoNothing()); + base::RunLoop loop; + actor_ui_tab_controller_->OnUiTabStateChange( + ui_tab_state, base::BindLambdaForTesting([&](bool result) { + EXPECT_TRUE(result); + loop.Quit(); + })); + loop.Run(); } TEST_F(ActorUiTabControllerTest, OnUiTabStateChange_NoOpIfStateIsUnchanged) { @@ -176,51 +158,55 @@ ActorOverlayState(true, false, std::nullopt), HandoffButtonState(true, HandoffButtonState::ControlOwnership::kAgent)); - EXPECT_CALL(*mock_handoff_button_controller(), UpdateState(_, _)).Times(1); + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(_, _)).Times(1); - actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state, - base::DoNothing()); - - actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state, - base::DoNothing()); + for (int i = 0; i < 2; i++) { + base::RunLoop loop; + actor_ui_tab_controller_->OnUiTabStateChange( + ui_tab_state, base::BindLambdaForTesting([&](bool result) { + EXPECT_TRUE(result); + loop.Quit(); + })); + loop.Run(); + } } TEST_F(ActorUiTabControllerTest, SetHandoffButtonVisibility_TrueWhenTabIsActiveAndInputIsTrue) { // First, ensure the tab is active. - actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab()); + actor_ui_tab_controller_->OnTabActiveStatusChanged(true, &mock_tab()); // Expect UpdateState to be called with is_visible set to true. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(HandoffButtonState(), true)); - actor_ui_tab_controller()->SetHandoffButtonVisibility(true); + actor_ui_tab_controller_->SetHandoffButtonVisibility(true); } TEST_F(ActorUiTabControllerTest, SetHandoffButtonVisibility_FalseWhenTabIsActiveAndInputIsFalse) { // First, ensure the tab is active. - actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab()); + actor_ui_tab_controller_->OnTabActiveStatusChanged(true, &mock_tab()); // Expect UpdateState to be called with is_visible set to false. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(HandoffButtonState(), false)); - actor_ui_tab_controller()->SetHandoffButtonVisibility(false); + actor_ui_tab_controller_->SetHandoffButtonVisibility(false); } TEST_F(ActorUiTabControllerTest, SetHandoffButtonVisibility_AlwaysFalseWhenTabIsInactive) { // First, ensure the tab is inactive. - actor_ui_tab_controller()->OnTabActiveStatusChanged(false, &mock_tab()); + actor_ui_tab_controller_->OnTabActiveStatusChanged(false, &mock_tab()); // Expect UpdateState to be called with is_visible set to false. - EXPECT_CALL(*mock_handoff_button_controller(), + EXPECT_CALL(*mock_handoff_button_controller_, UpdateState(HandoffButtonState(), false)) .Times(2); - actor_ui_tab_controller()->SetHandoffButtonVisibility(true); - actor_ui_tab_controller()->SetHandoffButtonVisibility(false); + actor_ui_tab_controller_->SetHandoffButtonVisibility(true); + actor_ui_tab_controller_->SetHandoffButtonVisibility(false); } } // namespace
diff --git a/chrome/browser/ai/BUILD.gn b/chrome/browser/ai/BUILD.gn index 4a5f995..9d6a06db 100644 --- a/chrome/browser/ai/BUILD.gn +++ b/chrome/browser/ai/BUILD.gn
@@ -118,6 +118,8 @@ source_set("ai_model_download_progress_manager") { sources = [ + "ai_crx_component.cc", + "ai_crx_component.h", "ai_model_download_progress_manager.cc", "ai_model_download_progress_manager.h", ] @@ -153,6 +155,7 @@ source_set("unit_tests") { testonly = true sources = [ + "ai_crx_component_unittest.cc", "ai_language_model_unittest.cc", "ai_manager_unittest.cc", "ai_model_download_progress_manager_unittest.cc",
diff --git a/chrome/browser/ai/ai_crx_component.cc b/chrome/browser/ai/ai_crx_component.cc new file mode 100644 index 0000000..6c56f62 --- /dev/null +++ b/chrome/browser/ai/ai_crx_component.cc
@@ -0,0 +1,113 @@ +// Copyright 2025 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/ai/ai_crx_component.h" + +#include <memory> + +#include "components/update_client/crx_update_item.h" + +namespace on_device_ai { + +namespace { + +bool IsDownloadEvent(const component_updater::CrxUpdateItem& item) { + // See class comment: components/update_client/component.h + switch (item.state) { + case update_client::ComponentState::kDownloading: + case update_client::ComponentState::kUpdating: + case update_client::ComponentState::kUpToDate: + case update_client::ComponentState::kDownloadingDiff: + case update_client::ComponentState::kUpdatingDiff: + return item.downloaded_bytes >= 0 && item.total_bytes >= 0; + case update_client::ComponentState::kNew: + case update_client::ComponentState::kChecking: + case update_client::ComponentState::kCanUpdate: + case update_client::ComponentState::kUpdated: + case update_client::ComponentState::kUpdateError: + case update_client::ComponentState::kRun: + case update_client::ComponentState::kLastStatus: + return false; + } +} + +bool IsAlreadyInstalled(const component_updater::CrxUpdateItem& item) { + // See class comment: components/update_client/component.h + switch (item.state) { + case update_client::ComponentState::kUpdated: + case update_client::ComponentState::kUpToDate: + return true; + case update_client::ComponentState::kNew: + case update_client::ComponentState::kChecking: + case update_client::ComponentState::kCanUpdate: + case update_client::ComponentState::kDownloading: + case update_client::ComponentState::kUpdating: + case update_client::ComponentState::kUpdateError: + case update_client::ComponentState::kRun: + case update_client::ComponentState::kDownloadingDiff: + case update_client::ComponentState::kUpdatingDiff: + case update_client::ComponentState::kLastStatus: + return false; + } +} + +} // namespace + +// static +base::flat_set<std::unique_ptr<AIModelDownloadProgressManager::Component>> +AICrxComponent::FromComponentIds( + component_updater::ComponentUpdateService* component_update_service, + base::flat_set<std::string> component_ids) { + base::flat_set<std::unique_ptr<Component>> components; + components.reserve(component_ids.size()); + + for (std::string component_id : component_ids) { + components.emplace(std::make_unique<AICrxComponent>( + component_update_service, std::move(component_id))); + } + + return components; +} + +AICrxComponent::AICrxComponent( + component_updater::ComponentUpdateService* component_update_service, + std::string component_id) + : component_id_(std::move(component_id)) { + component_updater::CrxUpdateItem item; + bool success = + component_update_service->GetComponentDetails(component_id_, &item); + + // When `success` returns false, it means the component hasn't + // been registered yet. `GetComponentDetails` doesn't fill out `item` in this + // case, and we can just treat the component as if it had a state of `kNew`. + if (success && IsAlreadyInstalled(item)) { + // We just need to set the downloaded bytes and total bytes equal to each + // other to indicate to the `AIModelDownloadProgressManager` that we're + // installed. + // + // We don't set it to `item`'s `downloaded_bytes` and `total_bytes` because + // they may be less than zero which `AIModelDownloadProgressManager` doesn't + // allow. + SetDownloadedBytes(0); + SetTotalBytes(0); + return; + } + + // Watch for progress updates. + component_updater_observation_.Observe(component_update_service); +} + +AICrxComponent::~AICrxComponent() = default; + +// component_updater::ServiceObserver: +void AICrxComponent::OnEvent(const component_updater::CrxUpdateItem& item) { + if (!IsDownloadEvent(item) || item.id != component_id_) { + return; + } + + SetDownloadedBytes(item.downloaded_bytes); + SetTotalBytes(item.total_bytes); +} + +} // namespace on_device_ai
diff --git a/chrome/browser/ai/ai_crx_component.h b/chrome/browser/ai/ai_crx_component.h new file mode 100644 index 0000000..7502d13 --- /dev/null +++ b/chrome/browser/ai/ai_crx_component.h
@@ -0,0 +1,41 @@ +// Copyright 2025 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_AI_AI_CRX_COMPONENT_H_ +#define CHROME_BROWSER_AI_AI_CRX_COMPONENT_H_ + +#include "chrome/browser/ai/ai_model_download_progress_manager.h" +#include "components/component_updater/component_updater_service.h" + +namespace on_device_ai { + +// A `AIModelDownloadProgressManager::Component` to report progress updates from +// the `ComponentUpdateService` for the `component_id`. +class AICrxComponent : public AIModelDownloadProgressManager::Component, + public component_updater::ServiceObserver { + public: + // Helper function to convert a set of crx component ids to a set of + // `std::unique_ptr`s of this class. + static base::flat_set<std::unique_ptr<Component>> FromComponentIds( + component_updater::ComponentUpdateService* component_update_service, + base::flat_set<std::string> component_ids); + + AICrxComponent( + component_updater::ComponentUpdateService* component_update_service, + std::string component_id); + ~AICrxComponent() override; + + // component_updater::ServiceObserver: + void OnEvent(const component_updater::CrxUpdateItem& item) override; + + private: + std::string component_id_; + + base::ScopedObservation<component_updater::ComponentUpdateService, + component_updater::ComponentUpdateService::Observer> + component_updater_observation_{this}; +}; +} // namespace on_device_ai + +#endif // CHROME_BROWSER_AI_AI_CRX_COMPONENT_H_
diff --git a/chrome/browser/ai/ai_crx_component_unittest.cc b/chrome/browser/ai/ai_crx_component_unittest.cc new file mode 100644 index 0000000..b3cbe6f --- /dev/null +++ b/chrome/browser/ai/ai_crx_component_unittest.cc
@@ -0,0 +1,227 @@ +// Copyright 2025 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/ai/ai_crx_component.h" + +#include <cstdint> +#include <memory> +#include <utility> + +#include "base/barrier_closure.h" +#include "base/task/current_thread.h" +#include "base/test/gtest_util.h" +#include "base/time/time.h" +#include "chrome/browser/ai/ai_model_download_progress_manager.h" +#include "chrome/browser/ai/ai_test_utils.h" +#include "chrome/browser/ai/ai_utils.h" +#include "testing/gmock/include/gmock/gmock-matchers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace on_device_ai { + +using component_updater::CrxUpdateItem; +using testing::_; +using update_client::ComponentState; + +class AICrxComponentTest : public testing::Test { + public: + AICrxComponentTest() = default; + ~AICrxComponentTest() override = default; + + protected: + // Send a download update. + void SendUpdate(const AITestUtils::FakeComponent& component, + ComponentState state, + uint64_t downloaded_bytes) { + component_update_service_.SendUpdate( + component.CreateUpdateItem(state, downloaded_bytes)); + } + + void FastForwardBy(base::TimeDelta delta) { + task_environment_.FastForwardBy(delta); + } + + AITestUtils::FakeComponent& CreateComponent(std::string id, + uint64_t total_bytes) { + auto [iter, emplaced] = fake_components_.try_emplace(id, id, total_bytes); + CHECK(emplaced); + return iter->second; + } + + AITestUtils::MockComponentUpdateService component_update_service_; + + private: + void SetUp() override { + EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) + .WillRepeatedly([&](const std::string& id, CrxUpdateItem* item) { + auto iter = fake_components_.find(id); + if (iter == fake_components_.end()) { + return false; + } + + *item = iter->second.CreateUpdateItem( + update_client::ComponentState::kNew, 0); + + return true; + }); + } + + std::map<std::string, AITestUtils::FakeComponent> fake_components_; + + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; +}; + +TEST_F(AICrxComponentTest, DoesntReceiveUpdatesForNonDownloadEvents) { + AIModelDownloadProgressManager manager; + AITestUtils::FakeMonitor monitor; + AITestUtils::FakeComponent& component = CreateComponent("component_id", 100); + + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds( + &component_update_service_, {component.id()})); + + // Doesn't receive any update for these event states. + for (const auto state : { + ComponentState::kNew, + ComponentState::kChecking, + ComponentState::kCanUpdate, + ComponentState::kUpdated, + ComponentState::kUpdateError, + ComponentState::kRun, + ComponentState::kLastStatus, + }) { + SendUpdate(component, state, 10); + monitor.ExpectNoUpdate(); + FastForwardBy(base::Milliseconds(51)); + } +} + +TEST_F(AICrxComponentTest, + DoesntReceiveUpdatesForEventsWithNegativeDownloadedBytes) { + AIModelDownloadProgressManager manager; + AITestUtils::FakeMonitor monitor; + AITestUtils::FakeComponent& component = CreateComponent("component_id", 100); + + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds( + &component_update_service_, {component.id()})); + + // Doesn't receive an update when the downloaded bytes are negative. + SendUpdate(component, ComponentState::kDownloading, -1); + monitor.ExpectNoUpdate(); + FastForwardBy(base::Milliseconds(51)); +} + +TEST_F(AICrxComponentTest, + DoesntReceiveUpdatesForEventsWithNegativeTotalBytes) { + AIModelDownloadProgressManager manager; + AITestUtils::FakeMonitor monitor; + AITestUtils::FakeComponent& component = CreateComponent("component_id", -1); + + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds( + &component_update_service_, {component.id()})); + + // Doesn't receive an update when the total bytes are negative. + SendUpdate(component, ComponentState::kDownloading, 0); + monitor.ExpectNoUpdate(); + FastForwardBy(base::Milliseconds(51)); +} + +TEST_F(AICrxComponentTest, DoesntReceiveUpdatesForComponentsNotObserving) { + AIModelDownloadProgressManager manager; + AITestUtils::FakeMonitor monitor; + AITestUtils::FakeComponent& component_observed = + CreateComponent("component_id1", 100); + AITestUtils::FakeComponent& component_not_observed = + CreateComponent("component_id2", 100); + + manager.AddObserver( + monitor.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds(&component_update_service_, + {component_observed.id()})); + + // Doesn't receive any update for these event states. + SendUpdate(component_not_observed, ComponentState::kDownloading, 10); + monitor.ExpectNoUpdate(); + FastForwardBy(base::Milliseconds(51)); +} + +TEST_F(AICrxComponentTest, ObservesComponentsMidDownload) { + AIModelDownloadProgressManager manager; + AITestUtils::FakeMonitor monitor1; + AITestUtils::FakeMonitor monitor2; + AITestUtils::FakeComponent& component = CreateComponent("component_id", 100); + + // First, `monitor1` observes `component`. + { + manager.AddObserver(monitor1.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds( + &component_update_service_, {component.id()})); + } + + // Only `monitor1` will receive this update since `monitor2` is not observing. + SendUpdate(component, ComponentState::kDownloading, 0); + monitor1.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); + monitor2.ExpectNoUpdate(); + + // Now both `monitor1` and `monitor2` are observing `component`. + { + manager.AddObserver(monitor2.BindNewPipeAndPassRemote(), + AICrxComponent::FromComponentIds( + &component_update_service_, {component.id()})); + } + + // Send the first update to for `monitor2` waiting more than 50ms so that both + // monitors receive it. + constexpr int64_t update1_for_monitor2 = 60; + FastForwardBy(base::Milliseconds(51)); + SendUpdate(component, ComponentState::kDownloading, update1_for_monitor2); + { + base::RunLoop run_loop; + base::RepeatingClosure update_callback = + base::BarrierClosure(2, run_loop.QuitClosure()); + + // `monitor1` should still be normalized against the total bytes of the + // component. + monitor1.ExpectReceivedNormalizedUpdate( + update1_for_monitor2, component.total_bytes(), update_callback); + + // This is `monitor2`'s first update so it should receive zero and be + // normalized against the remaining bytes. + monitor2.ExpectReceivedNormalizedUpdate( + 0, component.total_bytes() - update1_for_monitor2, update_callback); + + run_loop.Run(); + } + + // Send a second update to for `monitor2` waiting more than 50ms so that both + // monitors receive it. + constexpr int64_t update2_for_monitor2 = 75; + FastForwardBy(base::Milliseconds(51)); + SendUpdate(component, ComponentState::kDownloading, update2_for_monitor2); + { + base::RunLoop run_loop; + base::RepeatingClosure update_callback = + base::BarrierClosure(2, run_loop.QuitClosure()); + + // `monitor1` should still be normalized against the total bytes of the + // component. + monitor1.ExpectReceivedNormalizedUpdate( + update2_for_monitor2, component.total_bytes(), update_callback); + + // `monitor2` should still be normalized against the remaining bytes it + // observed on its first update. The downloaded bytes should also not + // include any bytes that were downloaded before `monitor2` started + // observing. + monitor2.ExpectReceivedNormalizedUpdate( + update2_for_monitor2 - update1_for_monitor2, + component.total_bytes() - update1_for_monitor2, update_callback); + + run_loop.Run(); + } +} + +} // namespace on_device_ai
diff --git a/chrome/browser/ai/ai_manager.cc b/chrome/browser/ai/ai_manager.cc index b30cb01..1279436 100644 --- a/chrome/browser/ai/ai_manager.cc +++ b/chrome/browser/ai/ai_manager.cc
@@ -25,6 +25,7 @@ #include "base/types/pass_key.h" #include "chrome/browser/ai/ai_context_bound_object.h" #include "chrome/browser/ai/ai_context_bound_object_set.h" +#include "chrome/browser/ai/ai_crx_component.h" #include "chrome/browser/ai/ai_language_model.h" #include "chrome/browser/ai/ai_proofreader.h" #include "chrome/browser/ai/ai_rewriter.h" @@ -975,9 +976,11 @@ mojo::PendingRemote<blink ::mojom::ModelDownloadProgressObserver> observer_remote) { model_download_progress_manager_.AddObserver( - &component_update_service_.get(), std::move(observer_remote), - {component_updater::OptimizationGuideOnDeviceModelInstallerPolicy:: - GetOnDeviceModelExtensionId()}); + std::move(observer_remote), + on_device_ai::AICrxComponent::FromComponentIds( + &component_update_service_.get(), + {component_updater::OptimizationGuideOnDeviceModelInstallerPolicy:: + GetOnDeviceModelExtensionId()})); } void AIManager::RenderWidgetHostVisibilityChanged(
diff --git a/chrome/browser/ai/ai_manager.h b/chrome/browser/ai/ai_manager.h index ce2d9f6c..b024d19c 100644 --- a/chrome/browser/ai/ai_manager.h +++ b/chrome/browser/ai/ai_manager.h
@@ -18,6 +18,7 @@ #include "chrome/browser/ai/ai_proofreader.h" #include "chrome/browser/ai/ai_summarizer.h" #include "chrome/browser/ai/ai_utils.h" +#include "components/component_updater/component_updater_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_observer.h"
diff --git a/chrome/browser/ai/ai_model_download_progress_manager.cc b/chrome/browser/ai/ai_model_download_progress_manager.cc index d8c3ac7..8e6efaa9 100644 --- a/chrome/browser/ai/ai_model_download_progress_manager.cc +++ b/chrome/browser/ai/ai_model_download_progress_manager.cc
@@ -5,68 +5,19 @@ #include "chrome/browser/ai/ai_model_download_progress_manager.h" #include "base/functional/bind.h" -#include "base/types/pass_key.h" #include "chrome/browser/ai/ai_utils.h" -#include "components/update_client/crx_update_item.h" -#include "components/update_client/update_client.h" namespace on_device_ai { -namespace { - -bool IsDownloadEvent(const component_updater::CrxUpdateItem& item) { - // See class comment: components/update_client/component.h - switch (item.state) { - case update_client::ComponentState::kDownloading: - case update_client::ComponentState::kUpdating: - case update_client::ComponentState::kUpToDate: - case update_client::ComponentState::kDownloadingDiff: - case update_client::ComponentState::kUpdatingDiff: - return item.downloaded_bytes >= 0 && item.total_bytes >= 0; - case update_client::ComponentState::kNew: - case update_client::ComponentState::kChecking: - case update_client::ComponentState::kCanUpdate: - case update_client::ComponentState::kUpdated: - case update_client::ComponentState::kUpdateError: - case update_client::ComponentState::kRun: - case update_client::ComponentState::kLastStatus: - return false; - } -} - -bool IsAlreadyInstalled(const component_updater::CrxUpdateItem& item) { - // See class comment: components/update_client/component.h - switch (item.state) { - case update_client::ComponentState::kUpdated: - case update_client::ComponentState::kUpToDate: - return true; - case update_client::ComponentState::kNew: - case update_client::ComponentState::kChecking: - case update_client::ComponentState::kCanUpdate: - case update_client::ComponentState::kDownloading: - case update_client::ComponentState::kUpdating: - case update_client::ComponentState::kUpdateError: - case update_client::ComponentState::kRun: - case update_client::ComponentState::kDownloadingDiff: - case update_client::ComponentState::kUpdatingDiff: - case update_client::ComponentState::kLastStatus: - return false; - } -} - -} // namespace - AIModelDownloadProgressManager::AIModelDownloadProgressManager() = default; AIModelDownloadProgressManager::~AIModelDownloadProgressManager() = default; void AIModelDownloadProgressManager::AddObserver( - component_updater::ComponentUpdateService* component_update_service, mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> observer_remote, - base::flat_set<std::string> component_ids) { - reporters_.emplace(std::make_unique<Reporter>(*this, component_update_service, - std::move(observer_remote), - std::move(component_ids))); + base::flat_set<std::unique_ptr<Component>> components) { + reporters_.emplace(std::make_unique<Reporter>( + *this, std::move(observer_remote), std::move(components))); } void AIModelDownloadProgressManager::RemoveReporter(Reporter* reporter) { @@ -78,49 +29,86 @@ return reporters_.size(); } +AIModelDownloadProgressManager::Component::Component() = default; +AIModelDownloadProgressManager::Component::~Component() = default; + +AIModelDownloadProgressManager::Component::Component(Component&&) = default; + +void AIModelDownloadProgressManager::Component::SetDownloadedBytes( + int64_t downloaded_bytes) { + if (downloaded_bytes == downloaded_bytes_) { + return; + } + + // `downloaded_bytes` should be monotonically increasing. + CHECK_GT(downloaded_bytes, downloaded_bytes_.value_or(-1)); + CHECK_GE(downloaded_bytes, 0); + + downloaded_bytes_ = downloaded_bytes; + MaybeRunEventCallback(); +} +void AIModelDownloadProgressManager::Component::SetTotalBytes( + int64_t total_bytes) { + if (total_bytes == total_bytes_) { + return; + } + + // `total_bytes_` should never change after it's been set. + CHECK(!total_bytes_.has_value()); + CHECK_GE(total_bytes, 0); + + total_bytes_ = total_bytes; + MaybeRunEventCallback(); +} + +void AIModelDownloadProgressManager::Component::SetEventCallback( + EventCallback event_callback) { + event_callback_ = std::move(event_callback); +} + +void AIModelDownloadProgressManager::Component::MaybeRunEventCallback() { + if (!determined_bytes() || !event_callback_) { + return; + } + event_callback_.Run(*this); +} + AIModelDownloadProgressManager::Reporter::Reporter( AIModelDownloadProgressManager& manager, - component_updater::ComponentUpdateService* component_update_service, mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> observer_remote, - base::flat_set<std::string> component_ids) + base::flat_set<std::unique_ptr<Component>> components) : manager_(manager), observer_remote_(std::move(observer_remote)), - component_ids_(std::move(component_ids)) { - CHECK(component_update_service); - + components_(std::move(components)) { observer_remote_.set_disconnect_handler(base::BindOnce( - &AIModelDownloadProgressManager::Reporter::OnRemoteDisconnect, - weak_ptr_factory_.GetWeakPtr())); + &Reporter::OnRemoteDisconnect, weak_ptr_factory_.GetWeakPtr())); // Don't watch any components that are already installed. - for (auto iter = component_ids_.begin(); iter != component_ids_.end();) { - component_updater::CrxUpdateItem item; - bool success = component_update_service->GetComponentDetails(*iter, &item); - - // When `success` is false, it means the component hasn't been registered - // yet. `GetComponentDetails` doesn't fill out `item` in this case, and we - // can just treat the component as if it had a state of `kNew`. - if (success && IsAlreadyInstalled(item)) { - iter = component_ids_.erase(iter); + for (auto iter = components_.begin(); iter != components_.end();) { + if ((*iter)->is_complete()) { + iter = components_.erase(iter); } else { + // TODO(crbug.com/425322243): Support passing in an uninstalled component + // with undetermined bytes. + CHECK(!(*iter)->determined_bytes()); + + // Watch for progress updates. + (*iter)->SetEventCallback(base::BindRepeating( + &Reporter::OnEvent, weak_ptr_factory_.GetWeakPtr())); ++iter; } } // If there are no component ids to observe, just send zero and one hundred // percent. - if (component_ids_.empty()) { + if (components_.empty()) { observer_remote_->OnDownloadProgressUpdate( 0, AIUtils::kNormalizedDownloadProgressMax); observer_remote_->OnDownloadProgressUpdate( AIUtils::kNormalizedDownloadProgressMax, AIUtils::kNormalizedDownloadProgressMax); - return; } - - // Watch for progress updates. - component_updater_observation_.Observe(component_update_service); } AIModelDownloadProgressManager::Reporter::~Reporter() = default; @@ -140,16 +128,19 @@ } void AIModelDownloadProgressManager::Reporter::ProcessEvent( - const component_updater::CrxUpdateItem& item) { - CHECK_GE(item.downloaded_bytes, 0); - CHECK_GE(item.total_bytes, 0); + const Component& component) { + // Should only receive events for components that have their bytes determined. + CHECK(component.determined_bytes()); - auto iter = observed_downloaded_bytes_.find(item.id); + CHECK_GE(component.downloaded_bytes(), 0); + CHECK_GE(component.total_bytes(), 0); + + auto iter = observed_downloaded_bytes_.find(&component); // If we've seen this component before, then just update the downloaded bytes // for it. if (iter != observed_downloaded_bytes_.end()) { - iter->second = item.downloaded_bytes; + iter->second = component.downloaded_bytes(); return; } @@ -157,15 +148,15 @@ // `component_downloaded_bytes_` map. CHECK(!ready_to_report_); - auto result = - observed_downloaded_bytes_.insert({item.id, item.downloaded_bytes}); + auto result = observed_downloaded_bytes_.insert( + {&component, component.downloaded_bytes()}); CHECK(result.second); - components_total_bytes_ += item.total_bytes; + components_total_bytes_ += component.total_bytes(); // If we have observed the downloaded bytes of all our components then we're // ready to start reporting. - ready_to_report_ = observed_downloaded_bytes_.size() == component_ids_.size(); + ready_to_report_ = observed_downloaded_bytes_.size() == components_.size(); if (!ready_to_report_) { return; @@ -185,13 +176,8 @@ 0, AIUtils::kNormalizedDownloadProgressMax); } -void AIModelDownloadProgressManager::Reporter::OnEvent( - const component_updater::CrxUpdateItem& item) { - if (!IsDownloadEvent(item) || !component_ids_.contains(item.id)) { - return; - } - - ProcessEvent(item); +void AIModelDownloadProgressManager::Reporter::OnEvent(Component& component) { + ProcessEvent(component); // Wait for the total number of bytes to be downloaded to become determined. if (!ready_to_report_) {
diff --git a/chrome/browser/ai/ai_model_download_progress_manager.h b/chrome/browser/ai/ai_model_download_progress_manager.h index 6c11b74..2686f12 100644 --- a/chrome/browser/ai/ai_model_download_progress_manager.h +++ b/chrome/browser/ai/ai_model_download_progress_manager.h
@@ -11,7 +11,7 @@ #include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" -#include "components/component_updater/component_updater_service.h" +#include "base/types/id_type.h" #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/ai/model_download_progress_observer.mojom.h" @@ -21,6 +21,67 @@ // progress updates for their respective components. class AIModelDownloadProgressManager { public: + // A component can be implemented to report progress for any resource or + // operation. When added to `AIModelDownloadProgressManager` via + // `AddObserver`, it will report its progress updates to the respective + // `ModelDownloadProgressObserver`. + class Component { + public: + Component(); + virtual ~Component(); + + // Move only. + Component(Component&&); + Component& operator=(Component&&) = default; + + protected: + // The implementer calls these when downloaded bytes is changed. Downloaded + // bytes should only ever monotonically increase. + void SetDownloadedBytes(int64_t downloaded_bytes); + + // The implementer calls this when total bytes has been determined. Total + // bytes should never change after its been determined. + void SetTotalBytes(int64_t total_bytes); + + private: + friend AIModelDownloadProgressManager; + + using EventCallback = base::RepeatingCallback<void(Component&)>; + + // Only call if `determined_bytes()` is true. + int64_t downloaded_bytes() const { + CHECK(determined_bytes()); + return downloaded_bytes_.value(); + } + + int64_t total_bytes() const { + CHECK(determined_bytes()); + return total_bytes_.value(); + } + + // True if both total and downloaded bytes are determined and they equal + // each other. + bool is_complete() const { + return determined_bytes() && + (total_bytes_.value() == downloaded_bytes_.value()); + } + + // Returns true if both total and downloaded bytes are determined. + bool determined_bytes() const { + return downloaded_bytes_.has_value() && total_bytes_.has_value(); + } + + // `AIModelDownloadProgressManager` sets the event callback. + void SetEventCallback(EventCallback event_callback); + void MaybeRunEventCallback(); + + std::optional<int64_t> downloaded_bytes_; + std::optional<int64_t> total_bytes_; + + // Called anytime `SetDownloadedBytes()` or `SetTotalBytes()` is called. + EventCallback event_callback_; + }; + AIModelDownloadProgressManager(); ~AIModelDownloadProgressManager(); @@ -31,38 +92,34 @@ const AIModelDownloadProgressManager&) = delete; // Adds a `ModelDownloadProgressObserver` to send progress updates for - // `component_ids`. + // `components`. void AddObserver( - component_updater::ComponentUpdateService* component_update_service, mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> observer_remote, - base::flat_set<std::string> component_ids); + base::flat_set<std::unique_ptr<Component>> components); int GetNumberOfReporters(); private: - // Observes progress updates from the `component_update_service`, filters and - // processes them, and reports the result to `observer_remote`. - class Reporter : public component_updater::ServiceObserver { + // Observes progress updates from `components`, filters and processes them, + // and reports the result to `observer_remote`. + class Reporter { public: - Reporter( - AIModelDownloadProgressManager& manager, - component_updater::ComponentUpdateService* component_update_service, - mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> - observer_remote, - base::flat_set<std::string> component_ids); - ~Reporter() override; + Reporter(AIModelDownloadProgressManager& manager, + mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> + observer_remote, + base::flat_set<std::unique_ptr<Component>> components); + ~Reporter(); // Not copyable or movable. Reporter(const Reporter&) = delete; Reporter& operator=(const Reporter&) = delete; - // component_updater::ServiceObserver: - void OnEvent(const component_updater::CrxUpdateItem& item) override; + void OnEvent(Component& component); private: void OnRemoteDisconnect(); - void ProcessEvent(const component_updater::CrxUpdateItem& item); + void ProcessEvent(const Component& component); int64_t GetDownloadedBytes(); // `manager_` owns `this`. @@ -70,16 +127,15 @@ mojo::Remote<blink::mojom::ModelDownloadProgressObserver> observer_remote_; - base::ScopedObservation<component_updater::ComponentUpdateService, - component_updater::ComponentUpdateService::Observer> - component_updater_observation_{this}; - - // The ids of the components we're reporting the progress for. - base::flat_set<std::string> component_ids_; + // The components we're reporting the progress for. + base::flat_set<std::unique_ptr<Component>> components_; // Map of the components to their observed downloaded bytes. Also serves as // a way to keep track of what components we've observed the total bytes of. - std::map<std::string, int64_t> observed_downloaded_bytes_; + // + // `raw_ptr` safe since `this` owns the `Component` in `components_` and + // `components_` and all its members outlive `observed_downloaded_bytes_`. + std::map<raw_ptr<const Component>, int64_t> observed_downloaded_bytes_; // Sum of all observed components' total_bytes. int64_t components_total_bytes_ = 0;
diff --git a/chrome/browser/ai/ai_model_download_progress_manager_unittest.cc b/chrome/browser/ai/ai_model_download_progress_manager_unittest.cc index 54f39da..2f19649 100644 --- a/chrome/browser/ai/ai_model_download_progress_manager_unittest.cc +++ b/chrome/browser/ai/ai_model_download_progress_manager_unittest.cc
@@ -5,12 +5,9 @@ #include "chrome/browser/ai/ai_model_download_progress_manager.h" #include <cstdint> +#include <memory> -#include "base/barrier_closure.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" #include "base/task/current_thread.h" -#include "base/task/sequenced_task_runner.h" #include "base/test/gtest_util.h" #include "base/time/time.h" #include "chrome/browser/ai/ai_test_utils.h" @@ -20,9 +17,77 @@ namespace on_device_ai { -using component_updater::CrxUpdateItem; using testing::_; -using update_client::ComponentState; +using ComponentList = + base::flat_set<std::unique_ptr<AIModelDownloadProgressManager::Component>>; + +namespace { + +class FakeComponent { + public: + FakeComponent(std::optional<int64_t> downloaded_bytes, + std::optional<int64_t> total_bytes) + : downloaded_bytes_(downloaded_bytes), total_bytes_(total_bytes) {} + + int64_t total_bytes() { + CHECK(total_bytes_.has_value()); + return total_bytes_.value(); + } + + std::unique_ptr<AIModelDownloadProgressManager::Component> GetImpl() { + CHECK(!impl_); + + std::unique_ptr<Impl> impl = std::make_unique<Impl>(); + impl_ = impl->weak_ptr_factory_.GetWeakPtr(); + + // Update total bytes if its already been set. + if (total_bytes_) { + impl_->SetTotalBytes(total_bytes_.value()); + } + // Update downloaded bytes if its already been set. + if (downloaded_bytes_) { + impl_->SetDownloadedBytes(downloaded_bytes_.value()); + } + + return impl; + } + + ComponentList GetImplAsList() { + ComponentList component_list; + component_list.insert(GetImpl()); + return component_list; + } + + void SetTotalBytes(int64_t total_bytes) { + total_bytes_ = total_bytes; + + if (impl_) { + impl_->SetTotalBytes(total_bytes); + } + } + + void SetDownloadedBytes(int64_t downloaded_bytes) { + downloaded_bytes_ = downloaded_bytes; + + if (impl_) { + impl_->SetDownloadedBytes(downloaded_bytes); + } + } + + private: + class Impl : public AIModelDownloadProgressManager::Component { + protected: + friend FakeComponent; + base::WeakPtrFactory<Impl> weak_ptr_factory_{this}; + }; + + base::WeakPtr<Impl> impl_; + + std::optional<int64_t> downloaded_bytes_; + std::optional<int64_t> total_bytes_; +}; + +} // namespace class AIModelDownloadProgressManagerTest : public testing::Test { public: @@ -30,35 +95,11 @@ ~AIModelDownloadProgressManagerTest() override = default; protected: - // Send a download update. - void SendUpdate(const AITestUtils::FakeComponent& component, - ComponentState state, - uint64_t downloaded_bytes) { - component_update_service_.SendUpdate( - component.CreateUpdateItem(state, downloaded_bytes)); - } - void FastForwardBy(base::TimeDelta delta) { task_environment_.FastForwardBy(delta); } - AITestUtils::MockComponentUpdateService component_update_service_; - private: - void SetUp() override { - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillRepeatedly([](const std::string& id, CrxUpdateItem* item) { - item->state = update_client::ComponentState::kNew; - - // Currently the `AIDownloadProgressManager` doesn't check these - // fields, so we can set them to anything. - item->id = id; - item->downloaded_bytes = 0; - item->total_bytes = 100; - - return true; - }); - } base::test::SingleThreadTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; }; @@ -70,21 +111,20 @@ // Should start with no reporters. EXPECT_EQ(manager.GetNumberOfReporters(), 0); - AITestUtils::FakeComponent component("component_id", 100); - { // Adding an Observer, should create a reporter. + FakeComponent component1(std::nullopt, std::nullopt); AITestUtils::FakeMonitor monitor1; - manager.AddObserver(&component_update_service_, - monitor1.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor1.BindNewPipeAndPassRemote(), + component1.GetImplAsList()); EXPECT_EQ(manager.GetNumberOfReporters(), 1); { // Adding an Observer, should create a reporter. + FakeComponent component2(std::nullopt, std::nullopt); AITestUtils::FakeMonitor monitor2; - manager.AddObserver(&component_update_service_, - monitor2.BindNewPipeAndPassRemote(), - {component.id()}); + manager.AddObserver(monitor2.BindNewPipeAndPassRemote(), + component2.GetImplAsList()); EXPECT_EQ(manager.GetNumberOfReporters(), 2); } // `manager` should have destroyed the `Reporter` associated with @@ -99,10 +139,10 @@ TEST_F(AIModelDownloadProgressManagerTest, FirstUpdateIsReportedAsZero) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); + FakeComponent component(std::nullopt, 100); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // No events should be fired until the first update. monitor.ExpectNoUpdate(); @@ -110,7 +150,7 @@ // The first update should be reported as zero. And `total_bytes` should // always be `kNormalizedProgressMax` (0x10000). - SendUpdate(component, ComponentState::kDownloading, 10); + component.SetDownloadedBytes(10); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); // No other events should be fired. @@ -120,13 +160,13 @@ TEST_F(AIModelDownloadProgressManagerTest, ProgressIsNormalized) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); + FakeComponent component(std::nullopt, 100); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Should receive the first update. - SendUpdate(component, ComponentState::kDownloading, 0); + component.SetDownloadedBytes(0); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Wait more than 50ms so we can receive the next event. @@ -138,7 +178,7 @@ AIUtils::NormalizeModelDownloadProgress(downloaded_bytes, component.total_bytes()); - SendUpdate(component, ComponentState::kDownloading, downloaded_bytes); + component.SetDownloadedBytes(downloaded_bytes); monitor.ExpectReceivedUpdate(normalized_downloaded_bytes, AIUtils::kNormalizedDownloadProgressMax); } @@ -147,15 +187,15 @@ AlreadyDownloadedBytesArentIncludedInProgress) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); + FakeComponent component(std::nullopt, 100); int64_t already_downloaded_bytes = 10; - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Send the first update with the already downloaded bytes for `component`. - SendUpdate(component, ComponentState::kDownloading, already_downloaded_bytes); + component.SetDownloadedBytes(already_downloaded_bytes); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Wait more than 50ms so we can receive the next event. @@ -168,7 +208,7 @@ downloaded_bytes - already_downloaded_bytes, component.total_bytes() - already_downloaded_bytes); - SendUpdate(component, ComponentState::kDownloading, downloaded_bytes); + component.SetDownloadedBytes(downloaded_bytes); monitor.ExpectReceivedUpdate(normalized_downloaded_bytes, AIUtils::kNormalizedDownloadProgressMax); } @@ -177,14 +217,14 @@ MaxIsSentWhenDownloadedBytesEqualsTotalBytes) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component( - "component_id", AIUtils::kNormalizedDownloadProgressMax * 5); + FakeComponent component(std::nullopt, + AIUtils::kNormalizedDownloadProgressMax * 5); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Should receive the zero update. - SendUpdate(component, ComponentState::kDownloading, 10); + component.SetDownloadedBytes(10); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Wait more than 50ms so we can receive the next event. @@ -192,13 +232,12 @@ // Sending less than the total bytes should not send the // `kNormalizedDownloadProgressMax`. - SendUpdate(component, ComponentState::kDownloading, - component.total_bytes() - 1); + component.SetDownloadedBytes(component.total_bytes() - 1); monitor.ExpectReceivedUpdate(AIUtils::kNormalizedDownloadProgressMax - 1, AIUtils::kNormalizedDownloadProgressMax); // Sending the total bytes should send the `kNormalizedDownloadProgressMax`. - SendUpdate(component, ComponentState::kDownloading, component.total_bytes()); + component.SetDownloadedBytes(component.total_bytes()); monitor.ExpectReceivedUpdate(AIUtils::kNormalizedDownloadProgressMax, AIUtils::kNormalizedDownloadProgressMax); } @@ -207,99 +246,26 @@ MaxIsSentWhenDownloadedBytesEqualsTotalBytesForFirstUpdate) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component( - "component_id", AIUtils::kNormalizedDownloadProgressMax * 5); + FakeComponent component(std::nullopt, + AIUtils::kNormalizedDownloadProgressMax * 5); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // If the first update has downloaded bytes equal to total bytes, then both // the the zero and max events should be fired. - SendUpdate(component, ComponentState::kDownloading, component.total_bytes()); + component.SetDownloadedBytes(component.total_bytes()); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); monitor.ExpectReceivedUpdate(AIUtils::kNormalizedDownloadProgressMax, AIUtils::kNormalizedDownloadProgressMax); } TEST_F(AIModelDownloadProgressManagerTest, - DoesntReceiveUpdatesForNonDownloadEvents) { - AIModelDownloadProgressManager manager; - AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); - - // Doesn't receive any update for these event states. - for (const auto state : { - ComponentState::kNew, - ComponentState::kChecking, - ComponentState::kCanUpdate, - ComponentState::kUpdated, - ComponentState::kUpdateError, - ComponentState::kRun, - ComponentState::kLastStatus, - }) { - SendUpdate(component, state, 10); - monitor.ExpectNoUpdate(); - FastForwardBy(base::Milliseconds(51)); - } -} - -TEST_F(AIModelDownloadProgressManagerTest, - DoesntReceiveUpdatesForEventsWithNegativeDownloadedBytes) { - AIModelDownloadProgressManager manager; - AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); - - // Doesn't receive an update when the downloaded bytes are negative. - SendUpdate(component, ComponentState::kDownloading, -1); - monitor.ExpectNoUpdate(); - FastForwardBy(base::Milliseconds(51)); -} - -TEST_F(AIModelDownloadProgressManagerTest, - DoesntReceiveUpdatesForEventsWithNegativeTotalBytes) { - AIModelDownloadProgressManager manager; - AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", -1); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); - - // Doesn't receive an update when the total bytes are negative. - SendUpdate(component, ComponentState::kDownloading, 0); - monitor.ExpectNoUpdate(); - FastForwardBy(base::Milliseconds(51)); -} - -TEST_F(AIModelDownloadProgressManagerTest, - DoesntReceiveUpdatesForComponentsNotObserving) { - AIModelDownloadProgressManager manager; - AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component_observed("component_id1", 100); - AITestUtils::FakeComponent component_not_observed("component_id2", 100); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component_observed.id()}); - - // Doesn't receive any update for these event states. - SendUpdate(component_not_observed, ComponentState::kDownloading, 10); - monitor.ExpectNoUpdate(); - FastForwardBy(base::Milliseconds(51)); -} - -TEST_F(AIModelDownloadProgressManagerTest, ReceiveZeroAndHundredPercentForNoComponents) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), {}); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); monitor.ExpectReceivedUpdate(AIUtils::kNormalizedDownloadProgressMax, AIUtils::kNormalizedDownloadProgressMax); @@ -308,29 +274,29 @@ TEST_F(AIModelDownloadProgressManagerTest, OnlyReceivesUpdatesEvery50ms) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); + FakeComponent component(std::nullopt, 100); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Should receive the first update. - SendUpdate(component, ComponentState::kDownloading, 0); + component.SetDownloadedBytes(0); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Shouldn't receive this update since it hasn't been 50ms since the last // update. - SendUpdate(component, ComponentState::kDownloading, 15); + component.SetDownloadedBytes(15); // Wait more than 50ms so we can receive the next event. FastForwardBy(base::Milliseconds(51)); // Should receive the this since it's been over 50ms since the last update. - SendUpdate(component, ComponentState::kDownloading, 20); + component.SetDownloadedBytes(20); monitor.ExpectReceivedNormalizedUpdate(20, component.total_bytes()); // Shouldn't receive this update since it hasn't been 50ms since the last // update. - SendUpdate(component, ComponentState::kDownloading, 25); + component.SetDownloadedBytes(25); } TEST_F(AIModelDownloadProgressManagerTest, OnlyReceivesUpdatesForNewProgress) { @@ -338,14 +304,14 @@ AITestUtils::FakeMonitor monitor; // Set its total to twice kNormalizedProgressMax so that there are two raw // download progresses that map to every normalized download progress. - AITestUtils::FakeComponent component( - "component_id", AIUtils::kNormalizedDownloadProgressMax * 2); + FakeComponent component(std::nullopt, + AIUtils::kNormalizedDownloadProgressMax * 2); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Should receive the first update as zero. - SendUpdate(component, ComponentState::kDownloading, 0); + component.SetDownloadedBytes(0); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Wait more than 50ms so we can receive the next event. @@ -353,14 +319,14 @@ // Should be able to receive this progress event since we haven't seen it // before. - SendUpdate(component, ComponentState::kDownloading, 10); + component.SetDownloadedBytes(10); monitor.ExpectReceivedNormalizedUpdate(10, component.total_bytes()); // Wait more than 50ms so we can receive the next event. FastForwardBy(base::Milliseconds(51)); // Shouldn't be able to receive this progress event since we've just seen it. - SendUpdate(component, ComponentState::kDownloading, 10); + component.SetDownloadedBytes(10); // Wait more than 50ms so we can receive the next event. FastForwardBy(base::Milliseconds(51)); @@ -370,25 +336,25 @@ CHECK_EQ( AIUtils::NormalizeModelDownloadProgress(10, component.total_bytes()), AIUtils::NormalizeModelDownloadProgress(11, component.total_bytes())); - SendUpdate(component, ComponentState::kDownloading, 11); + component.SetDownloadedBytes(11); FastForwardBy(base::Milliseconds(51)); } TEST_F(AIModelDownloadProgressManagerTest, ShouldReceive100percent) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component("component_id", 100); + FakeComponent component(std::nullopt, 100); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), {component.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + component.GetImplAsList()); // Should receive the first update. - SendUpdate(component, ComponentState::kDownloading, 10); + component.SetDownloadedBytes(10); monitor.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); // Should receive the second update since it's 100% even though 50ms haven't // elapsed. - SendUpdate(component, ComponentState::kDownloading, component.total_bytes()); + component.SetDownloadedBytes(component.total_bytes()); monitor.ExpectReceivedNormalizedUpdate(component.total_bytes(), component.total_bytes()); @@ -400,20 +366,22 @@ AllComponentsMustBeObservedBeforeSendingEvents) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); + FakeComponent component1(std::nullopt, 100); + FakeComponent component2(std::nullopt, 1000); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); // Shouldn't receive this updates since we haven't observed `component2` yet. - SendUpdate(component1, ComponentState::kDownloading, 0); + component1.SetDownloadedBytes(0); monitor.ExpectNoUpdate(); FastForwardBy(base::Milliseconds(51)); // Should receive this update since now we've seen both components. - SendUpdate(component2, ComponentState::kDownloading, 10); + component2.SetDownloadedBytes(10); uint64_t total_bytes = component1.total_bytes() + component2.total_bytes(); monitor.ExpectReceivedNormalizedUpdate(0, total_bytes); } @@ -422,20 +390,20 @@ ProgressIsNormalizedAgainstTheSumOfTheComponentsTotalBytes) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); + FakeComponent component1(std::nullopt, 100); + FakeComponent component2(std::nullopt, 1000); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); // Trigger the first event by sending updates for components 1 and 2. uint64_t component1_downloaded_bytes = 0; - SendUpdate(component1, ComponentState::kDownloading, - component1_downloaded_bytes); + component1.SetDownloadedBytes(component1_downloaded_bytes); uint64_t component2_downloaded_bytes = 0; - SendUpdate(component2, ComponentState::kDownloading, - component2_downloaded_bytes); + component2.SetDownloadedBytes(component2_downloaded_bytes); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); // Wait more than 50ms so we can receive the next event. @@ -443,8 +411,7 @@ // Component 2 receives another 5 bytes. component2_downloaded_bytes += 5; - SendUpdate(component2, ComponentState::kDownloading, - component2_downloaded_bytes); + component2.SetDownloadedBytes(component2_downloaded_bytes); // Should receive an update of the sum of component1 and component2's // downloaded bytes normalized with the sum of their total_bytes @@ -462,33 +429,32 @@ AlreadyDownloadedBytesArentIncludedInProgressForMultipleComponents) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); + FakeComponent component1(std::nullopt, 100); + FakeComponent component2(std::nullopt, 1000); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); int64_t already_downloaded_bytes = 0; - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); // Send an update for component 1. uint64_t component1_downloaded_bytes = 5; already_downloaded_bytes += 5; - SendUpdate(component1, ComponentState::kDownloading, - component1_downloaded_bytes); + component1.SetDownloadedBytes(component1_downloaded_bytes); // Send a second update for component 1. This increases the already downloaded // bytes that shouldn't be included in the progress. component1_downloaded_bytes += 5; already_downloaded_bytes += 5; - SendUpdate(component1, ComponentState::kDownloading, - component1_downloaded_bytes); + component1.SetDownloadedBytes(component1_downloaded_bytes); // Send an update for component 2 triggering the zero event. This increases // the already downloaded bytes that shouldn't be included in the progress. uint64_t component2_downloaded_bytes = 10; already_downloaded_bytes += 10; - SendUpdate(component2, ComponentState::kDownloading, - component2_downloaded_bytes); + component2.SetDownloadedBytes(component2_downloaded_bytes); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); // Wait more than 50ms so we can receive the next event. @@ -496,8 +462,7 @@ // Component 2 receives another 5 bytes. component2_downloaded_bytes += 5; - SendUpdate(component2, ComponentState::kDownloading, - component2_downloaded_bytes); + component2.SetDownloadedBytes(component2_downloaded_bytes); // The progress we receive shouldn't include the `already_downloaded_bytes`. uint64_t downloaded_bytes = @@ -512,78 +477,43 @@ AIUtils::kNormalizedDownloadProgressMax); } -class AIModelDownloadProgressManagerHasPreviousDownloadsTest - : public AIModelDownloadProgressManagerTest { - public: - AIModelDownloadProgressManagerHasPreviousDownloadsTest() = default; - ~AIModelDownloadProgressManagerHasPreviousDownloadsTest() override = default; - - private: - // Don't expect that GetComponentIDs will return an empty vector. - void SetUp() override {} -}; - -TEST_F(AIModelDownloadProgressManagerHasPreviousDownloadsTest, +TEST_F(AIModelDownloadProgressManagerTest, AlreadyInstalledComponentsAreNotObserved) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); + FakeComponent component1(100, 100); + FakeComponent component2(std::nullopt, 1000); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component1.CreateUpdateItem( - update_client::ComponentState::kUpToDate, 0); - return true; - }) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = - component2.CreateUpdateItem(update_client::ComponentState::kNew, 0); - return true; - }); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); // Should receive this despite not observing component 1 yet since component1 // is already downloaded. - SendUpdate(component2, ComponentState::kDownloading, 0); + component2.SetDownloadedBytes(0); monitor.ExpectReceivedNormalizedUpdate(0, component2.total_bytes()); } -TEST_F(AIModelDownloadProgressManagerHasPreviousDownloadsTest, +TEST_F(AIModelDownloadProgressManagerTest, ProgressIsNormalizedAgainstOnlyUninstalledComponents) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); - AITestUtils::FakeComponent component3("component_id3", 500); + FakeComponent component1(100, 100); + FakeComponent component2(std::nullopt, 1000); + FakeComponent component3(std::nullopt, 500); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); + component_list.insert(component3.GetImpl()); - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component1.CreateUpdateItem( - update_client::ComponentState::kUpToDate, 0); - return true; - }) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = - component2.CreateUpdateItem(update_client::ComponentState::kNew, 0); - return true; - }) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = - component3.CreateUpdateItem(update_client::ComponentState::kNew, 0); - return true; - }); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id(), component3.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); // Fire the zero progress event by sending events for component 2 and 3. - SendUpdate(component2, ComponentState::kDownloading, 0); - SendUpdate(component3, ComponentState::kDownloading, 0); + component2.SetDownloadedBytes(0); + component3.SetDownloadedBytes(0); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); // Wait more than 50ms so we can receive the next event. @@ -591,122 +521,26 @@ // Progress should be normalized against only components 2 and 3 since 1 is // already installed. - SendUpdate(component2, ComponentState::kDownloading, 10); + component2.SetDownloadedBytes(10); uint64_t total_bytes = component2.total_bytes() + component3.total_bytes(); monitor.ExpectReceivedNormalizedUpdate(10, total_bytes); } -TEST_F(AIModelDownloadProgressManagerHasPreviousDownloadsTest, +TEST_F(AIModelDownloadProgressManagerTest, ReceiveZeroAndHundredPercentWhenEverythingIsInstalled) { AIModelDownloadProgressManager manager; AITestUtils::FakeMonitor monitor; - AITestUtils::FakeComponent component1("component_id1", 100); - AITestUtils::FakeComponent component2("component_id2", 1000); + FakeComponent component1(100, 100); + FakeComponent component2(1000, 1000); + ComponentList component_list; + component_list.insert(component1.GetImpl()); + component_list.insert(component2.GetImpl()); - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component1.CreateUpdateItem( - update_client::ComponentState::kUpToDate, 0); - return true; - }) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component2.CreateUpdateItem( - update_client::ComponentState::kUpToDate, 0); - return true; - }); - - manager.AddObserver(&component_update_service_, - monitor.BindNewPipeAndPassRemote(), - {component1.id(), component2.id()}); + manager.AddObserver(monitor.BindNewPipeAndPassRemote(), + std::move(component_list)); monitor.ExpectReceivedUpdate(0, AIUtils::kNormalizedDownloadProgressMax); monitor.ExpectReceivedUpdate(AIUtils::kNormalizedDownloadProgressMax, AIUtils::kNormalizedDownloadProgressMax); } -TEST_F(AIModelDownloadProgressManagerHasPreviousDownloadsTest, - ObservesComponentsMidDownload) { - AIModelDownloadProgressManager manager; - AITestUtils::FakeMonitor monitor1; - AITestUtils::FakeMonitor monitor2; - AITestUtils::FakeComponent component("component_id1", 100); - - // First, `monitor1` observes `component`. - { - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component.CreateUpdateItem( - update_client::ComponentState::kNew, 0); - return true; - }); - manager.AddObserver(&component_update_service_, - monitor1.BindNewPipeAndPassRemote(), {component.id()}); - } - - // Only `monitor1` will receive this update since `monitor2` is not observing. - SendUpdate(component, ComponentState::kDownloading, 0); - monitor1.ExpectReceivedNormalizedUpdate(0, component.total_bytes()); - monitor2.ExpectNoUpdate(); - - // Now both `monitor1` and `monitor2` are observing `component`. - { - EXPECT_CALL(component_update_service_, GetComponentDetails(_, _)) - .WillOnce([&](const std::string& id, CrxUpdateItem* item) { - *item = component.CreateUpdateItem( - update_client::ComponentState::kDownloading, 0); - return true; - }); - manager.AddObserver(&component_update_service_, - monitor2.BindNewPipeAndPassRemote(), {component.id()}); - } - - // Send the first update to for `monitor2` waiting more than 50ms so that both - // monitors receive it. - constexpr int64_t update1_for_monitor2 = 60; - FastForwardBy(base::Milliseconds(51)); - SendUpdate(component, ComponentState::kDownloading, update1_for_monitor2); - { - base::RunLoop run_loop; - base::RepeatingClosure update_callback = - base::BarrierClosure(2, run_loop.QuitClosure()); - - // `monitor1` should still be normalized against the total bytes of the - // component. - monitor1.ExpectReceivedNormalizedUpdate( - update1_for_monitor2, component.total_bytes(), update_callback); - - // This is `monitor2`'s first update so it should receive zero and be - // normalized against the remaining bytes. - monitor2.ExpectReceivedNormalizedUpdate( - 0, component.total_bytes() - update1_for_monitor2, update_callback); - - run_loop.Run(); - } - - // Send a second update to for `monitor2` waiting more than 50ms so that both - // monitors receive it. - constexpr int64_t update2_for_monitor2 = 75; - FastForwardBy(base::Milliseconds(51)); - SendUpdate(component, ComponentState::kDownloading, update2_for_monitor2); - { - base::RunLoop run_loop; - base::RepeatingClosure update_callback = - base::BarrierClosure(2, run_loop.QuitClosure()); - - // `monitor1` should still be normalized against the total bytes of the - // component. - monitor1.ExpectReceivedNormalizedUpdate( - update2_for_monitor2, component.total_bytes(), update_callback); - - // `monitor2` should still be normalized against the remaining bytes it - // observed on its first update. The downloaded bytes should also not - // include any bytes that were downloaded before `monitor2` started - // observing. - monitor2.ExpectReceivedNormalizedUpdate( - update2_for_monitor2 - update1_for_monitor2, - component.total_bytes() - update1_for_monitor2, update_callback); - - run_loop.Run(); - } -} - } // namespace on_device_ai
diff --git a/chrome/browser/ai/ai_rewriter_unittest.cc b/chrome/browser/ai/ai_rewriter_unittest.cc index 41a39651..1595d3e 100644 --- a/chrome/browser/ai/ai_rewriter_unittest.cc +++ b/chrome/browser/ai/ai_rewriter_unittest.cc
@@ -477,6 +477,21 @@ callback.Get()); } +TEST_F(AIRewriterTest, ToProtoOptionsLanguagesSupported) { + // Rewriter proto expects base language display names in English. + std::vector<std::pair<std::string, std::string>> languages = { + {"en", "English"}, {"en-us", "English"}, {"en-uk", "English"}, + {"es", "Spanish"}, {"es-sp", "Spanish"}, {"es-mx", "Spanish"}, + {"ja", "Japanese"}, {"ja-jp", "Japanese"}, {"ja-foo", "Japanese"}, + }; + blink::mojom::AIRewriterCreateOptionsPtr options = GetDefaultOptions(); + for (const auto& language : languages) { + options->output_language = AILanguageCode::New(language.first); + const auto proto_options = AIRewriter::ToProtoOptions(options); + EXPECT_EQ(proto_options->output_language(), language.second); + } +} + TEST_F(AIRewriterTest, RewriteDefault) { SetupMockOptimizationGuideKeyedService(); SetupMockSession();
diff --git a/chrome/browser/ai/ai_summarizer_unittest.cc b/chrome/browser/ai/ai_summarizer_unittest.cc index 5f7d67db..6025098 100644 --- a/chrome/browser/ai/ai_summarizer_unittest.cc +++ b/chrome/browser/ai/ai_summarizer_unittest.cc
@@ -249,6 +249,21 @@ callback.Get()); } +TEST_F(AISummarizerTest, ToProtoOptionsLanguagesSupported) { + // Summarizer proto expects a limited set of BCP 47 base language codes. + std::vector<std::pair<std::string, std::string>> languages = { + {"en", "en"}, {"en-us", "en"}, {"en-uk", "en"}, + {"es", "es"}, {"es-sp", "es"}, {"es-mx", "es"}, + {"ja", "ja"}, {"ja-jp", "ja"}, {"ja-foo", "ja"}, + }; + blink::mojom::AISummarizerCreateOptionsPtr options = GetDefaultOptions(); + for (const auto& language : languages) { + options->output_language = AILanguageCode::New(language.first); + const auto proto_options = AISummarizer::ToProtoOptions(options); + EXPECT_EQ(proto_options->output_language(), language.second); + } +} + TEST_F(AISummarizerTest, CreateSummarizerNoService) { SetupNullOptimizationGuideKeyedService(); MockCreateSummarizerClient mock_create_summarizer_client;
diff --git a/chrome/browser/ai/ai_writer_unittest.cc b/chrome/browser/ai/ai_writer_unittest.cc index 26dea31ac..73657de 100644 --- a/chrome/browser/ai/ai_writer_unittest.cc +++ b/chrome/browser/ai/ai_writer_unittest.cc
@@ -238,6 +238,21 @@ GetAIManagerInterface()->CanCreateWriter(std::move(options), callback.Get()); } +TEST_F(AIWriterTest, ToProtoOptionsLanguagesSupported) { + // Writer proto expects base language display names in English. + std::vector<std::pair<std::string, std::string>> languages = { + {"en", "English"}, {"en-us", "English"}, {"en-uk", "English"}, + {"es", "Spanish"}, {"es-sp", "Spanish"}, {"es-mx", "Spanish"}, + {"ja", "Japanese"}, {"ja-jp", "Japanese"}, {"ja-foo", "Japanese"}, + }; + blink::mojom::AIWriterCreateOptionsPtr options = GetDefaultOptions(); + for (const auto& language : languages) { + options->output_language = AILanguageCode::New(language.first); + const auto proto_options = AIWriter::ToProtoOptions(options); + EXPECT_EQ(proto_options->output_language(), language.second); + } +} + TEST_F(AIWriterTest, CreateWriterNoService) { SetupNullOptimizationGuideKeyedService(); MockCreateWriterClient mock_create_writer_client;
diff --git a/chrome/browser/android/compositor/decoration_icon_title.h b/chrome/browser/android/compositor/decoration_icon_title.h index 4295c26..de91d068 100644 --- a/chrome/browser/android/compositor/decoration_icon_title.h +++ b/chrome/browser/android/compositor/decoration_icon_title.h
@@ -60,7 +60,7 @@ std::unique_ptr<gfx::Transform> transform_; gfx::PointF icon_position_; bool icon_needs_refresh_ = true; - bool should_hide_icon_; + bool should_hide_icon_ = false; }; } // namespace android
diff --git a/chrome/browser/android/compositor/decoration_title.h b/chrome/browser/android/compositor/decoration_title.h index f0cf808..f3a72be3 100644 --- a/chrome/browser/android/compositor/decoration_title.h +++ b/chrome/browser/android/compositor/decoration_title.h
@@ -71,7 +71,7 @@ private: bool needs_refresh_ = true; - bool should_hide_title_text_; + bool should_hide_title_text_ = false; }; } // namespace android
diff --git a/chrome/browser/android/metrics/BUILD.gn b/chrome/browser/android/metrics/BUILD.gn index 44ae3e0..d4c5783 100644 --- a/chrome/browser/android/metrics/BUILD.gn +++ b/chrome/browser/android/metrics/BUILD.gn
@@ -86,6 +86,7 @@ "//chrome/browser/signin/services/android:java", "//chrome/browser/tab:java", "//chrome/test/android:chrome_java_integration_test_support", + "//chrome/test/android:chrome_java_transit", "//components/browsing_data/core:java", "//components/metrics:metrics_java", "//content/public/test/android:content_java_test_support",
diff --git a/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java b/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java index 9e7b599..8beffac 100644 --- a/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java +++ b/chrome/browser/android/metrics/javatests/src/org/chromium/chrome/browser/metrics/UkmTest.java
@@ -27,7 +27,9 @@ import org.chromium.chrome.browser.profiles.ProfileManager; import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; +import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.components.metrics.MetricsSwitches; @@ -40,11 +42,14 @@ }) public class UkmTest { @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + public FreshCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.freshChromeTabbedActivityRule(); + + private WebPageStation mPage; @Before public void setUp() throws InterruptedException { - mActivityTestRule.startMainActivityOnBlankPage(); + mPage = mActivityTestRule.startOnBlankPage(); } // LINT.IfChange(HistoryDeleteCheck)
diff --git a/chrome/browser/ash/DEPS b/chrome/browser/ash/DEPS index dd93e44..052bde9c 100644 --- a/chrome/browser/ash/DEPS +++ b/chrome/browser/ash/DEPS
@@ -16,4 +16,5 @@ # moved out of chrome/. "+chrome/browser/ash/browser_delegate/browser_controller.h", "+chrome/browser/ash/browser_delegate/browser_delegate.h", + "+chrome/browser/ash/browser_delegate/browser_type.h", ]
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc index 228647f..52a8209 100644 --- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -254,13 +254,16 @@ sm()->ExpectSpeech("Click me"); } -// TODO(crbug.com/388867840): Add manifest v3 variant when migration is -// complete. INSTANTIATE_TEST_SUITE_P( ManifestV2, LoggedInSpokenFeedbackTest, ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kTwo))); +INSTANTIATE_TEST_SUITE_P( + ManifestV3, + LoggedInSpokenFeedbackTest, + ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kThree))); + // Flaky test, crbug.com/1081563 IN_PROC_BROWSER_TEST_P(LoggedInSpokenFeedbackTest, DISABLED_AddBookmark) { chromevox_test_utils()->EnableChromeVox(); @@ -536,13 +539,16 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// TODO(crbug.com/388867840): Add manifest v3 variant when migration is -// complete. INSTANTIATE_TEST_SUITE_P( ManifestV2, CaptionSpokenFeedbackTest, ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kTwo))); +INSTANTIATE_TEST_SUITE_P( + ManifestV3, + CaptionSpokenFeedbackTest, + ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kThree))); + IN_PROC_BROWSER_TEST_P(CaptionSpokenFeedbackTest, ToggleCaptions) { PrefChangeRegistrar change_observer; chromevox_test_utils()->EnableChromeVox(); @@ -642,13 +648,16 @@ std::unique_ptr<NotificationCenterTestApi> test_api_; }; -// TODO(crbug.com/388867840): Add manifest v3 variant when migration is -// complete. INSTANTIATE_TEST_SUITE_P( ManifestV2, NotificationCenterSpokenFeedbackTest, ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kTwo))); +INSTANTIATE_TEST_SUITE_P( + ManifestV3, + NotificationCenterSpokenFeedbackTest, + ::testing::Values(SpokenFeedbackTestConfig(ManifestVersion::kThree))); + // Tests the spoken feedback text when using the notification center accelerator // to navigate to the notification center. IN_PROC_BROWSER_TEST_P(NotificationCenterSpokenFeedbackTest,
diff --git a/chrome/browser/ash/browser_delegate/BUILD.gn b/chrome/browser/ash/browser_delegate/BUILD.gn index f4990fb8..e96d8583 100644 --- a/chrome/browser/ash/browser_delegate/BUILD.gn +++ b/chrome/browser/ash/browser_delegate/BUILD.gn
@@ -46,6 +46,7 @@ "//chrome/browser/ui:browser_navigator_params_headers", "//chrome/browser/ui/autofill", "//chrome/browser/ui/tabs:tab_strip", + "//chrome/browser/ui/web_applications", "//chrome/browser/web_applications", "//chromeos/ash/components/browser_context_helper", "//components/sessions:session_id",
diff --git a/chrome/browser/ash/browser_delegate/browser_delegate.h b/chrome/browser/ash/browser_delegate/browser_delegate.h index 32009409..b671e51 100644 --- a/chrome/browser/ash/browser_delegate/browser_delegate.h +++ b/chrome/browser/ash/browser_delegate/browser_delegate.h
@@ -8,6 +8,7 @@ #include "chrome/browser/ash/browser_delegate/browser_type.h" #include "components/account_id/account_id.h" #include "components/sessions/core/session_id.h" +#include "components/webapps/common/web_app_id.h" #include "ui/gfx/geometry/rect.h" class Browser; @@ -69,6 +70,12 @@ // closed. virtual aura::Window* GetNativeWindow() const = 0; + // Returns the browser application id, if applicable. + virtual std::optional<webapps::AppId> GetAppId() const = 0; + + // Returns whether the browser is a web app window/pop-up. + virtual bool IsWebApp() const = 0; + // Returns whether the browser is in the process of being closed and deleted. virtual bool IsClosing() const = 0;
diff --git a/chrome/browser/ash/browser_delegate/browser_delegate_impl.cc b/chrome/browser/ash/browser_delegate/browser_delegate_impl.cc index d09f551..1bd01e7 100644 --- a/chrome/browser/ash/browser_delegate/browser_delegate_impl.cc +++ b/chrome/browser/ash/browser_delegate/browser_delegate_impl.cc
@@ -14,7 +14,9 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" +#include "chrome/browser/web_applications/web_app_helpers.h" #include "chromeos/ash/components/browser_context_helper/annotated_account_id.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_info.h" @@ -74,6 +76,18 @@ return browser_->window()->GetNativeWindow(); } +std::optional<webapps::AppId> BrowserDelegateImpl::GetAppId() const { + // The implementation of `GetAppIdFromApplicationName()` isn't specific to + // WebApps, although the function resides in web_app_helpers.cc|h. + std::string app_id = + web_app::GetAppIdFromApplicationName(browser_->app_name()); + return app_id.empty() ? std::nullopt : std::optional<webapps::AppId>(app_id); +} + +bool BrowserDelegateImpl::IsWebApp() const { + return web_app::AppBrowserController::IsWebApp(&*browser_); +} + bool BrowserDelegateImpl::IsClosing() const { return browser_->IsBrowserClosing(); }
diff --git a/chrome/browser/ash/browser_delegate/browser_delegate_impl.h b/chrome/browser/ash/browser_delegate/browser_delegate_impl.h index 6a97f31..a8f0f20 100644 --- a/chrome/browser/ash/browser_delegate/browser_delegate_impl.h +++ b/chrome/browser/ash/browser_delegate/browser_delegate_impl.h
@@ -28,6 +28,8 @@ size_t GetWebContentsCount() const override; content::WebContents* GetWebContentsAt(size_t index) const override; aura::Window* GetNativeWindow() const override; + std::optional<webapps::AppId> GetAppId() const override; + bool IsWebApp() const override; bool IsClosing() const override; bool IsActive() const override; void Show() override;
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc index b8f4161..56271bf9 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -2485,9 +2485,11 @@ if (options.enable_skyvault) { enabled_features.push_back(features::kSkyVault); enabled_features.push_back(features::kSkyVaultV2); + enabled_features.push_back(features::kSkyVaultV3); } else { disabled_features.push_back(features::kSkyVault); disabled_features.push_back(features::kSkyVaultV2); + disabled_features.push_back(features::kSkyVaultV3); } // This is destroyed in |TearDown()|. We cannot initialize this in the
diff --git a/chrome/browser/ash/file_manager/file_manager_policy_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_policy_browsertest.cc index 146874c6..31c070d 100644 --- a/chrome/browser/ash/file_manager/file_manager_policy_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_manager_policy_browsertest.cc
@@ -1186,7 +1186,8 @@ const std::string* provider = value.FindString("provider"); CHECK(provider); CHECK(*provider == download_dir_util::kLocationGoogleDrive || - *provider == download_dir_util::kLocationOneDrive); + *provider == download_dir_util::kLocationOneDrive || + *provider == "delete"); g_browser_process->local_state()->SetString( prefs::kLocalUserFilesMigrationDestination, *provider); return true; @@ -1412,6 +1413,9 @@ .EnableSkyVault(), TestCase("skyVaultMigrationRemovesMyFilesOpenAfter") .DontMountVolumes() + .EnableSkyVault(), + TestCase("skyVaultMigrationDeleteLocalFiles") + .DontMountVolumes() .EnableSkyVault())); } // namespace file_manager
diff --git a/chrome/browser/ash/growth/DEPS b/chrome/browser/ash/growth/DEPS index 1c7ef37..d413eac 100644 --- a/chrome/browser/ash/growth/DEPS +++ b/chrome/browser/ash/growth/DEPS
@@ -1,12 +1,4 @@ include_rules = [ - # ChromeOS should not depend on //chrome. See //docs/chromeos/code.md for - # details. - "-chrome", - - # This directory is in //chrome, which violates the rule above. Allow this - # directory to #include its own files. - "+chrome/browser/ash/growth", - # Existing dependencies within //chrome. There is an active effort to # refactor //chrome/browser/ash to break these dependencies; see b/332804822. # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ash/growth/campaigns_manager_session.cc b/chrome/browser/ash/growth/campaigns_manager_session.cc index 843222f6..a3c515fa 100644 --- a/chrome/browser/ash/growth/campaigns_manager_session.cc +++ b/chrome/browser/ash/growth/campaigns_manager_session.cc
@@ -21,6 +21,9 @@ #include "base/timer/timer.h" #include "chrome/browser/apps/app_service/app_service_proxy_ash.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/ash/browser_delegate/browser_controller.h" +#include "chrome/browser/ash/browser_delegate/browser_delegate.h" +#include "chrome/browser/ash/browser_delegate/browser_type.h" #include "chrome/browser/ash/ownership/owner_settings_service_ash.h" #include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" @@ -294,26 +297,29 @@ } bool HasValidPwaBrowserForAppId(const std::string& app_id) { - for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) { - if (browser->profile()->IsOffTheRecord() || !browser->IsActive()) { - continue; - } - - if (browser->type() != Browser::TYPE_APP) { - CAMPAIGNS_LOG(ERROR) << "Not pwa browser type"; - return false; - } - - if (!web_app::AppBrowserController::IsForWebApp(browser, app_id)) { - CAMPAIGNS_LOG(ERROR) << "Browser belongs to a different app"; - return false; - } - - return true; + ash::BrowserDelegate* browser = + ash::BrowserController::GetInstance()->GetLastUsedBrowser(); + if (!browser) { + return false; } - CAMPAIGNS_LOG(ERROR) << "No browser window"; - return false; + if (browser->IsOffTheRecord() || !browser->IsActive()) { + CAMPAIGNS_LOG(ERROR) << "No browser window"; + return false; + } + + if (browser->GetType() != ash::BrowserType::kApp) { + CAMPAIGNS_LOG(ERROR) << "Not pwa browser type"; + return false; + } + + std::optional<webapps::AppId> browser_app_id = browser->GetAppId(); + if (!browser->IsWebApp() || browser_app_id != app_id) { + CAMPAIGNS_LOG(ERROR) << "Browser belongs to a different app"; + return false; + } + + return true; } void SetCampaignManagerPrefService(Profile* profile) {
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc index d6d0cae..93f34c5 100644 --- a/chrome/browser/autofill/captured_sites_test_utils.cc +++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -152,12 +152,12 @@ static auto map = [] { std::map<std::string_view, autofill::FieldType> map; for (autofill::FieldType field_type : autofill::kAllFieldTypes) { - map[autofill::AutofillType(field_type).ToStringView()] = field_type; + map[autofill::FieldTypeToStringView(field_type)] = field_type; } for (autofill::HtmlFieldType html_field_type : autofill::kAllHtmlFieldTypes) { - autofill::AutofillType field_type(html_field_type); - map[field_type.ToStringView()] = field_type.GetStorableType(); + map[autofill::FieldTypeToStringView(html_field_type)] = + autofill::HtmlFieldTypeToBestCorrespondingFieldType(html_field_type); } return map; }();
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 756e1a29..aad2886 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1430,21 +1430,13 @@ // Check if the local storage was successfully removed. ClearData only // guarantees that tasks to delete data are scheduled when its callback is - // invoked. It doesn't guarantee data has actually been cleared. So use - // RunUntil to verify data is cleared. - EXPECT_TRUE(base::test::RunUntil([&]() { - std::vector<blink::mojom::KeyValuePtr> data; - base::RunLoop loop; - area->GetAll( - /*new_observer=*/mojo::NullRemote(), - base::BindLambdaForTesting( - [&](std::vector<blink::mojom::KeyValuePtr> data_in) { - data = std::move(data_in); - loop.Quit(); - })); - loop.Run(); - return data.size() == 0UL; - })); + // invoked. It doesn't guarantee data has actually been cleared. Use + // TestFuture to verify that data is cleared. + base::test::TestFuture<std::vector<blink::mojom::KeyValuePtr>> get_all_future; + area->GetAll(/*new_observer=*/mojo::NullRemote(), + get_all_future.GetCallback()); + EXPECT_TRUE(get_all_future.Wait()); + EXPECT_EQ(0UL, get_all_future.Get().size()); } #endif
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc index 6345761b..15978e3 100644 --- a/chrome/browser/chrome_browser_field_trials.cc +++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -119,6 +119,10 @@ feature_overrides.DisableFeature(features::kEyeDropper); } #elif BUILDFLAG(IS_ANDROID) // BUILDFLAG(IS_LINUX) + // TODO(crbug.com/422902880): Remove when tablet rollout is complete. + feature_overrides.EnableFeature( + base::features::kUseSharedRebindServiceConnection); + feature_overrides.EnableFeature(features::kGroupRebindingForGroupImportance); #if BUILDFLAG(IS_DESKTOP_ANDROID) // Nota bene: Anything here is expected to be short-lived, unless deemed too // risky to launch to non-desktop platforms. New features being added here @@ -148,16 +152,12 @@ feature_overrides.EnableFeature(features::kUserMediaScreenCapturing); // Enable desktop tab management features. - // TODO(crbug.com/422902880): Remove when tablet rollout is complete. - feature_overrides.EnableFeature( - base::features::kUseSharedRebindServiceConnection); // TODO(crbug.com/422902940): Remove when tablet rollout is complete. feature_overrides.EnableFeature( base::features::kBackgroundNotPerceptibleBinding); // TODO(crbug.com/422902625): Remove when rollout is complete to all form // factors. feature_overrides.EnableFeature(chrome::android::kProcessRankPolicyAndroid); - feature_overrides.EnableFeature(features::kGroupRebindingForGroupImportance); feature_overrides.EnableFeature(chrome::android::kProtectedTabsAndroid); // TODO(crbug.com/422903297): Remove when tablet rollout is complete. feature_overrides.EnableFeature(features::kRendererProcessLimitOnAndroid);
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc b/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc index c832d14..7c623fe 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc +++ b/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/optimization_guide/browser_test_util.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" +#include "chrome/browser/preloading/scoped_prewarm_feature_list.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/browser.h" @@ -67,6 +68,12 @@ {features::kGlic, {}}, {features::kTabstripComboButton, {}}}, {}); + // Initialize `scoped_prewarm_feature_list_` after the + // `scoped_feature_list_` that will be removed in the parent class's + // destructor, so that these instances are destroyed in the reversed order. + scoped_prewarm_feature_list_ = + std::make_unique<test::ScopedPrewarmFeatureList>( + test::ScopedPrewarmFeatureList::PrewarmState::kDisabled); } void SetUpOnMainThread() override { @@ -77,6 +84,10 @@ void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch(switches::kGlicDev); } + private: + // TODO(https://crbug.com/423465927): Explore a better approach to make the + // existing tests run with the prewarm feature enabled. + std::unique_ptr<test::ScopedPrewarmFeatureList> scoped_prewarm_feature_list_; }; // A WebContentsObserver that asks for zero state suggestions every
diff --git a/chrome/browser/dom_distiller/tab_utils.cc b/chrome/browser/dom_distiller/tab_utils.cc index bb65691b..3f0d9d98 100644 --- a/chrome/browser/dom_distiller/tab_utils.cc +++ b/chrome/browser/dom_distiller/tab_utils.cc
@@ -12,7 +12,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "build/build_config.h" -#include "chrome/browser/android/tab_android.h" #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/common/chrome_isolated_world_ids.h" @@ -30,6 +29,10 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" +#if BUILDFLAG(IS_ANDROID) +#include "chrome/browser/android/tab_android.h" +#endif + namespace { using dom_distiller::ArticleDistillationUpdate; @@ -192,14 +195,17 @@ SelfDeletingRequestDelegate* view_request_delegate = new SelfDeletingRequestDelegate(new_web_contents.get()); +#if BUILDFLAG(IS_ANDROID) TabAndroid* tab = TabAndroid::FromWebContents(old_web_contents); std::unique_ptr<content::WebContents> old_web_contents_owned = tab->SwapWebContents(std::move(new_web_contents), /*did_start_load=*/false, /*did_finish_load=*/false); + old_web_contents = old_web_contents_owned.release(); +#endif std::unique_ptr<SourcePageHandleWebContents> source_page_handle( - new SourcePageHandleWebContents(old_web_contents_owned.release(), true)); + new SourcePageHandleWebContents(old_web_contents, true)); MaybeStartDistillation(std::move(source_page_handle), view_request_delegate); }
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc index a92ce8c..88577fa 100644 --- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc +++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -66,7 +66,7 @@ const char* kSimpleArticlePath = "/dom_distiller/simple_article.html"; const char* kOriginalArticleTitle = "Test Page Title"; const char* kExpectedArticleHeading = "Test Page Title"; -const char* kExpectedDocumentTitle = "Test Page Title"; +const char* kExpectedDocumentTitle = "Test Page Title - Reading Mode"; std::unique_ptr<content::WebContents> NewContentsWithSameParamsAs( content::WebContents* source_web_contents) { @@ -196,8 +196,9 @@ EXPECT_EQ(kExpectedArticleHeading, GetArticleHeading(after_web_contents)); } -IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, - BackForwardNavigationRegeneratesDistillabilitySignal) { +IN_PROC_BROWSER_TEST_F( + DomDistillerTabUtilsBrowserTest, + DISABLED_BackForwardNavigationRegeneratesDistillabilitySignal) { content::WebContents* initial_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); TestDistillabilityObserver distillability_observer(initial_web_contents); @@ -262,7 +263,7 @@ } IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, - DomDistillDisableForBackForwardCache) { + DISABLED_DomDistillDisableForBackForwardCache) { content::BackForwardCacheDisabledTester tester; GURL url1(article_url()); @@ -298,7 +299,8 @@ kDomDistiller_SelfDeletingRequestDelegate))); } -IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, SecurityStateIsNone) { +IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, + DISABLED_SecurityStateIsNone) { content::WebContents* initial_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); TestDistillabilityObserver distillability_observer(initial_web_contents); @@ -326,7 +328,7 @@ // TODO(crbug.com/40776875): Flaky on Mac. IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, - FaviconFromOriginalPage) { + DISABLED_FaviconFromOriginalPage) { content::WebContents* initial_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -390,7 +392,7 @@ }; IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsMPArchTest, - TaskTrackerRemovedWhenPrimaryPageChanged) { + DISABLED_TaskTrackerRemovedWhenPrimaryPageChanged) { NavigateAndDistill(); // Ensure the TaskTracker for distilling the source article exist. EXPECT_TRUE(HasTaskTracker()); @@ -419,7 +421,7 @@ }; IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsFencedFrameTest, - TaskTrackerNotRemovedByFencedFrame) { + DISABLED_TaskTrackerNotRemovedByFencedFrame) { NavigateAndDistill(); // Ensure the TaskTracker for distilling the source article exist. EXPECT_TRUE(HasTaskTracker()); @@ -460,7 +462,7 @@ }; IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsPrerenderTest, - TaskTrackerNotRemovedByPrerendering) { + DISABLED_TaskTrackerNotRemovedByPrerendering) { NavigateAndDistill(); // Ensure the TaskTracker for distilling the source article exist. EXPECT_TRUE(HasTaskTracker());
diff --git a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc index d4c2723..e6a1ffe 100644 --- a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc +++ b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc
@@ -89,7 +89,7 @@ void ClipboardRequestHandler::ReportWarningBypass( std::optional<std::u16string> user_justification) { ReportAnalysisConnectorWarningBypass( - profile_, /*url*/ url_, /*tab_url*/ url_, + profile_, *content_analysis_info_, /*source*/ data_controls::ReportingService::GetClipboardSourceString( clipboard_source_),
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc index 9a04f7c..af865377 100644 --- a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc +++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc
@@ -9,12 +9,14 @@ #include "base/strings/string_number_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "components/download/public/common/download_item.h" #include "components/enterprise/connectors/core/content_area_user_provider.h" #include "components/enterprise/connectors/core/features.h" #include "components/enterprise/connectors/core/reporting_utils.h" #include "components/safe_browsing/core/common/features.h" #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" #include "components/signin/public/identity_manager/identity_manager.h" +#include "content/public/browser/download_item_utils.h" #include "net/base/url_util.h" #include "third_party/re2/src/re2/re2.h" @@ -135,4 +137,60 @@ const GURL& tab_url) : im_(im), tab_url_(tab_url) {} +DownloadContentAreaUserProvider::DownloadContentAreaUserProvider( + const download::DownloadItem& download_item) + : url_(download_item.GetURL()), + tab_url_(download_item.GetTabUrl()), + im_(IdentityManagerFactory::GetForProfile(Profile::FromBrowserContext( + content::DownloadItemUtils::GetBrowserContext(&download_item)))) {} + +std::string DownloadContentAreaUserProvider::url() const { + return url_.spec(); +} + +const GURL& DownloadContentAreaUserProvider::tab_url() const { + return tab_url_; +} + +signin::IdentityManager* DownloadContentAreaUserProvider::identity_manager() + const { + return im_; +} + +const enterprise_connectors::AnalysisSettings& +DownloadContentAreaUserProvider::settings() const { + NOTREACHED(); +} + +int DownloadContentAreaUserProvider::user_action_requests_count() const { + NOTREACHED(); +} + +std::string DownloadContentAreaUserProvider::tab_title() const { + NOTREACHED(); +} + +std::string DownloadContentAreaUserProvider::user_action_id() const { + NOTREACHED(); +} + +std::string DownloadContentAreaUserProvider::email() const { + NOTREACHED(); +} + +enterprise_connectors::ContentAnalysisRequest::Reason +DownloadContentAreaUserProvider::reason() const { + NOTREACHED(); +} + +google::protobuf::RepeatedPtrField<::safe_browsing::ReferrerChainEntry> +DownloadContentAreaUserProvider::referrer_chain() const { + NOTREACHED(); +} + +google::protobuf::RepeatedPtrField<std::string> +DownloadContentAreaUserProvider::frame_url_chain() const { + NOTREACHED(); +} + } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.h b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.h index 745ded3..1c5e8854 100644 --- a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.h +++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.h
@@ -11,6 +11,10 @@ #include "components/safe_browsing/core/common/proto/csd.pb.h" #include "content/public/browser/clipboard_types.h" +namespace download { +class DownloadItem; +} // namespace download + namespace enterprise_connectors { // Implementation of `ContentAnalysisInfoBase` for chrome/ platforms. @@ -29,8 +33,10 @@ std::string GetContentAreaAccountEmail() const; }; -// Simple implementation of `ContentAnalysisInfo` meant to be used for -// `GetContentAreaAccountEmail` only +// Simple implementation of `ContentAnalysisInfo` meant to obtain the value +// returned by `GetContentAreaAccountEmail`. This class shouldn't expose +// non-static methods unless every other override required to support it are +// implemented. class ContentAreaUserProvider : public ContentAnalysisInfo { public: static std::string GetUser(Profile* profile, const GURL& tab_url); @@ -57,6 +63,36 @@ raw_ref<const GURL> tab_url_; }; +// Download-specific implementation of `ContentAnalysisInfo`. This is meant to +// be used only for reporting, so only public fields should be called. +class DownloadContentAreaUserProvider : public ContentAnalysisInfo { + public: + explicit DownloadContentAreaUserProvider( + const download::DownloadItem& download_item); + + // ContentAnalysisInfo: + std::string url() const override; + const GURL& tab_url() const override; + signin::IdentityManager* identity_manager() const override; + + private: + // ContentAnalysisInfo: + const AnalysisSettings& settings() const override; + int user_action_requests_count() const override; + std::string tab_title() const override; + std::string user_action_id() const override; + std::string email() const override; + ContentAnalysisRequest::Reason reason() const override; + google::protobuf::RepeatedPtrField<::safe_browsing::ReferrerChainEntry> + referrer_chain() const override; + google::protobuf::RepeatedPtrField<std::string> frame_url_chain() + const override; + + GURL url_; + GURL tab_url_; + raw_ptr<signin::IdentityManager> im_; +}; + } // namespace enterprise_connectors #endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_ANALYSIS_CONTENT_ANALYSIS_INFO_H_
diff --git a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc index fa6e9209..b4a86cb 100644 --- a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc +++ b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc
@@ -151,7 +151,7 @@ size_t index = warning.first; ReportAnalysisConnectorWarningBypass( - profile_, url_, url_, source_, destination_, + profile_, *content_analysis_info_, source_, destination_, paths_[index].AsUTF8Unsafe(), file_info_[index].sha256, file_info_[index].mime_type, AccessPointToTriggerString(access_point_), content_transfer_method_, file_info_[index].size,
diff --git a/chrome/browser/enterprise/connectors/analysis/page_print_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/page_print_request_handler.cc index 19e16fe..54491e3 100644 --- a/chrome/browser/enterprise/connectors/analysis/page_print_request_handler.cc +++ b/chrome/browser/enterprise/connectors/analysis/page_print_request_handler.cc
@@ -100,8 +100,7 @@ void PagePrintRequestHandler::ReportWarningBypass( std::optional<std::u16string> user_justification) { ReportAnalysisConnectorWarningBypass( - profile_, GURL(content_analysis_info_->url()), - content_analysis_info_->tab_url(), /*source*/ "", + profile_, *content_analysis_info_, /*source*/ "", /*destination*/ printer_name_, content_analysis_info_->tab_title(), /*sha256*/ std::string(), /*mime_type*/ std::string(), kPagePrintDataTransferEventTrigger,
diff --git a/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc b/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc index ee07a54..9eb22747 100644 --- a/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" #include "chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_api.h" #include "chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.h" +#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h" #include "chrome/browser/extensions/commands/command_service.h" #include "chrome/common/buildflags.h" #include "extensions/buildflags/buildflags.h" @@ -46,7 +47,6 @@ #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" #include "chrome/browser/extensions/api/tab_groups/tab_groups_event_router_factory.h" #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h" -#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h" #include "components/safe_browsing/buildflags.h" #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h" #include "extensions/browser/api/networking_private/networking_private_delegate_factory.h" @@ -98,6 +98,7 @@ extensions::WebAuthenticationProxyAPI::GetFactoryInstance(); extensions::WebAuthenticationProxyRegistrarFactory::GetInstance(); extensions::WebAuthenticationProxyServiceFactory::GetInstance(); + extensions::WebrtcAudioPrivateEventService::GetFactoryInstance(); #if BUILDFLAG(ENABLE_EXTENSIONS) extensions::ActivityLogAPI::GetFactoryInstance(); @@ -141,7 +142,6 @@ extensions::VerifyTrustApiService::GetFactoryInstance(); #endif extensions::WebNavigationAPI::GetFactoryInstance(); - extensions::WebrtcAudioPrivateEventService::GetFactoryInstance(); #if BUILDFLAG(IS_CHROMEOS) extensions::WMDesksPrivateEventsAPI::GetFactoryInstance(); #endif
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client_android.cc b/chrome/browser/extensions/api/chrome_extensions_api_client_android.cc index 3fd8ffe..0714a0d7 100644 --- a/chrome/browser/extensions/api/chrome_extensions_api_client_android.cc +++ b/chrome/browser/extensions/api/chrome_extensions_api_client_android.cc
@@ -4,7 +4,10 @@ #include "chrome/browser/extensions/api/chrome_extensions_api_client.h" +#include <memory> + #include "base/notimplemented.h" +#include "extensions/browser/supervised_user_extensions_delegate.h" #include "extensions/buildflags/buildflags.h" // TODO(crbug.com/417770773): This file contains stubs for the parts of @@ -36,8 +39,8 @@ ChromeExtensionsAPIClient::CreateSupervisedUserExtensionsDelegate( content::BrowserContext* browser_context) const { // TODO(crbug.com/402488726): Support supervised users on desktop Android. - NOTIMPLEMENTED(); - return nullptr; + // This is a stub implementation that always blocks installs. + return std::make_unique<SupervisedUserExtensionsDelegate>(); } std::unique_ptr<DisplayInfoProvider>
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc index 79bfc4e..8c68a58 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -39,8 +39,6 @@ #include "chrome/browser/extensions/sync/extension_sync_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" -#include "chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h" -#include "chrome/browser/supervised_user/supervised_user_test_util.h" #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/api/developer_private.h" @@ -52,13 +50,13 @@ #include "components/signin/public/base/signin_switches.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/signin/public/identity_manager/identity_test_utils.h" -#include "components/supervised_user/core/common/features.h" #include "extensions/browser/blocklist_state.h" #include "extensions/browser/disable_reason.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registrar.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/supervised_user_extensions_delegate.h" +#include "extensions/buildflags/buildflags.h" #include "extensions/common/api/extension_action/action_info.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" @@ -77,6 +75,14 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h" +#include "chrome/browser/supervised_user/supervised_user_test_util.h" +#include "components/supervised_user/core/common/features.h" +#endif + +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + namespace extensions { using mojom::ManifestLocation; @@ -1433,8 +1439,7 @@ } } -// TODO(crbug.com/421799257): Enable the tests on desktop android. -#if BUILDFLAG(ENABLE_SUPERVISED_USERS) && BUILDFLAG(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) // Tests for supervised users (child accounts). Supervised users are not allowed // to install apps or extensions unless their parent approves. @@ -1521,7 +1526,7 @@ EXPECT_FALSE(info->disable_reasons.parent_disabled_permissions); } -#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) && BUILDFLAG(ENABLE_EXTENSIONS) +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc index e8036691..dd311483 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -351,6 +351,7 @@ const std::string& trigger, const std::string& scan_id, const std::string& content_transfer_method, + const std::string& active_user_email, const safe_browsing::ReferrerChain& referrer_chain, const enterprise_connectors::ContentAnalysisResponse::Result& result, const int64_t content_size, @@ -394,12 +395,9 @@ if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) { enterprise_connectors::AddReferrerChainToEvent(referrer_chain, event); } - std::string content_area_account_email = - enterprise_connectors::ContentAreaUserProvider::GetUser( - Profile::FromBrowserContext(context_), tab_url); - if (!content_area_account_email.empty()) { + if (!active_user_email.empty()) { event.Set(enterprise_connectors::kKeyWebAppSignedInAccount, - content_area_account_email); + active_user_email); } AddAnalysisConnectorVerdictToEvent(result, event); @@ -408,7 +406,7 @@ enterprise_connectors::kKeySensitiveDataEvent, std::move(settings.value()), std::move(event)); #endif // BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS) - } +} void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarningBypassed( const GURL& url,
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h index 5b73a63..4ea248c4 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
@@ -135,6 +135,7 @@ const std::string& trigger, const std::string& scan_id, const std::string& content_transfer_method, + const std::string& active_user_email, const safe_browsing::ReferrerChain& referrer_chain, const enterprise_connectors::ContentAnalysisResponse::Result& result, const int64_t content_size,
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc index 18df484..879948b 100644 --- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc +++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -27,12 +27,9 @@ #include "chrome/browser/media/webrtc/media_device_salt_service_factory.h" #include "chrome/browser/media/webrtc/webrtc_log_uploader.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/recently_audible_helper.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/buildflags.h" #include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/ui_test_utils.h" #include "components/media_device_salt/media_device_salt_service.h" #include "components/network_session_configurator/common/network_switches.h" #include "content/public/browser/audio_service.h" @@ -42,6 +39,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "extensions/browser/api_test_utils.h" +#include "extensions/buildflags/buildflags.h" #include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permissions_data.h" #include "media/audio/audio_device_description.h" @@ -58,6 +56,8 @@ #include "base/win/windows_version.h" #endif +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + using base::JSONWriter; using content::RenderProcessHost; using content::WebContents; @@ -297,12 +297,10 @@ // This runs the end-to-end JavaScript test for the Hangout Services // component extension, which uses the webrtcAudioPrivate API among // others. - ASSERT_TRUE(ui_test_utils::NavigateToURL( - browser(), - https_server().GetURL("meet.google.com", - "/extensions/hangout_services_test.html"))); + ASSERT_TRUE(NavigateToURL(https_server().GetURL( + "meet.google.com", "/extensions/hangout_services_test.html"))); - WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + WebContents* tab = GetActiveWebContents(); WaitUntilAudioIsPlaying(tab); // Use a test server URL for uploading.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index c30faa3..3312f22b 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -871,11 +871,6 @@ "expiry_milestone": 145 }, { - "name": "autofill-enable-show-save-card-securely-message", - "owners": [ "qihuizhao@google.com"], - "expiry_milestone": 145 - }, - { "name": "autofill-enable-support-for-home-and-work", "owners": ["vidhanj@google.com", "jsobiech@google.com"], "expiry_milestone": 145 @@ -1194,6 +1189,11 @@ "expiry_milestone": 145 }, { + "name": "bookmark-tab-group-conversion", + "owners": [ "yuhengh@google.com", "top-chrome-desktop-ui@google.com" ], + "expiry_milestone": 145 + }, + { "name": "bookmarks-and-reading-list-behind-opt-in", "owners": [ "wylieb@google.com", "bsazonov@chromium.org" ], "expiry_milestone": 126 @@ -1601,7 +1601,7 @@ }, { "name": "chromebox-usb-passthrough-restrictions", - "owners": [ "denniskempin@chromium.org", "drmasquatch@google.com", "clumptini@google.com" ], + "owners": [ "drmasquatch@google.com", "clumptini@google.com" ], "expiry_milestone": 150 }, { @@ -1933,17 +1933,17 @@ }, { "name": "crostini-container-install", - "owners": [ "davidmunro@google.com", "clumptini@google.com" ], - "expiry_milestone": 150 - }, - { - "name": "crostini-containerless", "owners": [ "clumptini@google.com" ], "expiry_milestone": 150 }, { + "name": "crostini-containerless", + "owners": [ "drmasquatch@google.com", "clumptini@google.com" ], + "expiry_milestone": 150 + }, + { "name": "crostini-gpu-support", - "owners": [ "denniskempin@chromium.org", "drmasquatch@google.com", "clumptini@google.com" ], + "owners": [ "drmasquatch@google.com", "clumptini@google.com" ], "expiry_milestone": 150 }, { @@ -1954,17 +1954,17 @@ }, { "name": "crostini-qt-ime-support", - "owners": [ "timloh@chromium.org", "sophialin@google.com", "clumptini@google.com" ], + "owners": [ "clumptini@google.com" ], "expiry_milestone": 150 }, { "name": "crostini-reset-lxd-db", - "owners": [ "easy@google.com", "jamesye@google.com", "sidereal@google.com", "clumptini@google.com" ], + "owners": [ "clumptini@google.com" ], "expiry_milestone": 150 }, { "name": "crostini-virtual-keyboard-support", - "owners": [ "timloh@chromium.org", "sophialin@google.com", "clumptini@google.com" ], + "owners": [ "clumptini@google.com" ], "expiry_milestone": 150 }, { @@ -2101,6 +2101,14 @@ "expiry_milestone": 125 }, { + "name": "default-search-engine-prewarm", + "owners": [ + "toyoshim@chromium.org", + "//content/browser/preloading/prerender/OWNERS" + ], + "expiry_milestone": 150 + }, + { "name": "default-site-instance-groups", "owners": [ "yangsharon@chromium.org", "chrome-security-architecture@google.com" ], "expiry_milestone": 150 @@ -2218,7 +2226,7 @@ }, { "name": "disable-bruschetta-install-checks", - "owners": [ "denniskempin@chromium.org", "drmasquatch@google.com", "clumptini@google.com" ], + "owners": [ "drmasquatch@google.com", "clumptini@google.com" ], // This flag does not expire because it allows developers to disable hardcoded // install checks that may need to change during development. "expiry_milestone": -1 @@ -5612,6 +5620,11 @@ "expiry_milestone": 140 }, { + "name": "http-cache-custom-backend", + "owners": ["horo@chromium.org", "net-dev@chromium.org"], + "expiry_milestone": 145 + }, + { "name": "http-cache-no-vary-search", "owners": ["ricea@chromium.org", "net-dev@chromium.org"], "expiry_milestone": 145
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 954637b..3de8c8c 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -419,6 +419,10 @@ "UI changes and removal of the bulk password deletion option from the " "dialog."; +const char kDefaultSearchEnginePrewarmName[] = "Default search engine prewarm"; +const char kDefaultSearchEnginePrewarmDescription[] = + "Performance optimization to prewarm the default search engine used in the Omnibox"; + const char kDisableAutofillStrikeSystemName[] = "Disable the Autofill strike system"; const char kDisableAutofillStrikeSystemDescription[] = @@ -886,12 +890,6 @@ #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID) -const char kAutofillEnableShowSaveCardSecurelyMessageName[] = - "Enable updated credit card upload UI messaging"; -const char kAutofillEnableShowSaveCardSecurelyMessageDescription[] = - "When enabled, credit card upload messaging will match what is " - "shown on Desktop."; - const char kAutofillEnableSyncingOfPixBankAccountsName[] = "Sync Pix bank accounts from Google Payments"; const char kAutofillEnableSyncingOfPixBankAccountsDescription[] = @@ -1016,6 +1014,11 @@ const char kBlockCrossPartitionBlobUrlFetchingDescription[] = "Blocks fetching of cross-partitioned Blob URL."; +const char kBookmarkTabGroupConversionName[] = + "Bookmark and tab group conversion"; +const char kBookmarkTabGroupConversionDescription[] = + "Enable conversion between bookmark and tab group"; + const char kBorealisBigGlName[] = "Borealis Big GL"; const char kBorealisBigGlDescription[] = "Enable Big GL when running Borealis."; @@ -1189,6 +1192,11 @@ const char kDsePreload2OnPressDescription[] = "Enables on-press triggers of DsePreload2"; +const char kHttpCacheCustomBackendName[] = + "Use custom disk cache backend for HTTP Cache"; +const char kHttpCacheCustomBackendDescription[] = + "Enables the experimental disk cache backend for HTTP Cache"; + const char kHttpCacheNoVarySearchName[] = "No Vary Search in Disk Cache"; const char kHttpCacheNoVarySearchDescription[] = "Enables the No-Vary-Search header in the disk cache";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 42bad431..dcd4009 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -280,6 +280,9 @@ extern const char kDbdRevampDesktopName[]; extern const char kDbdRevampDesktopDescription[]; +extern const char kDefaultSearchEnginePrewarmName[]; +extern const char kDefaultSearchEnginePrewarmDescription[]; + extern const char kDisableAutofillStrikeSystemName[]; extern const char kDisableAutofillStrikeSystemDescription[]; @@ -544,9 +547,6 @@ #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID) -extern const char kAutofillEnableShowSaveCardSecurelyMessageName[]; -extern const char kAutofillEnableShowSaveCardSecurelyMessageDescription[]; - extern const char kAutofillEnableSyncingOfPixBankAccountsName[]; extern const char kAutofillEnableSyncingOfPixBankAccountsDescription[]; #endif // BUILDFLAG(IS_ANDROID) @@ -610,6 +610,9 @@ extern const char kBlockCrossPartitionBlobUrlFetchingName[]; extern const char kBlockCrossPartitionBlobUrlFetchingDescription[]; +extern const char kBookmarkTabGroupConversionName[]; +extern const char kBookmarkTabGroupConversionDescription[]; + extern const char kBorealisBigGlName[]; extern const char kBorealisBigGlDescription[]; @@ -884,6 +887,9 @@ extern const char kDsePreload2OnPressName[]; extern const char kDsePreload2OnPressDescription[]; +extern const char kHttpCacheCustomBackendName[]; +extern const char kHttpCacheCustomBackendDescription[]; + extern const char kHttpCacheNoVarySearchName[]; extern const char kHttpCacheNoVarySearchDescription[];
diff --git a/chrome/browser/glic/host/context/glic_pinned_tab_manager.cc b/chrome/browser/glic/host/context/glic_pinned_tab_manager.cc index f9556a0..f348c63 100644 --- a/chrome/browser/glic/host/context/glic_pinned_tab_manager.cc +++ b/chrome/browser/glic/host/context/glic_pinned_tab_manager.cc
@@ -255,7 +255,6 @@ // Tab might be unloaded (e.g. discarded, restored from history). We reload // it now (and prevent it from being discarded elsewhere), so it can have // its context pulled. - // TODO(crbug.com/422767952): prevent pinned tabs from being discarded. if (tab->GetContents()) { if (tab->GetContents()->WasDiscarded()) { tab->GetContents()->GetController().SetNeedsReload();
diff --git a/chrome/browser/glic/host/context/glic_pinned_tab_manager_browsertest.cc b/chrome/browser/glic/host/context/glic_pinned_tab_manager_browsertest.cc index 74581a9..4e6ab8c 100644 --- a/chrome/browser/glic/host/context/glic_pinned_tab_manager_browsertest.cc +++ b/chrome/browser/glic/host/context/glic_pinned_tab_manager_browsertest.cc
@@ -223,4 +223,63 @@ HasTitle("Advanced Goldfish Obedience Training"))); } +IN_PROC_BROWSER_TEST_F(GlicPinnedTabManagerBrowserTest, PinTabs) { + CreateAndAddTab("/why-cats-are-liquid"); + + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + tabs::TabInterface* tab_interface = + tabs::TabInterface::GetFromContents(tab_strip_model->GetWebContentsAt(1)); + ASSERT_TRUE(tab_interface); + const tabs::TabHandle tab_handle = tab_interface->GetHandle(); + + base::test::TestFuture<tabs::TabInterface*, bool> pin_status_future; + auto subscription = pinned_tab_manager_->AddTabPinningStatusChangedCallback( + pin_status_future.GetRepeatingCallback()); + + // Pin a tab and verify it was pinned. + EXPECT_TRUE(pinned_tab_manager_->PinTabs({tab_handle})); + EXPECT_TRUE(pinned_tab_manager_->IsTabPinned(tab_handle)); + EXPECT_EQ(1u, pinned_tab_manager_->GetNumPinnedTabs()); + + + // Check that the callback was called with pinned=true. + { + auto [result_interface, result_pinned] = pin_status_future.Get(); + EXPECT_EQ(tab_interface, result_interface); + EXPECT_TRUE(result_pinned); + } +} + +IN_PROC_BROWSER_TEST_F(GlicPinnedTabManagerBrowserTest, unpinTabs) { + CreateAndAddTab("/why-cats-are-liquid"); + + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + tabs::TabInterface* tab_interface = + tabs::TabInterface::GetFromContents(tab_strip_model->GetWebContentsAt(1)); + ASSERT_TRUE(tab_interface); + const tabs::TabHandle tab_handle = tab_interface->GetHandle(); + + // Pin a tab and verify it was pinned. + EXPECT_TRUE(pinned_tab_manager_->PinTabs({tab_handle})); + EXPECT_TRUE(pinned_tab_manager_->IsTabPinned(tab_handle)); + EXPECT_EQ(1u, pinned_tab_manager_->GetNumPinnedTabs()); + + + base::test::TestFuture<tabs::TabInterface*, bool> pin_status_future; + auto subscription = pinned_tab_manager_->AddTabPinningStatusChangedCallback( + pin_status_future.GetRepeatingCallback()); + + // Unpin the tab and verify it was unpinned. + EXPECT_TRUE(pinned_tab_manager_->UnpinTabs({tab_handle})); + EXPECT_FALSE(pinned_tab_manager_->IsTabPinned(tab_handle)); + EXPECT_EQ(0u, pinned_tab_manager_->GetNumPinnedTabs()); + + // Check that the callback was called with pinned=false. + { + auto [result_interface, result_pinned] = pin_status_future.Get(); + EXPECT_EQ(tab_interface, result_interface); + EXPECT_FALSE(result_pinned); + } +} + } // namespace glic
diff --git a/chrome/browser/glic/host/glic_api_browsertest.cc b/chrome/browser/glic/host/glic_api_browsertest.cc index 529d27c..0a980cb 100644 --- a/chrome/browser/glic/host/glic_api_browsertest.cc +++ b/chrome/browser/glic/host/glic_api_browsertest.cc
@@ -377,6 +377,7 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +// Test fixture that preloads the web client before starting the test. class GlicApiTestWithOneTabAndPreloading : public GlicApiTestWithOneTab { public: GlicApiTestWithOneTabAndPreloading() { @@ -405,18 +406,6 @@ network::mojom::ConnectionType::CONNECTION_ETHERNET); } - void SetUpOnMainThread() override { - GlicApiTest::SetUpOnMainThread(); - RunTestSequence(InstrumentTab(kFirstTab), - NavigateWebContents(kFirstTab, page_url())); - } - - void TearDown() override { - GlicApiTestWithOneTab::TearDown(); - GlicProfileManager::ForceMemoryPressureForTesting(std::nullopt); - GlicProfileManager::ForceConnectionTypeForTesting(std::nullopt); - } - auto CreateAndWarmGlic() { return Do([this] { GetService()->TryPreload(); }); } @@ -429,6 +418,30 @@ }); } + void SetUpOnMainThread() override { + // GlicApiTestWithOneTab::SetUpOnMainThread also opens the glic panel, so + // duplicate everything else it does and call GlicApiTest::SetUpOnMainThread + // directly. + GlicApiTest::SetUpOnMainThread(); + histogram_tester = std::make_unique<base::HistogramTester>(); + RunTestSequence(InstrumentTab(kFirstTab), + NavigateWebContents(kFirstTab, page_url())); + + // Preload the web client. + RunTestSequence(WaitForShow(kGlicButtonElementId), ResetMemoryPressure(), + ObserveState(glic::test::internal::kWebUiState, &host()), + CreateAndWarmGlic(), + WaitForState(glic::test::internal::kWebUiState, + mojom::WebUiState::kReady), + CheckControllerShowing(false)); + } + + void TearDown() override { + GlicApiTestWithOneTab::TearDown(); + GlicProfileManager::ForceMemoryPressureForTesting(std::nullopt); + GlicProfileManager::ForceConnectionTypeForTesting(std::nullopt); + } + private: base::test::ScopedFeatureList features_; }; @@ -1009,14 +1022,8 @@ IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTabAndPreloading, testDeferredFocusedTabStateAtCreation) { - // Preload a web contents and then navigate. + // Navigate the first tab. RunTestSequence( - WaitForShow(kGlicButtonElementId), ResetMemoryPressure(), - ObserveState(glic::test::internal::kWebUiState, &host()), - CreateAndWarmGlic(), - WaitForState(glic::test::internal::kWebUiState, - mojom::WebUiState::kReady), - CheckControllerShowing(false), NavigateWebContents(kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL( "/scrollable_page_with_content.html"))); @@ -1026,6 +1033,23 @@ ContinueJsTest(); } +// Tests that both focused and arbitrary tab extraction are rejected +// when the glic panel is hidden. +IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTabAndPreloading, + testNoExtractionWhileHidden) { + // Attempt to extract context with the preloaded client. + ExecuteJsTest(); + + // Open the glic panel and attempt to extract context. + RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached, + GlicInstrumentMode::kHostAndContents)); + ContinueJsTest(); + + // Hide the glic panel again and attempt to extract context. + window_controller().Close(); + ContinueJsTest(); +} + IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab, testGetFocusedTabStateV2) { ExecuteJsTest(); } @@ -1099,6 +1123,11 @@ } IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab, + testGetContextFromPinnedTabWithoutPermission) { + ExecuteJsTest(); +} + +IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab, testGetContextFromFocusedTabWithNoRequestedData) { ExecuteJsTest(); } @@ -1526,6 +1555,17 @@ ExecuteJsTest(); } +IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab, testUnpinTabsWhileClosing) { + ExecuteJsTest(); +} + +IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab, testPinTabsWithTwoTabs) { + RunTestSequence(AddInstrumentedTab(kSecondTab, page_url())); + ExecuteJsTest(); + browser()->tab_strip_model()->SelectPreviousTab(); + ContinueJsTest(); +} + // TODO(b/431837630): Make this work on mac. #if BUILDFLAG(IS_MAC) #define MAYBE_testFetchInactiveTabScreenshot \
diff --git a/chrome/browser/glic/host/glic_page_handler.cc b/chrome/browser/glic/host/glic_page_handler.cc index 588ff56..3cf3da4 100644 --- a/chrome/browser/glic/host/glic_page_handler.cc +++ b/chrome/browser/glic/host/glic_page_handler.cc
@@ -810,10 +810,6 @@ void UnpinTabs(const std::vector<int32_t>& tab_ids, UnpinTabsCallback callback) override { - if (ShouldDoApiActivationGating()) { - std::move(callback).Run(false); - return; - } std::vector<tabs::TabHandle> tab_handles; for (auto tab_id : tab_ids) { tab_handles.push_back(tabs::TabHandle(tab_id));
diff --git a/chrome/browser/glic/media/glic_media_context.cc b/chrome/browser/glic/media/glic_media_context.cc index 95d7c14f7..475464f 100644 --- a/chrome/browser/glic/media/glic_media_context.cc +++ b/chrome/browser/glic/media/glic_media_context.cc
@@ -4,6 +4,12 @@ #include "chrome/browser/glic/media/glic_media_context.h" +#include <algorithm> +#include <iterator> +#include <vector> + +#include "base/metrics/histogram_functions.h" +#include "base/strings/string_util.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" #include "content/public/browser/render_frame_host.h" @@ -24,20 +30,107 @@ return false; } + // Nonfinal chunks get stored separately, and have no timing information. It + // will be inserted at the right place in `GetContext`. if (!result.is_final) { - most_recent_nonfinal_ = result.transcription; + most_recent_nonfinal_chunk_ = {result.transcription, {}}; return true; } - text_context_ += result.transcription; - most_recent_nonfinal_.clear(); - // Trim to `max_size`. Note that we should utf8-trim, but this is easier. - constexpr size_t max_size = 20000; - if (size_t text_context_size = text_context_.length()) { - if (text_context_size > max_size) { - // Remove the beginning of the context, leaving the end. - text_context_ = text_context_.substr(text_context_size - max_size); + // Discard results that have multiple media timestamps. These happen around + // seeks, but we can't attribute them to the right place in the transcript. + // Since it's a corner case, just discard. + std::optional<media::MediaTimestampRange> media_timestamp_range; + size_t timestamp_count = 0; + if (result.timing_information && + result.timing_information->originating_media_timestamps) { + timestamp_count = + result.timing_information->originating_media_timestamps->size(); + } + base::UmaHistogramExactLinear("Glic.Media.TimestampRangeCount", + timestamp_count, 10); + + if (timestamp_count > 1) { + // Continue transcribing, but discard this particular result. + return true; + } else if (timestamp_count == 1) { + // We'll copy this one to the `TranscriptChunk`. + media_timestamp_range.emplace( + (*result.timing_information->originating_media_timestamps)[0]); + } + + // Process final result. + TranscriptChunk new_chunk = {result.transcription, media_timestamp_range}; + new_chunk.sequence_number = next_sequence_number_++; + + if (new_chunk.HasMediaTimestamps()) { + // New chunk has timing information, process overlaps by removing existing + // overlapping chunks. + RemoveOverlappingChunks(new_chunk); + + // Insert the new chunk into the updated list, maintaining order by start + // time. This is the place before which the chunk will be inserted, so + // setting it equal to end() will append it to the list. + std::optional<std::list<TranscriptChunk>::iterator> insert_pos; + + // Optimization: check if we can insert after the last insertion point. + if (last_insertion_it_ != final_transcript_chunks_.end()) { + if (new_chunk.GetStartTime() >= last_insertion_it_->GetStartTime()) { + // The new chunk does come after the previous chunk. Make sure that the + // next chunk comes after, or there's no next chunk. + auto next_it = std::next(last_insertion_it_); + if (next_it == final_transcript_chunks_.end() || + new_chunk.GetStartTime() < next_it->GetStartTime()) { + // Insert immediately before this. + insert_pos = next_it; + } + } } + + // If the optimization didn't work, find the correct position. + if (!insert_pos) { + insert_pos = std::upper_bound( + final_transcript_chunks_.begin(), final_transcript_chunks_.end(), + new_chunk, [](const TranscriptChunk& a, const TranscriptChunk& b) { + return a.GetStartTime() < b.GetStartTime(); + }); + } + last_insertion_it_ = + final_transcript_chunks_.insert(*insert_pos, std::move(new_chunk)); + } else { + // New chunk has no timing information, just append it. + final_transcript_chunks_.push_back(std::move(new_chunk)); + last_insertion_it_ = std::prev(final_transcript_chunks_.end()); + } + + // Clear the most recent non-final result after a final result is processed. + most_recent_nonfinal_chunk_.reset(); + + // Trim `final_transcript_chunks_` to a reasonable size. + constexpr size_t kMaxTranscriptLength = 1000000; + size_t total_size = 0; + for (const auto& chunk : final_transcript_chunks_) { + total_size += chunk.text.length(); + } + + while (total_size > kMaxTranscriptLength) { + auto oldest_chunk_it = std::min_element( + final_transcript_chunks_.begin(), final_transcript_chunks_.end(), + [](const TranscriptChunk& a, const TranscriptChunk& b) { + return a.sequence_number < b.sequence_number; + }); + if (oldest_chunk_it == final_transcript_chunks_.end()) { + // This should not be reached if `total_size` is greater than zero. + break; + } + total_size -= oldest_chunk_it->text.length(); + // If we're about to remove the chunk that was also the append point, + // start over. This should be unlikely; unless there's ~one really big + // chunk, we're not appending after the oldest chunk. + if (last_insertion_it_ == oldest_chunk_it) { + last_insertion_it_ = final_transcript_chunks_.end(); + } + final_transcript_chunks_.erase(oldest_chunk_it); } return true; @@ -47,7 +140,37 @@ if (IsExcludedFromTranscript()) { return ""; } - return text_context_ + most_recent_nonfinal_; + + // If there are no final chunks, the transcript is either empty or just the + // non-final chunk. + if (final_transcript_chunks_.empty()) { + return most_recent_nonfinal_chunk_ ? most_recent_nonfinal_chunk_->text : ""; + } + + std::vector<std::string_view> pieces; + pieces.reserve(final_transcript_chunks_.size() + 1); + + // If `last_insertion_it_` is invalid, it's ambiguous where the non-final + // chunk should go, so we omit it. + if (last_insertion_it_ == final_transcript_chunks_.end()) { + for (const auto& chunk : final_transcript_chunks_) { + pieces.push_back(chunk.text); + } + return base::JoinString(pieces, ""); + } + + // Otherwise, insert the non-final chunk immediately after the chunk that + // `last_insertion_it_` points to. Assume that it will be the next in-order + // chunk, which is usually correct. + for (auto it = final_transcript_chunks_.begin(); + it != final_transcript_chunks_.end(); ++it) { + pieces.push_back(it->text); + if (it == last_insertion_it_ && most_recent_nonfinal_chunk_) { + pieces.push_back(most_recent_nonfinal_chunk_->text); + } + } + + return base::JoinString(pieces, ""); } void GlicMediaContext::OnPeerConnectionAdded() { @@ -56,10 +179,8 @@ bool GlicMediaContext::IsExcludedFromTranscript() const { if (is_excluded_from_transcript_) { - // Skip checking if it's already excluded. return true; } - content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(&render_frame_host()); is_excluded_from_transcript_ |= MediaCaptureDevicesDispatcher::GetInstance() @@ -69,4 +190,77 @@ return is_excluded_from_transcript_; } +void GlicMediaContext::RemoveOverlappingChunks( + const TranscriptChunk& new_chunk) { + auto it = final_transcript_chunks_.begin(); + while (it != final_transcript_chunks_.end()) { + if (it->HasMediaTimestamps()) { + // Existing chunk has timing information, check for overlap. + if (new_chunk.DoesOverlapWith(*it)) { + // If `new_chunk` somehow overlaps with the insertion hint, forget the + // hint and search the whole list next time. This is very rare; it + // requires the next chunk to overlap with the chunk we just added. + if (last_insertion_it_ == it) { + last_insertion_it_ = final_transcript_chunks_.end(); + } + // Overlap, erase the current chunk and get the iterator to the next. + it = final_transcript_chunks_.erase(it); + } else { + // No overlap, move to the next chunk. + ++it; + } + } else { + // Existing chunk has no timing information, keep it and move to the + // next. + ++it; + } + } +} + +GlicMediaContext::TranscriptChunk::TranscriptChunk() = default; +GlicMediaContext::TranscriptChunk::TranscriptChunk( + std::string text, + std::optional<media::MediaTimestampRange> timestamp_range) + : text(std::move(text)), + media_timestamp_range(std::move(timestamp_range)) {} +GlicMediaContext::TranscriptChunk::TranscriptChunk(const TranscriptChunk&) = + default; +GlicMediaContext::TranscriptChunk& GlicMediaContext::TranscriptChunk::operator=( + const TranscriptChunk&) = default; +GlicMediaContext::TranscriptChunk::~TranscriptChunk() = default; + +base::TimeDelta GlicMediaContext::TranscriptChunk::GetStartTime() const { + // Return a large value if no timing info, so these chunks sort last. + return media_timestamp_range.has_value() ? media_timestamp_range->start + : base::TimeDelta::Max(); +} + +base::TimeDelta GlicMediaContext::TranscriptChunk::GetEndTime() const { + // Return a small value if no timing info, so these chunks don't overlap based + // on time. + return media_timestamp_range.has_value() ? media_timestamp_range->end + : base::TimeDelta::Min(); +} + +bool GlicMediaContext::TranscriptChunk::DoesOverlapWith( + const TranscriptChunk& chunk2) const { + if (!HasMediaTimestamps() || !chunk2.HasMediaTimestamps()) { + // Cannot determine overlap without timing info + return false; + } + + base::TimeDelta chunk1_start = GetStartTime(); + base::TimeDelta chunk1_end = GetEndTime(); + base::TimeDelta chunk2_start = chunk2.GetStartTime(); + base::TimeDelta chunk2_end = chunk2.GetEndTime(); + + // The end times are exclusive, so we need strict inequality. + // Also note tht we could swap the chunks and the result wouldn't change. + return chunk1_start < chunk2_end && chunk2_start < chunk1_end; +} + +bool GlicMediaContext::TranscriptChunk::HasMediaTimestamps() const { + return media_timestamp_range.has_value(); +} + } // namespace glic
diff --git a/chrome/browser/glic/media/glic_media_context.h b/chrome/browser/glic/media/glic_media_context.h index 44901eb..8210514 100644 --- a/chrome/browser/glic/media/glic_media_context.h +++ b/chrome/browser/glic/media/glic_media_context.h
@@ -5,19 +5,19 @@ #ifndef CHROME_BROWSER_GLIC_MEDIA_GLIC_MEDIA_CONTEXT_H_ #define CHROME_BROWSER_GLIC_MEDIA_GLIC_MEDIA_CONTEXT_H_ +#include <list> +#include <optional> #include <string> +#include "base/time/time.h" #include "chrome/browser/glic/media/glic_media_page_cache.h" #include "content/public/browser/document_user_data.h" +#include "media/mojo/mojom/speech_recognition_result.h" namespace content { class RenderFrameHost; } // namespace content -namespace media { -struct SpeechRecognitionResult; -} // namespace media - namespace glic { // Per-document (frame) context. @@ -39,11 +39,59 @@ DOCUMENT_USER_DATA_KEY_DECL(); private: + // Represents a chunk of the transcript with associated timing information. + struct TranscriptChunk { + TranscriptChunk(); + TranscriptChunk( + std::string text, + std::optional<media::MediaTimestampRange> timing_information); + TranscriptChunk(const TranscriptChunk&); + TranscriptChunk& operator=(const TranscriptChunk&); + ~TranscriptChunk(); + + std::string text; + std::optional<media::MediaTimestampRange> media_timestamp_range; + + // The sequence number of this chunk, used to determine insertion order. + uint64_t sequence_number = 0; + + // Helper to get the start time for sorting. If there is no timing + // information, returns a large value so that this chunk sorts last. + base::TimeDelta GetStartTime() const; + + // Helper to get the end time for overlap checks. If there is no timing + // information, returns a small value so that this chunk doesn't overlap + // with any other chunk based on time. + base::TimeDelta GetEndTime() const; + + // Helper to check for overlap with another chunk. Chunks without timing + // information never overlap. + bool DoesOverlapWith(const TranscriptChunk& chunk2) const; + + // Helper to see if this chunk has media timestamps. + bool HasMediaTimestamps() const; + }; + bool IsExcludedFromTranscript() const; - std::string text_context_; - std::string most_recent_nonfinal_; + // Removes any chunks in `final_transcript_chunks_` that overlap with + // `new_chunk`. + void RemoveOverlappingChunks(const TranscriptChunk& new_chunk); + + // Stores final transcript chunks in timestamp order. + std::list<TranscriptChunk> final_transcript_chunks_; + // Stores the most recent non-final transcript chunk. + std::optional<TranscriptChunk> most_recent_nonfinal_chunk_; mutable bool is_excluded_from_transcript_ = false; + + // The next sequence number to assign to a new chunk. + uint64_t next_sequence_number_ = 0; + + // Iterator to the last inserted chunk, to optimize insertion. If it is + // `end()`, then the next insertion will scan the whole list to find the right + // insertion point. + std::list<TranscriptChunk>::iterator last_insertion_it_ = + final_transcript_chunks_.end(); }; } // namespace glic
diff --git a/chrome/browser/glic/media/glic_media_context_unittest.cc b/chrome/browser/glic/media/glic_media_context_unittest.cc index e1efa5b..8ad1967b 100644 --- a/chrome/browser/glic/media/glic_media_context_unittest.cc +++ b/chrome/browser/glic/media/glic_media_context_unittest.cc
@@ -4,7 +4,10 @@ #include "chrome/browser/glic/media/glic_media_context.h" +#include <vector> + #include "base/test/mock_callback.h" +#include "base/time/time.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" @@ -16,6 +19,21 @@ namespace glic { +// Helper to create a SpeechRecognitionResult with optional timing. +media::SpeechRecognitionResult CreateSpeechRecognitionResult( + const std::string& transcription, + bool is_final, + const std::vector<media::MediaTimestampRange>& timing_intervals = {}) { + media::SpeechRecognitionResult result; + result.transcription = transcription; + result.is_final = is_final; + if (!timing_intervals.empty()) { + result.timing_information = media::TimingInformation(); + result.timing_information->originating_media_timestamps = timing_intervals; + } + return result; +} + class GlicMediaContextTest : public ChromeRenderViewHostTestHarness { public: content::RenderFrameHost* rfh() { @@ -59,14 +77,15 @@ // Send in a very long string, and expect that it comes back shorter with // the end of the string retained. We don't care exactly how long it is, as // long as there's some limit to prevent it from going forever. - std::string long_cap(30000, 'A'); - long_cap.back() = 'B'; - context->OnResult( - media::SpeechRecognitionResult(long_cap, /*is_final=*/true)); + std::string long_cap(100000, 'A'); + constexpr int num_repeats = 15; + for (int i = 0; i < num_repeats; ++i) { + context->OnResult( + media::SpeechRecognitionResult(long_cap, /*is_final=*/true)); + } const std::string actual_cap = context->GetContext(); - EXPECT_LT(actual_cap.length(), long_cap.length()); - EXPECT_EQ(actual_cap.back(), long_cap.back()); + EXPECT_LT(actual_cap.length(), long_cap.length() * num_repeats); } TEST_F(GlicMediaContextTest, ContextContainsButReplacesNonFinal) { @@ -83,7 +102,8 @@ media::SpeechRecognitionResult(test_cap_2, /*is_final=*/false)); EXPECT_EQ(context->GetContext(), test_cap_1 + test_cap_2); - // Should replace cap_2. + // The final result "GHI" will be appended, and the non-final result "DEF" + // will be cleared. const std::string test_cap_3("GHI"); context->OnResult( media::SpeechRecognitionResult(test_cap_3, /*is_final=*/true)); @@ -124,4 +144,225 @@ EXPECT_EQ(context->GetContext(), ""); } +TEST_F(GlicMediaContextTest, OnResult_FinalResultWithTiming_EmptyContext) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + media::SpeechRecognitionResult result = CreateSpeechRecognitionResult( + "hello world", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))}); + + EXPECT_TRUE(media_context->OnResult(result)); + EXPECT_EQ(media_context->GetContext(), "hello world"); +} + +TEST_F(GlicMediaContextTest, OnResult_FinalResultWithTiming_NoOverlap) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add initial chunks using OnResult + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk three", true, + {media::MediaTimestampRange(base::Seconds(2), base::Seconds(3))})); + + // Add a new chunk that fits in between + media::SpeechRecognitionResult result = CreateSpeechRecognitionResult( + "chunk two", true, + {media::MediaTimestampRange(base::Seconds(1), base::Seconds(2))}); + + EXPECT_TRUE(media_context->OnResult(result)); + EXPECT_EQ(media_context->GetContext(), "chunk onechunk twochunk three"); +} + +TEST_F(GlicMediaContextTest, + OnResult_FinalResultWithTiming_OverlapsSingleChunk) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add initial chunks using OnResult + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk two", true, + {media::MediaTimestampRange(base::Seconds(1), base::Seconds(2))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk three", true, + {media::MediaTimestampRange(base::Seconds(2), base::Seconds(3))})); + + // Add a new chunk that overlaps with "chunk two". + // End time is exclusive, so we set it to end exactly where chunk two ends + // and chunk three starts, to be sure that only chunk two is removed. + media::SpeechRecognitionResult result = CreateSpeechRecognitionResult( + "new chunk", true, + {media::MediaTimestampRange(base::Seconds(1.2), base::Seconds(2))}); + + EXPECT_TRUE(media_context->OnResult(result)); + EXPECT_EQ(media_context->GetContext(), "chunk onenew chunkchunk three"); +} + +TEST_F(GlicMediaContextTest, + OnResult_FinalResultWithTiming_OverlapsMultipleChunks) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add initial chunks using OnResult + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk two", true, + {media::MediaTimestampRange(base::Seconds(1), base::Seconds(2))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk three", true, + {media::MediaTimestampRange(base::Seconds(2), base::Seconds(3))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk four", true, + {media::MediaTimestampRange(base::Seconds(3), base::Seconds(4))})); + + // Add a new chunk that overlaps with "chunk two" and "chunk three" + media::SpeechRecognitionResult result = CreateSpeechRecognitionResult( + "overlapping new chunk", true, + {media::MediaTimestampRange(base::Seconds(1.5), base::Seconds(2.5))}); + + EXPECT_TRUE(media_context->OnResult(result)); + EXPECT_EQ(media_context->GetContext(), + "chunk oneoverlapping new chunkchunk four"); +} + +TEST_F(GlicMediaContextTest, OnResult_FinalResultWithoutTiming) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add an initial timed chunk using OnResult + media_context->OnResult(CreateSpeechRecognitionResult( + "timed chunk", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + + // Add a new chunk without timing information + media::SpeechRecognitionResult result = CreateSpeechRecognitionResult( + "untimed chunk", true); // No timing intervals + + EXPECT_TRUE(media_context->OnResult(result)); + // Untimed chunks are currently just appended. + EXPECT_EQ(media_context->GetContext(), "timed chunkuntimed chunk"); +} + +TEST_F(GlicMediaContextTest, OnResult_MultipleFinalResultsWithoutTiming) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + media_context->OnResult(CreateSpeechRecognitionResult("first chunk", true)); + + // Add a new chunk without timing information + media::SpeechRecognitionResult result = + CreateSpeechRecognitionResult("second chunk", true); + + EXPECT_TRUE(media_context->OnResult(result)); + // Untimed chunks are currently just appended. + EXPECT_EQ(media_context->GetContext(), "first chunksecond chunk"); +} + +TEST_F(GlicMediaContextTest, OnResult_NonFinalResult) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + media::SpeechRecognitionResult result = + CreateSpeechRecognitionResult("non-final text", false); // Not final + + EXPECT_TRUE(media_context->OnResult(result)); + EXPECT_EQ(media_context->GetContext(), "non-final text"); +} + +TEST_F(GlicMediaContextTest, OnResult_FinalResultClearsNonFinal) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add a non-final result first + media::SpeechRecognitionResult non_final_result = + CreateSpeechRecognitionResult("non-final text", false); + media_context->OnResult(non_final_result); + EXPECT_EQ(media_context->GetContext(), "non-final text"); + + // Add a final result + media::SpeechRecognitionResult final_result = CreateSpeechRecognitionResult( + "final text", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))}); + + EXPECT_TRUE(media_context->OnResult(final_result)); + EXPECT_EQ(media_context->GetContext(), "final text"); +} + +TEST_F(GlicMediaContextTest, + OnResult_FinalResultWithTiming_MultipleMediaTimestamps) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add a final chunk using OnResult + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + + // Add another chunk with multiple timestamps. It should return true but + // ignore the chunk. + EXPECT_TRUE(media_context->OnResult(CreateSpeechRecognitionResult( + "chunk two", true, + {media::MediaTimestampRange(base::Seconds(1), base::Seconds(2)), + media::MediaTimestampRange(base::Seconds(3), base::Seconds(4))}))); + + EXPECT_EQ(media_context->GetContext(), "chunk one"); +} + +TEST_F(GlicMediaContextTest, + OnResult_FinalResultWithTiming_NonfinalChunkAppended) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add initial chunks using OnResult. `last_insertion_it_` will point to + // "chunk three" after the second call, which is also the chronologically last + // entry in the list of chunks. The nonfinal entry will be appended to the + // end of the list. + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk three", true, + {media::MediaTimestampRange(base::Seconds(2), base::Seconds(3))})); + + // Insert a non-final chunk. It should be placed after "chunk three". + media_context->OnResult(CreateSpeechRecognitionResult("chunk two", false)); + + EXPECT_EQ(media_context->GetContext(), "chunk onechunk threechunk two"); +} + +TEST_F(GlicMediaContextTest, + OnResult_FinalResultWithTiming_NonfinalChunkFollowsLastFinalChunk) { + auto* media_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Add initial chunks using OnResult. `last_insertion_it_` will point to + // "chunk three" after the second call. However, it is not last + // chronologically, so the next nonfinal chunk should end up after it but + // before "chunk one". + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk one", true, + {media::MediaTimestampRange(base::Seconds(2), base::Seconds(3))})); + media_context->OnResult(CreateSpeechRecognitionResult( + "chunk three", true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + + // Insert a non-final chunk. It should be placed after "chunk three". + media_context->OnResult(CreateSpeechRecognitionResult("chunk two", false)); + + EXPECT_EQ(media_context->GetContext(), "chunk threechunk twochunk one"); +} + +TEST_F(GlicMediaContextTest, ContextShouldTruncateLeastRecentlyAdded) { + auto* context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh()); + + // Send a long string, then a short one. The context should truncate the long + // one first, even though it has a later timestamp. + std::string long_cap(1000000, 'A'); + context->OnResult(CreateSpeechRecognitionResult( + long_cap, /*is_final=*/true, + {media::MediaTimestampRange(base::Seconds(1), base::Seconds(2))})); + context->OnResult(CreateSpeechRecognitionResult( + "B", /*is_final=*/true, + {media::MediaTimestampRange(base::Seconds(0), base::Seconds(1))})); + + // The long one should have been evicted. + EXPECT_EQ(context->GetContext(), "B"); +} + } // namespace glic
diff --git a/chrome/browser/media/webrtc/BUILD.gn b/chrome/browser/media/webrtc/BUILD.gn index 9e6e2cd2..86a14c25 100644 --- a/chrome/browser/media/webrtc/BUILD.gn +++ b/chrome/browser/media/webrtc/BUILD.gn
@@ -215,6 +215,13 @@ if (enable_glic) { deps += [ "//chrome/browser/glic" ] } + + if (is_win) { + sources += [ + "desktop_capture_devices_util_win.cc", + "desktop_capture_devices_util_win.h", + ] + } } if (is_mac) {
diff --git a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc index 75230379..e281ac4 100644 --- a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc +++ b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc
@@ -9,8 +9,11 @@ #include <utility> #include "base/check_op.h" +#include "base/feature_list.h" +#include "base/process/process_handle.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" +#include "base/task/thread_pool.h" #include "base/unguessable_token.h" #include "build/build_config.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" @@ -24,7 +27,9 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents_media_capture_id.h" #include "content/public/common/content_features.h" +#include "media/audio/application_loopback_device_helper.h" #include "media/audio/audio_device_description.h" +#include "media/audio/audio_features.h" #include "media/mojo/mojom/capture_handle.mojom.h" #include "media/mojo/mojom/display_media_information.mojom.h" #include "third_party/blink/public/common/features_generated.h" @@ -33,6 +38,10 @@ #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" #include "ui/base/l10n/l10n_util.h" +#if BUILDFLAG(IS_WIN) +#include "chrome/browser/media/webrtc/desktop_capture_devices_util_win.h" +#endif // BUILDFLAG(IS_WIN) + namespace { // TODO(crbug.com/40181897): Eliminate code duplication with @@ -246,6 +255,10 @@ blink::mojom::MediaStreamType media_stream_type) { if (desktop_media_id_type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { return blink::MediaStreamDevice(media_stream_type, device_id, "Tab audio"); + } else if (desktop_media_id_type == content::DesktopMediaID::TYPE_WINDOW && + media::IsApplicationAudioCaptureSupported()) { + return blink::MediaStreamDevice(media_stream_type, device_id, + "Application Audio"); } else { return blink::MediaStreamDevice(media_stream_type, device_id, "System Audio"); @@ -345,6 +358,19 @@ std::move(on_media_stream_capture_indicator_ui_created_callback)); } +std::optional<std::string> GetApplicationId(intptr_t window_id) { +#if BUILDFLAG(IS_WIN) + base::ProcessId process_id = GetAppMainProcessId(window_id); + if (process_id == base::kNullProcessId) { + return std::nullopt; + } + + return media::CreateApplicationLoopbackDeviceId(process_id); +#else + return std::nullopt; +#endif // BUILDFLAG(IS_WIN) +} + void GetAudioDeviceId(content::DesktopMediaID desktop_media_id, blink::mojom::MediaStreamType media_stream_type, bool disable_local_echo, @@ -363,6 +389,13 @@ web_id.disable_local_echo = disable_local_echo || suppress_local_audio_playback; device_id = web_id.ToString(); + } else if (desktop_media_id.type == content::DesktopMediaID::TYPE_WINDOW) { + if (media::IsApplicationAudioCaptureSupported()) { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&GetApplicationId, desktop_media_id.id), + std::move(audio_device_id_obtained_callback)); + return; + } } else { // Use the special loopback device ID for system audio capture. if (restrict_own_audio) {
diff --git a/chrome/browser/media/webrtc/desktop_capture_devices_util_win.cc b/chrome/browser/media/webrtc/desktop_capture_devices_util_win.cc new file mode 100644 index 0000000..36a0a63 --- /dev/null +++ b/chrome/browser/media/webrtc/desktop_capture_devices_util_win.cc
@@ -0,0 +1,159 @@ +// Copyright 2025 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/media/webrtc/desktop_capture_devices_util_win.h" + +#include <windows.h> + +#include <array> + +#include "base/base_paths_win.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/process/process_handle.h" +#include "base/win/scoped_handle.h" +#include "base/win/window_enumerator.h" +#include "base/win/windows_types.h" + +namespace { + +bool IsUWPApp(const base::FilePath& app_path) { + base::FilePath system_path; + if (!base::PathService::Get(base::DIR_SYSTEM, &system_path)) { + return false; + } + + // The ApplicationFrameHost.exe is the host process for UWP apps. It is + // located in the system directory (usually C:\Windows\System32). + if (base::FilePath::CompareEqualIgnoreCase(system_path.value(), + app_path.DirName().value()) && + base::FilePath::CompareEqualIgnoreCase(app_path.BaseName().value(), + L"ApplicationFrameHost.exe")) { + return true; + } + + return false; +} + +// Callback to be provided to `base::win::EnumerateChildWindows` to find the +// child window of the UWP app with the "Windows.UI.Core.CoreWindow" class name. +// When the target window is found, this function should return `true`, +// signaling to `base::win::EnumerateChildWindows` that it should stop +// enumerating and store the found window handle in `out_uwp_app_core_window`. +// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms633493(v=vs.85) +bool IsUWPAppCoreWindow(HWND& out_uwp_app_core_window, HWND hwnd) { + std::wstring class_name = base::win::GetWindowClass(hwnd); + // Check if the class name matches the UWP app's core window class name. + if (class_name == L"Windows.UI.Core.CoreWindow") { + out_uwp_app_core_window = hwnd; + return true; + } + + return false; +} + +// Given a window handle `hwnd` for a UWP app, finds the pid of the app's main +// process. +base::ProcessId GetUWPAppCoreWindowProcessId(HWND hwnd) { + HWND main_uwp_app_core_window = nullptr; + + // For UWP apps, we need to find the child window which has the class name + // Windows.UI.Core.CoreWindow and get the process ID from it. + base::win::EnumerateChildWindows( + hwnd, base::BindRepeating(&IsUWPAppCoreWindow, + std::ref(main_uwp_app_core_window))); + // There is no child window with the class name Windows.UI.Core.CoreWindow. + if (!main_uwp_app_core_window) { + return base::kNullProcessId; + } + + DWORD main_process_id; + DWORD thread_id = + GetWindowThreadProcessId(main_uwp_app_core_window, &main_process_id); + if (!thread_id || !main_process_id) { + return base::kNullProcessId; + } + + return main_process_id; +} + +// Returns the executable's path for the given process handle. +base::FilePath GetProcessExecutablePath(HANDLE process_handle) { + std::wstring image_path(MAX_PATH, L'\0'); + DWORD path_length = image_path.size(); + BOOL success = QueryFullProcessImageNameW(process_handle, 0, + image_path.data(), &path_length); + if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Process name is potentially greater than MAX_PATH, try larger max size. + // https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation + image_path.resize(UNICODE_STRING_MAX_CHARS); + path_length = image_path.size(); + success = QueryFullProcessImageName(process_handle, 0, image_path.data(), + &path_length); + if (!success) { + return base::FilePath(); + } + } + + return base::FilePath(image_path); +} + +} // namespace + +base::ProcessId GetAppMainProcessId(intptr_t window_id) { + HWND hwnd = reinterpret_cast<HWND>(window_id); + DWORD process_id; + DWORD thread_id = GetWindowThreadProcessId(hwnd, &process_id); + if (!thread_id || !process_id) { + return base::kNullProcessId; + } + + base::win::ScopedHandle process_handle( + OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, + /*bInheritHandle=*/FALSE, process_id)); + if (!process_handle.is_valid()) { + return base::kNullProcessId; + } + + // UWP apps' UI follow a hierarchy where the top-level window is created by + // ApplicationFrameHost.exe and the actual app window is a child window of the + // top-level window. Therefore, in this situation, we need to look down in the + // window hierarchy to find the correct process id. + base::FilePath app_path = GetProcessExecutablePath(process_handle.get()); + // Checks if process is a UWP app. + if (IsUWPApp(app_path)) { + return GetUWPAppCoreWindowProcessId(hwnd); + } + + base::ProcessId main_process_id_candidate = process_id; + base::ProcessId parent_id = base::GetParentProcessId(process_handle.get()); + if (parent_id <= 0) { + // If there is no parent process, we return the current process id. + return main_process_id_candidate; + } + + base::win::ScopedHandle parent_process_handle(OpenProcess( + PROCESS_QUERY_LIMITED_INFORMATION, /*bInheritHandle=*/FALSE, parent_id)); + while (parent_process_handle.is_valid()) { + base::FilePath parent_path = + GetProcessExecutablePath(parent_process_handle.get()); + if (parent_path.empty()) { + return main_process_id_candidate; + } + + // If the executables are different, we return the last PID whose executable + // was the same as `app_path` + if (!base::FilePath::CompareEqualIgnoreCase(parent_path.value(), + app_path.value())) { + return main_process_id_candidate; + } + + main_process_id_candidate = parent_id; + parent_id = base::GetParentProcessId(parent_process_handle.Get()); + parent_process_handle.Set(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, + /*bInheritHandle=*/FALSE, parent_id)); + } + + return main_process_id_candidate; +}
diff --git a/chrome/browser/media/webrtc/desktop_capture_devices_util_win.h b/chrome/browser/media/webrtc/desktop_capture_devices_util_win.h new file mode 100644 index 0000000..51b0e14 --- /dev/null +++ b/chrome/browser/media/webrtc/desktop_capture_devices_util_win.h
@@ -0,0 +1,39 @@ +// Copyright 2025 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_MEDIA_WEBRTC_DESKTOP_CAPTURE_DEVICES_UTIL_WIN_H_ +#define CHROME_BROWSER_MEDIA_WEBRTC_DESKTOP_CAPTURE_DEVICES_UTIL_WIN_H_ + +#include <stdint.h> + +#include "base/process/process_handle.h" + +// Given a window handle, returns the PID of the application's "main process" +// for audio capture purposes. If an error occurs, returns +// `base::kNullProcessId`. +// +// On Windows, a window is merely a GUI element created by a process and the +// window itself does not play any audio. A process is responsible for rendering +// the application audio. In some multi-process scenarios, the process that +// creates and owns the window might not be the same that renders audio - e.g. +// Chromium. +// +// Despite not being able to capture audio from windows, Windows has an OS API +// that allows an application to capture audio from a process tree instead. +// Given a HWND value, it is possible to obtain the process id (PID) of the +// process that created the window. Therefore, the best we can do is to try find +// the root process of the application's process tree and use it to capture +// audio. This function does that. +// +// Let "window process" be the process that created the window identified by the +// provided HWND. Depending on the type of the application, there are different +// definitions of "main process" for this function: +// - For UWP apps, the "main process" is the process that created the child +// window with the "Windows.UI.Core.CoreWindow" class name. +// - For all other apps, the "main process" is the oldest ancestor process of +// "window process" that shares the same executable image with "window +// process". +base::ProcessId GetAppMainProcessId(intptr_t window_id); + +#endif // CHROME_BROWSER_MEDIA_WEBRTC_DESKTOP_CAPTURE_DEVICES_UTIL_WIN_H_
diff --git a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc index 82f93e82..3dd17c8 100644 --- a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc +++ b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
@@ -14,6 +14,7 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/mock_callback.h" +#include "base/test/with_feature_override.h" #include "base/types/expected.h" #include "build/build_config.h" #include "chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h" @@ -26,6 +27,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/navigation_simulator.h" +#include "media/audio/audio_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/mediastream/media_stream_request.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h" @@ -44,6 +46,13 @@ #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #endif // !BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_WIN) +#include "base/process/process.h" +#include "base/test/bind.h" +#include "base/win/message_window.h" +#include "media/audio/application_loopback_device_helper.h" +#endif // BUILDFLAG(IS_WIN) + class DisplayMediaAccessHandlerTest : public ChromeRenderViewHostTestHarness { public: DisplayMediaAccessHandlerTest() = default; @@ -904,3 +913,83 @@ &wait_loop, &result, devices); wait_loop.Run(); } + +#if BUILDFLAG(IS_WIN) +class DisplayMediaAccessHandlerWindowAudioCaptureWinTest + : public base::test::WithFeatureOverride, + public DisplayMediaAccessHandlerTest { + public: + DisplayMediaAccessHandlerWindowAudioCaptureWinTest() + : base::test::WithFeatureOverride(features::kApplicationAudioCaptureWin) { + } +}; + +TEST_P(DisplayMediaAccessHandlerWindowAudioCaptureWinTest, ValidWindowId) { + blink::mojom::MediaStreamRequestResult result; + blink::mojom::StreamDevices devices; + + // Create a fake window to simulate a valid window ID. Fortunately, we don't + // need to actually show the window, just to have a valid HWND. + base::win::MessageWindow window; + EXPECT_TRUE(window.Create( + base::BindLambdaForTesting([&](UINT message, WPARAM wparam, LPARAM lparam, + LRESULT* result) { return true; }))); + ProcessRequest( + content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, + reinterpret_cast<intptr_t>(window.hwnd()), + true /* audio_share */), + &result, devices, true /* request_audio */); + + EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, result); + // If the feature is disabled, we expect only the video device. + if (IsParamFeatureEnabled()) { + EXPECT_EQ(2u, blink::CountDevices(devices)); + } else { + EXPECT_EQ(1u, blink::CountDevices(devices)); + } + EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE, + devices.video_device.value().type); + EXPECT_TRUE(devices.video_device.value().display_media_info); + + if (IsParamFeatureEnabled()) { + EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE, + devices.audio_device.value().type); + EXPECT_TRUE(devices.audio_device.value().input.IsValid()); + + // Unit tests are executed in a child process that also use the same + // executable image (unit_tests.exe) unless the --single-process flag is + // passed. Therefore, the application process ID should match either the + // parent's process PID or the child's process PID. + uint32_t application_process_id = + media::GetApplicationIdFromApplicationLoopbackDeviceId( + devices.audio_device.value().id); + EXPECT_THAT(application_process_id, + testing::AnyOf(base::Process::Current().Pid(), + base::GetParentProcessId( + base::Process::Current().Handle()))); + + } else { + EXPECT_FALSE(devices.audio_device.has_value()); + } +} + +TEST_P(DisplayMediaAccessHandlerWindowAudioCaptureWinTest, InvalidWindowId) { + blink::mojom::MediaStreamRequestResult result; + blink::mojom::StreamDevices devices; + ProcessRequest(content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, + content::DesktopMediaID::kFakeId, + true /* audio_share */), + &result, devices, true /* request_audio */); + + // If the window ID is invalid, audio should not be captured. + EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, result); + EXPECT_EQ(1u, blink::CountDevices(devices)); + EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE, + devices.video_device.value().type); + EXPECT_TRUE(devices.video_device.value().display_media_info); +} + +INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE( + DisplayMediaAccessHandlerWindowAudioCaptureWinTest); + +#endif // BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc index 93a6811..c9e98ec 100644 --- a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc +++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc
@@ -72,6 +72,8 @@ {"https://www.google.com", "https://www.youtube.com", "https://www.wikipedia.org", "https://maps.google.com"}, 199)); + } else if (data_type_param.find("Fake Zero State") != std::string::npos) { + // No-op: the zero state card only appears when there's no data. } std::move(callback).Run(std::move(tab_groups_mojom));
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc index be12f55b..a318e56 100644 --- a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc +++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc
@@ -91,3 +91,15 @@ EXPECT_EQ(4u, group4->favicon_urls.size()); EXPECT_EQ(199, group4->total_tab_count); } + +TEST_F(TabGroupsPageHandlerTest, GetFakeZeroStateTabGroups) { + // Enable the feature and set the parameter to "Fake Zero State". + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + ntp_features::kNtpTabGroupsModule, + {{ntp_features::kNtpTabGroupsModuleDataParam, "Fake Zero State"}}); + + auto tab_groups_mojom = RunGetTabGroups(); + + EXPECT_TRUE(tab_groups_mojom.empty()); +}
diff --git a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc index 8897bd1..4ce36f3b 100644 --- a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc +++ b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
@@ -12,7 +12,6 @@ #include "base/strings/string_number_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "chrome/browser/offline_pages/offline_page_model_factory.h" #include "chrome/browser/offline_pages/request_coordinator_factory.h" #include "chrome/browser/offline_pages/test_offline_page_model_builder.h" @@ -26,6 +25,7 @@ #include "components/offline_pages/core/offline_page_model.h" #include "components/offline_pages/core/offline_page_test_archiver.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/browser_task_environment.h" #include "content/public/test/navigation_simulator.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" @@ -95,7 +95,6 @@ ~RecentTabHelperTest() override = default; void SetUp() override; - void TearDown() override; const std::vector<OfflinePageItem>& GetAllPages(); void FailLoad(const GURL& url); @@ -173,13 +172,6 @@ bool all_pages_needs_updating_; std::unique_ptr<base::HistogramTester> histogram_tester_; - // Mocks the RenderViewHostTestHarness' main thread runner. Needs to be delay - // initialized in SetUp() -- can't be a simple member -- since - // RenderViewHostTestHarness only initializes its main thread environment in - // its SetUp() :(. - std::unique_ptr<base::ScopedMockTimeMessageLoopTaskRunner> - mocked_main_runner_; - base::WeakPtrFactory<RecentTabHelperTest> weak_ptr_factory_{this}; }; @@ -208,7 +200,9 @@ } RecentTabHelperTest::RecentTabHelperTest() - : recent_tab_helper_(nullptr), + : ChromeRenderViewHostTestHarness( + base::test::TaskEnvironment::TimeSource::MOCK_TIME), + recent_tab_helper_(nullptr), model_(nullptr), default_test_delegate_(nullptr), page_added_count_(0), @@ -218,9 +212,6 @@ void RecentTabHelperTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); - mocked_main_runner_ = - std::make_unique<base::ScopedMockTimeMessageLoopTaskRunner>(); - // Sets up the factories for testing. OfflinePageModelFactory::GetInstance()->SetTestingFactoryAndUse( profile()->GetProfileKey(), @@ -244,11 +235,6 @@ histogram_tester_ = std::make_unique<base::HistogramTester>(); } -void RecentTabHelperTest::TearDown() { - mocked_main_runner_.reset(); - ChromeRenderViewHostTestHarness::TearDown(); -} - void RecentTabHelperTest::FailLoad(const GURL& url) { content::NavigationSimulator::NavigateAndFailFromBrowser( web_contents(), url, net::ERR_INTERNET_DISCONNECTED); @@ -270,12 +256,12 @@ } void RecentTabHelperTest::RunUntilIdle() { - (*mocked_main_runner_)->RunUntilIdle(); + task_environment()->RunUntilIdle(); } void RecentTabHelperTest::FastForwardSnapshotController() { constexpr base::TimeDelta kLongDelay = base::Seconds(100); - (*mocked_main_runner_)->FastForwardBy(kLongDelay); + task_environment()->FastForwardBy(kLongDelay); } void RecentTabHelperTest::StartAndCommitNavigation(
diff --git a/chrome/browser/on_device_translation/translation_manager_impl.cc b/chrome/browser/on_device_translation/translation_manager_impl.cc index 83a984c..cca4f84 100644 --- a/chrome/browser/on_device_translation/translation_manager_impl.cc +++ b/chrome/browser/on_device_translation/translation_manager_impl.cc
@@ -9,6 +9,7 @@ #include "base/feature_list.h" #include "base/rand_util.h" #include "base/task/sequenced_task_runner.h" +#include "chrome/browser/ai/ai_crx_component.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/component_updater/translate_kit_component_installer.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -354,8 +355,9 @@ crx_file::id_util::GenerateIdFromHash(config.public_key_sha)); } model_download_progress_manager_.AddObserver( - GetComponentUpdateService(), std::move(options->observer_remote), - std::move(component_ids)); + std::move(options->observer_remote), + on_device_ai::AICrxComponent::FromComponentIds( + GetComponentUpdateService(), std::move(component_ids))); } base::OnceClosure create_translator =
diff --git a/chrome/browser/on_device_translation/translation_manager_impl.h b/chrome/browser/on_device_translation/translation_manager_impl.h index d9ac3ae..56c970a8 100644 --- a/chrome/browser/on_device_translation/translation_manager_impl.h +++ b/chrome/browser/on_device_translation/translation_manager_impl.h
@@ -16,6 +16,7 @@ #include "base/supports_user_data.h" #include "base/types/pass_key.h" #include "chrome/browser/ai/ai_model_download_progress_manager.h" +#include "components/component_updater/component_updater_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h"
diff --git a/chrome/browser/optimization_guide/BUILD.gn b/chrome/browser/optimization_guide/BUILD.gn index 91b8b8d..082af18 100644 --- a/chrome/browser/optimization_guide/BUILD.gn +++ b/chrome/browser/optimization_guide/BUILD.gn
@@ -11,7 +11,7 @@ "chrome_hints_manager.h", "chrome_model_quality_logs_uploader_service.h", "chrome_prediction_model_store.h", - "model_execution/chrome_model_broker_state.h", + "model_execution/optimization_guide_global_state.h", "model_validator_keyed_service.h", "model_validator_keyed_service_factory.h", "optimization_guide_internals_ui.h", @@ -49,7 +49,7 @@ "chrome_hints_manager.cc", "chrome_model_quality_logs_uploader_service.cc", "chrome_prediction_model_store.cc", - "model_execution/chrome_model_broker_state.cc", + "model_execution/optimization_guide_global_state.cc", "model_validator_keyed_service.cc", "model_validator_keyed_service_factory.cc", "optimization_guide_internals_ui.cc",
diff --git a/chrome/browser/optimization_guide/model_execution/model_execution_browsertest.cc b/chrome/browser/optimization_guide/model_execution/model_execution_browsertest.cc index 3e999e34..a482116 100644 --- a/chrome/browser/optimization_guide/model_execution/model_execution_browsertest.cc +++ b/chrome/browser/optimization_guide/model_execution/model_execution_browsertest.cc
@@ -15,7 +15,7 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" -#include "chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h" +#include "chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.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/signin/identity_test_environment_profile_adaptor.h" @@ -33,6 +33,7 @@ #include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h" #include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h" #include "components/optimization_guide/core/model_execution/optimization_guide_model_execution_error.h" +#include "components/optimization_guide/core/model_execution/performance_class.h" #include "components/optimization_guide/core/model_execution/test/fake_model_assets.h" #include "components/optimization_guide/core/model_execution/test/feature_config_builder.h" #include "components/optimization_guide/core/model_quality/model_execution_logging_wrappers.h" @@ -460,6 +461,11 @@ {}); } + void SetUpLocalStatePrefService(PrefService* local_state) override { + UpdatePerformanceClassPref(local_state, + OnDeviceModelPerformanceClass::kServiceCrash); + } + OptimizationGuideKeyedService* GetOptGuideKeyedService() { return OptimizationGuideKeyedServiceFactory::GetForProfile( browser()->profile()); @@ -690,15 +696,20 @@ {}); } - ChromeModelBrokerState* broker_state() { + OptimizationGuideGlobalState* broker_state() { // Ensure keyed service is created, which should create and hold state. GetOptimizationGuideKeyedService(); - return ChromeModelBrokerState::CreateOrGet().get(); + return OptimizationGuideGlobalState::CreateOrGet().get(); + } + + void SetUpLocalStatePrefService(PrefService* local_state) override { + model_execution::prefs::RecordFeatureUsage( + local_state, ModelBasedCapabilityKey::kCompose); + UpdatePerformanceClassPref(local_state, + OnDeviceModelPerformanceClass::kVeryHigh); } void SetUpGlobalAssets() { - model_execution::prefs::RecordFeatureUsage( - g_browser_process->local_state(), ModelBasedCapabilityKey::kCompose); base_model_asset_.SetReadyIn(broker_state()->component_state_manager()); } @@ -708,7 +719,7 @@ } private: - optimization_guide::FakeBaseModelAsset base_model_asset_; + FakeBaseModelAsset base_model_asset_; FakeAdaptationAsset compose_asset_{{ .config = []() {
diff --git a/chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.cc b/chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.cc similarity index 78% rename from chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.cc rename to chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.cc index 1e4a3773..2baf36e 100644 --- a/chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.cc +++ b/chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.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/optimization_guide/model_execution/chrome_model_broker_state.h" +#include "chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h" #include <memory> @@ -75,8 +75,8 @@ } }; -base::WeakPtr<ChromeModelBrokerState>& GetInstance() { - static base::NoDestructor<base::WeakPtr<ChromeModelBrokerState>> instance; +base::WeakPtr<OptimizationGuideGlobalState>& GetInstance() { + static base::NoDestructor<base::WeakPtr<OptimizationGuideGlobalState>> instance; return *instance.get(); } @@ -108,7 +108,7 @@ } }; -ChromeModelBrokerState::ChromeModelBrokerState() +OptimizationGuideGlobalState::OptimizationGuideGlobalState() : model_broker_state_( g_browser_process->local_state(), std::make_unique<OnDeviceModelComponentStateManagerDelegate>(), @@ -118,29 +118,18 @@ .ListenForPerformanceClassAvailable( base::BindOnce(&ChromeOnDeviceModelServiceController:: RegisterPerformanceClassSyntheticTrial)); - if ((base::FeatureList::IsEnabled( - optimization_guide::features::kLogOnDeviceMetricsOnStartup) || - optimization_guide::features::IsOnDeviceExecutionEnabled()) && - component_state_manager().NeedsPerformanceClassUpdate()) { - base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( - FROM_HERE, - base::BindOnce( - &PerformanceClassifier::EnsurePerformanceClassAvailable, - model_broker_state_.performance_classifier().GetWeakPtr(), - base::DoNothing()), - optimization_guide::features::GetOnDeviceStartupMetricDelay()); - } + model_broker_state_.performance_classifier().ScheduleEvaluation(); } -ChromeModelBrokerState::~ChromeModelBrokerState() = default; +OptimizationGuideGlobalState::~OptimizationGuideGlobalState() = default; -scoped_refptr<ChromeModelBrokerState> ChromeModelBrokerState::CreateOrGet() { - base::WeakPtr<ChromeModelBrokerState>& instance = GetInstance(); +scoped_refptr<OptimizationGuideGlobalState> OptimizationGuideGlobalState::CreateOrGet() { + base::WeakPtr<OptimizationGuideGlobalState>& instance = GetInstance(); if (!instance) { - auto new_instance = base::WrapRefCounted(new ChromeModelBrokerState()); + auto new_instance = base::WrapRefCounted(new OptimizationGuideGlobalState()); instance = new_instance->weak_ptr_factory_.GetWeakPtr(); return new_instance; } - return scoped_refptr<ChromeModelBrokerState>(instance.get()); + return scoped_refptr<OptimizationGuideGlobalState>(instance.get()); } } // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h b/chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h similarity index 63% rename from chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h rename to chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h index 0e455d8..b26e43f 100644 --- a/chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h +++ b/chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_CHROME_MODEL_BROKER_STATE_H_ -#define CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_CHROME_MODEL_BROKER_STATE_H_ +#ifndef CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_OPTIMIZATION_GUIDE_GLOBAL_STATE_H_ +#define CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_OPTIMIZATION_GUIDE_GLOBAL_STATE_H_ #include <memory> @@ -17,16 +17,17 @@ namespace optimization_guide { -// This holds the ModelBrokerState shared between profiles. -// Since it holds raw_ptr to local state prefs, it must not outlive the +// This holds the ModelBrokerState and other common objects shared between +// profiles. Since some of the membersit hold raw_ptr to browser process level +// objects, such as local state prefs, profile manager, it must not outlive the // browser process, so each profile holds a ref to it in // OptimizationGuideKeyedService to keep it alive until all profiles are // destroyed. -class ChromeModelBrokerState final - : public base::RefCounted<ChromeModelBrokerState> { +class OptimizationGuideGlobalState final + : public base::RefCounted<OptimizationGuideGlobalState> { public: // Retrieves or creates the instance. - static scoped_refptr<ChromeModelBrokerState> CreateOrGet(); + static scoped_refptr<OptimizationGuideGlobalState> CreateOrGet(); OnDeviceModelComponentStateManager& component_state_manager() { return model_broker_state_.component_state_manager(); @@ -51,22 +52,26 @@ .EnsurePerformanceClassAvailable(std::move(complete)); } + on_device_model::Capabilities GetPossibleOnDeviceCapabilities() const { + return model_broker_state_.GetPossibleOnDeviceCapabilities(); + } + private: - friend base::RefCounted<ChromeModelBrokerState>; - ChromeModelBrokerState(); - ~ChromeModelBrokerState(); + friend base::RefCounted<OptimizationGuideGlobalState>; + OptimizationGuideGlobalState(); + ~OptimizationGuideGlobalState(); ModelBrokerState model_broker_state_; ChromePredictionModelStore prediction_model_store_; - base::WeakPtrFactory<ChromeModelBrokerState> weak_ptr_factory_{this}; + base::WeakPtrFactory<OptimizationGuideGlobalState> weak_ptr_factory_{this}; }; // Chrome uses a single shared instance of ModelBrokerState. // This retrieves it, or creates it if it doesn't exist yet. -ChromeModelBrokerState& GetOrCreateChromeModelBrokerState(); +OptimizationGuideGlobalState& GetOrCreateChromeModelBrokerState(); } // namespace optimization_guide -#endif // CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_CHROME_MODEL_BROKER_STATE_H_ +#endif // CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_OPTIMIZATION_GUIDE_GLOBAL_STATE_H_
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc index d1e2945..f6fa9df 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -29,7 +29,7 @@ #include "chrome/browser/optimization_guide/chrome_hints_manager.h" #include "chrome/browser/optimization_guide/chrome_model_quality_logs_uploader_service.h" #include "chrome/browser/optimization_guide/chrome_prediction_model_store.h" -#include "chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h" +#include "chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_key.h" @@ -176,14 +176,14 @@ optimization_guide::features::kOptimizationGuideOnDeviceModel)) { return; } - chrome_model_broker_state_->service_controller().BindBroker( + optimization_guide_global_state_->service_controller().BindBroker( std::move(receiver)); } std::unique_ptr<optimization_guide::ModelBrokerClient> OptimizationGuideKeyedService::CreateModelBrokerClient() { mojo::PendingRemote<optimization_guide::mojom::ModelBroker> remote; - chrome_model_broker_state_->service_controller().BindBroker( + optimization_guide_global_state_->service_controller().BindBroker( remote.InitWithNewPipeAndPassReceiver()); return std::make_unique<optimization_guide::ModelBrokerClient>( std::move(remote), optimization_guide::CreateSessionArgs( @@ -268,8 +268,8 @@ : nullptr; hint_store = hint_store_ ? hint_store_->AsWeakPtr() : nullptr; } - chrome_model_broker_state_ = - optimization_guide::ChromeModelBrokerState::CreateOrGet(); + optimization_guide_global_state_ = + optimization_guide::OptimizationGuideGlobalState::CreateOrGet(); optimization_guide_logger_ = OptimizationGuideLogger::GetInstance(); DCHECK(optimization_guide_logger_); @@ -281,7 +281,7 @@ optimization_guide_logger_.get()); prediction_manager_ = std::make_unique<optimization_guide::PredictionManager>( - &chrome_model_broker_state_->prediction_model_store(), + &optimization_guide_global_state_->prediction_model_store(), g_browser_process->shared_url_loader_factory(), g_browser_process->local_state(), g_browser_process->GetApplicationLocale(), @@ -348,9 +348,9 @@ if (base::FeatureList::IsEnabled( optimization_guide::features::kOptimizationGuideOnDeviceModel)) { service_controller = - chrome_model_broker_state_->service_controller().GetWeakPtr(); + optimization_guide_global_state_->service_controller().GetWeakPtr(); on_device_asset_manager_ = - chrome_model_broker_state_->CreateAssetManager(this); + optimization_guide_global_state_->CreateAssetManager(this); } model_execution_manager_ = @@ -498,10 +498,10 @@ void OptimizationGuideKeyedService::AddOnDeviceModelAvailabilityChangeObserver( optimization_guide::ModelBasedCapabilityKey feature, optimization_guide::OnDeviceModelAvailabilityObserver* observer) { - if (!chrome_model_broker_state_) { + if (!optimization_guide_global_state_) { return; } - chrome_model_broker_state_->service_controller() + optimization_guide_global_state_->service_controller() .AddOnDeviceModelAvailabilityChangeObserver(feature, observer); } @@ -509,10 +509,10 @@ RemoveOnDeviceModelAvailabilityChangeObserver( optimization_guide::ModelBasedCapabilityKey feature, optimization_guide::OnDeviceModelAvailabilityObserver* observer) { - if (!chrome_model_broker_state_) { + if (!optimization_guide_global_state_) { return; } - chrome_model_broker_state_->service_controller() + optimization_guide_global_state_->service_controller() .RemoveOnDeviceModelAvailabilityChangeObserver(feature, observer); } @@ -733,7 +733,7 @@ void OptimizationGuideKeyedService::EnsurePerformanceClassAvailable( base::OnceClosure complete) { - chrome_model_broker_state_->EnsurePerformanceClassAvailable( + optimization_guide_global_state_->EnsurePerformanceClassAvailable( std::move(complete)); } @@ -754,16 +754,8 @@ on_device_model::Capabilities OptimizationGuideKeyedService::GetPossibleOnDeviceCapabilities() const { - if (!chrome_model_broker_state_) { + if (!optimization_guide_global_state_) { return {}; } - auto& manager = chrome_model_broker_state_->component_state_manager(); - on_device_model::Capabilities capabilities; - if (manager.SupportsImageInput()) { - capabilities.Put(on_device_model::CapabilityFlags::kImageInput); - } - if (manager.SupportsAudioInput()) { - capabilities.Put(on_device_model::CapabilityFlags::kAudioInput); - } - return capabilities; + return optimization_guide_global_state_->GetPossibleOnDeviceCapabilities(); }
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h index c1acbc8e..6b081f18 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
@@ -13,7 +13,7 @@ #include "base/memory/scoped_refptr.h" #include "base/scoped_observation.h" #include "build/build_config.h" -#include "chrome/browser/optimization_guide/model_execution/chrome_model_broker_state.h" +#include "chrome/browser/optimization_guide/model_execution/optimization_guide_global_state.h" #include "chrome/browser/profiles/profile_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "components/optimization_guide/core/delivery/optimization_guide_model_provider.h" @@ -320,7 +320,7 @@ optimization_guide::OnDeviceModelComponentStateManager* GetComponentManager() { - return &chrome_model_broker_state_->component_state_manager(); + return &optimization_guide_global_state_->component_state_manager(); } optimization_guide::ModelExecutionManager* GetModelExecutionManager() { @@ -392,8 +392,8 @@ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_; // Keep a reference to this so it stays alive. - scoped_refptr<optimization_guide::ChromeModelBrokerState> - chrome_model_broker_state_; + scoped_refptr<optimization_guide::OptimizationGuideGlobalState> + optimization_guide_global_state_; // The tab URL provider to use for fetching information for the user's active // tabs. Will be null if the user is off the record.
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_store_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_model_store_browsertest.cc index 003d9a8..a2996a5 100644 --- a/chrome/browser/optimization_guide/prediction/prediction_model_store_browsertest.cc +++ b/chrome/browser/optimization_guide/prediction/prediction_model_store_browsertest.cc
@@ -172,7 +172,7 @@ } base::FilePath GetModelStoreBaseDir() { - return optimization_guide::ChromeModelBrokerState::CreateOrGet() + return optimization_guide::OptimizationGuideGlobalState::CreateOrGet() ->prediction_model_store() .GetBaseStoreDirForTesting(); }
diff --git a/chrome/browser/performance_manager/frame_node_impl_browsertest.cc b/chrome/browser/performance_manager/frame_node_impl_browsertest.cc index 555e600..872f5bf 100644 --- a/chrome/browser/performance_manager/frame_node_impl_browsertest.cc +++ b/chrome/browser/performance_manager/frame_node_impl_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/preloading/scoped_prewarm_feature_list.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -55,7 +56,16 @@ /*shift=*/false, /*alt=*/false, /*command=*/false); } -using FrameNodeImplBrowserTest = InProcessBrowserTest; +class FrameNodeImplBrowserTest : public InProcessBrowserTest { + public: + ~FrameNodeImplBrowserTest() override = default; + + private: + // TODO(https://crbug.com/423465927): Explore a better approach to make the + // existing tests run with the prewarm feature enabled. + test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{ + test::ScopedPrewarmFeatureList::PrewarmState::kDisabled}; +}; class ParameterizedFrameNodeImplBrowserTest : public FrameNodeImplBrowserTest,
diff --git a/chrome/browser/performance_manager/policies/process_rank_policy_android.cc b/chrome/browser/performance_manager/policies/process_rank_policy_android.cc index 494d2ab..1ed608e 100644 --- a/chrome/browser/performance_manager/policies/process_rank_policy_android.cc +++ b/chrome/browser/performance_manager/policies/process_rank_policy_android.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/performance_manager/policies/discard_eligibility_policy.h" #include "content/public/browser/android/child_process_importance.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" namespace performance_manager::policies { @@ -160,7 +161,20 @@ page_node->GetWebContents(); CHECK(web_contents, base::NotFatalUntil::M140); if (web_contents) { - web_contents->SetPrimaryMainFrameImportance(importance); + content::ChildProcessImportance subframe_importance = + content::ChildProcessImportance::NORMAL; + if (base::FeatureList::IsEnabled(features::kSubframePriorityContribution) && + base::FeatureList::IsEnabled(features::kSubframeImportance) && + importance >= content::ChildProcessImportance::PERCEPTIBLE) { + if (is_perceptible_importance_supported_) { + subframe_importance = content::ChildProcessImportance::PERCEPTIBLE; + } else if (base::FeatureList::IsEnabled( + chrome::android::kProtectedTabsAndroid) && + chrome::android::kFallbackToModerateParam.Get()) { + subframe_importance = content::ChildProcessImportance::MODERATE; + } + } + web_contents->SetPrimaryPageImportance(importance, subframe_importance); } }
diff --git a/chrome/browser/performance_manager/policies/process_rank_policy_android_unittest.cc b/chrome/browser/performance_manager/policies/process_rank_policy_android_unittest.cc index 7aa98f0f..c3260d17 100644 --- a/chrome/browser/performance_manager/policies/process_rank_policy_android_unittest.cc +++ b/chrome/browser/performance_manager/policies/process_rank_policy_android_unittest.cc
@@ -21,6 +21,7 @@ #include "components/performance_manager/test_support/graph_test_harness.h" #include "content/public/browser/android/child_process_importance.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -669,4 +670,139 @@ content::ChildProcessImportance::NORMAL); } +TEST_F(ProcessRankPolicyAndroidTest, SubframeImportanceForImportant) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_ + .InitWithFeatures(/*enabled_features=*/ + {::features::kSubframeImportance, + ::features::kSubframePriorityContribution}, + /*disabled_features=*/{}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(true)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(true); + page_graph.page.get()->SetIsVisible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::PERCEPTIBLE); +} + +TEST_F(ProcessRankPolicyAndroidTest, + SubframeImportanceForImportantWithoutPerceptibleSupport) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_ + .InitWithFeatures(/*enabled_features=*/ + {::features::kSubframeImportance, + ::features::kSubframePriorityContribution}, + /*disabled_features=*/{ + chrome::android::kProtectedTabsAndroid}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(false)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(true); + page_graph.page.get()->SetIsVisible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::NORMAL); +} + +TEST_F(ProcessRankPolicyAndroidTest, + SubframeImportanceForImportantFallbackToModerate) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_.InitWithFeaturesAndParameters( + /*enabled_features=*/ + {{chrome::android::kProtectedTabsAndroid, + {{"fallback_to_moderate", "true"}}}, + {::features::kSubframeImportance, {}}, + {::features::kSubframePriorityContribution, {}}}, + /*disabled_features=*/{}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(false)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(true); + page_graph.page.get()->SetIsVisible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::MODERATE); +} + +TEST_F(ProcessRankPolicyAndroidTest, SubframeImportanceForProtectedTab) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_ + .InitWithFeatures(/*enabled_features=*/ + {chrome::android::kProtectedTabsAndroid, + ::features::kSubframeImportance, + ::features::kSubframePriorityContribution}, + /*disabled_features=*/{}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(true)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(false); + page_graph.page.get()->SetIsVisible(false); + page_graph.page.get()->SetIsAudible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::PERCEPTIBLE); +} + +TEST_F(ProcessRankPolicyAndroidTest, + SubframeImportanceForProtectedTabWithoutPerceptibleSupport) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_.InitWithFeaturesAndParameters( + /*enabled_features=*/ + {{chrome::android::kProtectedTabsAndroid, + {{"fallback_to_moderate", "false"}}}, + {::features::kSubframeImportance, {}}, + {::features::kSubframePriorityContribution, {}}}, + /*disabled_features=*/{}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(false)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(false); + page_graph.page.get()->SetIsVisible(false); + page_graph.page.get()->SetIsAudible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::NORMAL); +} + +TEST_F(ProcessRankPolicyAndroidTest, + SubframeImportanceForProtectedTabFallbackToModerate) { + if (!content::IsPerceptibleImportanceSupported()) { + GTEST_SKIP() << "Perceptible importance is not supported."; + } + scoped_feature_list_.InitWithFeaturesAndParameters( + /*enabled_features=*/ + {{chrome::android::kProtectedTabsAndroid, + {{"fallback_to_moderate", "true"}}}, + {::features::kSubframeImportance, {}}, + {::features::kSubframePriorityContribution, {}}}, + /*disabled_features=*/{}); + graph_->PassToGraph(std::make_unique<ProcessRankPolicyAndroid>(false)); + MockPageGraph page_graph = CreateDefaultPage(); + DefaultNavigation(page_graph.page.get()); + + page_graph.page.get()->SetIsFocused(false); + page_graph.page.get()->SetIsVisible(false); + page_graph.page.get()->SetIsAudible(true); + + EXPECT_EQ(web_contents()->GetPrimaryPageSubframeImportanceForTesting(), + content::ChildProcessImportance::MODERATE); +} + } // namespace performance_manager::policies
diff --git a/chrome/browser/preloading/prerender/prerender_browsertest.cc b/chrome/browser/preloading/prerender/prerender_browsertest.cc index 3eb2667..bc44594 100644 --- a/chrome/browser/preloading/prerender/prerender_browsertest.cc +++ b/chrome/browser/preloading/prerender/prerender_browsertest.cc
@@ -1007,9 +1007,13 @@ ASSERT_TRUE(host_id); prerender_helper().WaitForPrerenderLoadCompletion(host_id); + content::test::PrerenderHostObserver prerender_observer( + *GetActiveWebContents(), host_id); // Trigger a new prerender under the same site GURL prerender_url = embedded_test_server()->GetURL("/simple.html?1"); prerender_helper().AddPrerender(prerender_url); + prerender_observer.WaitForDestroyed(); + ASSERT_TRUE(prerender_observer.WasHostReused()); auto reuse_host_id = prerender_helper().GetHostForUrl(prerender_url); ASSERT_EQ(host_id, reuse_host_id);
diff --git a/chrome/browser/preloading/prerender/prerender_manager.cc b/chrome/browser/preloading/prerender/prerender_manager.cc index 5aec2a5..1b7c0c6 100644 --- a/chrome/browser/preloading/prerender/prerender_manager.cc +++ b/chrome/browser/preloading/prerender/prerender_manager.cc
@@ -31,6 +31,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "content/public/common/content_features.h" #include "net/base/url_util.h" #include "url/gurl.h" @@ -286,12 +287,23 @@ const GURL& canonical_search_url, const GURL& prerendering_url, base::WeakPtr<content::PreloadingAttempt> preloading_attempt) { - // If the caller does not want to prerender a new result, this does not need - // to do anything. - if (!ResetSearchPrerenderTaskIfNecessary(canonical_search_url, - preloading_attempt)) { + // Do not re-prerender the same search result. + if (search_prerender_task_ && + search_prerender_task_->prerendered_canonical_search_url() == + canonical_search_url) { + // In case a prerender is already present for the URL, prerendering is + // eligible but mark triggering outcome as a duplicate. + if (preloading_attempt) { + preloading_attempt->SetEligibility( + content::PreloadingEligibility::kEligible); + MarkPreloadingAttemptAsDuplicate(preloading_attempt.get()); + } return; } + // Keep a reference to the previous search prerenderer task so that the + // PrerenderHost is not destructed and can be reused. + std::unique_ptr<SearchPrerenderTask> previous_search_prerender_task = + std::move(search_prerender_task_); // web_contents() owns the instance that stores this callback, so it is safe // to call std::ref. @@ -319,7 +331,7 @@ kPrerender), preloading_attempt.get(), std::move(url_match_predicate), /*prerender_navigation_handle_callback=*/{}, - /*allow_reuse=*/true); + features::kPrerender2ReuseSearchResultHost.Get()); if (prerender_handle) { CHECK(!search_prerender_task_) @@ -327,6 +339,10 @@ search_prerender_task_ = std::make_unique<SearchPrerenderTask>( canonical_search_url, std::move(prerender_handle)); } + if (previous_search_prerender_task) { + previous_search_prerender_task->set_prediction_status( + PrerenderPredictionStatus::kCancelled); + } } void PrerenderManager::StopPrerenderSearchResult( @@ -402,32 +418,6 @@ } } -bool PrerenderManager::ResetSearchPrerenderTaskIfNecessary( - const GURL& canonical_search_url, - base::WeakPtr<content::PreloadingAttempt> preloading_attempt) { - if (!search_prerender_task_) { - return true; - } - - // Do not re-prerender the same search result. - if (search_prerender_task_->prerendered_canonical_search_url() == - canonical_search_url) { - // In case a prerender is already present for the URL, prerendering is - // eligible but mark triggering outcome as a duplicate. - if (preloading_attempt) { - preloading_attempt->SetEligibility( - content::PreloadingEligibility::kEligible); - - MarkPreloadingAttemptAsDuplicate(preloading_attempt.get()); - } - return false; - } - search_prerender_task_->set_prediction_status( - PrerenderPredictionStatus::kCancelled); - search_prerender_task_.reset(); - return true; -} - PrerenderManager::PrerenderManager(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), content::WebContentsUserData<PrerenderManager>(*web_contents) {}
diff --git a/chrome/browser/preloading/prerender/prerender_manager.h b/chrome/browser/preloading/prerender/prerender_manager.h index dfd5e69..6dab44a07 100644 --- a/chrome/browser/preloading/prerender/prerender_manager.h +++ b/chrome/browser/preloading/prerender/prerender_manager.h
@@ -118,16 +118,6 @@ void ResetPrerenderHandlesOnPrimaryPageChanged( content::NavigationHandle* navigation_handle); - // Maybe cancel the ongoing search prerender to restart a new one if this - // finds the callers' intentions changed. The number of concurrence search - // prerender is limited to 1, so it is needed to cancel the old one in order - // to start a new one. Returns true if this finds the caller wants to - // prerender another search result. Here `attempt` represents the - // PreloadingAttempt corresponding to this prerender attempt to log metrics. - bool ResetSearchPrerenderTaskIfNecessary( - const GURL& canonical_search_url, - base::WeakPtr<content::PreloadingAttempt> attempt); - std::unique_ptr<content::PrerenderHandle> search_prewarm_handle_; std::optional<GURL> prewarm_url_for_testing_;
diff --git a/chrome/browser/preloading/prerender/prerender_manager_unittest.cc b/chrome/browser/preloading/prerender/prerender_manager_unittest.cc index 93e977b..3a6b3d5 100644 --- a/chrome/browser/preloading/prerender/prerender_manager_unittest.cc +++ b/chrome/browser/preloading/prerender/prerender_manager_unittest.cc
@@ -15,6 +15,7 @@ #include "components/search_engines/template_url_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "content/public/test/preloading_test_util.h" #include "content/public/test/prerender_test_util.h" #include "content/public/test/web_contents_tester.h" @@ -32,7 +33,10 @@ content::BrowserTaskEnvironment::REAL_IO_THREAD), prerender_helper_( base::BindRepeating(&PrerenderManagerTest::GetActiveWebContents, - base::Unretained(this))) {} + base::Unretained(this))) { + reuse_feature_list_.InitAndEnableFeatureWithParameters( + features::kPrerender2ReuseHost, {{"reuse_search_host", "true"}}); + } void SetUp() override { prerender_helper_.RegisterServerRequestMonitor(&test_server_); @@ -118,6 +122,7 @@ content::test::PrerenderTestHelper prerender_helper_; test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{ test::ScopedPrewarmFeatureList::PrewarmState::kDisabled}; + base::test::ScopedFeatureList reuse_feature_list_; std::unique_ptr<content::test::ScopedPrerenderWebContentsDelegate> web_contents_delegate_; @@ -162,6 +167,9 @@ EXPECT_TRUE(prerender_manager()->HasSearchResultPagePrerendered()); EXPECT_EQ(canonical_url2, prerender_manager()->GetPrerenderCanonicalSearchURLForTesting()); + content::FrameTreeNodeId prerender_host_id2 = + prerender_helper().GetHostForUrl(prerendering_url2); + EXPECT_EQ(prerender_host_id1, prerender_host_id2); } // Tests that the old prerender is not destroyed when starting prerendering the
diff --git a/chrome/browser/preloading/search_preload/search_preload_browsertest.cc b/chrome/browser/preloading/search_preload/search_preload_browsertest.cc index e9aa742..91c843a4 100644 --- a/chrome/browser/preloading/search_preload/search_preload_browsertest.cc +++ b/chrome/browser/preloading/search_preload/search_preload_browsertest.cc
@@ -932,8 +932,17 @@ // - Prefetch matching fails due to lack of No-Vary-Search hint and "pf=cs" // param. // - Prefetch is not used. -IN_PROC_BROWSER_TEST_F(SearchPreloadBrowserTest, - TriggersPrefetchButMatchingFailedDueToNoVarySearchHint) { +// TODO(crbug.com/434918482): Re-enable this test on Mac. +#if BUILDFLAG(IS_MAC) +#define MAYBE_TriggersPrefetchButMatchingFailedDueToNoVarySearchHint \ + DISABLED_TriggersPrefetchButMatchingFailedDueToNoVarySearchHint +#else +#define MAYBE_TriggersPrefetchButMatchingFailedDueToNoVarySearchHint \ + TriggersPrefetchButMatchingFailedDueToNoVarySearchHint +#endif +IN_PROC_BROWSER_TEST_F( + SearchPreloadBrowserTest, + MAYBE_TriggersPrefetchButMatchingFailedDueToNoVarySearchHint) { HistogramTesterWrapper uma_tester; SetUpTemplateURLService(); SetUpSearchPreloadService({ @@ -998,9 +1007,17 @@ // - Prefetch matching fails due to lack of No-Vary-Search hint and "pf=cs" // param. // - Prefetch is not used. +// TODO(crbug.com/434918482): Re-enable this test on Mac. +#if BUILDFLAG(IS_MAC) +#define MAYBE_TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint \ + DISABLED_TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint +#else +#define MAYBE_TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint \ + TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint +#endif IN_PROC_BROWSER_TEST_F( SearchPreloadBrowserTest, - TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint) { + MAYBE_TriggersPrefetchAndPrerenderButPrerenderFailsDueToNoVarySearchHint) { HistogramTesterWrapper uma_tester; SetUpTemplateURLService(); SetUpSearchPreloadService({
diff --git a/chrome/browser/private_network_access/local_network_access_browsertest.cc b/chrome/browser/private_network_access/local_network_access_browsertest.cc index e074e7f..c183596 100644 --- a/chrome/browser/private_network_access/local_network_access_browsertest.cc +++ b/chrome/browser/private_network_access/local_network_access_browsertest.cc
@@ -219,7 +219,7 @@ content::EvalJsResult::IsOk()); ASSERT_TRUE(nav_manager.WaitForNavigationFinished()); - // Check that the child iframe failed to fetch. + // Check that the child iframe was successfully fetched. EXPECT_TRUE(nav_manager.was_successful()); } @@ -524,3 +524,56 @@ content::JsReplace("fetch($1).then(response => response.ok)", https_server().GetURL("b.com", kLnaPath)))); } + +IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, DeprecationTrialIframe) { + content::DeprecationTrialURLLoaderInterceptor interceptor; + WebFeatureHistogramTester feature_histogram_tester; + + // Deprecation trial allows LNA on non-secure contexts (with permission + // grant). + ASSERT_TRUE( + content::NavigateToURL(web_contents(), interceptor.EnabledHttpUrl())); + EXPECT_EQ(feature_histogram_tester.GetCount( + WebFeature:: + kLocalNetworkAccessNonSecureContextAllowedDeprecationTrial), + 1); + + // Enable auto-accept of LNA permission request. + bubble_factory()->set_response_type( + permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL); + + GURL iframe_url = https_server().GetURL("b.com", kLnaPath); + content::TestNavigationManager nav_manager(web_contents(), iframe_url); + std::string_view script_template = R"( + const child = document.createElement("iframe"); + child.src = $1; + document.body.appendChild(child); + )"; + EXPECT_THAT(content::EvalJs(web_contents(), + content::JsReplace(script_template, iframe_url)), + content::EvalJsResult::IsOk()); + ASSERT_TRUE(nav_manager.WaitForNavigationFinished()); + + // Check that the child iframe was successfully fetched. + EXPECT_TRUE(nav_manager.was_successful()); +} + +IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, + DeprecationTrialDedicatedWorker) { + content::DeprecationTrialURLLoaderInterceptor interceptor; + WebFeatureHistogramTester feature_histogram_tester; + + ASSERT_TRUE(content::NavigateToURL(web_contents(), + interceptor.EnabledHttpWorkerUrl())); + + // Enable auto-accept of LNA permission request. + bubble_factory()->set_response_type( + permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL); + + GURL fetch_url = https_server().GetURL("b.com", kLnaPath); + std::string_view script_template = "fetch_from_worker($1);"; + // URL fetched, body is just the header that's set. + EXPECT_EQ("Access-Control-Allow-Origin: *", + content::EvalJs(web_contents(), + content::JsReplace(script_template, fetch_url))); +}
diff --git a/chrome/browser/resources/ash/settings/BUILD.gn b/chrome/browser/resources/ash/settings/BUILD.gn index a0426e0..b787e20 100644 --- a/chrome/browser/resources/ash/settings/BUILD.gn +++ b/chrome/browser/resources/ash/settings/BUILD.gn
@@ -335,7 +335,6 @@ "os_reset_page/os_powerwash_dialog_esim_item.ts", "os_reset_page/os_sanitize_dialog.ts", "os_reset_page/reset_settings_card.ts", - "os_search_page/google_assistant_subpage.ts", "os_search_page/magic_boost_review_terms_banner.ts", "os_search_page/search_and_assistant_settings_card.ts", "os_search_page/search_engine.ts", @@ -468,7 +467,6 @@ "os_privacy_page/privacy_hub_browser_proxy.ts", "os_privacy_page/privacy_hub_metrics_util.ts", "os_reset_page/os_reset_browser_proxy.ts", - "os_search_page/google_assistant_browser_proxy.ts", "os_search_page/magic_boost_browser_proxy.ts", "os_search_page/search_engines_browser_proxy.ts", "os_settings.ts",
diff --git a/chrome/browser/resources/ash/settings/common/load_time_booleans.ts b/chrome/browser/resources/ash/settings/common/load_time_booleans.ts index da04fcd..f96e93c7 100644 --- a/chrome/browser/resources/ash/settings/common/load_time_booleans.ts +++ b/chrome/browser/resources/ash/settings/common/load_time_booleans.ts
@@ -87,10 +87,6 @@ } // Search page -export function isAssistantAllowed(): boolean { - return loadTimeData.getBoolean('isAssistantAllowed'); -} - export function isQuickAnswersSupported(): boolean { return loadTimeData.getBoolean('isQuickAnswersSupported'); }
diff --git a/chrome/browser/resources/ash/settings/lazy_load.ts b/chrome/browser/resources/ash/settings/lazy_load.ts index 22b3e637..9a68896 100644 --- a/chrome/browser/resources/ash/settings/lazy_load.ts +++ b/chrome/browser/resources/ash/settings/lazy_load.ts
@@ -85,7 +85,6 @@ import './os_languages_page/os_edit_dictionary_page.js'; import './os_languages_page/os_japanese_manage_user_dictionary_page.js'; import './os_languages_page/os_languages_page_v2.js'; -import './os_search_page/google_assistant_subpage.js'; import './os_search_page/search_subpage.js'; import './os_people_page/fingerprint_list_subpage.js'; import './os_people_page/lock_screen_subpage.js'; @@ -334,7 +333,5 @@ export {OsResetBrowserProxyImpl} from './os_reset_page/os_reset_browser_proxy.js'; export {OsSettingsSanitizeDialogElement} from './os_reset_page/os_sanitize_dialog.js'; export {ResetSettingsCardElement} from './os_reset_page/reset_settings_card.js'; -export {GoogleAssistantBrowserProxy, GoogleAssistantBrowserProxyImpl} from './os_search_page/google_assistant_browser_proxy.js'; -export {ConsentStatus, DspHotwordState, SettingsGoogleAssistantSubpageElement} from './os_search_page/google_assistant_subpage.js'; export {SettingsSearchSubpageElement} from './os_search_page/search_subpage.js'; export {OsSettingsSubpageElement} from './os_settings_page/os_settings_subpage.js';
diff --git a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_browser_proxy.ts b/chrome/browser/resources/ash/settings/os_search_page/google_assistant_browser_proxy.ts deleted file mode 100644 index 0d4a8bec..0000000 --- a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_browser_proxy.ts +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview A helper object used from the google assistant section - * to interact with the browser. - */ - -export interface GoogleAssistantBrowserProxy { - /** Launches into the Google Assistant app settings. */ - showGoogleAssistantSettings(): void; - - /** Retrain the Assistant voice model. */ - retrainAssistantVoiceModel(): void; - - /** Sync the voice model status. */ - syncVoiceModelStatus(): void; -} - -let instance: GoogleAssistantBrowserProxy|null = null; - -export class GoogleAssistantBrowserProxyImpl implements - GoogleAssistantBrowserProxy { - static getInstance(): GoogleAssistantBrowserProxy { - return instance || (instance = new GoogleAssistantBrowserProxyImpl()); - } - - static setInstanceForTesting(obj: GoogleAssistantBrowserProxy): void { - instance = obj; - } - - showGoogleAssistantSettings(): void { - chrome.send('showGoogleAssistantSettings'); - } - - retrainAssistantVoiceModel(): void { - chrome.send('retrainAssistantVoiceModel'); - } - - syncVoiceModelStatus(): void { - chrome.send('syncVoiceModelStatus'); - } -}
diff --git a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.html b/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.html deleted file mode 100644 index db2ca11..0000000 --- a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.html +++ /dev/null
@@ -1,117 +0,0 @@ -<style include="settings-shared md-select"> - .text-area { - margin-inline-end: 24px; - } - - select.md-select { - min-width: 200px; - } - - cr-policy-pref-indicator { - margin-inline-end: var(--cr-controlled-by-spacing); - } -</style> -<settings-toggle-button id="google-assistant-enable" - class="primary-toggle" - pref="{{prefs.settings.voice_interaction.enabled}}" - label="[[getAssistantOnOffLabel_( - prefs.settings.voice_interaction.enabled.value)]]" - disabled="[[prefs.settings.assistant.disabled_by_policy.value]]" - aria-label="[[getAssistantOnOffLabel_( - prefs.settings.voice_interaction.enabled.value)]]" - deep-link-focus-id$="[[Setting.kAssistantOnOff]]"> -</settings-toggle-button> -<template is="dom-if" - if="[[prefs.settings.voice_interaction.enabled.value]]"> - <settings-toggle-button id="google-assistant-context-enable" - class="hr" - pref="{{prefs.settings.voice_interaction.context.enabled}}" - label="$i18n{googleAssistantEnableContext}" - sub-label="$i18n{googleAssistantEnableContextDescription}" - deep-link-focus-id$="[[Setting.kAssistantRelatedInfo]]"> - </settings-toggle-button> - <template is="dom-if" if="[[hotwordDspAvailable_]]" restamp> - <settings-toggle-button id="google-assistant-hotword-enable" - class="hr" - pref="{{prefs.settings.voice_interaction.hotword.enabled}}" - label="$i18n{googleAssistantEnableHotword}" - sub-label="$i18n{googleAssistantEnableHotwordDescription}" - on-settings-boolean-control-change="onEnableHotwordChange_" - disabled="[[hotwordEnforcedForChild_]]" - deep-link-focus-id$="[[Setting.kAssistantOkGoogle]]"> - </settings-toggle-button> - </template> - <template is="dom-if" if="[[!hotwordDspAvailable_]]" restamp> - <div class="settings-box" id="dsp-hotword-container"> - <div class="start text-area settings-box-text" aria-hidden="true"> - <div class="label" id="googleAssistantEnableHotword"> - $i18n{googleAssistantEnableHotword} - </div> - <div class="secondary label" - id="googleAssistantEnableHotwordDescription"> - $i18n{googleAssistantEnableHotwordWithoutDspDescription} - </div> - </div> - <template is="dom-if" if="[[hotwordEnforced_]]" restamp> - <cr-policy-pref-indicator id="hotword-policy-pref-indicator" - pref="{{prefs.settings.voice_interaction.hotword.enabled}}"> - </cr-policy-pref-indicator> - </template> - <!-- We don't use the settings_dropdown_menu for the dspHotwordState - drop down, because the dspHotwordState manages 2 preferences. - <select id="dsp-hotword-state" class="md-select" - The settings_dropdown_menu is designed to manage only a single - preference. --> - <select id="dsp-hotword-state" class="md-select" - aria-labelledby="googleAssistantEnableHotword" - aria-describedby="googleAssistantEnableHotwordDescription" - on-change="onDspHotwordStateChange_" - disabled="[[hotwordEnforced_]]" - deep-link-focus-id$="[[Setting.kAssistantOkGoogle]]"> - <template is="dom-repeat" items="[[hotwordDropdownList_]]"> - <option value="[[item.value]]" - selected="[[isDspHotwordStateMatch_(item.value)]]"> - [[item.name]] - </option> - </template> - </select> - </div> - </template> - <template is="dom-if" if="[[shouldShowVoiceMatchSettings_]]"> - <div class="settings-box continuation embedded"> - <div class="start text-area settings-box-text"> - <div class="label"> - $i18n{googleAssistantVoiceSettings} - </div> - <div class="secondary label"> - $i18n{googleAssistantVoiceSettingsDescription} - </div> - </div> - <controlled-button id="retrain-voice-model" - on-click="onRetrainVoiceModelClick_" - label="$i18n{googleAssistantVoiceSettingsRetrainButton}" - pref="{{prefs.settings.voice_interaction.hotword.enabled}}" - deep-link-focus-id$="[[Setting.kTrainAssistantVoiceModel]]"> - </controlled-button> - </div> - </template> - <settings-toggle-button id="google-assistant-notification-enable" - class="hr" - pref="{{prefs.settings.voice_interaction.notification.enabled}}" - label="$i18n{googleAssistantEnableNotification}" - sub-label="$i18n{googleAssistantEnableNotificationDescription}" - deep-link-focus-id$="[[Setting.kAssistantNotifications]]"> - </settings-toggle-button> - <settings-toggle-button id="google-assistant-launch-with-mic-open" - class="hr" - pref="{{prefs.settings.voice_interaction.launch_with_mic_open}}" - label="$i18n{googleAssistantLaunchWithMicOpen}" - sub-label="$i18n{googleAssistantLaunchWithMicOpenDescription}" - deep-link-focus-id$="[[Setting.kAssistantVoiceInput]]"> - </settings-toggle-button> - <cr-link-row id="google-assistant-settings" class="hr" - on-click="onGoogleAssistantSettingsClick_" - label="$i18n{googleAssistantSettings}" - external> - </cr-link-row> -</template>
diff --git a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.ts b/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.ts deleted file mode 100644 index 7ca98fda..0000000 --- a/chrome/browser/resources/ash/settings/os_search_page/google_assistant_subpage.ts +++ /dev/null
@@ -1,286 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'settings-google-assistant-subpage' is the settings page - * containing Google Assistant settings. - */ -import 'chrome://resources/ash/common/cr_elements/cr_link_row/cr_link_row.js'; -import 'chrome://resources/ash/common/cr_elements/md_select.css.js'; -import 'chrome://resources/ash/common/cr_elements/policy/cr_policy_pref_indicator.js'; -import '../controls/controlled_button.js'; -import '../controls/settings_toggle_button.js'; -import '/shared/settings/prefs/pref_util.js'; -import '../settings_shared.css.js'; - -import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js'; -import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; -import {WebUiListenerMixin} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.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 {cast, castExists} from '../assert_extras.js'; -import {DeepLinkingMixin} from '../common/deep_linking_mixin.js'; -import {RouteObserverMixin} from '../common/route_observer_mixin.js'; -import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; -import {recordSettingChange} from '../metrics_recorder.js'; -import {Setting} from '../mojom-webui/setting.mojom-webui.js'; -import type {Route} from '../router.js'; -import {routes} from '../router.js'; - -import type {GoogleAssistantBrowserProxy} from './google_assistant_browser_proxy.js'; -import {GoogleAssistantBrowserProxyImpl} from './google_assistant_browser_proxy.js'; -import {getTemplate} from './google_assistant_subpage.html.js'; - -/** - * The types of Hotword enable status without Dsp support. - */ -export enum DspHotwordState { - DEFAULT_ON = 0, - ALWAYS_ON = 1, - OFF = 2, -} - -/** - * Indicates user's activity control consent status. - * - * Note: This should be kept in sync with ConsentStatus in - * chromeos/ash/services/assistant/public/cpp/assistant_prefs.h - */ -export enum ConsentStatus { - // The status is unknown. - UNKNOWN = 0, - - // The user accepted activity control access. - ACTIVITY_CONTROL_ACCEPTED = 1, - - // The user is not authorized to give consent. - UNAUTHORIZED = 2, - - // The user's consent information is not found. This is typically the case - // when consent from the user has never been requested. - NOT_FOUND = 3, -} - -const SettingsGoogleAssistantSubpageElementBase = - DeepLinkingMixin(RouteObserverMixin( - PrefsMixin(WebUiListenerMixin(I18nMixin(PolymerElement))))); - -export class SettingsGoogleAssistantSubpageElement extends - SettingsGoogleAssistantSubpageElementBase { - static get is() { - return 'settings-google-assistant-subpage'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - shouldShowVoiceMatchSettings_: { - type: Boolean, - value: false, - }, - - hotwordDspAvailable_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('hotwordDspAvailable'); - }, - }, - - hotwordDropdownList_: { - type: Array, - value() { - return [ - { - name: loadTimeData.getString( - 'googleAssistantEnableHotwordWithoutDspRecommended'), - value: DspHotwordState.DEFAULT_ON, - }, - { - name: loadTimeData.getString( - 'googleAssistantEnableHotwordWithoutDspAlwaysOn'), - value: DspHotwordState.ALWAYS_ON, - }, - { - name: loadTimeData.getString( - 'googleAssistantEnableHotwordWithoutDspOff'), - value: DspHotwordState.OFF, - }, - ]; - }, - }, - - hotwordEnforced_: { - type: Boolean, - value: false, - }, - - hotwordEnforcedForChild_: { - type: Boolean, - value: false, - }, - - dspHotwordState_: Number, - }; - } - - static get observers() { - return [ - 'onPrefsChanged_(' + - 'prefs.settings.voice_interaction.hotword.enabled.value, ' + - 'prefs.settings.voice_interaction.hotword.always_on.value, ' + - 'prefs.settings.voice_interaction.activity_control.consent_status' + - '.value, ' + - 'prefs.settings.assistant.disabled_by_policy.value)', - ]; - } - - // DeepLinkingMixin override - override supportedSettingIds = new Set<Setting>([ - Setting.kAssistantOnOff, - Setting.kAssistantRelatedInfo, - Setting.kAssistantOkGoogle, - Setting.kAssistantNotifications, - Setting.kAssistantVoiceInput, - Setting.kTrainAssistantVoiceModel, - ]); - - private browserProxy_: GoogleAssistantBrowserProxy; - private dspHotwordState_: DspHotwordState; - private hotwordDropdownList_: Array<{name: string, value: number}>; - private hotwordDspAvailable_: boolean; - private hotwordEnforced_: boolean; - private hotwordEnforcedForChild_: boolean; - private shouldShowVoiceMatchSettings_: boolean; - - constructor() { - super(); - - this.browserProxy_ = GoogleAssistantBrowserProxyImpl.getInstance(); - } - - override ready(): void { - super.ready(); - - this.addWebUiListener('hotwordDeviceUpdated', (hasHotword: boolean) => { - this.hotwordDspAvailable_ = hasHotword; - }); - - chrome.send('initializeGoogleAssistantPage'); - } - - override currentRouteChanged(route: Route, _oldRoute?: Route): void { - // Does not apply to this page. - if (route !== routes.GOOGLE_ASSISTANT) { - return; - } - - this.attemptDeepLink(); - } - - private getAssistantOnOffLabel_(toggleValue: boolean): string { - return this.i18n( - toggleValue ? 'searchGoogleAssistantOn' : 'searchGoogleAssistantOff'); - } - - private onGoogleAssistantSettingsClick_(): void { - this.browserProxy_.showGoogleAssistantSettings(); - } - - private onRetrainVoiceModelClick_(): void { - this.browserProxy_.retrainAssistantVoiceModel(); - recordSettingChange(Setting.kTrainAssistantVoiceModel); - } - - private onEnableHotwordChange_(event: Event): void { - const target = cast(event.target, SettingsToggleButtonElement); - if (target.checked) { - this.browserProxy_.syncVoiceModelStatus(); - } - } - - private onDspHotwordStateChange_(): void { - const dspHotwordStateEl = - castExists(this.shadowRoot!.querySelector<HTMLSelectElement>( - '#dsp-hotword-state')); - - switch (Number(dspHotwordStateEl.value)) { - case DspHotwordState.DEFAULT_ON: - this.setPrefValue('settings.voice_interaction.hotword.enabled', true); - this.setPrefValue( - 'settings.voice_interaction.hotword.always_on', false); - this.browserProxy_.syncVoiceModelStatus(); - break; - case DspHotwordState.ALWAYS_ON: - this.setPrefValue('settings.voice_interaction.hotword.enabled', true); - this.setPrefValue('settings.voice_interaction.hotword.always_on', true); - this.browserProxy_.syncVoiceModelStatus(); - break; - case DspHotwordState.OFF: - this.setPrefValue('settings.voice_interaction.hotword.enabled', false); - this.setPrefValue( - 'settings.voice_interaction.hotword.always_on', false); - break; - default: - console.error('Invalid Dsp hotword settings state'); - } - } - - private isDspHotwordStateMatch_(state: number): boolean { - return state === this.dspHotwordState_; - } - - private onPrefsChanged_(): void { - if (this.getPref('settings.assistant.disabled_by_policy').value) { - this.setPrefValue('settings.voice_interaction.enabled', false); - return; - } - - this.refreshDspHotwordState_(); - - this.shouldShowVoiceMatchSettings_ = - !loadTimeData.getBoolean('voiceMatchDisabled') && - !!this.getPref('settings.voice_interaction.hotword.enabled').value; - - const hotwordEnabled = - this.getPref('settings.voice_interaction.hotword.enabled'); - - this.hotwordEnforced_ = hotwordEnabled.enforcement === - chrome.settingsPrivate.Enforcement.ENFORCED; - - this.hotwordEnforcedForChild_ = this.hotwordEnforced_ && - hotwordEnabled.controlledBy === - chrome.settingsPrivate.ControlledBy.CHILD_RESTRICTION; - } - - private refreshDspHotwordState_(): void { - if (!this.getPref('settings.voice_interaction.hotword.enabled').value) { - this.dspHotwordState_ = DspHotwordState.OFF; - } else if (this.getPref('settings.voice_interaction.hotword.always_on') - .value) { - this.dspHotwordState_ = DspHotwordState.ALWAYS_ON; - } else { - this.dspHotwordState_ = DspHotwordState.DEFAULT_ON; - } - - const dspHotwordStateEl = - this.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - if (dspHotwordStateEl) { - dspHotwordStateEl.value = String(this.dspHotwordState_); - } - } -} - -declare global { - interface HTMLElementTagNameMap { - 'settings-google-assistant-subpage': SettingsGoogleAssistantSubpageElement; - } -} - -customElements.define( - SettingsGoogleAssistantSubpageElement.is, - SettingsGoogleAssistantSubpageElement);
diff --git a/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.html b/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.html index a7aa7ced..b1c62024 100644 --- a/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.html +++ b/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.html
@@ -31,19 +31,6 @@ </cr-link-row> </template> - <!-- Google Assistant --> - <template is="dom-if" if="[[isAssistantAllowed_]]"> - <cr-link-row - id="assistantRow" - start-icon="os-settings:assistant" - class="hr" - label="$i18n{searchGoogleAssistant}" - sub-label="[[getAssistantEnabledDisabledLabel_( - prefs.settings.voice_interaction.enabled.value)]]" - on-click="onGoogleAssistantClick_" - role-description="$i18n{subpageArrowRoleDescription}"> - </cr-link-row> - </template> <settings-toggle-button id="contentRecommendationsToggle" class="hr" icon="os-settings:content-recommend"
diff --git a/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.ts b/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.ts index 4fff1881..78ffc46 100644 --- a/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.ts +++ b/chrome/browser/resources/ash/settings/os_search_page/search_and_assistant_settings_card.ts
@@ -23,7 +23,7 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {DeepLinkingMixin} from '../common/deep_linking_mixin.js'; -import {isAssistantAllowed, isLobsterSettingsToggleVisible, isMagicBoostFeatureEnabled, isMagicBoostNoticeBannerVisible, isQuickAnswersSupported, isScannerSettingsToggleVisible} from '../common/load_time_booleans.js'; +import {isLobsterSettingsToggleVisible, isMagicBoostFeatureEnabled, isMagicBoostNoticeBannerVisible, isQuickAnswersSupported, isScannerSettingsToggleVisible} from '../common/load_time_booleans.js'; import {RouteOriginMixin} from '../common/route_origin_mixin.js'; import type {PrefsState} from '../common/types.js'; import {Setting} from '../mojom-webui/setting.mojom-webui.js'; @@ -119,14 +119,6 @@ readOnly: true, value: () => [ENTERPRISE_POLICY_DISALLOWED], }, - - /** Can be disallowed due to flag, policy, locale, etc. */ - isAssistantAllowed_: { - type: Boolean, - value: () => { - return isAssistantAllowed(); - }, - }, }; } @@ -144,7 +136,6 @@ ]); private readonly enterprisePolicyToggleUncheckedValues_: number[]; - private isAssistantAllowed_: boolean; private isHmrAllowedByEnterprisePolicy_: boolean; private isHmwAllowedByEnterprisePolicy_: boolean; private isLobsterAllowedByEnterprisePolicy_: boolean; @@ -166,7 +157,6 @@ super.ready(); this.addFocusConfig(routes.SEARCH_SUBPAGE, '#searchRow'); - this.addFocusConfig(routes.GOOGLE_ASSISTANT, '#assistantRow'); } override currentRouteChanged(newRoute: Route, oldRoute?: Route): void { @@ -185,18 +175,6 @@ Router.getInstance().navigateTo(routes.SEARCH_SUBPAGE); } - private onGoogleAssistantClick_(): void { - assert(this.isAssistantAllowed_); - Router.getInstance().navigateTo(routes.GOOGLE_ASSISTANT); - } - - private getAssistantEnabledDisabledLabel_(isAssistantEnabled: boolean): - string { - return this.i18n( - isAssistantEnabled ? 'searchGoogleAssistantEnabled' : - 'searchGoogleAssistantDisabled'); - } - private isEnterprisePolicyAllowed_(value: number): boolean { return value !== ENTERPRISE_POLICY_DISALLOWED; }
diff --git a/chrome/browser/resources/ash/settings/os_settings_routes.ts b/chrome/browser/resources/ash/settings/os_settings_routes.ts index e0dffe6..b53d8b2 100644 --- a/chrome/browser/resources/ash/settings/os_settings_routes.ts +++ b/chrome/browser/resources/ash/settings/os_settings_routes.ts
@@ -180,7 +180,6 @@ DISPLAY: Route; EXTERNAL_STORAGE_PREFERENCES: Route; FINGERPRINT: Route; - GOOGLE_ASSISTANT: Route; GOOGLE_DRIVE: Route; GRAPHICS_TABLET: Route; HOTSPOT_DETAIL: Route; @@ -581,12 +580,9 @@ Subpage.kAppLanguages); } - // Search and Assistant subpages. + // Search subpages. r.SEARCH_SUBPAGE = createSubpage( r.SYSTEM_PREFERENCES, routesMojom.SEARCH_SUBPAGE_PATH, Subpage.kSearch); - r.GOOGLE_ASSISTANT = createSubpage( - r.SYSTEM_PREFERENCES, routesMojom.ASSISTANT_SUBPAGE_PATH, - Subpage.kAssistant); // Storage and power subpages. r.STORAGE = createSubpage(
diff --git a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts index f3a71e1d..4aa940f 100644 --- a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts +++ b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
@@ -680,8 +680,6 @@ return 'os-settings:apps-parental-controls'; case SearchResultIcon.kAppsGrid: return 'os-settings:apps'; - case SearchResultIcon.kAssistant: - return 'os-settings:assistant'; case SearchResultIcon.kAudio: return 'os-settings:device-audio'; case SearchResultIcon.kAuthKey:
diff --git a/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.html b/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.html index 6b88dc1..b92aac6 100644 --- a/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.html +++ b/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.html
@@ -96,7 +96,7 @@ </os-settings-subpage> </template> - <!-- Search and Assistant subpages --> + <!-- Search subpages --> <template is="dom-if" if="[[isQuickAnswersSupported_]]"> <template is="dom-if" route-path="/osSearch/search"> <os-settings-subpage page-title="$i18n{searchSubpageTitle}"> @@ -106,15 +106,6 @@ </template> </template> - <template is="dom-if" if="[[isAssistantAllowed_]]"> - <template is="dom-if" route-path="/googleAssistant"> - <os-settings-subpage page-title="$i18n{googleAssistantPageTitle}"> - <settings-google-assistant-subpage prefs="{{prefs}}"> - </settings-google-assistant-subpage> - </os-settings-subpage> - </template> - </template> - <!-- Storage and Power subpages --> <template is="dom-if" route-path="/storage"> <os-settings-subpage page-title="$i18n{storageTitle}">
diff --git a/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.ts b/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.ts index 88457b2..a5a70d6 100644 --- a/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.ts +++ b/chrome/browser/resources/ash/settings/system_preferences_page/system_preferences_page.ts
@@ -24,7 +24,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {isAssistantAllowed, isExternalStorageEnabled, isGuest, isPowerwashAllowed, isQuickAnswersSupported, shouldShowStartup} from '../common/load_time_booleans.js'; +import {isExternalStorageEnabled, isGuest, isPowerwashAllowed, isQuickAnswersSupported, shouldShowStartup} from '../common/load_time_booleans.js'; import type {PrefsState} from '../common/types.js'; import {Section} from '../mojom-webui/routes.mojom-webui.js'; import type {LanguageHelper, LanguagesModel} from '../os_languages_page/languages_types.js'; @@ -97,13 +97,6 @@ }, }, - isAssistantAllowed_: { - type: Boolean, - value: () => { - return isAssistantAllowed(); - }, - }, - isExternalStorageEnabled_: { type: Boolean, value: () => { @@ -157,9 +150,8 @@ // Reset subsection private shouldShowResetSettingsCard_: boolean; - // Search and Assistant subsection + // Search subsection private isQuickAnswersSupported_: boolean; - private isAssistantAllowed_: boolean; // Startup subsection private readonly shouldShowStartupSettingsCard_: boolean;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts index 1e3b9187..395fa43 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts
@@ -291,12 +291,14 @@ } /** @param outputCallback A callback to run after output is requested. */ - static output(text: string, outputCallback?: VoidFunction): void { + static output( + text: string, outputCallback?: VoidFunction, + doNotInterrupt?: Boolean): void { BackgroundBridge.TtsBackground.speak( text, LearnMode.shouldFlushSpeech_ ? QueueMode.CATEGORY_FLUSH : QueueMode.QUEUE, - new TtsSpeechProperties({endCallback: outputCallback})); + new TtsSpeechProperties({doNotInterrupt, endCallback: outputCallback})); BackgroundBridge.Braille.write(text); LearnMode.shouldFlushSpeech_ = false; if (outputCallback) { @@ -338,7 +340,9 @@ } private static close_(): void { - LearnMode.output(Msgs.getMsg('learn_mode_outtro')); + LearnMode.output( + Msgs.getMsg('learn_mode_outtro'), /*outputCallback=*/ undefined, + /*doNotInterrupt=*/ true); LearnMode.resetListeners_(); window.close(); } @@ -348,6 +352,20 @@ LearnMode.init(); }, false); +// Key up and down events are handled offscreen and forwarded to LearnMode when +// it's active (see onkeyDown and onKeyUp above). However, we also receive DOM +// events directly in LearnMode, so we need to cancel these to prevent them from +// propagating. +document.addEventListener('keydown', (evt) => { + evt.preventDefault(); + evt.stopPropagation(); +}, false); + +document.addEventListener('keyup', (evt) => { + evt.preventDefault(); + evt.stopPropagation(); +}, false); + // Local to module. /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/menu_manager.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/menu_manager.ts index ecb6001..ff07083 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/menu_manager.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/menu_manager.ts
@@ -351,7 +351,7 @@ // Title messages are intentionally missing for some keyboard shortcuts. if (!(command in COMMANDS_WITH_NO_MSG_ID) && !MenuManager.disableMissingMsgsErrorsForTesting) { - console.error('No localization for: ' + command); + console.log('No localization for: ' + command); } binding.title = ''; continue;
diff --git a/chrome/browser/resources/chromeos/accessibility/common/local_storage_test.js b/chrome/browser/resources/chromeos/accessibility/common/local_storage_test.js index f88b60f2..ddf234e 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/local_storage_test.js +++ b/chrome/browser/resources/chromeos/accessibility/common/local_storage_test.js
@@ -17,8 +17,15 @@ } }; +// TODO(crbug.com/260589686): Remove after localStorage migration is done. AX_TEST_F( 'AccessibilityExtensionLocalStorageTest', 'Migration', async function() { + if (isRunningInServiceWorker()) { + console.log( + 'Skip because "localStorage" is not available in service worker.'); + return; + } + localStorage['catSound'] = 'meow'; localStorage['catIsShy'] = String(false); localStorage['catIsFluffy'] = String(true);
diff --git a/chrome/browser/resources/chromeos/accessibility/common/testing/common.js b/chrome/browser/resources/chromeos/accessibility/common/testing/common.js index 75c412d1..eebfd32 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/testing/common.js +++ b/chrome/browser/resources/chromeos/accessibility/common/testing/common.js
@@ -31,6 +31,19 @@ } /** + * Helper to keep the service worker alive by calling an extension API. + * Caller should use `await` on the returned promise to yield control to + * allow the service worker to respond to pings. + */ +function keepServiceWorkerAlive() { + if (!isRunningInServiceWorker()) { + return Promise.resolve(); + } + + return chrome.runtime.getPlatformInfo(); +} + +/** * Helper to import a module, and expose it onto window. * @param {string|!Array<string>} toImport Names of the module exports to * expose.
diff --git a/chrome/browser/resources/chromeos/accessibility/common/tree_walker_test.js b/chrome/browser/resources/chromeos/accessibility/common/tree_walker_test.js index 74d081ab..470a69036 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/tree_walker_test.js +++ b/chrome/browser/resources/chromeos/accessibility/common/tree_walker_test.js
@@ -60,7 +60,7 @@ TEST_F( 'AccessibilityExtensionAutomationTreeWalkerTest', 'MAYBE_Forward', function() { - chrome.automation.getDesktop(this.newCallback(function(d) { + chrome.automation.getDesktop(this.newCallback(async function(d) { const resultList = []; this.flattenTree(d, resultList); let it = new AutomationTreeWalker(d, 'forward'); @@ -70,6 +70,10 @@ assertEquals(null, it.next().node); for (let j = 0; j < resultList.length; j++) { + // This is needed because this iteration could take more than 30s on + // MSAN bots. + await keepServiceWorkerAlive(); + it = new AutomationTreeWalker(resultList[j], 'forward'); const start = it.node; let cur = it.next().node; @@ -91,7 +95,7 @@ TEST_F( 'AccessibilityExtensionAutomationTreeWalkerTest', 'MAYBE_Backward', function() { - chrome.automation.getDesktop(this.newCallback(function(d) { + chrome.automation.getDesktop(this.newCallback(async function(d) { const resultList = []; this.flattenTree(d, resultList); let it = new AutomationTreeWalker( @@ -101,6 +105,10 @@ } for (let j = resultList.length - 1; j >= 0; j--) { + // This is needed because this iteration could take more than 30s on + // MSAN bots. + await keepServiceWorkerAlive(); + it = new AutomationTreeWalker(resultList[j], 'backward'); const start = it.node; let cur = it.next().node;
diff --git a/chrome/browser/resources/glic/BUILD.gn b/chrome/browser/resources/glic/BUILD.gn index 5d0895c..2054b53 100644 --- a/chrome/browser/resources/glic/BUILD.gn +++ b/chrome/browser/resources/glic/BUILD.gn
@@ -52,7 +52,6 @@ "$root_gen_dir/chrome/browser/glic/host/glic.mojom-webui.ts", "$root_gen_dir/components/content_settings/core/common/content_settings_types.mojom-webui.ts", "$root_gen_dir/third_party/blink/public/mojom/content_extraction/ai_page_content_metadata.mojom-webui.ts", - ] ts_definitions = [
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn index ab0f678..fe88d40 100644 --- a/chrome/browser/resources/new_tab_page/BUILD.gn +++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -15,6 +15,7 @@ icons_html_files = [ "modules/v2/icons.html", "modules/v2/most_relevant_tab_resumption/icons.html", + "modules/v2/tab_groups/icons.html", "ntp_promo/ntp_promo_icons.html", ]
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/icons.html b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/icons.html new file mode 100644 index 0000000..f4f6328 --- /dev/null +++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/icons.html
@@ -0,0 +1,9 @@ +<cr-iconset name="tab_groups" size="20"> + <svg> + <defs> + <g id="create_new_tab_group" width="17" height="18" viewBox="0 0 17 18" fill="none"> + <path d="M9.375 10.875H10.875V8.125H13.625V6.625H10.875V3.875H9.375V6.625H6.625V8.125H9.375V10.875ZM5.16667 14.0625C4.69444 14.0625 4.28472 13.8958 3.9375 13.5625C3.60417 13.2153 3.4375 12.8056 3.4375 12.3333V2.4375C3.4375 1.96528 3.60417 1.5625 3.9375 1.22917C4.28472 0.881944 4.69444 0.708332 5.16667 0.708332H15.0625C15.5347 0.708332 15.9375 0.881944 16.2708 1.22917C16.6181 1.5625 16.7917 1.96528 16.7917 2.4375V12.3333C16.7917 12.8056 16.6181 13.2153 16.2708 13.5625C15.9375 13.8958 15.5347 14.0625 15.0625 14.0625H5.16667ZM5.16667 12.3333H15.0625V2.4375H5.16667V12.3333ZM1.9375 17.2917C1.46528 17.2917 1.05556 17.125 0.708333 16.7917C0.375 16.4444 0.208333 16.0347 0.208333 15.5625V3.9375H1.9375V15.5625H13.5625V17.2917H1.9375ZM5.16667 2.4375V12.3333V2.4375Z" fill="#041E49"> + </g> + </defs> + </svg> +</cr-iconset> \ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css index b6da840..b9b0f63 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css +++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css
@@ -4,7 +4,10 @@ /* #css_wrapper_metadata_start * #type=style-lit + * #import=chrome://resources/cr_elements/cr_shared_style_lit.css.js + * #import=chrome://resources/cr_elements/cr_icons_lit.css.js * #scheme=relative + * #include=cr-shared-style-lit cr-icons-lit * #css_wrapper_metadata_end */ :host { @@ -31,10 +34,19 @@ } #tabGroups { + align-items: flex-start; + align-self: stretch; background-color: var(--color-new-tab-page-module-item-background); border-radius: var(--ntp-module-item-border-radius); + container-type: inline-size; + display: flex; + flex-direction: column; margin: 8px; +} + +#tabGroupsContainer { padding: 4px 0px; + width: 100%; } .tab-group-container { @@ -46,6 +58,106 @@ position: relative; } +#zeroTabGroupsContainer { + align-items: center; + align-self: stretch; + border-radius: 12px; + display: flex; + flex-direction: column; + gap: 24px; + justify-content: center; + padding: 32px 40px; + position: relative; +} + +@container (max-width: 312px) { + #zeroTabGroupsContainer { + padding: 8px 40px 32px; + } +} + +#zeroTabGroupsImageContainer { + align-items: center; + background-color: var(--color-sys-surface5); + border-radius: 8px; + display: flex; + flex-direction: column; + justify-content: flex-end; + padding: 40px 22px 0 22px; +} + +#imagePlaceholder { + width: 236px; + height: 93px; + flex-shrink: 0; + /* TODO(crbug.com/432533358) Add illustration. */ + background-color: cornflowerblue; +} + +#zeroTabGroupsContentContainer { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + align-self: stretch; +} + +#zeroTabGroupsTextContainer { + align-items: center; + align-self: stretch; + display: flex; + flex-direction: column; + gap: 4px; +} + +#zeroTabGroupsTitle { + color: var(--color-sys-on-surface); + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; + align-self: stretch; + text-align: center; +} + +#zeroTabGroupsText { + color: var(--color-sys-on-surface-subtle); + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 20px; + text-align: center; +} + +#createNewTabGroup { + display: flex; + justify-content: center; + align-items: center; +} + +#createNewTabGroupButton { + --cr-hover-background-color: + var(--color-new-tab-page-button-background-hovered); + --cr-button-text-color: var(--color-new-tab-page-button-foreground); + --cr-button-background-color: var(--color-new-tab-page-button-background); + display: flex; + height: 36px; + padding: 8px 16px; + align-items: center; + gap: 8px; + border-radius: var(--corner-radii-fully-round, 100px); + border: none; +} + +#createNewTabGroupButtonIcon { + display: flex; + width: 20px; + height: 20px; + flex-direction: column; + justify-content: center; + flex-shrink: 0; +} + .tab-group { display: flex; align-items: center;
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html index c78f762..67bda3a 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html +++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html
@@ -5,18 +5,48 @@ '', 'modulesMoreActions', 'modulesTabGroupsTitle')}"> </ntp-module-header-v2> <div id="tabGroups"> - ${this.getTabGroups_().map(item => html` - <div class="tab-group-container"> - <div id="hoverLayer"></div> - <a class="tab-group"> - <ntp-icon-container class="icon-container" - .faviconUrls="${this.getFaviconUrls_(item.faviconUrls)}" - .totalTabCount="${item.totalTabCount}"> - </ntp-icon-container> - <div class="tab-group-info"> - <div class="tab-group-title">${item.title}</div> + ${this.shouldShowZeroStateCard_() ? html` + <div id="zeroTabGroupsContainer" class="tab-groups"> + <div id="zeroTabGroupsImageContainer"> + <div id="imagePlaceholder"></div> + </div> + <div id="zeroTabGroupsContentContainer"> + <div id="zeroTabGroupsTextContainer"> + <div id="zeroTabGroupsTitle"> + ${this.i18n('modulesTabGroupsZeroStateTitle')} + </div> + <div id="zeroTabGroupsText"> + ${this.i18n('modulesTabGroupsZeroStateText')} + </div> </div> - </a> + <div id="createNewTabGroup"> + <cr-button id="createNewTabGroupButton"> + <cr-icon id="createNewTabGroupButtonIcon" + icon="tab_groups:create_new_tab_group" slot="prefix-icon"> + </cr-icon> + <div id="createNewTabGroupButtonText"> + ${this.i18n('modulesTabGroupsCreateNewTabGroup')} + </div> + </cr-button> + </div> + </div> </div> - `)} -</div> \ No newline at end of file + `: html` + <div id="tabGroupsContainer"> + ${this.getTabGroups_().map(item => html` + <div class="tab-group-container"> + <div id="hoverLayer"></div> + <a class="tab-group"> + <ntp-icon-container class="icon-container" + .faviconUrls="${this.getFaviconUrls_(item.faviconUrls)}" + .totalTabCount="${item.totalTabCount}"> + </ntp-icon-container> + <div class="tab-group-info"> + <div class="tab-group-title">${item.title}</div> + </div> + </a> + </div> + `)} + </div> + `} +</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts index 734bcf72..d75ca33 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts
@@ -2,8 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; import '/strings.m.js'; import '../module_header.js'; +import './icons.html.js'; import './icon_container.js'; import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; @@ -77,6 +81,10 @@ ]; } + protected shouldShowZeroStateCard_(): boolean { + return this.tabGroups.length === 0; + } + protected getTabGroups_(): TabGroup[] { return this.tabGroups.slice(0, MAX_TAB_GROUPS); } @@ -91,13 +99,12 @@ async function createElement(): Promise<ModuleElement|null> { const {tabGroups} = await TabGroupsProxyImpl.getInstance().handler.getTabGroups(); - if (!tabGroups || tabGroups.length === 0) { - // TODO(crbug.com/431278744): Show zero-state card. - return null; - } const element = new ModuleElement(); - element.tabGroups = tabGroups; + + if (tabGroups && tabGroups.length > 0) { + element.tabGroups = tabGroups; + } return element; }
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts index 589c12a..7bc1431 100644 --- a/chrome/browser/resources/settings/route.ts +++ b/chrome/browser/resources/settings/route.ts
@@ -252,7 +252,7 @@ r.ADDRESSES.hasMigratedToPlugin = true; if (loadTimeData.getBoolean('showAutofillAiControl')) { - r.AUTOFILL_AI = r.AUTOFILL.createChild('/autofillAi'); + r.AUTOFILL_AI = r.AUTOFILL.createChild('/enhancedAutofill'); r.AUTOFILL_AI.hasMigratedToPlugin = true; }
diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html index f9ab0d0..7ff0c93a 100644 --- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html +++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html
@@ -30,7 +30,8 @@ id="settingsCategoryDefaultRadioGroup" pref="{{pref_}}" selectable-elements="settings-collapse-radio-button" - on-change="onSelectedChanged_"> + on-change="onSelectedChanged_" + group-aria-label=[[header]]> <settings-collapse-radio-button id="enabledRadioOption" class$="[[getEnabledButtonClass_(allowOptionSubLabel)]]"
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc index 4131d3bf..8d4ab83 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
@@ -212,8 +212,7 @@ void ReportAnalysisConnectorWarningBypass( Profile* profile, - const GURL& url, - const GURL& tab_url, + const enterprise_connectors::ContentAnalysisInfo& content_analysis_info, const std::string& source, const std::string& destination, const std::string& file_name, @@ -237,9 +236,11 @@ continue; router->OnAnalysisConnectorWarningBypassed( - url, tab_url, source, destination, file_name, download_digest_sha256, - mime_type, trigger, response.request_token(), content_transfer_method, - referrer_chain, result, content_size, user_justification); + GURL(content_analysis_info.url()), content_analysis_info.tab_url(), + source, destination, file_name, download_digest_sha256, mime_type, + trigger, response.request_token(), content_transfer_method, + content_analysis_info.GetContentAreaAccountEmail(), referrer_chain, + result, content_size, user_justification); } }
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h index d4fccb1..34eb4e3 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
@@ -52,8 +52,7 @@ // base::HexEncode. void ReportAnalysisConnectorWarningBypass( Profile* profile, - const GURL& url, - const GURL& tab_url, + const enterprise_connectors::ContentAnalysisInfo& content_analysis_info, const std::string& source, const std::string& destination, const std::string& file_name,
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_observer.cc b/chrome/browser/safe_browsing/download_protection/download_protection_observer.cc index 3e48480..6e7f1b7 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_observer.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_observer.cc
@@ -7,6 +7,7 @@ #include "base/strings/string_number_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/simple_download_manager_coordinator_factory.h" +#include "chrome/browser/enterprise/connectors/analysis/content_analysis_info.h" #include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/profiles/profile_manager.h" @@ -154,19 +155,19 @@ static_cast<enterprise_connectors::ScanResult*>( download->GetUserData(enterprise_connectors::ScanResult::kKey)); + enterprise_connectors::DownloadContentAreaUserProvider info(*download); if (stored_result) { for (const auto& metadata : stored_result->file_metadata) { ReportAnalysisConnectorWarningBypass( - profile, download->GetURL(), download->GetTabUrl(), "", "", - metadata.filename, metadata.sha256, metadata.mime_type, + profile, info, "", "", metadata.filename, metadata.sha256, + metadata.mime_type, enterprise_connectors::kFileDownloadDataTransferEventTrigger, "", metadata.size, referrer_chain, metadata.scan_response, stored_result->user_justification); } } else { ReportAnalysisConnectorWarningBypass( - profile, download->GetURL(), download->GetTabUrl(), "", "", - download->GetTargetFilePath().AsUTF8Unsafe(), + profile, info, "", "", download->GetTargetFilePath().AsUTF8Unsafe(), base::HexEncode(download->GetHash()), download->GetMimeType(), enterprise_connectors::kFileDownloadDataTransferEventTrigger, "", download->GetTotalBytes(), referrer_chain,
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc index 502b9e8..a010b1c 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -519,6 +519,7 @@ if (scan_result && item->GetDangerType() == download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING) { + enterprise_connectors::DownloadContentAreaUserProvider info(*item); for (const auto& metadata : scan_result->file_metadata) { for (const auto& result : metadata.scan_response.results()) { if (result.tag() != "dlp") @@ -528,7 +529,8 @@ item->GetURL(), item->GetTabUrl(), "", "", metadata.filename, metadata.sha256, metadata.mime_type, enterprise_connectors::kFileDownloadDataTransferEventTrigger, - metadata.scan_response.request_token(), "", referrer_chain, result, + metadata.scan_response.request_token(), "", + info.GetContentAreaAccountEmail(), referrer_chain, result, metadata.size, /*user_justification=*/std::nullopt);
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc index 8c1cd971..44bf45f 100644 --- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -19,7 +19,6 @@ #include "base/task/single_thread_task_runner.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/prefs/browser_prefs.h" @@ -273,7 +272,7 @@ 0, // avatar_id (unused) TestingProfile::TestingFactories()); - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); return profile; } @@ -338,11 +337,8 @@ bool DelayedAnalysisRan() const { return delayed_analysis_ran_; } // Fakes BrowserThreads and the main MessageLoop. - content::BrowserTaskEnvironment task_environment_; - - // Replaces the main MessageLoop's TaskRunner with a TaskRunner on which time - // is mocked to allow testing of things bound to timers below. - base::ScopedMockTimeMessageLoopTaskRunner mock_time_task_runner_; + content::BrowserTaskEnvironment task_environment_{ + content::BrowserTaskEnvironment::TimeSource::MOCK_TIME}; extensions::QuotaService::ScopedDisablePurgeForTesting disable_purge_for_testing_; @@ -618,7 +614,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that environment and extension collection took place. EXPECT_TRUE(HasCollectedEnvironmentAndExtensionData()); @@ -647,7 +643,7 @@ ON_PROFILE_ADDITION_ADD_TWO_INCIDENTS, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that environment and extension collection took place. EXPECT_TRUE(HasCollectedEnvironmentAndExtensionData()); @@ -676,7 +672,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no report upload took place. AssertNoUpload(); @@ -700,7 +696,7 @@ receiver->AddIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Downloads and environment data should have not been collected // (DownloadFinder will be created, but should be a no-op since no eligible @@ -721,7 +717,7 @@ profile, MakeTestIncident("squids")); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that environment collection took place. EXPECT_TRUE(HasCollectedEnvironmentAndExtensionData()); @@ -748,7 +744,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that the download finder was run but that no report upload took // place. @@ -773,7 +769,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Assert that no report upload took place. AssertNoUpload(); @@ -786,7 +782,7 @@ profile, MakeTestIncident("leeches")); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that an additional report upload took place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -808,7 +804,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Assert that no report upload took place. AssertNoUpload(); @@ -820,7 +816,7 @@ AddTestIncident(profile); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no additional report upload took place. AssertNoUpload(); @@ -841,7 +837,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that the download finder was run but that no report upload took // place. @@ -864,7 +860,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that report upload took place and contained the incident and // environment data. @@ -874,7 +870,7 @@ AddTestIncident(profile); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no additional report upload took place. AssertNoUpload(); @@ -893,7 +889,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that report upload took place and contained the incident and // environment data. @@ -904,7 +900,7 @@ profile, MakeTestIncident("leeches")); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that an additional report upload took place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -922,7 +918,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that report upload took place and contained the incident and // environment data. @@ -933,7 +929,7 @@ ON_PROFILE_ADDITION_ADD_INCIDENT, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that a second report upload took place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -956,7 +952,7 @@ DeleteProfileOnUpload(profile); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that report upload took place and contained the incident and // environment data. @@ -977,7 +973,7 @@ AddTestIncident(nullptr); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // No upload should have taken place. AssertNoUpload(); @@ -998,7 +994,7 @@ AddTestIncident(nullptr); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // An upload should have taken place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -1007,7 +1003,7 @@ AddTestIncident(nullptr); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no additional report upload took place. AssertNoUpload(); @@ -1030,7 +1026,7 @@ receiver->AddIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // An upload should have taken place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -1039,7 +1035,7 @@ receiver->AddIncidentForProcess(MakeTestIncident("leeches")); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that an additional report upload took place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -1056,7 +1052,7 @@ AddTestIncident(nullptr); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no report upload took place. AssertNoUpload(); @@ -1066,7 +1062,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // No upload should have taken place. AssertNoUpload(); @@ -1081,7 +1077,7 @@ RegisterAnalysis(ON_DELAYED_ANALYSIS_NO_ACTION); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Confirm that the callback was not run. ASSERT_FALSE(DelayedAnalysisRan()); @@ -1094,7 +1090,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Confirm that the callback was run. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1114,7 +1110,7 @@ RegisterAnalysis(ON_DELAYED_ANALYSIS_NO_ACTION); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Not run yet. ASSERT_FALSE(DelayedAnalysisRan()); @@ -1124,7 +1120,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // And now they have. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1146,7 +1142,7 @@ RegisterAnalysis(ON_DELAYED_ANALYSIS_NO_ACTION); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Confirm that the callbacks were run. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1168,7 +1164,7 @@ std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // The callback should not have been run. ASSERT_FALSE(DelayedAnalysisRan()); @@ -1192,7 +1188,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // The callback should have been run. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1204,7 +1200,7 @@ AddTestIncident(nullptr); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that no additional report upload took place. AssertNoUpload(); @@ -1231,7 +1227,7 @@ AddTestIncident(profile); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Verify that the download finder was run but that no report upload took // place. @@ -1258,7 +1254,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Confirm that the callbacks were run. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1284,7 +1280,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::nullopt); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // Confirm that the callbacks were run. ASSERT_TRUE(DelayedAnalysisRan()); @@ -1319,7 +1315,7 @@ ON_PROFILE_ADDITION_NO_ACTION, std::move(incidents_sent)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); const base::Value::Dict& new_state = profile->GetPrefs()->GetDict(prefs::kSafeBrowsingIncidentsSent); @@ -1344,7 +1340,7 @@ receiver->AddIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // An upload should have taken place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -1353,7 +1349,7 @@ receiver->ClearIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // No uploads should have taken place. ExpectTestIncidentUploadWithBinaryDownload(0); @@ -1362,7 +1358,7 @@ receiver->AddIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // An upload should have taken place. ExpectTestIncidentUploadWithBinaryDownload(1); @@ -1384,7 +1380,7 @@ receiver->ClearIncidentForProcess(MakeTestIncident(nullptr)); // Let all tasks run. - mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + task_environment_.FastForwardUntilNoTasksRemain(); // No uploads should have taken place. ExpectTestIncidentUploadWithBinaryDownload(0);
diff --git a/chrome/browser/task_manager/providers/fallback_task_provider_unittest.cc b/chrome/browser/task_manager/providers/fallback_task_provider_unittest.cc index 9b03cae..7c1dcbc 100644 --- a/chrome/browser/task_manager/providers/fallback_task_provider_unittest.cc +++ b/chrome/browser/task_manager/providers/fallback_task_provider_unittest.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 "chrome/browser/task_manager/providers/fallback_task_provider.h" + #include <stdint.h> #include <vector> @@ -9,8 +11,6 @@ #include "base/containers/contains.h" #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" -#include "chrome/browser/task_manager/providers/fallback_task_provider.h" #include "chrome/browser/task_manager/providers/task.h" #include "chrome/browser/task_manager/task_manager_observer.h" #include "content/public/common/process_type.h" @@ -177,8 +177,13 @@ return seen_tasks_; } + void FastForwardBy(base::TimeDelta delay) { + task_environment_.FastForwardBy(delay); + } + private: - content::BrowserTaskEnvironment task_environment_; + content::BrowserTaskEnvironment task_environment_{ + content::BrowserTaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<FallbackTaskProvider> task_provider_; std::vector<raw_ptr<Task, VectorExperimental>> seen_tasks_; }; @@ -187,7 +192,6 @@ // The delay for showing a secondary source is 750ms; delay 1000ms to ensure // we see them. base::TimeDelta delay = base::Milliseconds(1000); - base::ScopedMockTimeMessageLoopTaskRunner mock_main_runner; StartUpdating(); // There are two primary task providers and one secondary task provider. The @@ -200,12 +204,12 @@ FakeTask fake_secondary_task_1_1(1, Task::RENDERER, "S_1_1"); SecondaryTaskAdded(&fake_secondary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ("S_1_1\n", DumpSeenTasks()); FakeTask fake_secondary_task_1_2(1, Task::RENDERER, "S_1_2"); SecondaryTaskAdded(&fake_secondary_task_1_2); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "S_1_1\n" "S_1_2\n", @@ -213,17 +217,17 @@ FakeTask fake_primary_task_1_1(1, Task::RENDERER, "P_1_1"); FirstPrimaryTaskAdded(&fake_primary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ("P_1_1\n", DumpSeenTasks()); FakeTask fake_secondary_task_1_3(1, Task::RENDERER, "S_1_3"); SecondaryTaskAdded(&fake_secondary_task_1_3); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ("P_1_1\n", DumpSeenTasks()); FakeTask fake_secondary_task_2_1(2, Task::RENDERER, "S_2_1"); SecondaryTaskAdded(&fake_secondary_task_2_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "P_1_1\n" "S_2_1\n", @@ -231,7 +235,7 @@ FakeTask fake_primary_task_3_1(3, Task::RENDERER, "Q_3_1"); SecondPrimaryTaskAdded(&fake_primary_task_3_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "P_1_1\n" "S_2_1\n" @@ -239,7 +243,7 @@ DumpSeenTasks()); FirstPrimaryTaskRemoved(&fake_primary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "S_2_1\n" "Q_3_1\n" @@ -254,7 +258,7 @@ // After updating the primary tasks (Ps) will be added before the secondary // tasks (Ss) so it is reordered. StartUpdating(); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "S_1_1\n" @@ -264,7 +268,7 @@ DumpSeenTasks()); FirstPrimaryTaskAdded(&fake_primary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "S_2_1\n" @@ -281,7 +285,7 @@ DumpSeenTasks()); FirstPrimaryTaskRemoved(&fake_primary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "S_2_1\n" @@ -289,21 +293,21 @@ DumpSeenTasks()); SecondaryTaskRemoved(&fake_secondary_task_2_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "P_1_2\n", DumpSeenTasks()); SecondaryTaskRemoved(&fake_secondary_task_1_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "P_1_2\n", DumpSeenTasks()); FirstPrimaryTaskRemoved(&fake_primary_task_1_2); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "Q_3_1\n" "S_1_2\n" @@ -311,7 +315,7 @@ DumpSeenTasks()); SecondPrimaryTaskRemoved(&fake_primary_task_3_1); - mock_main_runner->FastForwardBy(delay); + FastForwardBy(delay); EXPECT_EQ( "S_1_2\n" "S_1_3\n",
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn b/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn index b8374db..bf4078f 100644 --- a/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn +++ b/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn
@@ -13,6 +13,7 @@ deps = [ ":jni", "//base", + "//chrome/browser/extensions", "//chrome/browser/ui/browser_window", ] } @@ -46,9 +47,11 @@ deps = [ ":internal", "//base", + "//chrome/browser/extensions", "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_java", "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_jni", "//chrome/browser/ui/browser_window", + "//components/sessions:session_id", "//testing/gtest", ] }
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc index 74801e4..7da4429 100644 --- a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc +++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc
@@ -8,6 +8,8 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" +#include "chrome/browser/extensions/browser_extension_window_controller.h" +#include "chrome/browser/extensions/window_controller.h" #include "chrome/browser/ui/android/extensions/windowing/internal/jni/ExtensionWindowControllerBridgeImpl_jni.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" @@ -33,7 +35,8 @@ const base::android::JavaParamRef<jobject>& java_extension_window_controller_bridge, BrowserWindowInterface* browser_window) - : browser_window_(browser_window) { + : extension_window_controller_( + extensions::BrowserExtensionWindowController(browser_window)) { java_extension_window_controller_bridge_.Reset( env, java_extension_window_controller_bridge); } @@ -47,7 +50,7 @@ delete this; } -BrowserWindowInterface* -ExtensionWindowControllerBridge::GetBrowserWindowForTesting() const { - return browser_window_; +const extensions::BrowserExtensionWindowController& +ExtensionWindowControllerBridge::GetExtensionWindowControllerForTesting() { + return extension_window_controller_; }
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h index 33fac17..364fe56 100644 --- a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h +++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h
@@ -8,6 +8,7 @@ #include <jni.h> #include "base/android/scoped_java_ref.h" +#include "chrome/browser/extensions/browser_extension_window_controller.h" class BrowserWindowInterface; @@ -31,16 +32,14 @@ // Implements Java |ExtensionWindowControllerBridgeImpl.Natives#destroy|. void Destroy(JNIEnv* env); - // TODO(crbug.com/424856725): replace with a test-only function that returns - // the |extensions::WindowController|. - BrowserWindowInterface* GetBrowserWindowForTesting() const; + const extensions::BrowserExtensionWindowController& + GetExtensionWindowControllerForTesting(); private: base::android::ScopedJavaGlobalRef<jobject> java_extension_window_controller_bridge_; - // TODO(crbug.com/424856725): replace with an |extensions::WindowController|. - BrowserWindowInterface* browser_window_; + extensions::BrowserExtensionWindowController extension_window_controller_; }; #endif // CHROME_BROWSER_UI_ANDROID_EXTENSIONS_WINDOWING_INTERNAL_EXTENSION_WINDOW_CONTROLLER_BRIDGE_H_
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc index f9ea2db..38e04a54 100644 --- a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc +++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc
@@ -7,6 +7,7 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" +#include "chrome/browser/extensions/browser_extension_window_controller.h" #include "chrome/browser/ui/android/extensions/windowing/test/native_unit_test_support_jni/ExtensionWindowControllerBridgeNativeUnitTestSupport_jni.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,10 +61,13 @@ // Assert. ExtensionWindowControllerBridge* extension_window_controller_bridge = InvokeJavaGetNativePtrForTesting(); - BrowserWindowInterface* browser_window = - extension_window_controller_bridge->GetBrowserWindowForTesting(); + const extensions::BrowserExtensionWindowController& + extension_window_controller = + extension_window_controller_bridge + ->GetExtensionWindowControllerForTesting(); EXPECT_NE(nullptr, extension_window_controller_bridge); - EXPECT_NE(nullptr, browser_window); + EXPECT_NE(SessionID::InvalidValue().id(), + extension_window_controller.GetWindowId()); } TEST_F(ExtensionWindowControllerBridgeUnitTest,
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index 93c6fda..75e74d4 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -629,16 +629,18 @@ loadUrlParams.setInputStartTimestamp(omniboxLoadUrlParams.inputStartTimestamp); } - if (!TextUtils.isEmpty(omniboxLoadUrlParams.postDataType)) { + if (!omniboxLoadUrlParams.extraHeaders.isEmpty()) { StringBuilder headers = new StringBuilder(); - String prevHeader = loadUrlParams.getVerbatimHeaders(); - if (prevHeader != null && !prevHeader.isEmpty()) { - headers.append(prevHeader); + for (var entry : omniboxLoadUrlParams.extraHeaders.entrySet()) { + headers.append(entry.getKey()); + headers.append(": "); + headers.append(entry.getValue()); headers.append("\r\n"); } - - headers.append("Content-Type: "); - headers.append(omniboxLoadUrlParams.postDataType); + String previousHeaders = loadUrlParams.getVerbatimHeaders(); + if (!TextUtils.isEmpty(previousHeaders)) { + headers.append(previousHeaders); + } loadUrlParams.setVerbatimHeaders(headers.toString()); }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java index 84f924f..a0c09f8 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -112,7 +112,9 @@ import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** Unit tests for LocationBarMediator. */ @RunWith(BaseRobolectricTestRunner.class) @@ -475,7 +477,8 @@ testLoadUrlWithAutocompleteLoadCallback_base(); } - public void testLoadUrlWithPostData_base() { + @Test + public void testLoadUrlWithPostData() { mMediator.onFinishNativeInitialization(); String text = "text"; byte[] data = new byte[] {0, 1, 2, 3, 4}; @@ -484,7 +487,8 @@ doReturn(data).when(mResourceRequestBodyJni).createResourceRequestBodyFromBytes(any()); mMediator.loadUrl( new OmniboxLoadUrlParams.Builder(TEST_URL, PageTransition.TYPED) - .setpostDataAndType(data, text) + .setPostData(data) + .setExtraHeaders(Map.of("Content-Type", text)) .build()); verify(mTab).loadUrl(mLoadUrlParamsCaptor.capture()); @@ -497,15 +501,28 @@ } @Test - @DisableFeatures({OmniboxFeatureList.POST_DELAYED_TASK_FOCUS_TAB}) - public void testLoadUrlWithPostDataNoPostDelayedTaskFocusTab() { - testLoadUrlWithPostData_base(); - } + public void testLoadUrlWithExtraHeaders() { + mMediator.onFinishNativeInitialization(); + Map<String, String> headers = new HashMap<>(); + headers.put("Authorization", "Bearer token123"); + headers.put("Custom-Header", "custom-value"); + headers.put("Content-Type", "application/json"); - @Test - @EnableFeatures({OmniboxFeatureList.POST_DELAYED_TASK_FOCUS_TAB}) - public void testLoadUrlWithPostDataPostDelayedTaskFocusTab() { - testLoadUrlWithPostData_base(); + doReturn(mTab).when(mLocationBarDataProvider).getTab(); + mMediator.loadUrl( + new OmniboxLoadUrlParams.Builder(TEST_URL, PageTransition.TYPED) + .setExtraHeaders(headers) + .build()); + + verify(mTab).loadUrl(mLoadUrlParamsCaptor.capture()); + assertEquals(TEST_URL, mLoadUrlParamsCaptor.getValue().getUrl()); + assertEquals( + PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR, + mLoadUrlParamsCaptor.getValue().getTransitionType()); + String verbatimHeaders = mLoadUrlParamsCaptor.getValue().getVerbatimHeaders(); + assertTrue(verbatimHeaders.contains("Authorization: Bearer token123")); + assertTrue(verbatimHeaders.contains("Custom-Header: custom-value")); + assertTrue(verbatimHeaders.contains("Content-Type: application/json")); } @Test @@ -545,11 +562,12 @@ assertEquals(PageTransition.TYPED, params.transitionType); assertEquals(0, params.inputStartTimestamp); assertNull(null, params.postData); - assertNull(null, params.postDataType); + assertTrue(params.extraHeaders.isEmpty()); assertFalse(params.openInNewTab); verify(mTab, times(0)).loadUrl(any()); } + @Test public void testLoadUrl_openInNewTab_base() { mMediator.onFinishNativeInitialization();
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 fb332af..70843a3 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
@@ -1047,22 +1047,14 @@ } }; - if (suggestion.getType() == OmniboxSuggestionType.CLIPBOARD_IMAGE) { - mDelegate.loadUrl( - new OmniboxLoadUrlParams.Builder(url.getSpec(), transition) - .setInputStartTimestamp(inputStart) - .setpostDataAndType( - suggestion.getPostData(), suggestion.getPostContentType()) - .setAutocompleteLoadCallback(autocompleteLoadCallback) - .build()); - } else { - mDelegate.loadUrl( - new OmniboxLoadUrlParams.Builder(url.getSpec(), transition) - .setInputStartTimestamp(inputStart) - .setOpenInNewTab(openInNewTab) - .setAutocompleteLoadCallback(autocompleteLoadCallback) - .build()); - } + mDelegate.loadUrl( + new OmniboxLoadUrlParams.Builder(url.getSpec(), transition) + .setInputStartTimestamp(inputStart) + .setPostData(suggestion.getPostData()) + .setOpenInNewTab(openInNewTab) + .setExtraHeaders(suggestion.getExtraHeaders()) + .setAutocompleteLoadCallback(autocompleteLoadCallback) + .build()); mHandler.post(this::finishInteraction); }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParams.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParams.java index 5e40f00..248d9d99 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParams.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParams.java
@@ -9,6 +9,8 @@ import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteDelegate.AutocompleteLoadCallback; import org.chromium.ui.base.PageTransition; +import java.util.Map; + /** Holds parameters for AutocompleteDelegate.LoadUrl. */ @NullMarked public class OmniboxLoadUrlParams { @@ -17,7 +19,7 @@ public final long inputStartTimestamp; public final boolean openInNewTab; public final byte @Nullable [] postData; - public final @Nullable String postDataType; + public final Map<String, String> extraHeaders; public final @Nullable AutocompleteLoadCallback callback; private OmniboxLoadUrlParams( @@ -26,14 +28,14 @@ long inputStartTimestamp, boolean openInNewTab, byte @Nullable [] postData, - @Nullable String postDataType, + Map<String, String> extraHeaders, @Nullable AutocompleteLoadCallback callback) { this.url = url; this.transitionType = transitionType; this.inputStartTimestamp = inputStartTimestamp; this.openInNewTab = openInNewTab; this.postData = postData; - this.postDataType = postDataType; + this.extraHeaders = extraHeaders; this.callback = callback; } @@ -44,7 +46,7 @@ public long inputStartTimestamp; public boolean openInNewTab; public byte @Nullable [] postData; - public @Nullable String postDataType; + public Map<String, String> extraHeaders = Map.of(); public @Nullable AutocompleteLoadCallback callback; /** @@ -79,19 +81,26 @@ * Set the post data of this load, and its type. * * @param postData Post data for this http post load. - * @param postDataType Post data type for this http post load. */ - public Builder setpostDataAndType( - byte @Nullable [] postData, @Nullable String postDataType) { + public Builder setPostData(byte @Nullable [] postData) { this.postData = postData; - this.postDataType = postDataType; return this; } /** - * Set the callback of this loa. + * Set the extra headers for this navigation. * - * @param callback The callback will be called once the url is loaded. + * @param extraHeaders Extra headers to be included with the HTTP request. + */ + public Builder setExtraHeaders(Map<String, String> extraHeaders) { + this.extraHeaders = extraHeaders; + return this; + } + + /** + * Specify callback to be invoked once the URL is loaded. + * + * @param callback The callback to be invoked. */ public Builder setAutocompleteLoadCallback(AutocompleteLoadCallback callback) { this.callback = callback; @@ -106,7 +115,7 @@ inputStartTimestamp, openInNewTab, postData, - postDataType, + extraHeaders, callback); } }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParamsUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParamsUnitTest.java index 675f151f..47f2d5e 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParamsUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxLoadUrlParamsUnitTest.java
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -20,6 +21,9 @@ import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.ui.base.PageTransition; +import java.util.HashMap; +import java.util.Map; + /** Tests for {@link OmniboxLoadUrlParams}. */ @RunWith(BaseRobolectricTestRunner.class) public class OmniboxLoadUrlParamsUnitTest { @@ -35,7 +39,7 @@ assertEquals(PageTransition.TYPED, params.transitionType); assertEquals(0L, params.inputStartTimestamp); assertFalse(params.openInNewTab); - assertNull(params.postDataType); + assertTrue(params.extraHeaders.isEmpty()); assertNull(params.postData); assertNull(params.callback); } @@ -54,7 +58,8 @@ new OmniboxLoadUrlParams.Builder(TEST_URL, PageTransition.TYPED) .setInputStartTimestamp(100L) .setOpenInNewTab(true) - .setpostDataAndType(data, text) + .setPostData(data) + .setExtraHeaders(Map.of("Content-Type", text)) .setAutocompleteLoadCallback(callback) .build(); @@ -62,8 +67,29 @@ assertEquals(PageTransition.TYPED, params.transitionType); assertEquals(100L, params.inputStartTimestamp); assertTrue(params.openInNewTab); - assertEquals(params.postDataType, text); + assertNotNull(params.extraHeaders); + assertEquals(text, params.extraHeaders.get("Content-Type")); assertEquals(params.postData, data); assertEquals(params.callback, callback); } + + @Test + @SmallTest + public void setExtraHeaders() { + Map<String, String> headers = new HashMap<>(); + headers.put("Authorization", "Bearer token123"); + headers.put("Custom-Header", "custom-value"); + + OmniboxLoadUrlParams params = + new OmniboxLoadUrlParams.Builder(TEST_URL, PageTransition.TYPED) + .setExtraHeaders(headers) + .build(); + + assertEquals(TEST_URL, params.url); + assertEquals(PageTransition.TYPED, params.transitionType); + assertNotNull(params.extraHeaders); + assertEquals("Bearer token123", params.extraHeaders.get("Authorization")); + assertEquals("custom-value", params.extraHeaders.get("Custom-Header")); + assertEquals(2, params.extraHeaders.size()); + } }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 0e42b32..4ab10a5b 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -93,7 +93,6 @@ #include "chrome/browser/ui/bookmarks/bookmark_bar_controller.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" #include "chrome/browser/ui/bookmarks/bookmark_utils.h" -#include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_dialogs.h" @@ -629,12 +628,8 @@ creation_source_(params.creation_source), unload_controller_(this), app_controller_(web_app::MaybeCreateAppBrowserController(this)), - browser_actions_(new BrowserActions(*this)), - command_controller_(new chrome::BrowserCommandController(this)), window_has_shown_(false), user_title_(params.user_title) { - browser_actions_->InitializeBrowserActions(); - if (!profile_->IsOffTheRecord()) { profile_keep_alive_ = std::make_unique<ScopedProfileKeepAlive>( params.profile->GetOriginalProfile(), @@ -715,15 +710,6 @@ // TODO(crbug.com/40064092): convert this to CHECK. DCHECK(tab_strip_model_->empty()); - // Destroy the BrowserCommandController before removing the browser, so that - // it doesn't act on any notifications that are sent as a result of removing - // the browser. - command_controller_.reset(); - - // Remove listeners associated with browser actions so that - // it doesn't act on any during browser destruction. - browser_actions_->RemoveListeners(); - // Destroy ExclusiveAccessManager, which depends on `window_` which may be // destroyed by RemoveBrowser(). BrowserList::RemoveBrowser(this); @@ -1223,7 +1209,7 @@ } BrowserActions* Browser::GetActions() { - return browser_actions(); + return GetFeatures().browser_actions(); } BrowserWindowInterface::Type Browser::GetType() const { @@ -1424,13 +1410,13 @@ ->exclusive_access_manager() ->fullscreen_controller() ->WindowFullscreenStateChanged(); - command_controller_->FullscreenStateChanged(); + GetCommandController()->FullscreenStateChanged(); BookmarkBarController::From(this)->UpdateBookmarkBarState( BookmarkBarController::StateChangeReason::kToggleFullscreen); } void Browser::FullscreenTopUIStateChanged() { - command_controller_->FullscreenStateChanged(); + GetCommandController()->FullscreenStateChanged(); BookmarkBarController::From(this)->UpdateBookmarkBarState( BookmarkBarController::StateChangeReason::kToolbarOptionChange); } @@ -1440,7 +1426,7 @@ window()->UpdatePageActionIcon(PageActionIconType::kFind); } - command_controller_->FindBarVisibilityChanged(); + GetCommandController()->FindBarVisibilityChanged(); } /////////////////////////////////////////////////////////////////////////////// @@ -2094,7 +2080,7 @@ // state messages while destructing during browser tear-down. Ironically we // can't use IsShuttingDown() because by this point the browser is entirely // removed from the browser list. - if (!command_controller_) { + if (is_delete_scheduled_) { return; } @@ -2110,7 +2096,7 @@ if (changed_flags & (content::INVALIDATE_TYPE_URL | content::INVALIDATE_TYPE_LOAD | content::INVALIDATE_TYPE_TAB)) { - command_controller_->TabStateChanged(); + GetCommandController()->TabStateChanged(); } if (app_controller_) { @@ -2969,7 +2955,7 @@ if (data.web_contents == tab_strip_model_->GetActiveWebContents()) { window_->ZoomChangedForActiveTab(data.can_show_bubble); // Change the zoom commands state based on the zoom state - command_controller_->ZoomStateChanged(); + GetCommandController()->ZoomStateChanged(); } } @@ -3153,10 +3139,13 @@ UpdateToolbar((reason & CHANGE_REASON_REPLACED) == 0); // Update reload/stop state. - command_controller_->LoadingStateChanged(new_contents->IsLoading(), true); + chrome::BrowserCommandController* const browser_command_controller = + GetCommandController(); + browser_command_controller->LoadingStateChanged(new_contents->IsLoading(), + true); // Update commands to reflect current state. - command_controller_->TabStateChanged(); + browser_command_controller->TabStateChanged(); // Reset the status bubble. std::vector<StatusBubble*> status_bubbles = GetStatusBubbles(); @@ -3423,6 +3412,10 @@ } } +chrome::BrowserCommandController* Browser::GetCommandController() { + return GetFeatures().browser_command_controller(); +} + /////////////////////////////////////////////////////////////////////////////// // Browser, Session restore functions (private): @@ -3600,7 +3593,7 @@ WebContents* selected_contents = tab_strip_model_->GetActiveWebContents(); if (source == selected_contents) { bool is_loading = source->IsLoading() && should_show_loading_ui; - command_controller_->LoadingStateChanged(is_loading, false); + GetCommandController()->LoadingStateChanged(is_loading, false); std::vector<StatusBubble*> status_bubbles = GetStatusBubbles(); if (status_bubbles.size() > 0) {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index eb82055f..74152e6 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -464,10 +464,11 @@ return tab_strip_model_delegate_.get(); } - BrowserActions* browser_actions() const { return browser_actions_.get(); } + BrowserActions* browser_actions() { return GetActions(); } + // TODO(crbug.com/434734349): Remove this method once callsites are migrated. chrome::BrowserCommandController* command_controller() { - return command_controller_.get(); + return GetCommandController(); } SessionID session_id() const { return session_id_; } @@ -862,11 +863,8 @@ friend class ExclusiveAccessTest; friend class FullscreenControllerInteractiveTest; FRIEND_TEST_ALL_PREFIXES(AppModeTest, EnableAppModeTest); - FRIEND_TEST_ALL_PREFIXES(BrowserCommandControllerTest, - IsReservedCommandOrKeyIsApp); FRIEND_TEST_ALL_PREFIXES(BrowserCloseTest, LastIncognito); FRIEND_TEST_ALL_PREFIXES(BrowserCloseTest, LastRegular); - FRIEND_TEST_ALL_PREFIXES(BrowserCommandControllerTest, AppFullScreen); FRIEND_TEST_ALL_PREFIXES(BrowserTest, OpenAppWindowLikeNtp); FRIEND_TEST_ALL_PREFIXES(BrowserTest, AppIdSwitch); FRIEND_TEST_ALL_PREFIXES(ExclusiveAccessBubbleWindowControllerTest, @@ -1127,6 +1125,8 @@ // TODO(beng): remove this. std::vector<StatusBubble*> GetStatusBubbles(); + chrome::BrowserCommandController* GetCommandController(); + // Session restore functions //////////////////////////////////////////////// // Notifies the history database of the index for all tabs whose index is @@ -1351,11 +1351,6 @@ // set of commands are enabled. const std::unique_ptr<web_app::AppBrowserController> app_controller_; - - std::unique_ptr<BrowserActions> browser_actions_; - - std::unique_ptr<chrome::BrowserCommandController> command_controller_; - // True if the browser window has been shown at least once. bool window_has_shown_;
diff --git a/chrome/browser/ui/browser_actions.cc b/chrome/browser/ui/browser_actions.cc index bbae2b6..e030c5c 100644 --- a/chrome/browser/ui/browser_actions.cc +++ b/chrome/browser/ui/browser_actions.cc
@@ -8,6 +8,7 @@ #include <optional> #include <string> +#include "base/check_deref.h" #include "base/check_op.h" #include "base/functional/bind.h" #include "chrome/app/vector_icons/vector_icons.h" @@ -29,6 +30,7 @@ #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window/public/browser_window_features.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/commerce/commerce_ui_tab_helper.h" #include "chrome/browser/ui/customize_chrome/side_panel_controller.h" #include "chrome/browser/ui/intent_picker_tab_helper.h" @@ -159,9 +161,12 @@ } } // namespace -BrowserActions::BrowserActions(Browser& browser) : browser_(browser) {} +BrowserActions::BrowserActions(BrowserWindowInterface* bwi) + : bwi_(CHECK_DEREF(bwi)) {} BrowserActions::~BrowserActions() { + browser_action_prefs_listener_.reset(); + // Extract the unique ptr and destruct it after the raw_ptr to avoid a // dangling pointer scenario. std::unique_ptr<actions::ActionItem> owned_root_action_item = @@ -187,8 +192,8 @@ } void BrowserActions::InitializeBrowserActions() { - Profile* profile = browser_->profile(); - Browser* browser = &(browser_.get()); + Profile* profile = bwi_->GetProfile(); + Browser* browser = bwi_->GetBrowserForMigrationOnly(); const bool is_guest_session = profile->IsGuestSession(); actions::ActionManager::Get().AddAction( @@ -930,11 +935,9 @@ AddListeners(); } -void BrowserActions::RemoveListeners() { - browser_action_prefs_listener_.reset(); -} - void BrowserActions::AddListeners() { - browser_action_prefs_listener_ = - std::make_unique<BrowserActionPrefsListener>(browser_.get()); + // TODO(crbug.com/431668581): Refactor this to take only its dependencies + // (BrowserActions and Profile) instead of the entire Browser. + browser_action_prefs_listener_ = std::make_unique<BrowserActionPrefsListener>( + *bwi_->GetBrowserForMigrationOnly()); }
diff --git a/chrome/browser/ui/browser_actions.h b/chrome/browser/ui/browser_actions.h index 00d7994..21fc87a8 100644 --- a/chrome/browser/ui/browser_actions.h +++ b/chrome/browser/ui/browser_actions.h
@@ -9,8 +9,8 @@ #include "base/callback_list.h" -class Browser; class BrowserActionPrefsListener; +class BrowserWindowInterface; namespace actions { class ActionItem; @@ -19,7 +19,7 @@ // Actions that a user can take that are scoped to a browser window. class BrowserActions { public: - explicit BrowserActions(Browser& browser); + explicit BrowserActions(BrowserWindowInterface* bwi); BrowserActions(const BrowserActions&) = delete; BrowserActions& operator=(const BrowserActions&) = delete; ~BrowserActions(); @@ -31,8 +31,6 @@ // Initialization is separate from construction to allow more precise timing. void InitializeBrowserActions(); - void RemoveListeners(); - private: // Creates all the listeners for the action items that update different states // and property of the action item. @@ -40,7 +38,7 @@ raw_ptr<actions::ActionItem> root_action_item_ = nullptr; std::unique_ptr<BrowserActionPrefsListener> browser_action_prefs_listener_; - const raw_ref<Browser> browser_; + const raw_ref<BrowserWindowInterface> bwi_; }; #endif // CHROME_BROWSER_UI_BROWSER_ACTIONS_H_
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index ae3f93f9..54715c0 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -47,6 +47,7 @@ #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window/public/browser_window_features.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/bubble_anchor_util.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/customize_chrome/side_panel_controller.h" @@ -213,8 +214,10 @@ /////////////////////////////////////////////////////////////////////////////// // BrowserCommandController, public: -BrowserCommandController::BrowserCommandController(Browser* browser) - : browser_(browser), command_updater_(nullptr) { +// TODO(crbug.com/434734349): Implement dependency injection for this class to +// allow removing the Browser dependency. +BrowserCommandController::BrowserCommandController(BrowserWindowInterface* bwi) + : browser_(bwi->GetBrowserForMigrationOnly()) { browser_->tab_strip_model()->AddObserver(this); PrefService* local_state = g_browser_process->local_state(); if (local_state) { @@ -316,7 +319,6 @@ profile_pref_registrar_.RemoveAll(); local_pref_registrar_.RemoveAll(); glic_enabling_subscription_.reset(); - browser_->tab_strip_model()->RemoveObserver(this); } bool BrowserCommandController::IsReservedCommandOrKey( @@ -2212,16 +2214,16 @@ actions::ActionItem* BrowserCommandController::FindAction( actions::ActionId action_id) { - BrowserActions* browser_actions = browser_->browser_actions(); + actions::ActionItem* const root_action_item = + browser_->GetActions()->root_action_item(); // If there is no root action item then ActionManager falls back to the // root_action_parent_ which might contain actions from other browser windows. - if (!browser_actions->root_action_item()) { + if (!root_action_item) { return nullptr; } - return actions::ActionManager::Get().FindAction( - action_id, browser_actions->root_action_item()); + return actions::ActionManager::Get().FindAction(action_id, root_action_item); } void BrowserCommandController::UpdateCommandAndActionEnabled(
diff --git a/chrome/browser/ui/browser_command_controller.h b/chrome/browser/ui/browser_command_controller.h index 0699d296..e6580a3 100644 --- a/chrome/browser/ui/browser_command_controller.h +++ b/chrome/browser/ui/browser_command_controller.h
@@ -23,6 +23,7 @@ class Browser; class BrowserWindow; +class BrowserWindowInterface; class Profile; namespace input { @@ -38,7 +39,7 @@ public TabStripModelObserver, public sessions::TabRestoreServiceObserver { public: - explicit BrowserCommandController(Browser* browser); + explicit BrowserCommandController(BrowserWindowInterface* bwi); BrowserCommandController(const BrowserCommandController&) = delete; BrowserCommandController& operator=(const BrowserCommandController&) = delete; @@ -231,13 +232,13 @@ actions::ActionId action_id, bool enabled); - inline BrowserWindow* window(); - inline Profile* profile(); + BrowserWindow* window(); + Profile* profile(); const raw_ptr<Browser> browser_; // The CommandUpdaterImpl that manages the browser window commands. - CommandUpdaterImpl command_updater_; + CommandUpdaterImpl command_updater_{nullptr}; PrefChangeRegistrar profile_pref_registrar_; PrefChangeRegistrar local_pref_registrar_;
diff --git a/chrome/browser/ui/browser_window/internal/BUILD.gn b/chrome/browser/ui/browser_window/internal/BUILD.gn index 91f20458..89dfceb 100644 --- a/chrome/browser/ui/browser_window/internal/BUILD.gn +++ b/chrome/browser/ui/browser_window/internal/BUILD.gn
@@ -12,6 +12,7 @@ "//base", "//chrome/browser/profiles:profile", "//chrome/browser/ui/browser_window", + "//components/sessions:session_id", "//ui/base/unowned_user_data", ] @@ -100,6 +101,7 @@ "//base", "//chrome/browser/ui/browser_window/test:native_unit_test_support_java", "//chrome/browser/ui/browser_window/test:native_unit_test_support_jni", + "//components/sessions:session_id", "//ui/base", ] }
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc b/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc index 091a8e8..5e2fe52 100644 --- a/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc +++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc
@@ -11,6 +11,7 @@ #include "base/notreached.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_window/internal/jni/AndroidBrowserWindow_jni.h" +#include "components/sessions/core/session_id.h" #include "ui/base/unowned_user_data/unowned_user_data_host.h" namespace { @@ -27,7 +28,8 @@ AndroidBrowserWindow::AndroidBrowserWindow( JNIEnv* env, - const JavaParamRef<jobject>& java_android_browser_window) { + const JavaParamRef<jobject>& java_android_browser_window) + : session_id_(SessionID::NewUnique()) { java_android_browser_window_.Reset(env, java_android_browser_window); } @@ -41,12 +43,12 @@ } ui::UnownedUserDataHost& AndroidBrowserWindow::GetUnownedUserDataHost() { - NOTREACHED(); + return unowned_user_data_host_; } const ui::UnownedUserDataHost& AndroidBrowserWindow::GetUnownedUserDataHost() const { - NOTREACHED(); + return unowned_user_data_host_; } ui::BaseWindow* AndroidBrowserWindow::GetWindow() { @@ -56,11 +58,13 @@ } Profile* AndroidBrowserWindow::GetProfile() { - NOTREACHED(); + // TODO(crbug.com/429037015): Return a proper Profile. + // Temporarily return nullptr to avoid crashing callers. + return nullptr; } const SessionID& AndroidBrowserWindow::GetSessionID() const { - NOTREACHED(); + return session_id_; } content::WebContents* AndroidBrowserWindow::OpenURL(
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window.h b/chrome/browser/ui/browser_window/internal/android/android_browser_window.h index 44c5600e..68c34d4 100644 --- a/chrome/browser/ui/browser_window/internal/android/android_browser_window.h +++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window.h
@@ -9,6 +9,8 @@ #include "base/android/scoped_java_ref.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "components/sessions/core/session_id.h" +#include "ui/base/unowned_user_data/unowned_user_data_host.h" // Android implementation of |BrowserWindowInterface|. class AndroidBrowserWindow final : public BrowserWindowInterface { @@ -39,6 +41,8 @@ private: base::android::ScopedJavaGlobalRef<jobject> java_android_browser_window_; + ui::UnownedUserDataHost unowned_user_data_host_; + const SessionID session_id_; }; #endif // CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc index 89d7ee4..546ca647 100644 --- a/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc +++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc
@@ -11,12 +11,14 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/ui/browser_window/internal/android/android_base_window.h" #include "chrome/browser/ui/browser_window/test/native_unit_test_support_jni/AndroidBrowserWindowNativeUnitTestSupport_jni.h" +#include "components/sessions/core/session_id.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/base_window.h" namespace { using base::android::AttachCurrentThread; using base::android::ScopedJavaGlobalRef; +using base::android::ScopedJavaLocalRef; } // namespace class AndroidBrowserWindowUnitTest : public testing::Test { @@ -108,3 +110,38 @@ InvokeJavaGetNativeBaseWindowPtrForTesting(); EXPECT_EQ(expected_base_window, base_window); } + +TEST_F(AndroidBrowserWindowUnitTest, GetSessionIDReturnsUniqueID) { + // Arrange: create two AndroidBrowserWindow objects. + // + // As each Java AndroidBrowserWindowNativeUnitTestSupport owns one native + // AndroidBrowserWindow object, we need to create two Java test support + // objects to get two instances of AndroidBrowserWindow. + // + // For clarity, we don't use the test fixture's java_test_support_ field. + ScopedJavaLocalRef<jobject> java_test_support1 = + Java_AndroidBrowserWindowNativeUnitTestSupport_Constructor( + AttachCurrentThread()); + ScopedJavaLocalRef<jobject> java_test_support2 = + Java_AndroidBrowserWindowNativeUnitTestSupport_Constructor( + AttachCurrentThread()); + AndroidBrowserWindow* android_browser_window1 = reinterpret_cast< + AndroidBrowserWindow*>( + Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetOrCreateNativePtr( + AttachCurrentThread(), java_test_support1)); + AndroidBrowserWindow* android_browser_window2 = reinterpret_cast< + AndroidBrowserWindow*>( + Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetOrCreateNativePtr( + AttachCurrentThread(), java_test_support2)); + + const SessionID& session_id1 = android_browser_window1->GetSessionID(); + const SessionID& session_id2 = android_browser_window2->GetSessionID(); + + EXPECT_NE(session_id1, session_id2); + + // Clean up. + Java_AndroidBrowserWindowNativeUnitTestSupport_invokeDestroy( + AttachCurrentThread(), java_test_support1); + Java_AndroidBrowserWindowNativeUnitTestSupport_invokeDestroy( + AttachCurrentThread(), java_test_support2); +}
diff --git a/chrome/browser/ui/browser_window/internal/browser_window_features.cc b/chrome/browser/ui/browser_window/internal/browser_window_features.cc index 01ed18c..7ee1efa1 100644 --- a/chrome/browser/ui/browser_window/internal/browser_window_features.cc +++ b/chrome/browser/ui/browser_window/internal/browser_window_features.cc
@@ -141,6 +141,13 @@ // later. browser_ = browser; + browser_actions_ = std::make_unique<BrowserActions>(browser); + + browser_command_controller_ = + std::make_unique<chrome::BrowserCommandController>(browser); + + browser_actions_->InitializeBrowserActions(); + // Initialize bookmark bar controller for all browser types. bookmark_bar_controller_ = std::make_unique<BookmarkBarController>( *browser, *browser->GetTabStripModel()); @@ -285,8 +292,8 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) extension_browser_window_helper_ = std::make_unique<extensions::ExtensionBrowserWindowHelper>( - browser->GetBrowserForMigrationOnly()->command_controller(), - browser->GetTabStripModel(), browser->GetProfile()); + browser_command_controller_.get(), browser->GetTabStripModel(), + browser->GetProfile()); #endif if (breadcrumbs::IsEnabled(g_browser_process->local_state())) { @@ -348,7 +355,7 @@ location_bar = browser_view->GetLocationBarView(); } lens_overlay_entry_point_controller_->Initialize( - browser, browser->command_controller(), location_bar); + browser, browser_command_controller_.get(), location_bar); } auto* experiment_manager =
diff --git a/chrome/browser/ui/browser_window/public/browser_window_features.h b/chrome/browser/ui/browser_window/public/browser_window_features.h index 527f8960..6e454c53 100644 --- a/chrome/browser/ui/browser_window/public/browser_window_features.h +++ b/chrome/browser/ui/browser_window/public/browser_window_features.h
@@ -27,6 +27,7 @@ class BookmarksSidePanelCoordinator; class BreadcrumbManagerBrowserAgent; class Browser; +class BrowserActions; class BrowserContentSettingBubbleModelDelegate; class BrowserInstantController; class BrowserLiveTabContext; @@ -99,6 +100,10 @@ class VerticalTabStripStateController; } // namespace tabs +namespace chrome { +class BrowserCommandController; +} // namespace chrome + namespace commerce { class ProductSpecificationsEntryPointController; } // namespace commerce @@ -175,6 +180,12 @@ void TearDownPreBrowserWindowDestruction(); // Public accessors for features: + BrowserActions* browser_actions() { return browser_actions_.get(); } + + chrome::BrowserCommandController* browser_command_controller() { + return browser_command_controller_.get(); + } + extensions::Mv2DisabledDialogController* mv2_disabled_dialog_controller_for_testing() { return mv2_disabled_dialog_controller_.get(); @@ -417,6 +428,10 @@ // Features that are per-browser window will each have a controller. e.g. // std::unique_ptr<FooFeature> foo_feature_; + std::unique_ptr<BrowserActions> browser_actions_; + + std::unique_ptr<chrome::BrowserCommandController> browser_command_controller_; + std::unique_ptr<BookmarkBarController> bookmark_bar_controller_; std::unique_ptr<BrowserInstantController> instant_controller_;
diff --git a/chrome/browser/ui/extensions/BUILD.gn b/chrome/browser/ui/extensions/BUILD.gn index c7e6cb0..21cd0c7 100644 --- a/chrome/browser/ui/extensions/BUILD.gn +++ b/chrome/browser/ui/extensions/BUILD.gn
@@ -21,6 +21,7 @@ if (enable_extensions_core) { sources += [ "extension_install_ui.h", + "extensions_dialogs.h", "extensions_menu_core_controller.h", ] @@ -31,7 +32,12 @@ if (is_win || is_mac || is_linux || is_chromeos) { sources += [ "extension_install_ui_desktop.h" ] } - public_deps += [ "//base" ] + public_deps += [ + "//base", + "//extensions/common", + "//ui/base:types", + "//ui/base/mojom:ui_base_types", + ] } if (enable_extensions) { @@ -48,7 +54,6 @@ "extension_settings_overridden_dialog.h", "extension_side_panel_utils.h", "extensions_container.h", - "extensions_dialogs.h", "extensions_overrides/simple_overrides.h", "hosted_app_browser_controller.h", "icon_with_badge_image_source.h",
diff --git a/chrome/browser/ui/extensions/extensions_dialogs.h b/chrome/browser/ui/extensions/extensions_dialogs.h index f91fa5f1..f99fbaa 100644 --- a/chrome/browser/ui/extensions/extensions_dialogs.h +++ b/chrome/browser/ui/extensions/extensions_dialogs.h
@@ -11,7 +11,6 @@ #include "base/functional/callback_forward.h" #include "build/build_config.h" #include "chrome/browser/ui/extensions/mv2_disabled_dialog_controller.h" -#include "extensions/buildflags/buildflags.h" #include "extensions/common/extension_id.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/mojom/dialog_button.mojom.h" @@ -22,8 +21,6 @@ #include "base/files/safe_base_name.h" #endif // BUILDFLAG(IS_CHROMEOS) -static_assert(BUILDFLAG(ENABLE_EXTENSIONS)); - class Browser; class SettingsOverriddenDialogController; class Profile;
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc index e6590b5..897b88f 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -914,9 +914,20 @@ AutocompleteMatchType::Type match_type, bool is_zero_prefix_suggestion, lens::LensOverlayInvocationSource invocation_source) { - // TODO(crbug.com/431293648): This should be passed through async calls. - base::Time query_start_time = base::Time::Now(); + IssueContextualSearchRequestInner( + /*query_start_time=*/base::Time::Now(), query_text, + additional_query_parameters, lens_overlay_query_controller, match_type, + is_zero_prefix_suggestion, invocation_source); +} +void LensOverlayController::IssueContextualSearchRequestInner( + base::Time query_start_time, + std::string query_text, + std::map<std::string, std::string> additional_query_parameters, + lens::LensOverlayQueryController* lens_overlay_query_controller, + AutocompleteMatchType::Type match_type, + bool is_zero_prefix_suggestion, + lens::LensOverlayInvocationSource invocation_source) { // Ignore the request if the overlay is off or closing. if (IsOverlayClosing()) { return; @@ -937,18 +948,19 @@ invocation_source, base::BindOnce( &LensOverlayController::OnPageContextUpdatedForSuggestion, - weak_factory_.GetWeakPtr(), query_text, additional_query_parameters, - match_type, is_zero_prefix_suggestion, invocation_source)); + weak_factory_.GetWeakPtr(), query_start_time, query_text, + additional_query_parameters, match_type, is_zero_prefix_suggestion, + invocation_source)); return; } if (IsOverlayInitializing()) { // Hold the request until the overlay has finished initializing. pending_contextual_search_request_ = base::BindOnce( - &LensOverlayController::IssueContextualSearchRequest, - weak_factory_.GetWeakPtr(), query_text, additional_query_parameters, - lens_overlay_query_controller, match_type, is_zero_prefix_suggestion, - invocation_source); + &LensOverlayController::IssueContextualSearchRequestInner, + weak_factory_.GetWeakPtr(), query_start_time, query_text, + additional_query_parameters, lens_overlay_query_controller, match_type, + is_zero_prefix_suggestion, invocation_source); return; } else if (state_ != State::kOff) { // If the state is not off or initializing, the Lens sessions should already @@ -959,8 +971,9 @@ GetContextualizationController()->TryUpdatePageContextualization( base::BindOnce( &LensOverlayController::OnPageContextUpdatedForSuggestion, - weak_factory_.GetWeakPtr(), query_text, additional_query_parameters, - match_type, is_zero_prefix_suggestion, invocation_source)); + weak_factory_.GetWeakPtr(), query_start_time, query_text, + additional_query_parameters, match_type, is_zero_prefix_suggestion, + invocation_source)); return; } @@ -1270,6 +1283,17 @@ lens_overlay_controller_->NotifyPageContentUpdated(); return; } + + // If back to page feature is enabled and the page changes, only the overlay + // needs to be hidden, possibly leaving the side panel open. The search + // controller will handle whether the side panel should stay open or the + // entire session should terminate. + if (lens::features::IsLensOverlayBackToPageEnabled()) { + lens_overlay_controller_->lens_search_controller_->HideOverlay( + lens::LensOverlayDismissalSource::kPageChanged); + return; + } + lens_overlay_controller_->lens_search_controller_->CloseLensSync( lens::LensOverlayDismissalSource::kPageChanged); } @@ -2811,14 +2835,12 @@ } void LensOverlayController::OnPageContextUpdatedForSuggestion( + base::Time query_start_time, std::string query, std::map<std::string, std::string> additional_query_parameters, AutocompleteMatchType::Type match_type, bool is_zero_prefix_suggestion, lens::LensOverlayInvocationSource invocation_source) { - // TODO(crbug.com/431293648): This should be passed through async calls. - base::Time query_start_time = base::Time::Now(); - // TODO(crbug.com/404941800): Eventually, this should be a CHECK or removed // once the contextualization controller is separated from the overlay. For // now, this is required to prevent failures when opening the side panel.
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.h b/chrome/browser/ui/lens/lens_overlay_controller.h index e758318..d9e16b0 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller.h +++ b/chrome/browser/ui/lens/lens_overlay_controller.h
@@ -664,6 +664,17 @@ class UnderlyingWebContentsObserver; + // Implementation of IssueContextualSearchRequest() for passing + // query_start_time. + void IssueContextualSearchRequestInner( + base::Time query_start_time, + std::string query_text, + std::map<std::string, std::string> additional_query_parameters, + lens::LensOverlayQueryController* lens_overlay_query_controller, + AutocompleteMatchType::Type match_type, + bool is_zero_prefix_suggestion, + lens::LensOverlayInvocationSource invocation_source); + // Takes a screenshot of the current viewport. void CaptureScreenshot(); @@ -922,6 +933,7 @@ // Callback to run when the page context has been updated and the suggestion // query should now be issued. void OnPageContextUpdatedForSuggestion( + base::Time query_start_time, std::string query_text, std::map<std::string, std::string> additional_query_parameters, AutocompleteMatchType::Type match_type,
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc b/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc index 8c50d10..d9cc43a 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc
@@ -1072,6 +1072,68 @@ // This tests the following CUJ: // (1) User navigates to a website. +// (2) User opens lens overlay and the side panel opens. +// (3) User navigates to a new page in the same tab. +// (4) The overlay should close, but the side panel should remain open. +IN_PROC_BROWSER_TEST_F(LensOverlayControllerReturnToPageCUJTest, + HidesOverlayOnClobberTab) { + WaitForTemplateURLServiceToLoad(); + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOverlayId); + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kActiveTab); + + const GURL second_url = embedded_test_server()->GetURL(kDocumentWithVideo); + auto* const browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + + const DeepQuery kPathToRegionSelection{ + "lens-overlay-app", + "lens-selection-overlay", + "#regionSelectionLayer", + }; + + auto off_center_point = base::BindLambdaForTesting([browser_view]() { + gfx::Point off_center = + browser_view->contents_web_view()->bounds().CenterPoint(); + off_center.Offset(100, 100); + return off_center; + }); + + RunTestSequence( + // Open lens overlay. + OpenLensOverlay(), + + // The overlay controller is an independent floating widget associated + // with a tab rather than a browser window, so by convention gets its own + // element context. + InAnyContext( + InstrumentNonTabWebView(kOverlayId, + LensOverlayController::kOverlayId), + WaitForWebContentsReady( + kOverlayId, GURL(chrome::kChromeUILensOverlayUntrustedURL))), + + // Wait for the webview to finish loading to prevent re-entrancy. Then do + // a drag offset from the center. + InSameContext(WaitForShow(LensOverlayController::kOverlayId), + WaitForScreenshotRendered(kOverlayId), + EnsurePresent(kOverlayId, kPathToRegionSelection), + MoveMouseTo(LensOverlayController::kOverlayId), + DragMouseTo(off_center_point)), + + // The drag should have opened the side panel with the results frame. + WaitForShow(LensOverlayController::kOverlaySidePanelWebViewId), + + // Navigate to another page in the same tab. + // The user navigates to a webpage. + InAnyContext(InstrumentTab(kActiveTab), + NavigateWebContents(kActiveTab, second_url)), + + // Ensure overlay is not visible but side panel is. + WaitForHide(kOverlayId), + EnsureNotPresent(kOverlayId), + EnsurePresent(LensOverlayController::kOverlaySidePanelWebViewId)); +} + +// This tests the following CUJ: +// (1) User navigates to a website. // (2) User opens lens overlay. // (3) User searches a region and the side panel opens. // (4) User clicks the close button.
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc index 152ca7ed..d2a964b 100644 --- a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc +++ b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
@@ -222,8 +222,8 @@ // also adds an additional check to make sure the text query parameters // match. if (lens::IsValidSearchResultsUrl(nav_url)) { - auto page_url_text_query = lens::GetTextQueryParameterValue(page_url); - auto nav_url_text_query = lens::GetTextQueryParameterValue(nav_url); + auto page_url_text_query = lens::ExtractTextQueryParameterValue(page_url); + auto nav_url_text_query = lens::ExtractTextQueryParameterValue(nav_url); if (page_url.host() != nav_url.host() || page_url.path() != nav_url.path() || page_url_text_query != nav_url_text_query) { @@ -279,7 +279,7 @@ // A search URL without a Lens mode parameter indicates a click on a related // search or other in-SRP refinement. In this case, we should clear all // selection and thumbnail state. - const std::string lens_mode = lens::GetLensModeParameterValue(search_url); + const std::string lens_mode = lens::ExtractLensModeParameterValue(search_url); if (lens_mode.empty()) { GetLensOverlayController()->SetAdditionalSearchQueryParams( /*additional_search_query_params=*/{});
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.cc b/chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.cc index d2f50f9..30fa932 100644 --- a/chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.cc +++ b/chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.cc
@@ -111,7 +111,7 @@ // This is the only time a query is guaranteed to end up in the side panel // for a user navigation.If the SRP url did not have the common search query // parameters, it will reload the frame and go through this flow anyway. - const std::string text_query = GetTextQueryParameterValue(url); + const std::string text_query = ExtractTextQueryParameterValue(url); controller->results_side_panel_coordinator()->NotifyNewQueryLoaded( std::move(text_query), navigation_handle()->GetURL()); return content::NavigationThrottle::PROCEED;
diff --git a/chrome/browser/ui/lens/lens_overlay_url_builder.cc b/chrome/browser/ui/lens/lens_overlay_url_builder.cc index 3d95c75..ec6da23 100644 --- a/chrome/browser/ui/lens/lens_overlay_url_builder.cc +++ b/chrome/browser/ui/lens/lens_overlay_url_builder.cc
@@ -375,13 +375,13 @@ return url_with_query_params; } -const std::string GetTextQueryParameterValue(const GURL& url) { +const std::string ExtractTextQueryParameterValue(const GURL& url) { std::string param_value = ""; net::GetValueForKeyInQuery(url, kTextQueryParameterKey, ¶m_value); return param_value; } -const std::string GetLensModeParameterValue(const GURL& url) { +const std::string ExtractLensModeParameterValue(const GURL& url) { std::string param_value = ""; net::GetValueForKeyInQuery(url, kLensModeParameterKey, ¶m_value); return param_value;
diff --git a/chrome/browser/ui/lens/lens_overlay_url_builder.h b/chrome/browser/ui/lens/lens_overlay_url_builder.h index c73bda1..22cb9b4 100644 --- a/chrome/browser/ui/lens/lens_overlay_url_builder.h +++ b/chrome/browser/ui/lens/lens_overlay_url_builder.h
@@ -61,11 +61,11 @@ // Returns the value of the text query parameter value from the provided search // URL if any. Empty string otherwise. -const std::string GetTextQueryParameterValue(const GURL& url); +const std::string ExtractTextQueryParameterValue(const GURL& url); // Returns the value of the lens mode parameter value from the provided search // URL if any. Empty string otherwise. -const std::string GetLensModeParameterValue(const GURL& url); +const std::string ExtractLensModeParameterValue(const GURL& url); // Returns true if the two URLs have the same base url, and the same query // parameters. This differs from comparing two GURLs using == since this method
diff --git a/chrome/browser/ui/lens/lens_permission_bubble_controller.cc b/chrome/browser/ui/lens/lens_permission_bubble_controller.cc index b03d6b2..6f47e1dc 100644 --- a/chrome/browser/ui/lens/lens_permission_bubble_controller.cc +++ b/chrome/browser/ui/lens/lens_permission_bubble_controller.cc
@@ -182,8 +182,9 @@ l10n_util::GetStringUTF16(lens::GetLensOverlayEntrypointLabelAltIds( IDS_LENS_PERMISSION_BUBBLE_DIALOG_TITLE))) #if BUILDFLAG(GOOGLE_CHROME_BRANDING) - .SetIcon(ui::ImageModel::FromVectorIcon(vector_icons::kGoogleColorIcon, - ui::kColorIcon, 20)) + .SetIcon(ui::ImageModel::FromImageSkia( + *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_GOOGLE_G_GRADIENT_20))) .SetBannerImage(ui::ImageModel::FromImageSkia( *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( lens::features::IsLensOverlayPermissionBubbleAltEnabled()
diff --git a/chrome/browser/ui/lens/lens_search_controller.cc b/chrome/browser/ui/lens/lens_search_controller.cc index a14b5b3..a47877a 100644 --- a/chrome/browser/ui/lens/lens_search_controller.cc +++ b/chrome/browser/ui/lens/lens_search_controller.cc
@@ -206,7 +206,8 @@ CHECK(invocation_source == lens::LensOverlayInvocationSource::kOmniboxContextualSuggestion); - std::string query_text = lens::GetTextQueryParameterValue(destination_url); + std::string query_text = + lens::ExtractTextQueryParameterValue(destination_url); std::map<std::string, std::string> additional_query_parameters = lens::GetParametersMapWithoutQuery(destination_url);
diff --git a/chrome/browser/ui/lens/lens_searchbox_controller.cc b/chrome/browser/ui/lens/lens_searchbox_controller.cc index 8f799b4..dd1c6ad 100644 --- a/chrome/browser/ui/lens/lens_searchbox_controller.cc +++ b/chrome/browser/ui/lens/lens_searchbox_controller.cc
@@ -281,7 +281,7 @@ AutocompleteMatchType::Type match_type, bool is_zero_prefix_suggestion) { base::Time query_start_time = base::Time::Now(); - std::string query_text = GetTextQueryParameterValue(destination_url); + std::string query_text = ExtractTextQueryParameterValue(destination_url); std::map<std::string, std::string> additional_query_parameters = GetParametersMapWithoutQuery(destination_url);
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc index 1bc64b9..fe98b9d 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -772,11 +772,17 @@ text, "match", match, "alternative_nav_match", alternative_nav_match); + std::string extra_headers; + for (const auto& header : match.extra_headers) { + base::StrAppend(&extra_headers, + {header.first, ": ", header.second, "\r\n"}); + } + // Store the details necessary to open the omnibox match via browser commands. location_bar_->set_navigation_params(LocationBar::NavigationParams( destination_url, disposition, transition, match_selection_timestamp, destination_url_entered_without_scheme, - destination_url_entered_with_http_scheme, match.extra_headers)); + destination_url_entered_with_http_scheme, extra_headers)); if (browser_) { auto navigation = chrome::OpenCurrentURL(browser_);
diff --git a/chrome/browser/ui/startup/default_browser_prompt/BUILD.gn b/chrome/browser/ui/startup/default_browser_prompt/BUILD.gn index 15a1e579..a4c6e62 100644 --- a/chrome/browser/ui/startup/default_browser_prompt/BUILD.gn +++ b/chrome/browser/ui/startup/default_browser_prompt/BUILD.gn
@@ -53,9 +53,9 @@ "//chrome/browser/ui:ui_features", "//chrome/browser/ui/browser_window", "//components/infobars/core", - "//components/prefs", "//components/omnibox/browser", "//components/omnibox/browser:vector_icons", + "//components/prefs", "//components/vector_icons", "//content/public/common", "//ui/base",
diff --git a/chrome/browser/ui/tabs/tab_strip_api/adapters/tree_builder/tab_collection_walker.cc b/chrome/browser/ui/tabs/tab_strip_api/adapters/tree_builder/tab_collection_walker.cc index 227bd081..7b6a9df 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/adapters/tree_builder/tab_collection_walker.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/adapters/tree_builder/tab_collection_walker.cc
@@ -17,7 +17,7 @@ mojom::TabCollectionContainerPtr TabCollectionWalker::Walk() const { auto mojo_tab_collection = - tabs_api::converters::BuildMojoTabCollection(target_); + tabs_api::converters::BuildMojoTabCollection(target_->GetHandle()); auto mojo_tab_collection_container = tabs_api::mojom::TabCollectionContainer::New(); mojo_tab_collection_container->collection = std::move(mojo_tab_collection);
diff --git a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc index 3d8c2bc..8922029 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc
@@ -36,7 +36,8 @@ } tabs_api::mojom::TabCollectionPtr BuildMojoTabCollection( - const tabs::TabCollection* collection) { + tabs::TabCollectionHandle handle) { + const tabs::TabCollection* collection = handle.Get(); CHECK(collection); auto node_id = tabs_api::NodeId( tabs_api::NodeId::Type::kCollection,
diff --git a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.h b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.h index 4f959b6..0cc3f3c84 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.h +++ b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.h
@@ -15,8 +15,11 @@ tabs_api::mojom::TabPtr BuildMojoTab(tabs::TabHandle handle, const TabRendererData& data); +// Builds a mojom::TabCollectionPtr based off a TabCollection. +// Note: Handle must be valid and point to a live TabCollection. There is a +// CHECK to enforce that precondition. tabs_api::mojom::TabCollectionPtr BuildMojoTabCollection( - const tabs::TabCollection* collection); + tabs::TabCollectionHandle handle); } // namespace tabs_api::converters
diff --git a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters_unittest.cc b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters_unittest.cc index ddc587d..21756a7 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters_unittest.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters_unittest.cc
@@ -39,7 +39,7 @@ FakeTabCollection collection(tabs::TabCollection::Type::TABSTRIP); const std::string expected_id = base::NumberToString(collection.GetHandle().raw_value()); - auto mojo = BuildMojoTabCollection(&collection); + auto mojo = BuildMojoTabCollection(collection.GetHandle()); ASSERT_TRUE(mojo->is_tab_strip());
diff --git a/chrome/browser/ui/tabs/tab_strip_api/events/event_transformation.cc b/chrome/browser/ui/tabs/tab_strip_api/events/event_transformation.cc index aa96d303..8610571 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/events/event_transformation.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/events/event_transformation.cc
@@ -83,7 +83,7 @@ tab_group_change.group); auto event = mojom::OnTabGroupCreatedEvent::New(); event->tab_collection = tabs_api::converters::BuildMojoTabCollection( - tab_group->GetCollectionHandle().Get()); + tab_group->GetCollectionHandle()); // TODO(crbug.com/412935315): Set the correct position. event->position = tabs_api::Position(0, NodeId::FromTabGroupId(tab_group_change.group)); @@ -130,7 +130,7 @@ tab_group_change.group); auto event = mojom::OnTabGroupVisualsChangedEvent::New(); event->tab_collection = tabs_api::converters::BuildMojoTabCollection( - tab_group->GetCollectionHandle().Get()); + tab_group->GetCollectionHandle()); return event; }
diff --git a/chrome/browser/ui/toasts/toast_service.cc b/chrome/browser/ui/toasts/toast_service.cc index 3d1f7828..ab3f6d7 100644 --- a/chrome/browser/ui/toasts/toast_service.cc +++ b/chrome/browser/ui/toasts/toast_service.cc
@@ -106,8 +106,8 @@ // updated. toast_registry_->RegisterToast( ToastId::kNonMilestoneUpdate, - ToastSpecification::Builder(kLinkChromeRefreshIcon, - IDS_LINK_COPIED_TOAST_BODY) + ToastSpecification::Builder(kBrowserLogoIcon, + IDS_NON_MILESTONE_UPDATE_TOAST_BODY) .AddGlobalScoped() .Build());
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 15118e5..647b359 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -159,6 +159,12 @@ MiniToolbarActiveConfiguration::ShowMenu, &kMiniToolbarActiveConfigurationOptions); +BASE_FEATURE_PARAM(int, + kSideBySideSnapDistance, + &kSideBySide, + "snap_distance", + 5); + // When enabled along with SideBySide flag, split tabs will be restored on // startup. BASE_FEATURE(kSideBySideSessionRestore, @@ -605,4 +611,12 @@ "NonMilestoneUpdateToast", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kBookmarkTabGroupConversion, + "BookmarkTabGroupConversion", + base::FEATURE_DISABLED_BY_DEFAULT); + +bool IsBookmarkTabGroupConversionEnabled() { + return base::FeatureList::IsEnabled(kBookmarkTabGroupConversion); +} + } // namespace features
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index d1d8069..c3035c1 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -158,6 +158,8 @@ BASE_DECLARE_FEATURE_PARAM(MiniToolbarActiveConfiguration, kSideBySideMiniToolbarActiveConfiguration); +BASE_DECLARE_FEATURE_PARAM(int, kSideBySideSnapDistance); + BASE_DECLARE_FEATURE(kSideBySideSessionRestore); bool IsRestoringSplitViewEnabled(); @@ -365,6 +367,11 @@ // Controls whether to show a toast for Chrome non milestone update. BASE_DECLARE_FEATURE(kNonMilestoneUpdateToast); +// Controls whether the updated bookmark and tab group conversion is enabled. +BASE_DECLARE_FEATURE(kBookmarkTabGroupConversion); + +bool IsBookmarkTabGroupConversionEnabled(); + } // namespace features #endif // CHROME_BROWSER_UI_UI_FEATURES_H_
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc index c35e562..d2bcee0 100644 --- a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc +++ b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
@@ -317,7 +317,14 @@ main_document_response_; }; -IN_PROC_BROWSER_TEST_P(FileSystemAccessBrowserSlowLoadTest, WaitUntilLoaded) { +// TODO(crbug.com/435037306): Flaky on Mac. +#if BUILDFLAG(IS_MAC) +#define MAYBE_WaitUntilLoaded DISABLED_WaitUntilLoaded +#else +#define MAYBE_WaitUntilLoaded WaitUntilLoaded +#endif +IN_PROC_BROWSER_TEST_P(FileSystemAccessBrowserSlowLoadTest, + MAYBE_WaitUntilLoaded) { const base::FilePath test_file = CreateTestFile(""); const std::string file_contents = "file contents to write";
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc index 373c21cb..702af24 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -76,11 +76,8 @@ BrowserFrameActiveState active_state) const { DCHECK(browser_view_->GetSupportsTabStrip()); - TabStrip* const tab_strip = browser_view_->tabstrip(); - const bool active = ShouldPaintAsActiveForState(active_state); - const std::optional<int> bg_id = - tab_strip->GetCustomBackgroundId(active_state); + const std::optional<int> bg_id = GetCustomBackgroundId(active_state); if (bg_id.has_value()) { // If the theme has a custom tab background image, assume tab shapes are // visible. This is pessimistic; the theme may use the same image as the
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.h b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.h index 55a18ef7..5abf84a 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.h
@@ -9,6 +9,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "components/remote_cocoa/common/native_widget_ns_window.mojom.h" @@ -104,9 +105,6 @@ // views::ViewObserver implementation void OnViewBoundsChanged(views::View* observed_view) override; - // views::WidgetObserver implementation - void OnWidgetDestroying(views::Widget* widget) override; - // views::Traversable: views::FocusSearch* GetFocusSearch() override; views::FocusTraversable* GetFocusTraversableParent() override; @@ -133,13 +131,14 @@ gfx::Insets GetTabStripRegionViewInsets(); + // Invoked when the associated browser is closed. + void BrowserDidClose(BrowserWindowInterface* browser); + raw_ptr<BrowserView> browser_view_ = nullptr; // weak std::unique_ptr<ImmersiveRevealedLock> focus_lock_; bool enabled_ = false; base::ScopedObservation<views::View, views::ViewObserver> top_container_observation_{this}; - base::ScopedObservation<views::Widget, views::WidgetObserver> - browser_frame_observation_{this}; ImmersiveModeOverlayWidgetObserver overlay_widget_observer_{this}; base::ScopedObservation<views::Widget, views::WidgetObserver> overlay_widget_observation_{&overlay_widget_observer_}; @@ -171,6 +170,8 @@ // space reserved for it) and the "Always Show Menu Bar" system setting. int menu_bar_height_ = 0; + std::optional<base::CallbackListSubscription> browser_close_subscription_; + std::unique_ptr<views::BoundsAnimator> tab_bounds_animator_ = nullptr; base::WeakPtrFactory<ImmersiveModeControllerMac> weak_ptr_factory_;
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm index 722dfc0..3a06e5a 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm
@@ -91,6 +91,10 @@ void ImmersiveModeControllerMac::Init(BrowserView* browser_view) { browser_view_ = browser_view; focus_search_ = std::make_unique<ImmersiveModeFocusSearchMac>(browser_view); + browser_close_subscription_ = + browser_view_->browser()->RegisterBrowserDidClose( + base::BindRepeating(&ImmersiveModeControllerMac::BrowserDidClose, + base::Unretained(this))); } void ImmersiveModeControllerMac::SetEnabled(bool enabled) { @@ -123,7 +127,6 @@ SetTabNativeWidgetID(tab_overlay_host->bridged_native_widget_id()); } top_container_observation_.Observe(browser_view_->top_container()); - browser_frame_observation_.Observe(browser_view_->GetWidget()); overlay_widget_observation_.Observe(browser_view_->overlay_widget()); // Capture the overlay content view before enablement. Once enabled the view @@ -198,7 +201,6 @@ browser_view_->tab_strip_region_view(), 0); } top_container_observation_.Reset(); - browser_frame_observation_.Reset(); overlay_widget_observation_.Reset(); // Notify BrowserView about the fullscreen exit so that the top container @@ -243,6 +245,11 @@ : gfx::Insets::TLBR(1, 0, 0, right_left_inset); } +void ImmersiveModeControllerMac::BrowserDidClose( + BrowserWindowInterface* browser) { + SetEnabled(false); +} + bool ImmersiveModeControllerMac::IsEnabled() const { return enabled_; } @@ -364,10 +371,6 @@ } } -void ImmersiveModeControllerMac::OnWidgetDestroying(views::Widget* widget) { - SetEnabled(false); -} - void ImmersiveModeControllerMac::LockDestroyed() { if (auto* window = GetNSWindowMojo()) { window->ImmersiveFullscreenRevealUnlock();
diff --git a/chrome/browser/ui/views/frame/multi_contents_view.cc b/chrome/browser/ui/views/frame/multi_contents_view.cc index 31c94f5..809df54 100644 --- a/chrome/browser/ui/views/frame/multi_contents_view.cc +++ b/chrome/browser/ui/views/frame/multi_contents_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/frame/multi_contents_view.h" #include <algorithm> +#include <cstdlib> #include "base/check_deref.h" #include "base/feature_list.h" @@ -231,22 +232,36 @@ initial_start_width_on_resize_ = std::make_optional(contents_container_views_[0]->size().width()); } - double total_width = contents_container_views_[0]->size().width() + contents_container_views_[0]->GetInsets().width() + contents_container_views_[1]->size().width() + contents_container_views_[1]->GetInsets().width(); - double start_ratio = (initial_start_width_on_resize_.value() + - contents_container_views_[0]->GetInsets().width() + - static_cast<double>(resize_amount)) / - total_width; - delegate_->ResizeWebContents(start_ratio, done_resizing); + double end_width = (initial_start_width_on_resize_.value() + + contents_container_views_[0]->GetInsets().width() + + static_cast<double>(resize_amount)); + + // If end_width is within the snap point widths, update to the snap point. + delegate_->ResizeWebContents( + CalculateRatioWithSnapPoints(end_width, total_width), done_resizing); if (done_resizing) { initial_start_width_on_resize_ = std::nullopt; } } +double MultiContentsView::CalculateRatioWithSnapPoints( + double end_width, + double total_width) const { + for (const double& snap_point : snap_points_) { + double dp_snap_point = snap_point * total_width; + if (std::abs(dp_snap_point - end_width) < + features::kSideBySideSnapDistance.Get()) { + return snap_point; + } + } + return end_width / total_width; +} + void MultiContentsView::OnPaint(gfx::Canvas* canvas) { // Paint the multi contents area background to match the toolbar. TopContainerBackground::PaintBackground(canvas, this, browser_view_);
diff --git a/chrome/browser/ui/views/frame/multi_contents_view.h b/chrome/browser/ui/views/frame/multi_contents_view.h index 30fe420..b5b01411 100644 --- a/chrome/browser/ui/views/frame/multi_contents_view.h +++ b/chrome/browser/ui/views/frame/multi_contents_view.h
@@ -11,6 +11,7 @@ #include "base/callback_list.h" #include "base/functional/callback_forward.h" #include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/contents_container_view.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/metadata/metadata_header_macros.h" @@ -182,6 +183,9 @@ void UpdateContentsBorderAndOverlay(); + double CalculateRatioWithSnapPoints(double end_width, + double total_width) const; + raw_ptr<BrowserView> browser_view_; std::unique_ptr<MultiContentsViewDelegate> delegate_; @@ -234,6 +238,10 @@ bool is_drag_and_drop_enabled_ = true; std::optional<int> min_contents_width_for_testing_ = std::nullopt; + + // Width ratios that a split view will snap to when resize is within a + // snap distance (kSideBySideSnapDistance). + std::vector<double> snap_points_ = {0.5}; }; #endif // CHROME_BROWSER_UI_VIEWS_FRAME_MULTI_CONTENTS_VIEW_H_
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc index bf52d6a1..98f7714 100644 --- a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/functional/bind.h" #include "base/numerics/clamped_math.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" @@ -35,6 +36,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "third_party/blink/public/common/input/web_mouse_event.h" +#include "ui/base/interaction/state_observer.h" #include "ui/events/base_event_utils.h" #include "ui/events/event_modifiers.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -100,18 +102,17 @@ return result; } - auto CheckResizeValues(base::RepeatingCallback<bool(double, double)> check) { - // MultiContentsView overrides Layout, causing an edge case where resizes - // don't take effect until the next layout pass. Use PollView and - // WaitForState to wait for the expected layout pass to be completed. - using MultiContentsViewLayoutObserver = - views::test::PollingViewObserver<bool, MultiContentsView>; - DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewLayoutObserver, - kMultiContentsViewLayoutObserver); + // MultiContentsView overrides Layout, causing an edge case where resizes + // don't take effect until the next layout pass. Use PollView and + // WaitForState to wait for the expected layout pass to be completed. + using MultiContentsViewLayoutObserver = + views::test::PollingViewObserver<bool, MultiContentsView>; + auto CheckResizeValues( + base::RepeatingCallback<bool(double, double)> check, + ui::test::StateIdentifier<MultiContentsViewLayoutObserver> observer_id) { auto result = Steps( - PollView(kMultiContentsViewLayoutObserver, - MultiContentsView::kMultiContentsViewElementId, + PollView(observer_id, MultiContentsView::kMultiContentsViewElementId, [check](const MultiContentsView* multi_contents_view) -> bool { double start_width = multi_contents_view->start_contents_view_for_testing() @@ -125,7 +126,7 @@ .width(); return check.Run(start_width, end_width); }), - WaitForState(kMultiContentsViewLayoutObserver, true)); + WaitForState(observer_id, true)); AddDescriptionPrefix(result, "CheckResizeValues()"); return result; } @@ -133,11 +134,26 @@ // Perform a check on the contents view sizes following a direct resize call auto CheckResize(int resize_amount, base::RepeatingCallback<bool(double, double)> check) { + DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewLayoutObserver, + kMultiContentsViewLayoutObserver); + auto result = + Steps(Do([resize_amount, this]() { + multi_contents_view()->OnResize(resize_amount, true); + }), + CheckResizeValues(check, kMultiContentsViewLayoutObserver)); + AddDescriptionPrefix(result, "CheckResize()"); + return result; + } + + auto CheckResizeWithId( + int resize_amount, + base::RepeatingCallback<bool(double, double)> check, + ui::test::StateIdentifier<MultiContentsViewLayoutObserver> observer_id) { auto result = Steps(Do([resize_amount, this]() { multi_contents_view()->OnResize(resize_amount, true); }), - CheckResizeValues(check)); - AddDescriptionPrefix(result, "CheckResize()"); + CheckResizeValues(check, observer_id)); + AddDescriptionPrefix(result, "CheckResizeWithId()"); return result; } @@ -145,13 +161,15 @@ // resize auto CheckResizeKey(ui::KeyboardCode key_code, base::RepeatingCallback<bool(double, double)> check) { + DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewLayoutObserver, + kMultiContentsViewLayoutObserver); auto result = Steps( FocusElement( MultiContentsResizeHandle::kMultiContentsResizeHandleElementId), SendKeyPress( MultiContentsResizeHandle::kMultiContentsResizeHandleElementId, key_code), - CheckResizeValues(check)); + CheckResizeValues(check, kMultiContentsViewLayoutObserver)); AddDescriptionPrefix(result, "CheckResizeKey()"); return result; } @@ -380,6 +398,33 @@ }))); } +IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, ResizesToSnapPointWidth) { + DEFINE_LOCAL_STATE_IDENTIFIER_VALUE( + MultiContentsViewLayoutObserver, + kMultiContentsViewLayoutInitialResizeObserver); + DEFINE_LOCAL_STATE_IDENTIFIER_VALUE( + MultiContentsViewLayoutObserver, + kMultiContentsViewLayoutSnapResizeObserver); + + RunTestSequence( + CreateTabsAndEnterSplitView(), ResizeWindow(1000), + // Resize outside of the snap point width + CheckResizeWithId( + 100, base::BindRepeating([](double start_width, double end_width) { + // Rounding differences mean this width is only changed by 199 + // instead of 200. + return start_width == end_width + 199; + }), + kMultiContentsViewLayoutInitialResizeObserver), + // Resize back to within the snap point margin and snap back to 50% width + CheckResizeWithId( + -96, base::BindRepeating([](double start_width, double end_width) { + // On large window, uses snap point width. + return end_width == start_width; + }), + kMultiContentsViewLayoutSnapResizeObserver)); +} + // TODO(crbug.com/399212996): Flaky on linux_chromium_asan_rel_ng, linux-rel // and linux-chromeos-rel. #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index a8b5c87..3ed249ac9 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -394,6 +394,9 @@ toolbar_divider_->SetPreferredSize( gfx::Size(GetLayoutConstant(TOOLBAR_DIVIDER_WIDTH), GetLayoutConstant(TOOLBAR_DIVIDER_HEIGHT))); + toolbar_divider_->SetBackground(views::CreateRoundedRectBackground( + kColorToolbarExtensionSeparatorEnabled, + GetLayoutConstant(TOOLBAR_DIVIDER_CORNER_RADIUS))); } pinned_toolbar_actions_container_ = container_view_->AddChildView( @@ -852,14 +855,6 @@ if (display_mode_ == DisplayMode::NORMAL) { LoadImages(); - - if (toolbar_divider_) { - const SkColor toolbar_extension_separator_color = - GetColorProvider()->GetColor(kColorToolbarExtensionSeparatorEnabled); - toolbar_divider_->SetBackground(views::CreateRoundedRectBackground( - toolbar_extension_separator_color, - GetLayoutConstant(TOOLBAR_DIVIDER_CORNER_RADIUS))); - } } SchedulePaint(); @@ -1266,8 +1261,8 @@ void ToolbarView::UpdateRecedingCornerRadius() { bool tab_strip_has_trailing_frame_buttons = - (browser_view_->tabstrip()->controller()->IsFrameButtonsRightAligned() ^ - base::i18n::IsRTL()); + browser_view_->tabstrip()->controller()->IsFrameButtonsRightAligned() ^ + base::i18n::IsRTL(); bool tab_strip_has_leading_action_buttons = (!tabs::GetTabSearchTrailingTabstrip(browser()->profile()) && !features::HasTabSearchToolbarButton());
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn index 9334063..f0ac821 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn +++ b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
@@ -8,8 +8,6 @@ static_library("search") { sources = [ - "google_assistant_handler.cc", - "google_assistant_handler.h", "magic_boost_notice_handler.cc", "magic_boost_notice_handler.h", "magic_boost_notice_page_handler_factory.cc", @@ -31,17 +29,14 @@ "//ash/constants", "//chrome/app:generated_resources", "//chrome/browser:browser_public_dependencies", - "//chrome/browser/ash/assistant", "//chrome/browser/ash/input_method", "//chrome/browser/ash/lobster", "//chrome/browser/ash/magic_boost", "//chrome/browser/profiles:profile", - "//chrome/browser/ui/webui/ash/assistant_optin", "//chrome/browser/ui/webui/ash/settings/search", "//chrome/common", "//chromeos/ash/experiences/arc", "//chromeos/ash/experiences/arc/session", - "//chromeos/ash/services/assistant/public/cpp", "//chromeos/components/mahi/public/cpp", "//chromeos/constants", "//components/language/core/browser",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/DEPS b/chrome/browser/ui/webui/ash/settings/pages/search/DEPS index 5f893bc..810b3ad 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/search/DEPS +++ b/chrome/browser/ui/webui/ash/settings/pages/search/DEPS
@@ -10,7 +10,6 @@ # Existing dependencies within //chrome. There is an active effort to # refactor //chrome/browser/ui/ash to break these dependencies; see b/332804822. # Whenever possible, avoid adding new //chrome dependencies to this list. - "+chrome/browser/ash/assistant", "+chrome/browser/ash/input_method", "+chrome/browser/ash/magic_boost", "+chrome/browser/ash/lobster/lobster_service.h", @@ -19,7 +18,6 @@ "+chrome/browser/ash/login/users/fake_chrome_user_manager.h", "+chrome/browser/profiles/profile.h", "+chrome/browser/search_engines", - "+chrome/browser/ui/webui/ash/assistant_optin", "+chrome/browser/ui/webui/ash/settings/pages", "+chrome/browser/ui/webui/ash/settings/search", "+chrome/browser/ui/webui/settings",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.cc b/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.cc deleted file mode 100644 index 8b61875..0000000 --- a/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.cc +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.h" - -#include <utility> - -#include "ash/public/cpp/assistant/assistant_setup.h" -#include "ash/public/cpp/assistant/controller/assistant_controller.h" -#include "base/functional/bind.h" -#include "base/functional/callback_helpers.h" -#include "base/values.h" -#include "chrome/browser/ui/webui/ash/assistant_optin/assistant_optin_ui.h" -#include "chromeos/ash/components/audio/cras_audio_handler.h" -#include "chromeos/ash/experiences/arc/arc_prefs.h" -#include "chromeos/ash/experiences/arc/session/arc_service_manager.h" -#include "chromeos/ash/services/assistant/public/cpp/assistant_service.h" -#include "content/public/browser/browser_context.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash::settings { - -GoogleAssistantHandler::GoogleAssistantHandler() { - CrasAudioHandler::Get()->AddAudioObserver(this); -} - -GoogleAssistantHandler::~GoogleAssistantHandler() { - CrasAudioHandler::Get()->RemoveAudioObserver(this); -} - -void GoogleAssistantHandler::OnJavascriptAllowed() { - if (pending_hotword_update_) { - OnAudioNodesChanged(); - } -} - -void GoogleAssistantHandler::OnJavascriptDisallowed() {} - -void GoogleAssistantHandler::OnAudioNodesChanged() { - if (!IsJavascriptAllowed()) { - pending_hotword_update_ = true; - return; - } - - pending_hotword_update_ = false; - FireWebUIListener("hotwordDeviceUpdated", - base::Value(CrasAudioHandler::Get()->HasHotwordDevice())); -} - -void GoogleAssistantHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "showGoogleAssistantSettings", - base::BindRepeating( - &GoogleAssistantHandler::HandleShowGoogleAssistantSettings, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "retrainAssistantVoiceModel", - base::BindRepeating(&GoogleAssistantHandler::HandleRetrainVoiceModel, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "syncVoiceModelStatus", - base::BindRepeating(&GoogleAssistantHandler::HandleSyncVoiceModelStatus, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "initializeGoogleAssistantPage", - base::BindRepeating(&GoogleAssistantHandler::HandleInitialized, - base::Unretained(this))); -} - -void GoogleAssistantHandler::HandleShowGoogleAssistantSettings( - const base::Value::List& args) { - CHECK_EQ(0U, args.size()); - AssistantController::Get()->OpenAssistantSettings(); -} - -void GoogleAssistantHandler::HandleRetrainVoiceModel( - const base::Value::List& args) { - CHECK_EQ(0U, args.size()); - AssistantOptInDialog::Show(FlowType::kSpeakerIdRetrain, base::DoNothing()); -} - -void GoogleAssistantHandler::HandleSyncVoiceModelStatus( - const base::Value::List& args) { - CHECK_EQ(0U, args.size()); - - auto* settings = assistant::AssistantSettings::Get(); - if (settings) { - settings->SyncSpeakerIdEnrollmentStatus(); - } -} - -void GoogleAssistantHandler::HandleInitialized(const base::Value::List& args) { - CHECK_EQ(0U, args.size()); - AllowJavascript(); -} - -} // namespace ash::settings
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.h b/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.h deleted file mode 100644 index 472f0391..0000000 --- a/chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_SEARCH_GOOGLE_ASSISTANT_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_SEARCH_GOOGLE_ASSISTANT_HANDLER_H_ - -#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "chromeos/ash/components/audio/cras_audio_handler.h" - -namespace ash::settings { - -class GoogleAssistantHandler : public ::settings::SettingsPageUIHandler, - CrasAudioHandler::AudioObserver { - public: - GoogleAssistantHandler(); - - GoogleAssistantHandler(const GoogleAssistantHandler&) = delete; - GoogleAssistantHandler& operator=(const GoogleAssistantHandler&) = delete; - - ~GoogleAssistantHandler() override; - - void RegisterMessages() override; - void OnJavascriptAllowed() override; - void OnJavascriptDisallowed() override; - - // CrasAudioHandler::AudioObserver overrides - void OnAudioNodesChanged() override; - - private: - // WebUI call to launch into the Google Assistant app settings. - void HandleShowGoogleAssistantSettings(const base::Value::List& args); - // WebUI call to retrain Assistant voice model. - void HandleRetrainVoiceModel(const base::Value::List& args); - // WebUI call to sync Assistant voice model status. - void HandleSyncVoiceModelStatus(const base::Value::List& args); - // WebUI call to signal js side is ready. - void HandleInitialized(const base::Value::List& args); - - bool pending_hotword_update_ = false; - - base::WeakPtrFactory<GoogleAssistantHandler> weak_factory_{this}; -}; - -} // namespace ash::settings - -#endif // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_SEARCH_GOOGLE_ASSISTANT_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc index 598a167..39df18b 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc
@@ -10,27 +10,21 @@ #include "ash/constants/ash_features.h" #include "ash/constants/url_constants.h" #include "ash/lobster/lobster_controller.h" -#include "ash/public/cpp/assistant/assistant_state.h" #include "ash/public/cpp/capture_mode/capture_mode_api.h" #include "ash/scanner/scanner_controller.h" #include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ash/assistant/assistant_util.h" #include "chrome/browser/ash/input_method/editor_mediator_factory.h" #include "chrome/browser/ash/lobster/lobster_service.h" #include "chrome/browser/ash/lobster/lobster_service_provider.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/ash/assistant_optin/assistant_optin_utils.h" -#include "chrome/browser/ui/webui/ash/settings/pages/search/google_assistant_handler.h" #include "chrome/browser/ui/webui/ash/settings/search/search_concept.h" #include "chrome/browser/ui/webui/ash/settings/search/search_tag_registry.h" #include "chrome/browser/ui/webui/settings/search_engines_handler.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" -#include "chromeos/ash/services/assistant/public/cpp/assistant_prefs.h" -#include "chromeos/ash/services/assistant/public/cpp/features.h" #include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h" #include "chromeos/components/mahi/public/cpp/mahi_manager.h" #include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" @@ -47,7 +41,6 @@ namespace ash::settings { namespace mojom { -using ::chromeos::settings::mojom::kAssistantSubpagePath; using ::chromeos::settings::mojom::kSearchSubpagePath; using ::chromeos::settings::mojom::kSystemPreferencesSectionPath; using ::chromeos::settings::mojom::Section; @@ -184,84 +177,6 @@ return tags; } -base::span<const SearchConcept> GetAssistantSearchConcepts() { - static constexpr auto tags = std::to_array<SearchConcept>({ - {IDS_OS_SETTINGS_TAG_ASSISTANT, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSubpage, - {.subpage = mojom::Subpage::kAssistant}}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantOkGoogle}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT1, - IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT2, - SearchConcept::kAltTagEnd}}, - }); - return tags; -} - -base::span<const SearchConcept> GetAssistantOnSearchConcepts() { - static constexpr auto tags = std::to_array<SearchConcept>({ - {IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_OFF, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantOnOff}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_OFF_ALT1, - SearchConcept::kAltTagEnd}}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_PREFERRED_INPUT, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kLow, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantVoiceInput}}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_NOTIFICATIONS, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kLow, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantNotifications}}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_RELATED_INFO, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kLow, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantRelatedInfo}}, - }); - return tags; -} - -base::span<const SearchConcept> GetAssistantOffSearchConcepts() { - static constexpr auto tags = std::to_array<SearchConcept>({ - {IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_ON, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kAssistantOnOff}, - {IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_ON_ALT1, SearchConcept::kAltTagEnd}}, - }); - return tags; -} - -base::span<const SearchConcept> GetAssistantVoiceMatchSearchConcepts() { - static constexpr auto tags = std::to_array<SearchConcept>({ - {IDS_OS_SETTINGS_TAG_ASSISTANT_TRAIN_VOICE_MODEL, - mojom::kAssistantSubpagePath, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kLow, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kTrainAssistantVoiceModel}}, - }); - return tags; -} - base::span<const SearchConcept> GetMagicBoostSearchConcepts() { static constexpr auto tags = std::to_array<SearchConcept>({ {IDS_OS_SETTINGS_TAG_MAGIC_BOOST, @@ -298,10 +213,6 @@ return tags; } -bool IsVoiceMatchAllowed() { - return !assistant::features::IsVoiceMatchDisabled(); -} - void AddQuickAnswersStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"quickAnswersEnable", IDS_SETTINGS_QUICK_ANSWERS_ENABLE}, @@ -328,47 +239,6 @@ "quickAnswersSubToggleEnabled", chromeos::features::IsQuickAnswersV2SettingsSubToggleEnabled()); } - -void AddGoogleAssistantStrings(content::WebUIDataSource* html_source) { - static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"googleAssistantPageTitle", IDS_SETTINGS_GOOGLE_ASSISTANT}, - {"googleAssistantEnableContext", IDS_ASSISTANT_SCREEN_CONTEXT_TITLE}, - {"googleAssistantEnableContextDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_SCREEN_CONTEXT_DESCRIPTION}, - {"googleAssistantEnableHotword", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD}, - {"googleAssistantEnableHotwordDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_DESCRIPTION}, - {"googleAssistantVoiceSettings", - IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS}, - {"googleAssistantVoiceSettingsDescription", - IDS_ASSISTANT_VOICE_MATCH_RECORDING}, - {"googleAssistantVoiceSettingsRetrainButton", - IDS_SETTINGS_GOOGLE_ASSISTANT_VOICE_SETTINGS_RETRAIN}, - {"googleAssistantEnableHotwordWithoutDspDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_DESCRIPTION}, - {"googleAssistantEnableHotwordWithoutDspRecommended", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_RECOMMENDED}, - {"googleAssistantEnableHotwordWithoutDspAlwaysOn", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_ALWAYS_ON}, - {"googleAssistantEnableHotwordWithoutDspOff", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_HOTWORD_WITHOUT_DSP_OFF}, - {"googleAssistantEnableNotification", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION}, - {"googleAssistantEnableNotificationDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_NOTIFICATION_DESCRIPTION}, - {"googleAssistantLaunchWithMicOpen", - IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN}, - {"googleAssistantLaunchWithMicOpenDescription", - IDS_SETTINGS_GOOGLE_ASSISTANT_LAUNCH_WITH_MIC_OPEN_DESCRIPTION}, - {"googleAssistantSettings", IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS}, - }; - html_source->AddLocalizedStrings(kLocalizedStrings); - - html_source->AddBoolean("hotwordDspAvailable", IsHotwordDspAvailable()); - html_source->AddBoolean("voiceMatchDisabled", !IsVoiceMatchAllowed()); -} - } // namespace SearchSection::SearchSection(Profile* profile, @@ -381,14 +251,6 @@ updater.AddSearchTags(GetScannerSearchConcepts()); } - AssistantState* assistant_state = AssistantState::Get(); - if (IsAssistantAllowed() && assistant_state) { - updater.AddSearchTags(GetAssistantSearchConcepts()); - - assistant_state->AddObserver(this); - UpdateAssistantSearchTags(); - } - if (QuickAnswersState::Get()) { QuickAnswersState::Get()->AddObserver(this); UpdateQuickAnswersSearchTags(); @@ -402,12 +264,7 @@ } } -SearchSection::~SearchSection() { - AssistantState* assistant_state = AssistantState::Get(); - if (IsAssistantAllowed() && assistant_state) { - assistant_state->RemoveObserver(this); - } -} +SearchSection::~SearchSection() = default; void SearchSection::AddLoadTimeData(content::WebUIDataSource* html_source) { webui::LocalizedString kLocalizedStrings[] = { @@ -429,13 +286,6 @@ {"enableScannerDesc", IDS_OS_SETTINGS_ENABLE_SCANNER_DESCRIPTION}, {"osSearchEngineLabel", IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL}, {"searchSubpageTitle", IDS_SETTINGS_SEARCH_SUBPAGE_TITLE}, - {"searchGoogleAssistant", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT}, - {"searchGoogleAssistantEnabled", - IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON}, - {"searchGoogleAssistantDisabled", - IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF}, - {"searchGoogleAssistantOn", IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ON}, - {"searchGoogleAssistantOff", IDS_OS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_OFF}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -472,39 +322,22 @@ html_source->AddBoolean("isScannerSettingsToggleVisible", IsScannerSettingsToggleVisible()); - const bool is_assistant_allowed = IsAssistantAllowed(); - html_source->AddBoolean("isAssistantAllowed", is_assistant_allowed); - - if (assistant::features::IsNewEntryPointEnabled()) { - html_source->AddLocalizedString( - "osSearchPageTitle", IDS_OS_SETTINGS_SEARCH_AND_SUGGESTIONS_TITLE); - } else { - html_source->AddLocalizedString( - "osSearchPageTitle", is_assistant_allowed - ? IDS_SETTINGS_SEARCH_AND_ASSISTANT - : IDS_SETTINGS_SEARCH); - } + html_source->AddLocalizedString("osSearchPageTitle", + IDS_OS_SETTINGS_SEARCH_AND_SUGGESTIONS_TITLE); html_source->AddString("osSearchEngineDescription", ui::SubstituteChromeOSDeviceType( IDS_OS_SETTINGS_SEARCH_ENGINE_DESCRIPTION)); AddQuickAnswersStrings(html_source); - AddGoogleAssistantStrings(html_source); } void SearchSection::AddHandlers(content::WebUI* web_ui) { web_ui->AddMessageHandler( std::make_unique<::settings::SearchEnginesHandler>(profile())); - web_ui->AddMessageHandler(std::make_unique<GoogleAssistantHandler>()); } int SearchSection::GetSectionNameMessageId() const { - if (assistant::features::IsNewEntryPointEnabled()) { - return IDS_OS_SETTINGS_SEARCH_AND_SUGGESTIONS_TITLE; - } - - return IsAssistantAllowed() ? IDS_SETTINGS_SEARCH_AND_ASSISTANT - : IDS_SETTINGS_SEARCH; + return IDS_OS_SETTINGS_SEARCH_AND_SUGGESTIONS_TITLE; } mojom::Section SearchSection::GetSection() const { @@ -602,38 +435,6 @@ kSearchSettingsWithoutPreferredSearchEngine, generator); } - - // Assistant. - generator->RegisterTopLevelSubpage( - IDS_SETTINGS_GOOGLE_ASSISTANT, mojom::Subpage::kAssistant, - mojom::SearchResultIcon::kAssistant, - mojom::SearchResultDefaultRank::kMedium, mojom::kAssistantSubpagePath); - static constexpr mojom::Setting kAssistantSettings[] = { - mojom::Setting::kAssistantOnOff, - mojom::Setting::kAssistantRelatedInfo, - mojom::Setting::kAssistantOkGoogle, - mojom::Setting::kAssistantNotifications, - mojom::Setting::kAssistantVoiceInput, - mojom::Setting::kTrainAssistantVoiceModel, - }; - RegisterNestedSettingBulk(mojom::Subpage::kAssistant, kAssistantSettings, - generator); -} - -void SearchSection::OnAssistantConsentStatusChanged(int consent_status) { - UpdateAssistantSearchTags(); -} - -void SearchSection::OnAssistantContextEnabled(bool enabled) { - UpdateAssistantSearchTags(); -} - -void SearchSection::OnAssistantSettingsEnabled(bool enabled) { - UpdateAssistantSearchTags(); -} - -void SearchSection::OnAssistantHotwordEnabled(bool enabled) { - UpdateAssistantSearchTags(); } void SearchSection::OnSettingsEnabled(bool enabled) { @@ -658,41 +459,6 @@ magic_boost_state_observation_.Reset(); } -bool SearchSection::IsAssistantAllowed() const { - // NOTE: This will be false when the flag is disabled. - return ::assistant::IsAssistantAllowedForProfile(profile()) == - assistant::AssistantAllowedState::ALLOWED; -} - -void SearchSection::UpdateAssistantSearchTags() { - SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); - - // Start without any Assistant search concepts, then add if needed below. - updater.RemoveSearchTags(GetAssistantOnSearchConcepts()); - updater.RemoveSearchTags(GetAssistantOffSearchConcepts()); - updater.RemoveSearchTags(GetAssistantVoiceMatchSearchConcepts()); - - AssistantState* assistant_state = AssistantState::Get(); - - // The setting_enabled() function is the top-level enabled state. If this is - // off, none of the sub-features are enabled. - if (!assistant_state->settings_enabled() || - !assistant_state->settings_enabled().value()) { - updater.AddSearchTags(GetAssistantOffSearchConcepts()); - return; - } - - updater.AddSearchTags(GetAssistantOnSearchConcepts()); - - if (IsVoiceMatchAllowed() && assistant_state->hotword_enabled() && - assistant_state->hotword_enabled().value() && - assistant_state->consent_status() && - assistant_state->consent_status().value() == - assistant::prefs::ConsentStatus::kActivityControlAccepted) { - updater.AddSearchTags(GetAssistantVoiceMatchSearchConcepts()); - } -} - void SearchSection::UpdateQuickAnswersSearchTags() { DCHECK(QuickAnswersState::Get());
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.h b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.h index 50ee221a..37a1913 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.h +++ b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_SEARCH_SEARCH_SECTION_H_ #define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_SEARCH_SEARCH_SECTION_H_ -#include "ash/public/cpp/assistant/assistant_state_base.h" #include "base/values.h" #include "chrome/browser/ui/webui/ash/settings/pages/os_settings_section.h" #include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h" @@ -19,11 +18,8 @@ class SearchTagRegistry; -// Provides UI strings and search tags for Search & Assistant settings. Search -// tags for Assistant settings are added/removed depending on whether the -// feature and relevant flags are enabled/disabled. +// Provides UI strings and search tags for Search settings. class SearchSection : public OsSettingsSection, - public AssistantStateObserver, public QuickAnswersStateObserver, public chromeos::MagicBoostState::Observer { public: @@ -42,12 +38,6 @@ void RegisterHierarchy(HierarchyGenerator* generator) const override; private: - // AssistantStateObserver: - void OnAssistantConsentStatusChanged(int consent_status) override; - void OnAssistantContextEnabled(bool enabled) override; - void OnAssistantSettingsEnabled(bool enabled) override; - void OnAssistantHotwordEnabled(bool enabled) override; - // QuickAnswersStateObserver: void OnSettingsEnabled(bool enabled) override; void OnEligibilityChanged(bool eligible) override; @@ -57,8 +47,6 @@ void OnMagicBoostEnabledUpdated(bool enabled) override; void OnIsDeleting() override; - bool IsAssistantAllowed() const; - void UpdateAssistantSearchTags(); void UpdateQuickAnswersSearchTags(); // Add or remove magic boost search tags based on `is_magic_boost_available`. // If available, also add / remove the sub search tags based on the magic
diff --git a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom index 2b92447..d64429cb 100644 --- a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom +++ b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
@@ -11,7 +11,6 @@ kAndroid, kAppsGrid, kAppsParentalControls, - kAssistant, kAudio, kAuthKey, kAutoclick,
diff --git a/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler.cc b/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler.cc index 05684bf..33bb369 100644 --- a/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler.cc +++ b/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler.cc
@@ -105,9 +105,18 @@ } void ComposeboxHandler::DeleteFile(const base::UnguessableToken& file_token) { + ComposeboxQueryController::FileInfo* file_info = + query_controller_->GetFileInfo(file_token); + lens::MimeType file_type = + file_info ? file_info->mime_type_ : lens::MimeType::kUnknown; + FileUploadStatus file_status = file_info ? file_info->GetFileUploadStatus() + : FileUploadStatus::kNotUploaded; + // If an UnguessabledToken that wasn't in the cache was sent, delete fails. // Report a bad message. - if (!query_controller_->DeleteFile(file_token)) { + bool success = query_controller_->DeleteFile(file_token); + metrics_recorder_->RecordFileDeletedMetrics(success, file_type, file_status); + if (!success) { handler_.ReportBadMessage("An invalid file token was sent to DeleteFile"); } }
diff --git a/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler_unittest.cc index 2de9fbb..6765a37 100644 --- a/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler_unittest.cc +++ b/chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler_unittest.cc
@@ -48,6 +48,8 @@ constexpr char kClientUploadDurationQueryParameter[] = "cud"; constexpr char kQuerySubmissionTimeQueryParameter[] = "qsubts"; constexpr char kQueryText[] = "query"; +constexpr char kComposeboxFileDeleted[] = + "NewTabPage.Composebox.Session.File.DeletedCount"; class MockPage : public composebox::mojom::Page { public: @@ -100,6 +102,9 @@ std::optional<composebox::ImageEncodingOptions> image_options)); MOCK_METHOD(bool, DeleteFile, (const base::UnguessableToken&)); MOCK_METHOD(void, ClearFiles, ()); + MOCK_METHOD(FileInfo*, + GetFileInfo, + (const base::UnguessableToken& file_token)); void NotifySessionStartedBase() { TestComposeboxQueryController::NotifySessionStarted(); @@ -374,6 +379,12 @@ } TEST_F(ComposeboxHandlerTest, DeleteFile_Success) { + std::string file_type = ".Image"; + std::string file_status = ".NotUploaded"; + std::unique_ptr<ComposeboxQueryController::FileInfo> file_info = + std::make_unique<ComposeboxQueryController::FileInfo>(); + file_info->file_name = "test.png"; + file_info->mime_type_ = lens::MimeType::kImage; base::UnguessableToken delete_file_token = base::UnguessableToken::Create(); base::UnguessableToken token_arg; EXPECT_CALL(query_controller(), DeleteFile) @@ -382,9 +393,18 @@ token_arg = token; return true; })); + + EXPECT_CALL(query_controller(), GetFileInfo) + .WillOnce( + testing::Invoke([&file_info](const base::UnguessableToken& token) { + return file_info.get(); + })); + handler().DeleteFile(delete_file_token); EXPECT_EQ(delete_file_token, token_arg); + histogram_tester().ExpectTotalCount( + kComposeboxFileDeleted + file_type + file_status, 1); } TEST_F(ComposeboxHandlerTest, DeleteFile_FailureThrowsMessage) {
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc index d6d1306..da84f2f 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -464,7 +464,12 @@ IDS_NTP_MICROSOFT_AUTHENTICATION_SUBHEADING}, {"modulesMicrosoftAuthSignIn", IDS_NTP_MICROSOFT_AUTHENTICATION_SIGN_IN_BUTTON_TEXT}, + {"modulesTabGroupsCreateNewTabGroup", IDS_CREATE_NEW_TAB_GROUP}, {"modulesTabGroupsTitle", IDS_NTP_MODULES_TAB_GROUPS_TITLE}, + {"modulesTabGroupsZeroStateTitle", + IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TITLE}, + {"modulesTabGroupsZeroStateText", + IDS_NTP_MODULES_TAB_GROUPS_ZERO_STATE_TEXT}, // Middle slot promo. {"undoDismissPromoButtonToast", IDS_NTP_UNDO_DISMISS_PROMO_BUTTON_TOAST},
diff --git a/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc index 59c47f70..c9dc6d5 100644 --- a/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc
@@ -296,13 +296,14 @@ ASSERT_TRUE(state_after_user_choice.has_value()); } - base::RunLoop run_loop; - web_app::OsIntegrationManager:: - SetOnFileHandlersSynchronizedCallbackForTesting(run_loop.QuitClosure()); - UpdateDefaultHandlersPrefs({{file_extension, kInstallUrl.spec()}}); - run_loop.Run(); + // Manually triggering OS synchronization. + // TODO(crbug.com/411023280): OS integration state is not automatically + // updated when the FileHandlingDefaultHandlers policy changes. + base::test::TestFuture<void> done; + provider().scheduler().SynchronizeOsIntegration(app_id, done.GetCallback()); + ASSERT_TRUE(done.Wait()); // Verify that file handling is allowed. { @@ -323,101 +324,6 @@ ApiApprovalState::kDisallowed); } } - -TEST_F(FileHandlingSubManagerConfigureTest, - PolicyRemovedMidSessionRevertsToUserChoice) { - const GURL kInstallUrl = - GURL("https://www.example.com/path/install_url.html"); - const GURL kStartUrl = GURL("https://example.com/path/"); - const GURL kManifestUrl = GURL("https://www.example.com/path/manifest.json"); - const webapps::AppId app_id = web_app::GenerateAppId(std::nullopt, kStartUrl); - const std::string file_extension = ".txt"; - - { - fake_provider().GetFakeWebContentsManager()->CreateBasicInstallPageState( - kInstallUrl, kManifestUrl, kWebAppUrl); - auto& page_state = - fake_provider().GetFakeWebContentsManager()->GetOrCreatePageState( - kInstallUrl); - - auto manifest = blink::mojom::Manifest::New(); - manifest->id = manifest->start_url.GetWithoutRef(); - manifest->scope = manifest->start_url.GetWithoutFilename(); - manifest->manifest_url = page_state.manifest_url; - manifest->start_url = kStartUrl; - - auto handler = blink::mojom::ManifestFileHandler::New(); - handler->action = kStartUrl; - handler->name = u"Text"; - std::vector<std::u16string> extensions = {u".txt"}; - handler->accept.emplace(u"text/plain", extensions); - manifest->file_handlers.push_back(std::move(handler)); - - page_state.manifest_before_default_processing = std::move(manifest); - } - - // Install app with file handlers - SynchronizeFuture result; - std::vector<ExternalInstallOptions> install_options_list; - install_options_list.emplace_back(kInstallUrl, - /*user_display_mode=*/std::nullopt, - ExternalInstallSource::kExternalPolicy); - - provider().externally_managed_app_manager().SynchronizeInstalledApps( - std::move(install_options_list), ExternalInstallSource::kExternalPolicy, - result.GetCallback()); - ASSERT_TRUE(result.Wait()); - - // Verify file handler os registration and default approval state. - ASSERT_TRUE(provider().registrar_unsafe().GetAppById(app_id)); - auto initial_state = - provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); - ASSERT_TRUE(initial_state.has_value()); - ASSERT_TRUE(initial_state.value().has_file_handling()); - EXPECT_EQ( - provider().registrar_unsafe().GetAppFileHandlerUserApprovalState(app_id), - ApiApprovalState::kRequiresPrompt); - - // User disallows file handling for the app. - base::test::TestFuture<void> future; - provider().scheduler().PersistFileHandlersUserChoice( - app_id, /*allowed=*/false, future.GetCallback()); - ASSERT_TRUE(future.Wait()); - - // Setting pref to overwrite the user choice. - base::test::TestFuture<void> file_handlers_os_sync_future; - web_app::OsIntegrationManager:: - SetOnFileHandlersSynchronizedCallbackForTesting( - file_handlers_os_sync_future.GetRepeatingCallback()); - UpdateDefaultHandlersPrefs({{file_extension, kInstallUrl.spec()}}); - ASSERT_TRUE(file_handlers_os_sync_future.Wait()); - - { - ASSERT_EQ(provider().registrar_unsafe().GetAppFileHandlerUserApprovalState( - app_id), - ApiApprovalState::kDisallowed); - ASSERT_EQ(provider().registrar_unsafe().GetAppFileHandlerApprovalState( - app_id, file_extension), - ApiApprovalState::kAllowed); - auto state_after_user_choice = - provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); - ASSERT_TRUE(state_after_user_choice.has_value()); - } - - // Resetting pref value, file handler approval state should default to - // previous user choice. - UpdateDefaultHandlersPrefs(); - ASSERT_TRUE(file_handlers_os_sync_future.Wait()); - - { - EXPECT_EQ(provider().registrar_unsafe().GetAppFileHandlerUserApprovalState( - app_id), - ApiApprovalState::kDisallowed); - EXPECT_EQ(provider().registrar_unsafe().GetAppFileHandlerApprovalState( - app_id, file_extension), - ApiApprovalState::kDisallowed); - } -} #endif // BUILDFLAG(IS_CHROMEOS) TEST_F(FileHandlingSubManagerConfigureTest, Uninstall) {
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.cc b/chrome/browser/web_applications/os_integration/os_integration_manager.cc index 2c3bc2e..a00f9d0 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.cc +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.cc
@@ -118,11 +118,6 @@ return *callback; } -base::OnceClosure& GetOnFileHandlersSynchronizedCallbackForTesting() { - static base::NoDestructor<base::OnceClosure> callback; - return *callback; -} - } // namespace OsIntegrationManager::ScopedSuppressForTesting::ScopedSuppressForTesting() { @@ -162,12 +157,6 @@ } // static -void OsIntegrationManager::SetOnFileHandlersSynchronizedCallbackForTesting( - base::OnceClosure callback) { - GetOnFileHandlersSynchronizedCallbackForTesting() = std::move(callback); -} - -// static base::OnceClosure& OsIntegrationManager::OnSetCurrentAppShortcutsVersionCallbackForTesting() { static base::NoDestructor<base::OnceClosure> callback; @@ -222,13 +211,6 @@ protocol_handler_manager_->Start(); } UpdateShortcutsForAllAppsIfNeeded(); -#if BUILDFLAG(IS_CHROMEOS) - pref_change_registrar_.Init(profile_->GetPrefs()); - pref_change_registrar_.Add( - prefs::kDefaultHandlersForFileExtensions, - base::BindRepeating(&OsIntegrationManager::UpdateWebAppFileHandlers, - weak_ptr_factory_.GetWeakPtr())); -#endif // BUILDFLAG(IS_CHROMEOS) } void OsIntegrationManager::Synchronize( @@ -707,27 +689,4 @@ return shortcut_info; } -void OsIntegrationManager::UpdateWebAppFileHandlers() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::ConcurrentClosures concurrent; - - for (const webapps::AppId& app_id : - provider_->registrar_unsafe().GetAppIds()) { - Synchronize(app_id, concurrent.CreateClosure()); - } - - std::move(concurrent) - .Done(base::BindOnce(&OsIntegrationManager::OnAllFileHandlersSynchronized, - weak_ptr_factory_.GetWeakPtr())); -} - -void OsIntegrationManager::OnAllFileHandlersSynchronized() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - if (base::OnceClosure& callback = - GetOnFileHandlersSynchronizedCallbackForTesting()) { - std::move(callback).Run(); - } -} - } // namespace web_app
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.h b/chrome/browser/web_applications/os_integration/os_integration_manager.h index 7d628db..22f0e7d 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.h +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.h
@@ -26,7 +26,6 @@ #include "chrome/browser/web_applications/web_app_install_info.h" #include "components/custom_handlers/protocol_handler.h" #include "components/pref_registry/pref_registry_syncable.h" -#include "components/prefs/pref_change_registrar.h" #include "components/services/app_service/public/cpp/file_handler.h" #include "components/webapps/common/web_app_id.h" @@ -75,9 +74,6 @@ static void SetUpdateShortcutsForAllAppsCallback( UpdateShortcutsForAllAppsCallback callback); - static void SetOnFileHandlersSynchronizedCallbackForTesting( - base::OnceClosure callback); - static base::OnceClosure& OnSetCurrentAppShortcutsVersionCallbackForTesting(); OsIntegrationManager( @@ -221,9 +217,6 @@ std::unique_ptr<ShortcutInfo> BuildShortcutInfoForWebApp(const WebApp* app); - void UpdateWebAppFileHandlers(); - void OnAllFileHandlersSynchronized(); - const raw_ptr<Profile> profile_; raw_ptr<WebAppProvider> provider_ = nullptr; @@ -237,8 +230,6 @@ base::RepeatingCallback<void(const webapps::AppId&)> force_unregister_callback_for_testing_ = base::DoNothing(); - PrefChangeRegistrar pref_change_registrar_; - base::WeakPtrFactory<OsIntegrationManager> weak_ptr_factory_{this}; };
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index e18530a..f5cac3d8 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1753768535-92ac2a764f8f91dd65aafa15514fe64a3f60b23c-6520cd593d02c2f408281c056adc3338a55ddd6a.profdata +chrome-android32-main-1753833443-71fe48aa830a6d42ccf89e13269d49b3e123db5b-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index d605fb3..df52b15 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1753808461-f676036b51b50c67022a7b3fb483bdc67bacbb0b-5d9031cfa860d7f21d59630187ca25b9232694a1.profdata +chrome-android64-main-1753853592-d809159508407d71cc8f4c17e229c68508e1ab25-32d91b3f5c8cb98c13ac19f698c7a43dda0947eb.profdata
diff --git a/chrome/build/android-desktop-arm64.pgo.txt b/chrome/build/android-desktop-arm64.pgo.txt index 8bcfaed..0e83ce75 100644 --- a/chrome/build/android-desktop-arm64.pgo.txt +++ b/chrome/build/android-desktop-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-arm64-main-1753774636-23e472a9d3ade4c5f4ad7cb8065fbc263a55a800-1beec4a855e7ce57d662249815574f9d015a54a1.profdata +chrome-android-desktop-arm64-main-1753832901-6fe9a25405d68430bfcc15be4b812ea506d0f020-540a0fc968af91773ada0cc5244d6c0b8da9bb78.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index 8724e374..9fd487d 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1753790367-e81ea6070f0cd7814ee7b1290626ee4d20bfdb04-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-android-desktop-x64-main-1753833443-0aacf94fc463d855d2c7895263d00b84b73012f4-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 97b711a..ef228faf 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1753790367-0e3f7cc564556a8cdda028703681cafaaef77dc6-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-mac-arm-main-1753847846-672febdc9de574219064af4dc8ea912c6d51b958-11c95804efd6e1bba54ec9b62e2536b5f71bd56f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 99f69b9e..761a2f33 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1753790367-7524c535595e54c1d0c7403ee2fa331595b65ce9-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-mac-main-1753833443-1a441d08f4fd8b8dcb638768a3f280462d9c1a3b-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index aed7e09..f52777c0 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1753790367-6e2ff289b7a6196881d6bb784b0a836c6fd9dff4-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-win-arm64-main-1753833443-537c24df99ccdb01e32163c79550218f0015bfdc-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index c6ae0b0..d08e9233 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1753790367-b1c579139e2e514d7c5f4944adfa147d75ee46ec-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-win32-main-1753833443-3aa5ff004b8855ce464c679d70b7b479fd1c8f34-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index a20db93..01c44aa 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1753790367-120fa34f572120b2bca244164d0fe0c9ea9ff818-1b32bbbcbe9a8ee34d78d61226bb4611fb7c5aab.profdata +chrome-win64-main-1753833443-a2fac2191bcdec136ff32a293320f935fd5ab6cc-da2b4788010e064c71ba71769f8772ab74fb726f.profdata
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 43b73c2..b708a60 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -1085,8 +1085,6 @@ "webrtcAudioPrivate": { "channel": "stable", "extension_types": ["extension"], - // "desktop_android" is not supported. - "platforms": ["chromeos", "linux", "mac", "win"], "allowlist": [ // Hangouts test extension "80B9DC58E5210749F052F5B4DB239C50CF72AEB6",
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index 9ac8aa7..ea53b8f 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -645,7 +645,7 @@ inline constexpr char kAllSitesSettingsSubpage[] = "content/all"; inline constexpr char kAppearanceSubPage[] = "appearance"; inline constexpr char kAutofillSubPage[] = "autofill"; -inline constexpr char kAutofillAiSubPage[] = "autofillAi"; +inline constexpr char kAutofillAiSubPage[] = "enhancedAutofill"; inline constexpr char kClearBrowserDataSubPage[] = "clearBrowserData"; inline constexpr char kContentSettingsSubPage[] = "content"; inline constexpr char kCookieSettingsSubPage[] = "cookies";
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index cd2cc25..8d1fd07 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1593,6 +1593,7 @@ "../browser/extensions/api/user_scripts/user_scripts_apitest.h", "../browser/extensions/api/web_accessible_resources_apitest.cc", "../browser/extensions/api/web_request/web_request_apitest.cc", + "../browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc", "../browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc", "../browser/extensions/api/webstore_private/webstore_private_apitest.cc", "../browser/extensions/background_script_executor_browsertest.cc", @@ -1647,6 +1648,7 @@ "//chrome/browser/ui/toolbar", "//components/bookmarks/managed", "//components/embedder_support", + "//components/media_device_salt", "//components/privacy_sandbox:privacy_sandbox_settings_headers", "//components/proxy_config", "//components/tabs:public", @@ -3196,6 +3198,7 @@ "../browser/direct_sockets/direct_sockets_apitest.cc", "../browser/dom_distiller/distillable_page_utils_browsertest.cc", "../browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc", + "../browser/dom_distiller/tab_utils_browsertest.cc", "../browser/dom_distiller/test_distillation_observers.cc", "../browser/dom_distiller/test_distillation_observers.h", "../browser/domain_reliability/browsertest.cc", @@ -3874,10 +3877,6 @@ ] } - if (is_android) { - sources += [ "../browser/dom_distiller/tab_utils_browsertest.cc" ] - } - if (!is_chrome_for_testing) { deps += [ "//chrome/browser/search_engine_choice", @@ -4567,7 +4566,6 @@ "../browser/extensions/api/usb/usb_manual_apitest.cc", "../browser/extensions/api/user_scripts/user_scripts_uitest.cc", "../browser/extensions/api/web_navigation/web_navigation_apitest.cc", - "../browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc", "../browser/extensions/api/webrtc_from_web_accessible_resource_browsertest.cc", "../browser/extensions/api/webrtc_logging_private/webrtc_logging_private_browsertest.cc", "../browser/extensions/api_binding_perf_browsertest.cc", @@ -9305,6 +9303,7 @@ "../common/extensions/permissions/settings_override_permission_unittest.cc", ] deps += [ + "//base", "//chrome/browser/extensions:cws_item_service_proto", "//chrome/browser/extensions:test_support", "//chrome/browser/extensions/api/bookmarks/test:test_support",
diff --git a/chrome/test/data/android/contextmenu/context_menu_test.html b/chrome/test/data/android/contextmenu/context_menu_test.html index f000ee2..94a426d 100644 --- a/chrome/test/data/android/contextmenu/context_menu_test.html +++ b/chrome/test/data/android/contextmenu/context_menu_test.html
@@ -1,6 +1,8 @@ <html> <head> +<!-- LINT.IfChange(PageScaleFactor) --> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5" /> +<!-- LINT.ThenChange(//chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java:PageScaleFactor) --> </head> <body>
diff --git a/chrome/test/data/private_network_access/fetch-from-worker-as-public-address.html b/chrome/test/data/private_network_access/fetch-from-worker-as-public-address.html index 7eca400..4a8d398e 100644 --- a/chrome/test/data/private_network_access/fetch-from-worker-as-public-address.html +++ b/chrome/test/data/private_network_access/fetch-from-worker-as-public-address.html
@@ -1,3 +1,9 @@ +<html> + <head> + <!-- Disable extra network request for /favicon.ico --> + <link rel="icon" href="data:,"> + </head> +<body> <script> const params = new URLSearchParams(location.search); const start_worker_manually = params.has('start_worker_manually'); @@ -21,3 +27,5 @@ start_worker(); } </script> +</body> +</html>
diff --git a/chrome/test/data/webui/chromeos/settings/BUILD.gn b/chrome/test/data/webui/chromeos/settings/BUILD.gn index c0f9595..cf3210a 100644 --- a/chrome/test/data/webui/chromeos/settings/BUILD.gn +++ b/chrome/test/data/webui/chromeos/settings/BUILD.gn
@@ -322,7 +322,6 @@ "os_privacy_page/test_privacy_page_browser_proxy.ts", "os_reset_page/reset_settings_card_test.ts", "os_reset_page/test_os_reset_browser_proxy.ts", - "os_search_page/google_assistant_subpage_test.ts", "os_search_page/search_and_assistant_settings_card_test.ts", "os_search_page/search_engine_test.ts", "os_search_page/search_subpage_test.ts",
diff --git a/chrome/test/data/webui/chromeos/settings/os_search_page/google_assistant_subpage_test.ts b/chrome/test/data/webui/chromeos/settings/os_search_page/google_assistant_subpage_test.ts deleted file mode 100644 index 57da5c9..0000000 --- a/chrome/test/data/webui/chromeos/settings/os_search_page/google_assistant_subpage_test.ts +++ /dev/null
@@ -1,507 +0,0 @@ -// Copyright 2017 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://os-settings/lazy_load.js'; - -import type {GoogleAssistantBrowserProxy, SettingsGoogleAssistantSubpageElement} from 'chrome://os-settings/lazy_load.js'; -import {ConsentStatus, DspHotwordState, GoogleAssistantBrowserProxyImpl} from 'chrome://os-settings/lazy_load.js'; -import type {ControlledButtonElement, CrLinkRowElement, SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js'; -import {CrSettingsPrefs, Router, routes} from 'chrome://os-settings/os_settings.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {getDeepActiveElement} from 'chrome://resources/js/util.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; -import {TestMock} from 'chrome://webui-test/test_mock.js'; - -suite('<settings-google-assistant-subpage>', () => { - let page: SettingsGoogleAssistantSubpageElement; - let browserProxy: TestMock<GoogleAssistantBrowserProxy>& - GoogleAssistantBrowserProxy; - let prefElement: SettingsPrefsElement; - - suiteSetup(() => { - loadTimeData.overrideValues({ - isAssistantAllowed: true, - hotwordDspAvailable: true, - }); - }); - - setup(async () => { - browserProxy = TestMock.fromClass(GoogleAssistantBrowserProxyImpl); - GoogleAssistantBrowserProxyImpl.setInstanceForTesting(browserProxy); - - prefElement = document.createElement('settings-prefs'); - document.body.appendChild(prefElement); - - await CrSettingsPrefs.initialized; - page = document.createElement('settings-google-assistant-subpage'); - page.prefs = prefElement.prefs; - document.body.appendChild(page); - }); - - teardown(() => { - page.remove(); - prefElement.remove(); - CrSettingsPrefs.resetForTesting(); - }); - - test('toggleAssistant', () => { - flush(); - const button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - - // Tap the enable toggle button and ensure the state becomes enabled. - button.click(); - flush(); - assertTrue(button.checked); - }); - - test('toggleAssistantContext', () => { - let button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-context-enable'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.context.enabled', false); - flush(); - button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-context-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - - button.click(); - flush(); - assertTrue(button.checked); - assertTrue( - !!page.getPref('settings.voice_interaction.context.enabled.value')); - }); - - test('toggleAssistantHotword', async () => { - let button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-hotword-enable'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.hotword.enabled', false); - flush(); - button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-hotword-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - - button.click(); - flush(); - assertTrue(button.checked); - assertTrue( - !!page.getPref('settings.voice_interaction.hotword.enabled.value')); - await browserProxy.whenCalled('syncVoiceModelStatus'); - }); - - test('hotwordToggleVisibility', () => { - let button = - page.shadowRoot!.querySelector('#google-assistant-hotword-enable'); - assertEquals(null, button); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - button = page.shadowRoot!.querySelector('#google-assistant-hotword-enable'); - assertTrue(!!button); - }); - - test('hotwordToggleDisabledForChildUser', () => { - page.setPrefValue('settings.voice_interaction.enabled', true); - page.set('prefs.settings.voice_interaction.hotword.enabled', { - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - controlledBy: chrome.settingsPrivate.ControlledBy.CHILD_RESTRICTION, - value: false, - }); - - flush(); - const button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-hotword-enable'); - assertTrue(!!button); - const indicator = - button.shadowRoot!.querySelector('cr-policy-pref-indicator'); - assertTrue(!!indicator); - assertTrue(button.disabled); - }); - - test('tapOnRetrainVoiceModel', async () => { - let button = page.shadowRoot!.querySelector<ControlledButtonElement>( - '#retrain-voice-model'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.hotword.enabled', true); - page.setPrefValue( - 'settings.voice_interaction.activity_control.consent_status', - ConsentStatus.ACTIVITY_CONTROL_ACCEPTED); - flush(); - button = page.shadowRoot!.querySelector<ControlledButtonElement>( - '#retrain-voice-model'); - assertTrue(!!button); - - button.click(); - flush(); - await browserProxy.whenCalled('retrainAssistantVoiceModel'); - }); - - test('retrainButtonVisibility', () => { - let button = page.shadowRoot!.querySelector('#retrain-voice-model'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - button = page.shadowRoot!.querySelector('#retrain-voice-model'); - assertEquals(null, button); - - // Hotword disabled. - // Button should not be shown. - page.setPrefValue('settings.voice_interaction.hotword.enabled', false); - flush(); - button = page.shadowRoot!.querySelector('#retrain-voice-model'); - assertEquals(null, button); - - // Hotword enabled. - // Button should be shown. - page.setPrefValue('settings.voice_interaction.hotword.enabled', true); - flush(); - button = page.shadowRoot!.querySelector('#retrain-voice-model'); - assertTrue(!!button); - }); - - test('Deep link to retrain voice model', async () => { - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.hotword.enabled', true); - page.setPrefValue( - 'settings.voice_interaction.activity_control.consent_status', - ConsentStatus.ACTIVITY_CONTROL_ACCEPTED); - flush(); - - const params = new URLSearchParams(); - params.append('settingId', '607'); - Router.getInstance().navigateTo(routes.GOOGLE_ASSISTANT, params); - - const button = page.shadowRoot!.querySelector<ControlledButtonElement>( - '#retrain-voice-model'); - assertTrue(!!button); - const deepLinkElement = button.shadowRoot!.querySelector('cr-button'); - assertTrue(!!deepLinkElement); - await waitAfterNextRender(deepLinkElement); - assertEquals( - deepLinkElement, getDeepActiveElement(), - 'Retrain model button should be focused for settingId=607.'); - }); - - test('toggleAssistantNotification', () => { - let button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-notification-enable'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.notification.enabled', false); - flush(); - button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-notification-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - - button.click(); - flush(); - assertTrue(button.checked); - assertTrue(!!page.getPref( - 'settings.voice_interaction.notification.enabled.value')); - }); - - test('toggleAssistantLaunchWithMicOpen', () => { - let button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-launch-with-mic-open'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - page.setPrefValue('settings.voice_interaction.launch_with_mic_open', false); - flush(); - button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-launch-with-mic-open'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - - button.click(); - flush(); - assertTrue(button.checked); - assertTrue(!!page.getPref( - 'settings.voice_interaction.launch_with_mic_open.value')); - }); - - test('tapOnAssistantSettings', async () => { - let button = page.shadowRoot!.querySelector<CrLinkRowElement>( - '#google-assistant-settings'); - assertEquals(null, button); - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - button = page.shadowRoot!.querySelector<CrLinkRowElement>( - '#google-assistant-settings'); - assertTrue(!!button); - - button.click(); - flush(); - await browserProxy.whenCalled('showGoogleAssistantSettings'); - }); - - test('assistantDisabledByPolicy', () => { - let button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertFalse(button.checked); - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - button = page.shadowRoot!.querySelector<SettingsToggleButtonElement>( - '#google-assistant-enable'); - assertTrue(!!button); - assertFalse(button.disabled); - assertTrue(button.checked); - - page.setPrefValue('settings.assistant.disabled_by_policy', true); - flush(); - assertTrue(!!button); - assertTrue(button.disabled); - assertFalse(button.checked); - }); -}); - -suite('<settings-google-assistant-subpage> With No Dsp Hotword', () => { - let page: SettingsGoogleAssistantSubpageElement; - let browserProxy: TestMock<GoogleAssistantBrowserProxy>& - GoogleAssistantBrowserProxy; - let prefElement: SettingsPrefsElement; - - suiteSetup(() => { - loadTimeData.overrideValues({ - isAssistantAllowed: true, - hotwordDspAvailable: false, - }); - }); - - setup(async () => { - browserProxy = TestMock.fromClass(GoogleAssistantBrowserProxyImpl); - GoogleAssistantBrowserProxyImpl.setInstanceForTesting(browserProxy); - - prefElement = document.createElement('settings-prefs'); - document.body.appendChild(prefElement); - - await CrSettingsPrefs.initialized; - page = document.createElement('settings-google-assistant-subpage'); - page.prefs = prefElement.prefs; - document.body.appendChild(page); - flush(); - }); - - teardown(() => { - page.remove(); - prefElement.remove(); - CrSettingsPrefs.resetForTesting(); - }); - - function selectValue(select: HTMLSelectElement, value: string) { - select.value = value; - select.dispatchEvent(new CustomEvent('change')); - flush(); - } - - test('hotwordToggleVisibilityWithNoDspHotword', () => { - let toggle = - page.shadowRoot!.querySelector('#google-assistant-hotword-enable'); - assertEquals(null, toggle); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - toggle = page.shadowRoot!.querySelector('#google-assistant-hotword-enable'); - assertEquals(null, toggle); - }); - - test('dspHotwordDropdownVisibilityWithNoDspHotword', () => { - let container = page.shadowRoot!.querySelector('#dsp-hotword-container'); - assertEquals(null, container); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - container = page.shadowRoot!.querySelector('#dsp-hotword-container'); - assertTrue(!!container); - }); - - test('dspHotwordDropdownIndicatorEnabled', () => { - let indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertEquals(null, indicator); - - page.setPrefValue('settings.voice_interaction.enabled', true); - page.set('prefs.settings.voice_interaction.hotword.enabled', { - enforcement: chrome.settingsPrivate.Enforcement.RECOMMENDED, - value: true, - }); - - flush(); - const dropdown = page.shadowRoot!.querySelector('#dsp-hotword-state'); - indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertTrue(!!dropdown); - assertEquals(null, indicator); - assertFalse(dropdown.hasAttribute('disabled')); - }); - - test('dspHotwordDropdownIndicatorDisabled', () => { - let indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertEquals(null, indicator); - - page.setPrefValue('settings.voice_interaction.enabled', true); - page.set('prefs.settings.voice_interaction.hotword.enabled', { - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - value: true, - }); - - flush(); - const dropdown = page.shadowRoot!.querySelector('#dsp-hotword-state'); - indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertTrue(!!dropdown); - assertTrue(!!indicator); - assertTrue(dropdown.hasAttribute('disabled')); - }); - - test('dspHotwordDropdownDisabledForChildUser', () => { - let indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertEquals(null, indicator); - - page.setPrefValue('settings.voice_interaction.enabled', true); - page.set('prefs.settings.voice_interaction.hotword.enabled', { - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - controlledBy: chrome.settingsPrivate.ControlledBy.CHILD_RESTRICTION, - value: false, - }); - - flush(); - const dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - indicator = - page.shadowRoot!.querySelector('#hotword-policy-pref-indicator'); - assertTrue(!!dropdown); - assertTrue(!!indicator); - assertTrue(dropdown.disabled); - }); - - test('dspHotwordDropdownSelection', () => { - let dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertEquals(null, dropdown); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertTrue(!!dropdown); - assertFalse(dropdown.disabled); - - selectValue(dropdown, String(DspHotwordState.DEFAULT_ON)); - flush(); - assertTrue( - !!page.getPref('settings.voice_interaction.hotword.enabled.value')); - assertEquals( - false, - page.getPref('settings.voice_interaction.hotword.always_on.value')); - - selectValue(dropdown, String(DspHotwordState.ALWAYS_ON)); - flush(); - assertTrue( - !!page.getPref('settings.voice_interaction.hotword.enabled.value')); - assertTrue( - !!page.getPref('settings.voice_interaction.hotword.always_on.value')); - - selectValue(dropdown, String(DspHotwordState.OFF)); - flush(); - assertEquals( - false, - page.getPref('settings.voice_interaction.hotword.enabled.value')); - assertEquals( - false, - page.getPref('settings.voice_interaction.hotword.always_on.value')); - }); - - test('dspHotwordDropdownStatus', () => { - let dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertEquals(null, dropdown); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertTrue(!!dropdown); - assertFalse(dropdown.disabled); - - page.setPrefValue('settings.voice_interaction.hotword.enabled', true); - page.setPrefValue('settings.voice_interaction.hotword.always_on', false); - flush(); - assertEquals(DspHotwordState.DEFAULT_ON, Number(dropdown.value)); - - page.setPrefValue('settings.voice_interaction.hotword.enabled', true); - page.setPrefValue('settings.voice_interaction.hotword.always_on', true); - flush(); - assertEquals(DspHotwordState.ALWAYS_ON, Number(dropdown.value)); - - page.setPrefValue('settings.voice_interaction.hotword.enabled', false); - page.setPrefValue('settings.voice_interaction.hotword.always_on', false); - flush(); - assertEquals(DspHotwordState.OFF, Number(dropdown.value)); - }); - - test('dspHotwordDropdownDefaultOnSync', async () => { - let dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertEquals(null, dropdown); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertTrue(!!dropdown); - assertFalse(dropdown.disabled); - selectValue(dropdown, String(DspHotwordState.OFF)); - flush(); - - selectValue(dropdown, String(DspHotwordState.DEFAULT_ON)); - flush(); - await browserProxy.whenCalled('syncVoiceModelStatus'); - }); - - test('dspHotwordDropdownAlwaysOnSync', async () => { - let dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertEquals(null, dropdown); - - page.setPrefValue('settings.voice_interaction.enabled', true); - flush(); - - dropdown = - page.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state'); - assertTrue(!!dropdown); - assertFalse(dropdown.disabled); - selectValue(dropdown, String(DspHotwordState.OFF)); - flush(); - - selectValue(dropdown, String(DspHotwordState.ALWAYS_ON)); - flush(); - await browserProxy.whenCalled('syncVoiceModelStatus'); - }); -});
diff --git a/chrome/test/data/webui/chromeos/settings/os_search_page/search_and_assistant_settings_card_test.ts b/chrome/test/data/webui/chromeos/settings/os_search_page/search_and_assistant_settings_card_test.ts index 0fd43e3..03c1598ce 100644 --- a/chrome/test/data/webui/chromeos/settings/os_search_page/search_and_assistant_settings_card_test.ts +++ b/chrome/test/data/webui/chromeos/settings/os_search_page/search_and_assistant_settings_card_test.ts
@@ -41,7 +41,6 @@ setup(() => { loadTimeData.overrideValues({ - isAssistantAllowed: false, isQuickAnswersSupported: false, }); }); @@ -1112,39 +1111,11 @@ }); }); - suite('when Assistant settings are available', () => { - setup(() => { - loadTimeData.overrideValues({isAssistantAllowed: true}); - }); - - test('Assistant row should be visible', () => { - createSearchAndAssistantCard(); - const assistantRow = - searchAndAssistantSettingsCard.shadowRoot!.querySelector( - '#assistantRow'); - assertTrue(isVisible(assistantRow)); - }); - }); - - suite('when Assistant settings are not available', () => { - test('Assistant row should not be stamped', () => { - createSearchAndAssistantCard(); - const assistantRow = - searchAndAssistantSettingsCard.shadowRoot!.querySelector( - '#assistantRow'); - assertNull(assistantRow); - }); - }); - const subpageTriggerData: SubpageTriggerData[] = [ { triggerSelector: '#searchRow', routeName: 'SEARCH_SUBPAGE', }, - { - triggerSelector: '#assistantRow', - routeName: 'GOOGLE_ASSISTANT', - }, ]; subpageTriggerData.forEach(({triggerSelector, routeName}) => { test(
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 c40aa58..521dfae 100644 --- a/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc +++ b/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc
@@ -1409,11 +1409,6 @@ RunSettingsTest("os_reset_page/reset_settings_card_test.js"); } -IN_PROC_BROWSER_TEST_F(OSSettingsMochaTest, - OsSearchPageGoogleAssistantSubpage) { - RunSettingsTest("os_search_page/google_assistant_subpage_test.js"); -} - IN_PROC_BROWSER_TEST_F(OSSettingsMochaTest, OsSearchPageSearchEngine) { RunSettingsTest("os_search_page/search_engine_test.js"); }
diff --git a/chrome/test/data/webui/chromeos/settings/system_preferences_page/system_preferences_page_test.ts b/chrome/test/data/webui/chromeos/settings/system_preferences_page/system_preferences_page_test.ts index bad67d9..9e27af4 100644 --- a/chrome/test/data/webui/chromeos/settings/system_preferences_page/system_preferences_page_test.ts +++ b/chrome/test/data/webui/chromeos/settings/system_preferences_page/system_preferences_page_test.ts
@@ -268,25 +268,6 @@ assertNull(subpage, 'Subpage should not be stamped.'); }); - test('Assistant subpage is visible if assistant is enabled', async () => { - loadTimeData.overrideValues({isAssistantAllowed: true}); - await createPage(); - - await navigateToSubpage(routes.GOOGLE_ASSISTANT); - assertSubpageIsVisible('settings-google-assistant-subpage'); - }); - - test( - 'Assistant subpage is not stamped if assistant is disabled', - async () => { - loadTimeData.overrideValues({isAssistantAllowed: false}); - await createPage(); - - await navigateToSubpage(routes.GOOGLE_ASSISTANT); - const subpage = page.shadowRoot!.querySelector( - 'settings-google-assistant-subpage'); - assertNull(subpage, 'Subpage should not be stamped.'); - }); }); suite('Startup subsection', () => {
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts index 57db22d..796b423 100644 --- a/chrome/test/data/webui/glic/api_test.ts +++ b/chrome/test/data/webui/glic/api_test.ts
@@ -397,8 +397,8 @@ observeSequence<FocusedTabData>(this.host.getFocusedTabStateV2()); const focus = await sequence.next(); assertTrue(!!focus.hasFocus); - assertTrue( - focus.hasFocus.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus.hasFocus.tabData.url).pathname, '/glic/test.html', `url=${focus.hasFocus.tabData.url}`); assertEquals('Test Page', focus.hasFocus.tabData.title); assertFalse(!!focus.hasNoFocus); @@ -411,8 +411,8 @@ observeSequence<FocusedTabData>(this.host.getFocusedTabStateV2()); const focus = await sequence.next(); assertTrue(!!focus.hasFocus); - assertTrue( - focus.hasFocus.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus.hasFocus.tabData.url).pathname, '/glic/test.html', `url=${focus.hasFocus.tabData.url}`); assertFalse(!!focus.hasNoFocus); @@ -420,9 +420,9 @@ await this.advanceToNextStep(); const focus2 = await sequence.next(); assertTrue(!!focus2.hasFocus); - assertTrue( - focus2.hasFocus.tabData.url.endsWith( - 'scrollable_page_with_content.html'), + assertEquals( + new URL(focus2.hasFocus.tabData.url).pathname, + '/scrollable_page_with_content.html', `url=${focus2.hasFocus.tabData.url}`); await this.advanceToNextStep(); @@ -441,8 +441,8 @@ // Final state, after the tab is fully loaded. assertTrue(!!focus3.hasFocus); - assertTrue( - focus3.hasFocus.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus3.hasFocus.tabData.url).pathname, '/glic/test.html', `url=${focus3.hasFocus.tabData.url}`); assertFalse(!!focus3.hasNoFocus); } @@ -455,8 +455,8 @@ observeSequence<FocusedTabData>(this.host.getFocusedTabStateV2()); const focus = await sequence.next(); assertTrue(!!focus.hasFocus); - assertTrue( - focus.hasFocus.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus.hasFocus.tabData.url).pathname, '/glic/test.html', `url=${focus.hasFocus.tabData.url}`); assertFalse(!!focus.hasNoFocus); @@ -484,13 +484,9 @@ }); // Final state, after the tab is fully loaded. - assertFalse( - !!focus2.hasFocus && - focus2.hasFocus.tabData.url.endsWith( - 'scrollable_page_with_content.html')); assertTrue(!!focus2.hasFocus); - assertTrue( - focus2.hasFocus.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus2.hasFocus.tabData.url).pathname, '/glic/test.html', `url=${focus2.hasFocus.tabData.url}`); assertFalse(!!focus2.hasNoFocus); } @@ -506,8 +502,8 @@ !!focus.hasFocus, `#1: should have a focused tab; FocusedTabData=${ JSON.stringify(focus)}`); - assertTrue( - !!focus.hasFocus?.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus.hasFocus?.tabData.url).pathname, '/glic/test.html', `#1: Unexpected URL; FocusedTabData=${JSON.stringify(focus)}`); assertTrue( sequence.isEmpty(), '#1: Spurious updates after first tab opened'); @@ -521,9 +517,9 @@ !!focus.hasFocus, `#2: should have a focused tab; FocusedTabData=${ JSON.stringify(focus)}`); - assertTrue( - !!focus.hasFocus?.tabData.url.endsWith( - 'scrollable_page_with_content.html'), + assertEquals( + new URL(focus.hasFocus?.tabData.url).pathname, + '/scrollable_page_with_content.html', `#2: Unexpected URL; FocusedTabData=${JSON.stringify(focus)}`); assertTrue( sequence.isEmpty(), '#2: Spurious updates after first tab navigated'); @@ -537,8 +533,8 @@ !!focus.hasFocus, `#3: should have a focused tab; FocusedTabData=${ JSON.stringify(focus)}`); - assertTrue( - !!focus.hasFocus?.tabData.url.endsWith('glic/test.html'), + assertEquals( + new URL(focus.hasFocus?.tabData.url).pathname, '/glic/test.html', `#3: Unexpected URL; FocusedTabData=${JSON.stringify(focus)}`); assertTrue( sequence.isEmpty(), '#3: Spurious updates after a new tab opened'); @@ -561,7 +557,7 @@ await this.host.setTabContextPermissionState(false); try { - await this.host.getContextFromFocusedTab?.({}); + await this.host.getContextFromFocusedTab({}); } catch (e) { assertEquals( 'tabContext failed: permission denied:' + @@ -570,14 +566,32 @@ } } + async testGetContextFromPinnedTabWithoutPermission() { + assertTrue(!!this.host.getContextFromTab); + assertTrue(!!this.host.getFocusedTabStateV2); + assertTrue(!!this.host.pinTabs); + await this.host.setTabContextPermissionState(false); + + const focusSequence = + observeSequence<FocusedTabData>(this.host.getFocusedTabStateV2()); + const focus = await focusSequence.next(); + const tabId = checkDefined(focus?.hasFocus?.tabData.tabId); + assertTrue(!!await this.host.pinTabs([tabId])); + const result = await this.host.getContextFromTab(tabId, {}); + assertTrue(!!result); + assertEquals( + new URL(result.tabData.url).pathname, '/glic/test.html', + `Tab data has unexpected url ${result.tabData.url}`); + } + async testGetContextFromFocusedTabWithNoRequestedData() { assertTrue(!!this.host.getContextFromFocusedTab); await this.host.setTabContextPermissionState(true); const result = await this.host.getContextFromFocusedTab({}); assertTrue(!!result); - assertTrue( - result.tabData.url.endsWith('glic/test.html') ?? false, + assertEquals( + new URL(result.tabData.url).pathname, '/glic/test.html', `Tab data has unexpected url ${result.tabData.url}`); assertFalse(!!result.annotatedPageData); assertFalse(!!result.pdfDocumentData); @@ -598,8 +612,8 @@ assertTrue(!!result); - assertTrue( - result.tabData.url.endsWith('glic/test.html') ?? false, + assertEquals( + new URL(result.tabData.url).pathname, '/glic/test.html', `Tab data has unexpected url ${result.tabData.url}`); assertFalse(!!result.pdfDocumentData); // The page is not a PDF. assertTrue(!!result.webPageData); @@ -652,8 +666,8 @@ return result; }); - assertTrue( - result.tabData.url.endsWith('pdf/test.pdf') ?? false, + assertEquals( + new URL(result.tabData.url).pathname, '/pdf/test.pdf', `Tab data has unexpected url ${result.tabData.url}`); assertFalse(!!result.webPageData); @@ -1033,16 +1047,68 @@ } } - async testPinTabs() { - // Pin the focused tab and verify it's sent. - assertTrue(!!this.host.pinTabs); - assertTrue(!!this.host.getPinnedTabs); + // Helper function to pin the focused tab. Asserts the tab is pinned, and + // returns the tab ID. + async pinFocusedTab(): Promise<string> { + assertDefined(this.host.pinTabs); + assertDefined(this.host.getPinnedTabs); + assertDefined(this.host.unpinTabs); const focus = this.host.getFocusedTabStateV2?.().getCurrentValue(); const tabId = checkDefined(focus?.hasFocus?.tabData.tabId); await this.host.pinTabs([tabId]); const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); await pinnedTabsUpdates.waitFor( - (tabs) => tabs.length === 1 && tabs[0]?.tabId === tabId); + (tabs) => tabs.some(t => t.tabId === tabId)); + return tabId; + } + + async testPinTabs() { + // Pin the focused tab and verify it's sent. + assertDefined(this.host.getPinnedTabs); + assertDefined(this.host.unpinTabs); + await this.pinFocusedTab(); + + // Unpin and verify the pinned tab list is updated. + const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); + const tabId = checkDefined((await pinnedTabsUpdates.next())[0]?.tabId); + assertEquals(true, await this.host.unpinTabs([tabId])); + await pinnedTabsUpdates.waitFor((tabs) => tabs.length === 0); + } + + async testUnpinTabsWhileClosing() { + assertDefined(this.host.closePanel); + const tabId = await this.pinFocusedTab(); + const {promise, resolve} = Promise.withResolvers<boolean>(); + this.client.onNotifyPanelWasClosed = () => { + this.host.unpinTabs!([tabId]).then(resolve); + }; + await this.host.closePanel(); + assertTrue(await promise); + } + + async testPinTabsWithTwoTabs() { + // Pin the focused tab and verify it's sent. + assertDefined(this.host.pinTabs); + assertDefined(this.host.getPinnedTabs); + assertDefined(this.host.unpinTabs); + assertDefined(this.host.getFocusedTabStateV2); + + const tabId = await this.pinFocusedTab(); + + // Focus the next tab. + await this.advanceToNextStep(); + + // Wait for focus to change and pin the focused tab. + await observeSequence(this.host.getFocusedTabStateV2()) + .waitFor((f) => !!f.hasFocus && f.hasFocus.tabData.tabId !== tabId); + const tabId2 = await this.pinFocusedTab(); + + // Wait until we see two pinned tabs. + const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); + await pinnedTabsUpdates.waitFor((tabs) => tabs.length === 2); + + assertEquals(true, await this.host.unpinTabs([tabId, tabId2])); + await pinnedTabsUpdates.waitFor((tabs) => tabs.length === 0); } // Helper for `testFetchInactiveTabScreenshot` and @@ -1257,11 +1323,59 @@ await this.advanceToNextStep(); focusedTabState = await tabStatePromise; assertTrue(!!focusedTabState.hasFocus); - assertTrue( - focusedTabState.hasFocus.tabData.url.endsWith( - 'scrollable_page_with_content.html'), + assertEquals( + new URL(focusedTabState.hasFocus.tabData.url).pathname, + '/scrollable_page_with_content.html', `url=${focusedTabState.hasFocus.tabData.url}`); } + + async testNoExtractionWhileHidden() { + assertTrue(!!this.host.getContextFromFocusedTab); + assertTrue(!!this.host.getContextFromTab); + assertTrue(!!this.host.getFocusedTabStateV2); + assertTrue(!!this.host.pinTabs); + await this.host.setTabContextPermissionState(true); + + // While still hidden (preloaded), focused tab extraction should fail. + let errorMessage = + await assertRejects(this.host.getContextFromFocusedTab({})); + assertEquals( + 'tabContext failed: permission denied: window not showing', + errorMessage); + + // Glic panel is open, so both focused and arbitrary tab extraction should + // succeed. + await this.advanceToNextStep(); + await this.client.waitForFirstOpen(); + let result = await this.host.getContextFromFocusedTab({}); + assertTrue(!!result); + assertEquals( + new URL(result.tabData.url).pathname, '/glic/test.html', + `Tab data has unexpected url ${result.tabData.url}`); + const focusedTab = await this.host.getFocusedTabStateV2().getCurrentValue(); + const tabId = checkDefined(focusedTab?.hasFocus?.tabData.tabId); + assertTrue(await this.host.pinTabs([tabId])); + result = await this.host.getContextFromTab(tabId, {}); + assertTrue(!!result); + assertEquals( + new URL(result.tabData.url).pathname, '/glic/test.html', + `Tab data has unexpected url ${result.tabData.url}`); + + // Glic panel is hidden again. Focused and arbitrary tab extraction should + // fail. + await this.advanceToNextStep(); + // Panel closure was only requested by native code, but still needs to be + // waited on. + await observeSequence(this.host.panelActive()).waitForValue(false); + errorMessage = await assertRejects(this.host.getContextFromFocusedTab({})); + assertEquals( + 'tabContext failed: permission denied: window not showing', + errorMessage); + errorMessage = await assertRejects(this.host.getContextFromTab(tabId, {})); + assertEquals( + 'tabContext failed: permission denied: window not showing', + errorMessage); + } } type InitFailureType = 'error'|'timeout'|'none'|'reloadAfterInitialize'| @@ -1603,6 +1717,12 @@ } } +function assertDefined<T>(x: T|undefined, message?: string): asserts x { + if (x === undefined) { + throw new Error(`assertDefined failed. ${message ?? ''}`); + } +} + function assertFalse(x: boolean, message?: string): asserts x is false { if (x) { throw new Error(
diff --git a/chrome/test/data/webui/glic/test_client/index.html b/chrome/test/data/webui/glic/test_client/index.html index f1657326..56143a0 100644 --- a/chrome/test/data/webui/glic/test_client/index.html +++ b/chrome/test/data/webui/glic/test_client/index.html
@@ -486,7 +486,7 @@ </div> </div> <div class="section"> - <h1>Test actInFocusedTab()</h1> + <h1>Test performActions()</h1> <div> <label for="actorTaskId">Task ID</label> <input id="actorTaskId" type="number" style="width: 8ch;" /> @@ -495,14 +495,10 @@ </div> <div> <label> <input type="text" id="actionProtoEncodedText" /> - Action Proto, base64-encoded from http://shortn/_Iyf96Pob5S + Action Proto, base64-encoded from http://shortn/_pPzGXm1TZR </label> - <button id="executeAction">Execute Action</button> + <button id="executeAction">Perform Actions</button> </div> - <div id="actionUpdatedScreenshot"> - <img id="actionUpdatedScreenshotImg" /> - </div> - <span id="actionUpdatedContextResult"></span> <span id="actionStatus"></span> </div> <div class="section" id="multiTabSection">
diff --git a/chrome/test/data/webui/glic/test_client/sections/action.ts b/chrome/test/data/webui/glic/test_client/sections/action.ts index ed584c6..8e3335cad 100644 --- a/chrome/test/data/webui/glic/test_client/sections/action.ts +++ b/chrome/test/data/webui/glic/test_client/sections/action.ts
@@ -2,47 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {client, logMessage, readStream} from '../client.js'; +import {client, logMessage} from '../client.js'; import {$} from '../page_element_types.js'; +function convertUint8ArrayToBase64(uint8Array: Uint8Array): string { + let binaryString = ''; + for (let i = 0; i < uint8Array.length; i++) { + binaryString += String.fromCharCode(uint8Array[i]!); + } + return btoa(binaryString); +} $.executeAction.addEventListener('click', async () => { logMessage('Starting Execute Action'); - // The action proto is expected to be a BrowserAction proto, which is binary + // The action proto is expected to be a Actions proto, which is binary // serialized and then base64 encoded. const protoBytes = Uint8Array.fromBase64($.actionProtoEncodedText.value); - - const params: any = { - actionProto: protoBytes.buffer, - tabContextOptions: {annotatedPageContent: true, viewportScreenshot: true}, - }; - - $.actionUpdatedContextResult.innerText = ''; - $.actionUpdatedScreenshotImg.src = ''; try { - const actionResult = await client!.browser!.actInFocusedTab!(params); - const pageContent = actionResult.tabContextResult; - if (pageContent) { - if (pageContent.viewportScreenshot) { - const blob = new Blob( - [pageContent.viewportScreenshot.data], {type: 'image/jpeg'}); - $.actionUpdatedScreenshotImg.src = URL.createObjectURL(blob); - } - if (pageContent.annotatedPageData && - pageContent.annotatedPageData.annotatedPageContent) { - const annotatedPageDataSize = - (await readStream( - pageContent.annotatedPageData.annotatedPageContent)) - .length; - $.actionUpdatedContextResult.innerText = - `Annotated page content data length: ${annotatedPageDataSize}`; - } - } - $.actionStatus.innerText = - `Finished Execute Action. Result code ${actionResult.actionResult}.`; - $.actionUpdatedContextResult.innerText += - `Returned data: ${JSON.stringify(pageContent, null, 2)}`; + const actionResult = await client!.browser!.performActions! + (protoBytes.buffer as ArrayBuffer); + $.actionStatus.innerText = `Finished Execute Action. Result code ${ + convertUint8ArrayToBase64(new Uint8Array(actionResult))}.`; } catch (error) { $.actionStatus.innerText = `Error in Execute Action: ${error}`; }
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts index 89ab9f0c..1333d85 100644 --- a/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts
@@ -32,11 +32,6 @@ return module; } - test('no module created if no tab groups data', async () => { - const module = await createModule([]); - assertEquals(null, module); - }); - test('create module', async () => { // Arrange. const tabGroups: TabGroup[] = [ @@ -209,4 +204,36 @@ const overflowText = overflowCells[0]!.textContent!.trim(); assertEquals('99+', overflowText); }); + + test('show zero state card when there are no tab groups', async () => { + // Arrange. + const module = await createModule([]); + + // Assert. + // The module must still exist without tab groups data. + assertTrue(!!module); + assertTrue( + isVisible(module.shadowRoot.querySelector('ntp-module-header-v2'))); + + // The zero-state container should be present and visible. + const zeroStateContainer = + module.shadowRoot.querySelector('#zeroTabGroupsContainer'); + assertTrue(!!zeroStateContainer); + assertTrue(isVisible(zeroStateContainer)); + + // Tab group rows should be absent. + const tabGroupContainers = + module.shadowRoot.querySelectorAll('.tab-group-container'); + assertEquals(0, tabGroupContainers.length); + + // Verify strings. + assertEquals( + 'Stay organized with tab groups', + zeroStateContainer.querySelector( + '#zeroTabGroupsTitle')!.textContent!.trim()); + assertEquals( + 'You can group tabs to keep related pages together and saved across your devices', + zeroStateContainer.querySelector( + '#zeroTabGroupsText')!.textContent!.trim()); + }); });
diff --git a/chrome/test/data/webui/settings/searchable_view_container_mixin_test.ts b/chrome/test/data/webui/settings/searchable_view_container_mixin_test.ts index 8ca3cb5..2829835 100644 --- a/chrome/test/data/webui/settings/searchable_view_container_mixin_test.ts +++ b/chrome/test/data/webui/settings/searchable_view_container_mixin_test.ts
@@ -5,6 +5,7 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {Router, routes, SearchableViewContainerMixin, SettingsViewMixin} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {isVisible} from 'chrome://webui-test/test_util.js'; suite('SearchableViewContainerMixin', function() { const TestParentViewElementBase = SettingsViewMixin(PolymerElement); @@ -37,24 +38,33 @@ static get template() { return html` + <style> + cr-view-manager [hidden-by-search], + cr-view-manager[show-all] [slot=view][data-parent-view-id] { + display: none; + } + cr-view-manager [slot=view]:not(.closing) { + position: initial; + } + </style> <div id="container" scrollable> <cr-view-manager show-all$="[[shouldShowAll]]"> + <test-parent-view slot="view" id="parentView0"> + <span>ParentView0</span> + <button data-child-trigger="childView0"></button> + </test-parent-view> + <test-parent-view slot="view" id="parentView1"> <span>ParentView1</span> <button data-child-trigger="childView1"></button> </test-parent-view> - <test-parent-view slot="view" id="parentView2"> - <span>ParentView2</span> - <button data-child-trigger="childView2"></button> - </test-parent-view> - + <div slot="view" id="childView0" data-parent-view-id="parentView0"> + ChildView0 + </div> <div slot="view" id="childView1" data-parent-view-id="parentView1"> ChildView1 </div> - <div slot="view" id="childView2" data-parent-view-id="parentView2"> - ChildView2 - </div> </cr-view-manager> </div> `; @@ -107,6 +117,7 @@ parentVisible: [boolean, boolean], childHasHits: [boolean, boolean]) { // Check parent views hidden-by-search attribute. for (let i = 0; i < parentVisible.length; i++) { + assertEquals(parentVisible[i], isVisible(parentViews[i]!)); assertEquals( parentVisible[i], !parentViews[i]!.hasAttribute('hidden-by-search')); @@ -129,56 +140,58 @@ } } - // Case1: Search results exist only in #parentView1. - let result = await testElement.searchContents('ParentView1'); + testElement.inSearchMode = true; + + // Case1: Search results exist only in #parentView0. + let result = await testElement.searchContents('ParentView0'); assertFalse(result.canceled); assertEquals(1, result.matchCount); assertFalse(result.wasClearSearch); assertDomState([true, false], [false, false]); - // Case2: Search results exist only in #parentView2. - result = await testElement.searchContents('ParentView2'); + // Case2: Search results exist only in #parentView1. + result = await testElement.searchContents('ParentView1'); assertFalse(result.canceled); assertEquals(1, result.matchCount); assertFalse(result.wasClearSearch); assertDomState([false, true], [false, false]); - // Case3: Search results exist in both #parentView1, #parentView2. + // Case3: Search results exist in both #parentView0, #parentView1. result = await testElement.searchContents('ParentView'); assertFalse(result.canceled); assertEquals(2, result.matchCount); assertFalse(result.wasClearSearch); assertDomState([true, true], [false, false]); - // Case4: Search results exist in both #parentView1, #childView1. + // Case4: Search results exist in both #parentView0, #childView0. + result = await testElement.searchContents('View0'); + assertFalse(result.canceled); + assertEquals(2, result.matchCount); + assertFalse(result.wasClearSearch); + assertDomState([true, false], [true, false]); + + // Case5: Search results exist only #childView0. + result = await testElement.searchContents('ChildView0'); + assertFalse(result.canceled); + assertEquals(1, result.matchCount); + assertFalse(result.wasClearSearch); + assertDomState([true, false], [true, false]); + + // Case6: Search results exist in both #parentView1, #childView1. result = await testElement.searchContents('View1'); assertFalse(result.canceled); assertEquals(2, result.matchCount); assertFalse(result.wasClearSearch); - assertDomState([true, false], [true, false]); + assertDomState([false, true], [false, true]); - // Case5: Search results exist only #childView1. + // Case7: Search results exist only #childView1. result = await testElement.searchContents('ChildView1'); assertFalse(result.canceled); assertEquals(1, result.matchCount); assertFalse(result.wasClearSearch); - assertDomState([true, false], [true, false]); - - // Case6: Search results exist in both #parentView2, #childView2. - result = await testElement.searchContents('View2'); - assertFalse(result.canceled); - assertEquals(2, result.matchCount); - assertFalse(result.wasClearSearch); assertDomState([false, true], [false, true]); - // Case7: Search results exist only #childView2. - result = await testElement.searchContents('ChildView2'); - assertFalse(result.canceled); - assertEquals(1, result.matchCount); - assertFalse(result.wasClearSearch); - assertDomState([false, true], [false, true]); - - // Case8: Search results exist only in #childView1, #childView2. + // Case8: Search results exist only in #childView0, #childView1. result = await testElement.searchContents('ChildView'); assertFalse(result.canceled); assertEquals(2, result.matchCount); @@ -191,5 +204,23 @@ assertEquals(0, result.matchCount); assertTrue(result.wasClearSearch); assertDomState([true, true], [false, false]); + + // Case10: childView0 has 'no-search'. + childViews[0]!.toggleAttribute('no-search', true); + result = await testElement.searchContents('ChildView'); + assertFalse(result.canceled); + assertEquals(1, result.matchCount); + assertFalse(result.wasClearSearch); + assertDomState([false, true], [false, true]); + + // Case11: childView1 also has 'no-search'. + childViews[1]!.toggleAttribute('no-search', true); + // Clear search first and then search again for 'ChildView'. + await testElement.searchContents(''); + result = await testElement.searchContents('ChildView'); + assertFalse(result.canceled); + assertEquals(0, result.matchCount); + assertFalse(result.wasClearSearch); + assertDomState([false, false], [false, false]); }); });
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/CastSettingsManager.java b/chromecast/base/java/src/org/chromium/chromecast/base/CastSettingsManager.java index 67291af3..0889bb0 100644 --- a/chromecast/base/java/src/org/chromium/chromecast/base/CastSettingsManager.java +++ b/chromecast/base/java/src/org/chromium/chromecast/base/CastSettingsManager.java
@@ -27,14 +27,12 @@ private final ContentResolver mContentResolver; - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - ContentObserver mDeviceNameObserver; - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - ContentObserver mIsDeviceProvisionedObserver; + @VisibleForTesting ContentObserver mDeviceNameObserver; + @VisibleForTesting ContentObserver mIsDeviceProvisionedObserver; /** - * Can be implemented to receive notifications from a CastSettingsManager instance when - * settings have changed. + * Can be implemented to receive notifications from a CastSettingsManager instance when settings + * have changed. */ public static class OnSettingChangedListener { public void onCastEnabledChanged(boolean enabled) {}
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index aaed1ce6..99f31dc 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16365.0.0-1070602 \ No newline at end of file +16365.0.0-1070611 \ No newline at end of file
diff --git a/chromeos/ash/experiences/arc/mojom/metrics.mojom b/chromeos/ash/experiences/arc/mojom/metrics.mojom index 34bb0394..11894893 100644 --- a/chromeos/ash/experiences/arc/mojom/metrics.mojom +++ b/chromeos/ash/experiences/arc/mojom/metrics.mojom
@@ -390,6 +390,7 @@ kHttp404 = 7, kHttp500 = 8, kHttp503 = 9, + kDevMode = 10, }; // Enumerates the types of Anr and Crash dialogs, based on the resource id the
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt index a6b4d4d..484a98a 100644 --- a/chromeos/profiles/arm.afdo.newest.txt +++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-none-140-7258.43-1753063931-benchmark-140.0.7320.0_pre1492415-r1-redacted.afdo.xz +chromeos-chrome-arm-none-140-7310.0-1753669715-benchmark-140.0.7324.0_pre1492793-r1-redacted.afdo.xz
diff --git a/clank b/clank index 83cc392..88c267f 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 83cc392fc295bf08ab5cb013564d48aec5a1e780 +Subproject commit 88c267fb3df8825e494ead1793b53c8ca174d23e
diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc index 5d42a99..8d790a4 100644 --- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc +++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
@@ -305,7 +305,7 @@ auto country_field = std::make_unique<AutofillField>(); country_field->set_server_predictions( {CreatePrediction(PASSPORT_ISSUING_COUNTRY)}); - country_field->SetTypeTo(AutofillType(ADDRESS_HOME_COUNTRY), + country_field->SetTypeTo(AutofillType(PASSPORT_ISSUING_COUNTRY), AutofillPredictionSource::kServerCrowdsourcing); // The passport number needs to be added in order for a form/set of fields // to be pass the passport entity requirements.
diff --git a/components/autofill/core/browser/payments/autofill_save_card_ui_info.cc b/components/autofill/core/browser/payments/autofill_save_card_ui_info.cc index f875ad7..5dbc2b2 100644 --- a/components/autofill/core/browser/payments/autofill_save_card_ui_info.cc +++ b/components/autofill/core/browser/payments/autofill_save_card_ui_info.cc
@@ -224,17 +224,9 @@ save_card_icon_description_text = l10n_util::GetStringUTF16( IDS_AUTOFILL_GOOGLE_PAY_LOGO_ACCESSIBLE_NAME); save_card_prompt_title_id = - base::FeatureList::IsEnabled( - features::kAutofillEnableShowSaveCardSecurelyMessage) - ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_SECURITY - : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3; - description_text = - base::FeatureList::IsEnabled( - features::kAutofillEnableShowSaveCardSecurelyMessage) - ? l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_SECURITY) - : l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD); + IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_SECURITY; + description_text = l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_SECURITY); } else { save_card_icon_id = IDR_INFOBAR_AUTOFILL_CC; save_card_prompt_title_id =
diff --git a/components/autofill/core/browser/payments/autofill_save_card_ui_info_unittest.cc b/components/autofill/core/browser/payments/autofill_save_card_ui_info_unittest.cc index 06987ac..f0d7f3ad2 100644 --- a/components/autofill/core/browser/payments/autofill_save_card_ui_info_unittest.cc +++ b/components/autofill/core/browser/payments/autofill_save_card_ui_info_unittest.cc
@@ -241,13 +241,6 @@ : public testing::Test, public testing::WithParamInterface<bool> { public: - AutofillSaveCardUiInfoTestForUploadSave() { -#if BUILDFLAG(IS_ANDROID) - features_.InitAndEnableFeature( - features::kAutofillEnableShowSaveCardSecurelyMessage); -#endif // #BUILDFLAG(IS_ANDROID) - } - ~AutofillSaveCardUiInfoTestForUploadSave() override = default; bool is_gpay_branded() const { return GetParam(); } @@ -479,36 +472,6 @@ // Verify that AutofillSaveCardUiInfo attributes are correctly set for the // upload-card-save-with-CVC bottom sheet. TEST_P(AutofillSaveCardUiInfoTestForUploadSave, - VerifyAttributesForCardSaveWithCvcBottomSheet_FlagOff) { - base::test::ScopedFeatureList features; - features.InitWithFeatures( - /*enabled_features=*/{features::kAutofillEnableCvcStorageAndFilling}, - /*disabled_features=*/{ - features::kAutofillEnableShowSaveCardSecurelyMessage}); - - auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest( - /*options=*/{.card_save_type = CardSaveType::kCardSaveWithCvc}, - is_gpay_branded()); - - EXPECT_EQ(ui_info.logo_icon_id, is_gpay_branded() ? IDR_AUTOFILL_GOOGLE_PAY - : IDR_INFOBAR_AUTOFILL_CC); - EXPECT_EQ( - ui_info.title_text, - l10n_util::GetStringUTF16( - is_gpay_branded() ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3 - : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD)); - EXPECT_EQ(ui_info.description_text, - is_gpay_branded() - ? l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD) - : u""); - EXPECT_EQ(ui_info.confirm_text, - l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT)); -} - -// Verify that AutofillSaveCardUiInfo attributes are correctly set for the -// upload-card-save-with-CVC bottom sheet. -TEST_P(AutofillSaveCardUiInfoTestForUploadSave, VerifyAttributesForCardSaveWithCvcBottomSheet) { base::test::ScopedFeatureList features( features::kAutofillEnableCvcStorageAndFilling);
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc index 4ec349b..bef49879 100644 --- a/components/autofill/core/common/autofill_payments_features.cc +++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -231,12 +231,6 @@ "AutofillEnableSeparatePixPreferenceItem", base::FEATURE_DISABLED_BY_DEFAULT); -// When enabled, save card securely message be displayed on upload card -// UI message. -BASE_FEATURE(kAutofillEnableShowSaveCardSecurelyMessage, - "AutofillEnableShowSaveCardSecurelyMessage", - base::FEATURE_ENABLED_BY_DEFAULT); - // When enabled, Pix bank accounts are synced from Chrome Sync backend and // stored in the local db. BASE_FEATURE(kAutofillEnableSyncingOfPixBankAccounts,
diff --git a/components/autofill/core/common/autofill_payments_features.h b/components/autofill/core/common/autofill_payments_features.h index 587293eb..36e6f181 100644 --- a/components/autofill/core/common/autofill_payments_features.h +++ b/components/autofill/core/common/autofill_payments_features.h
@@ -88,8 +88,6 @@ COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillEnableSeparatePixPreferenceItem); COMPONENT_EXPORT(AUTOFILL) -BASE_DECLARE_FEATURE(kAutofillEnableShowSaveCardSecurelyMessage); -COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillEnableSyncingOfPixBankAccounts); #endif
diff --git a/components/autofill/core/common/dense_set.h b/components/autofill/core/common/dense_set.h index d8393338..7ddb52d 100644 --- a/components/autofill/core/common/dense_set.h +++ b/components/autofill/core/common/dense_set.h
@@ -472,6 +472,11 @@ constexpr explicit DenseSet(const Range& range, Proj proj = {}) : DenseSet(std::ranges::begin(range), std::ranges::end(range), proj) {} + constexpr DenseSet(const DenseSet&) = default; + constexpr DenseSet& operator=(const DenseSet&) = default; + + constexpr ~DenseSet() = default; + // Returns a set containing all values from `kMinValue` to `kMaxValue`, // regardless of whether the values represent an existing enum. static constexpr DenseSet all() {
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 0bb4c8b..0283d24 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -190,12 +190,9 @@ <message name="IDS_AUTOFILL_SAVE_CVC_PROMPT_EXPLANATION_UPLOAD" desc="Explanation text for the Autofill save CVC prompt that offers to upload CVC to the Sync server for existing server cards. This prompt is shown if a CVC is detected for an existing server card on form submission."> This card's CVC will be encrypted and saved in your Google Account for faster checkout </message> - <message name="IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD" desc="Explanation for the effect of the Autofill save card prompt when the card is to be saved along with the CVC by uploading it to the server. The prompt will be shown on both the Desktop bubble and the Android bottom sheet."> - To pay faster next time, save your card, encrypted security code, and billing address in your Google Account + <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_SECURITY" desc="Explanation of the benefit of credit card upload save on Desktop, using security-focused messaging. Became the new default for Desktop in Dec. 2024 and new default for Android and IOS (bottomsheet only) in H1 2025."> + Pay faster when your card is saved. Card details are encrypted in your Google Account. </message> - <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_SECURITY" desc="Explanation of the benefit of credit card upload save on Desktop, using security-focused messaging. Became the new default for Desktop in Dec. 2024 and new default for Android and IOS (bottomsheet only) in H1 2025."> - Pay faster when your card is saved. Card details are encrypted in your Google Account. - </message> <if expr="is_android"> <message name="IDS_AUTOFILL_SAVE_CVC_MESSAGE_SAVE_ACCEPT" desc="Positive button label for the Autofill save CVC prompt that offers to save CVC for existing server cards. This prompt is shown if a CVC is detected for an existing server card on form submission. The prompt is shown in a Message UI on Android devices."> Save
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD.png.sha1 deleted file mode 100644 index e462763..0000000 --- a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -d5584dd67f54b2601a1226b7fc1b7b054809e32d \ No newline at end of file
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index d8a0796..fe6436e 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp
@@ -798,42 +798,42 @@ </message> <!-- Attributes of the passport entity --> - <message name="IDS_AUTOFILL_AI_PASSPORT_NAME_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “First and last name” and Delta might label it “Full name”. Once the information is saved with Autofill with AI, we just call the value “Name”."> + <message name="IDS_AUTOFILL_AI_PASSPORT_NAME_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “First and last name” and Delta might label it “Full name”. Once the information is saved with enhanced autofill, we just call the value “Name”."> Name </message> - <message name="IDS_AUTOFILL_AI_PASSPORT_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Passport” and Delta might label it “Passport number”. Once the information is saved with Autofill with AI, we just call the value “Number”."> + <message name="IDS_AUTOFILL_AI_PASSPORT_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Passport” and Delta might label it “Passport number”. Once the information is saved with enhanced autofill, we just call the value “Number”."> Number </message> - <message name="IDS_AUTOFILL_AI_PASSPORT_COUNTRY_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Region” and Delta might label it “Country”. Once the information is saved with Autofill with AI, we just call the value “Country”."> + <message name="IDS_AUTOFILL_AI_PASSPORT_COUNTRY_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Region” and Delta might label it “Country”. Once the information is saved with enhanced autofill, we just call the value “Country”."> Country </message> - <message name="IDS_AUTOFILL_AI_PASSPORT_EXPIRATION_DATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Expires” and Delta might label it “Date passport expires”. Once the information is saved with Autofill with AI, we just call the value “Expiration date”."> + <message name="IDS_AUTOFILL_AI_PASSPORT_EXPIRATION_DATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Expires” and Delta might label it “Date passport expires”. Once the information is saved with enhanced autofill, we just call the value “Expiration date”."> Expiration date </message> - <message name="IDS_AUTOFILL_AI_PASSPORT_ISSUE_DATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Issue” and Delta might label it “Date passport issue”. Once the information is saved with Autofill with AI, we just call the value “Issue date”."> + <message name="IDS_AUTOFILL_AI_PASSPORT_ISSUE_DATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, United Airlines might label the field “Issue” and Delta might label it “Date passport issue”. Once the information is saved with enhanced autofill, we just call the value “Issue date”."> Issue date </message> <!-- Attributes of the vehicle entity --> - <message name="IDS_AUTOFILL_AI_VEHICLE_MAKE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Type of car” and another might label it “Car make”. Once the information is saved with Autofill with AI, we just call the value “Make”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_MAKE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Type of car” and another might label it “Car make”. Once the information is saved with enhanced autofill, we just call the value “Make”."> Make </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_MODEL_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Model picker” and another might label it “Car model”. Once the information is saved with Autofill with AI, we just call the value “Model”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_MODEL_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Model picker” and another might label it “Car model”. Once the information is saved with enhanced autofill, we just call the value “Model”."> Model </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_YEAR_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Model year” and another might label it “Year of model”. Once the information is saved with Autofill with AI, we just call the value “Year”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_YEAR_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Model year” and another might label it “Year of model”. Once the information is saved with enhanced autofill, we just call the value “Year”."> Year </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_OWNER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Owner’s name” and another might label it “Your name”. Once the information is saved with Autofill with AI, we just call the value “Owner”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_OWNER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Owner’s name” and another might label it “Your name”. Once the information is saved with enhanced autofill, we just call the value “Owner”."> Owner </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_PLATE_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “License” and another might label it “plate number”. Once the information is saved with Autofill with AI, we just call the value “License plater”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_PLATE_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “License” and another might label it “plate number”. Once the information is saved with enhanced autofill, we just call the value “License plater”."> License plate </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_PLATE_STATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “State” and another might label it “Issuing state”. Once the information is saved with Autofill with AI, we just call the value “Plate state”."> + <message name="IDS_AUTOFILL_AI_VEHICLE_PLATE_STATE_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “State” and another might label it “Issuing state”. Once the information is saved with enhanced autofill, we just call the value “Plate state”."> Plate state </message> - <message name="IDS_AUTOFILL_AI_VEHICLE_VEHICLE_IDENTIFICATION_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Registration“ and another might label it “Vehicle Identification Number“. Once the information is saved with Autofill with AI, we just call the value “VIN (Vehicle Identification Number)“. Please use Glossary Manager or look up the official term for your country."> + <message name="IDS_AUTOFILL_AI_VEHICLE_VEHICLE_IDENTIFICATION_NUMBER_ATTRIBUTE_NAME" desc="A label that describes a piece of user data. This label loosely aligns with the original form the user submitted. For example, one website might label the field “Registration“ and another might label it “Vehicle Identification Number“. Once the information is saved with enhanced autofill, we just call the value “VIN (Vehicle Identification Number)“. Please use Glossary Manager or look up the official term for your country."> VIN (vehicle identification number) </message> @@ -852,27 +852,27 @@ <message name="IDS_AUTOFILL_PREDICTION_IMPROVEMENTS_UPDATE_DIALOG_UPDATE_BUTTON" desc="Text displayed on the accept/save button of the update dialog."> Update </message> - <message name="IDS_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_DIALOG_FOOTER_DETAILS" desc="Text displayed on the footer of the save dialog giving users details about how Autofill with AI data is saved."> + <message name="IDS_AUTOFILL_PREDICTION_IMPROVEMENTS_SAVE_DIALOG_FOOTER_DETAILS" desc="Text displayed on the footer of the save dialog giving users details about how enhanced autofill data is saved."> Saved info and the page from <ph name="WEBSITE">$1<ex>airline.com</ex></ph> are sent to Google and may be seen by human reviewers to improve this feature. </message> <!-- Iph --> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TITLE" desc="The title of a promotional bubble that is likely the user's first engagement with Autofill for AI. Many users are familiar with Chrome Autofill and use it to automatically fill in things like passwords and credit cards. This service promoted on this screen frames the new service as the autofill that users are familiar with but better, because it's powered by AI and can do more for you."> + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TITLE" desc="The title of a promotional bubble that is likely the user's first engagement with enhanced autofill. Many users are familiar with Chrome Autofill and use it to automatically fill in things like passwords and credit cards. This service promoted on this screen frames the new service as the autofill that users are familiar with but better, because it's powered by AI and can do more for you."> Autofill just got better </message> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_BODY" desc="The body text in a promotional bubble that appears beneath the title: “Autofill just got better”. * “Turn on”: This new feature is opt in, so we want to encourage users to click “Go to settings” and turn the feature on. “autofill with AI” is what we're calling this new feature. We want users to associate the new feature with the familiar autofill functionality they're already used to but want to convey how it's different (AI). * “automatically” should feel valuable to users as the autofill service is making tasks for them simpler. * “more fields”: the existing autofill functionality in Chrome covers things like passwords, credit cards, and building addresses. With this new service, we can also cover 1) passports, 2) vehicles, and 3) driver's licenses."> - Turn on autofill with AI to automatically fill more fields + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_BODY" desc="The body text in a promotional bubble that appears beneath the title: “Autofill just got better”. * “Turn on”: This new feature is opt in, so we want to encourage users to click “Go to settings” and turn the feature on. “enhanced autofill” is what we're calling this new feature. We want users to associate the new feature with the familiar autofill functionality they're already used to but want to convey how it's different (AI). * “automatically” should feel valuable to users as the autofill service is making tasks for them simpler. * “more fields”: the existing autofill functionality in Chrome covers things like passwords, credit cards, and building addresses. With this new service, we can also cover 1) passports, 2) vehicles, and 3) driver's licenses."> + Turn on enhanced autofill to automatically fill more fields </message> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_SEE_HOW" desc="The right of two buttons that’s the user’s path learning more and turning on Autofill with AI. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_SEE_HOW" desc="The right of two buttons that’s the user’s path learning more and turning on enhanced autofill. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> See how </message> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TURN_ON" desc="The right of two buttons that’s the user’s path learning more and turning on Autofill with AI. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TURN_ON" desc="The right of two buttons that’s the user’s path learning more and turning on enhanced autofill. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> Turn on </message> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TRY_IT" desc="The right of two buttons that’s the user’s path learning more and turning on Autofill with AI. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_TRY_IT" desc="The right of two buttons that’s the user’s path learning more and turning on enhanced autofill. This button label should pair with the title (in other words, assume the user doesn’t read the body text. Does the title and primary button label make sense together)?"> Try it </message> - <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_MAYBE_LATER" desc="The left of two buttons that’s essentially the user’s path to not learning more or turning on Autofill with AI. “Maybe later” conveys that the user won’t do it now but that they’ll have the choice to do it later. Localizer has existing translations of this button label."> + <message name="IDS_AUTOFILL_AI_OPT_IN_IPH_MAYBE_LATER" desc="The left of two buttons that’s essentially the user’s path to not learning more or turning on enhanced autofill. “Maybe later” conveys that the user won’t do it now but that they’ll have the choice to do it later. Localizer has existing translations of this button label."> Maybe later </message> @@ -913,16 +913,16 @@ </message> <!-- FFR Dialog --> - <message name="IDS_AUTOFILL_AI_FFR_WHEN_ON_TITLE" desc="A sub title that highlights the benefits of using ‘autofill with AI’. ‘More fields’ is referring to values in online forms. The user can fill more fields faster because ‘Autofill with AI’ supports more data types than standard autofill, including passports, driver’s licenses, and vehicles."> + <message name="IDS_AUTOFILL_AI_FFR_WHEN_ON_TITLE" desc="A sub title that highlights the benefits of using ‘enhanced autofill’. ‘More fields’ is referring to values in online forms. The user can fill more fields faster because ‘enhanced autofill’ supports more data types than standard autofill, including passports, driver’s licenses, and vehicles."> Fill more fields faster </message> - <message name="IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION" desc="Body text beneath the “Fill more fields faster” sub title. This conveys the value of using ‘Autofill with AI’."> - Autofill with AI understands forms better and can autofill them faster for you + <message name="IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION" desc="Body text beneath the “Fill more fields faster” sub title. This conveys the value of using ‘enhanced autofill’."> + Enhanced autofill understands forms better and can autofill them faster for you </message> - <message name="IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION" desc="Body text beneath the “Things to consider” sub title. This describes to users things they might want to weigh before using this feature. Ideally, we lead with ‘To offer suggestions’, because it redefines the value of ‘Autofill with AI’ and offers a rationale for the data use that immediately follows. The data used includes 1) the URL of a page visited and 2) the content of that page. Both are shared from Chrome to a Google service that generates autofill suggestions. Inludes a placeholder for a learn more link, $1 = IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE"> - To offer suggestions and improve this feature, the page’s URL and content are shared with Google. Change your mind anytime and <ph name="LEARN_MORE">$1<ex>learn more about autofill with AI in settings</ex></ph>. + <message name="IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION" desc="Body text beneath the “Things to consider” sub title. This describes to users things they might want to weigh before using this feature. Ideally, we lead with ‘To offer suggestions’, because it redefines the value of ‘enhanced autofill’ and offers a rationale for the data use that immediately follows. The data used includes 1) the URL of a page visited and 2) the content of that page. Both are shared from Chrome to a Google service that generates autofill suggestions. Inludes a placeholder for a learn more link, $1 = IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE"> + To offer suggestions and improve this feature, the page’s URL and content are shared with Google. Change your mind anytime and <ph name="LEARN_MORE">$1<ex>learn more about enhanced autofill in settings</ex></ph>. </message> - <message name="IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE" desc="Link for the Autofill AI settings page to learn more about this feature."> - learn more about autofill with AI in settings + <message name="IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE" desc="Link for the enhanced autofill settings page to learn more about this feature."> + learn more about enhanced autofill in settings </message> </grit-part>
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION.png.sha1 index 877b072..a40fe350 100644 --- a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION.png.sha1 +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_DESCRIPTION.png.sha1
@@ -1 +1 @@ -6b83b9b51fd09d4ff12510de3fd3ae8c21387b51 \ No newline at end of file +fecc088b7bc084465cac3d8cb2723c4756dce1a3 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE.png.sha1 index 2d48b60..a40fe350 100644 --- a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE.png.sha1 +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_CONSIDER_LEARN_MORE.png.sha1
@@ -1 +1 @@ -a97738bda7032f86545355aa2eef416556321481 \ No newline at end of file +fecc088b7bc084465cac3d8cb2723c4756dce1a3 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION.png.sha1 index 877b072..23bbd2be 100644 --- a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION.png.sha1 +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_FFR_WHEN_ON_DESCRIPTION.png.sha1
@@ -1 +1 @@ -6b83b9b51fd09d4ff12510de3fd3ae8c21387b51 \ No newline at end of file +1e2f6b80373a76a2fc38fe2b78cd6613ecfc3827 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_OPT_IN_IPH_BODY.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_OPT_IN_IPH_BODY.png.sha1 index 56cc61e6..8abd86b3 100644 --- a/components/autofill_strings_grdp/IDS_AUTOFILL_AI_OPT_IN_IPH_BODY.png.sha1 +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_AI_OPT_IN_IPH_BODY.png.sha1
@@ -1 +1 @@ -c95cb7247b6156b079c36ae71fc34e451ae76c74 \ No newline at end of file +f76c3398e69f9c57d2938eaf042c40500432033d \ No newline at end of file
diff --git a/components/browser_ui/theme/android/BUILD.gn b/components/browser_ui/theme/android/BUILD.gn index 283b6d2b..ac0ea497 100644 --- a/components/browser_ui/theme/android/BUILD.gn +++ b/components/browser_ui/theme/android/BUILD.gn
@@ -4,15 +4,22 @@ import("//build/config/android/rules.gni") +jinja_template_resources("theme_template_resources") { + res_dir = "templates/res" + resources = [ + "templates/res/values-night/themes.xml", + "templates/res/values/themes.xml", + ] +} + android_resources("java_resources") { sources = [ "java/res/values-night/colors.xml", - "java/res/values-night/themes.xml", "java/res/values/attrs.xml", "java/res/values/colors.xml", - "java/res/values/themes.xml", ] deps = [ + ":theme_template_resources", "//components/browser_ui/styles/android:java_resources", "//components/browser_ui/widget/android:java_resources", ]
diff --git a/components/browser_ui/theme/android/java/res/values-night/themes.xml b/components/browser_ui/theme/android/java/res/values-night/themes.xml deleted file mode 100644 index 9ac07b78..0000000 --- a/components/browser_ui/theme/android/java/res/values-night/themes.xml +++ /dev/null
@@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -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. ---> - -<resources> - <!-- Colors should be mirrored by Theme.BrowserUI.DialogWhenLarge.DayNight and - Theme.BrowserUI.AlertDialog.NoActionBar.DayNight. --> - <style name="Theme.BrowserUI.DayNight" parent="Theme.BrowserUI"> - <!-- Color palettes --> - <item name="colorPrimary">@color/baseline_primary_80</item> - <item name="colorPrimaryInverse">@color/baseline_primary_40</item> - <item name="colorOnPrimary">@color/baseline_primary_20</item> - <item name="colorPrimaryContainer">@color/baseline_primary_30</item> - <item name="colorOnPrimaryContainer">@color/baseline_primary_90</item> - <item name="colorSecondaryContainer">@color/baseline_secondary_30</item> - <item name="colorOnSecondaryContainer">@color/baseline_secondary_90</item> - <item name="android:colorBackground">@color/baseline_neutral_10</item> - <item name="colorOnBackground">@color/baseline_neutral_90</item> - <item name="colorSurface">@color/gm3_baseline_surface_dark</item> - <item name="colorOnSurface">@color/baseline_neutral_90</item> - <item name="colorSurfaceVariant">@color/baseline_neutral_variant_30</item> - <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_80</item> - <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> - <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_dark</item> - <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_dark</item> - <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_dark</item> - <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_dark</item> - <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_dark</item> - <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_dark</item> - <item name="colorOutline">@color/baseline_neutral_variant_60</item> - <item name="colorOutlineVariant">@color/baseline_neutral_variant_30</item> - <item name="colorError">@color/baseline_error_80</item> - </style> - - <!-- Colors should be mirrored by Theme.BrowserUI.DayNight. --> - <style name="Theme.BrowserUI.DialogWhenLarge.DayNight" parent="Theme.BrowserUI.DialogWhenLarge"> - <!-- Color palettes --> - <item name="colorPrimary">@color/baseline_primary_80</item> - <item name="colorPrimaryInverse">@color/baseline_primary_40</item> - <item name="colorOnPrimary">@color/baseline_primary_20</item> - <item name="colorPrimaryContainer">@color/baseline_primary_30</item> - <item name="colorOnPrimaryContainer">@color/baseline_primary_90</item> - <item name="colorSecondaryContainer">@color/baseline_secondary_30</item> - <item name="colorOnSecondaryContainer">@color/baseline_secondary_90</item> - <item name="android:colorBackground">@color/baseline_neutral_10</item> - <item name="colorOnBackground">@color/baseline_neutral_90</item> - <item name="colorSurface">@color/gm3_baseline_surface_dark</item> - <item name="colorOnSurface">@color/baseline_neutral_90</item> - <item name="colorSurfaceVariant">@color/baseline_neutral_variant_30</item> - <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_80</item> - <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> - <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_dark</item> - <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_dark</item> - <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_dark</item> - <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_dark</item> - <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_dark</item> - <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_dark</item> - <item name="colorOutline">@color/baseline_neutral_variant_60</item> - <item name="colorOutlineVariant">@color/baseline_neutral_variant_30</item> - <item name="colorError">@color/baseline_error_80</item> - </style> - - <!-- Colors should be mirrored by Theme.BrowserUI.DayNight. --> - <style name="Theme.BrowserUI.AlertDialog.NoActionBar.DayNight" parent="Theme.BrowserUI.AlertDialog.NoActionBar"> - <!-- Color palettes --> - <item name="colorPrimary">@color/baseline_primary_80</item> - <item name="colorPrimaryInverse">@color/baseline_primary_40</item> - <item name="colorOnPrimary">@color/baseline_primary_20</item> - <item name="colorPrimaryContainer">@color/baseline_primary_30</item> - <item name="colorOnPrimaryContainer">@color/baseline_primary_90</item> - <item name="colorSecondaryContainer">@color/baseline_secondary_30</item> - <item name="colorOnSecondaryContainer">@color/baseline_secondary_90</item> - <item name="android:colorBackground">@color/baseline_neutral_10</item> - <item name="colorOnBackground">@color/baseline_neutral_90</item> - <item name="colorSurface">@color/gm3_baseline_surface_dark</item> - <item name="colorOnSurface">@color/baseline_neutral_90</item> - <item name="colorSurfaceVariant">@color/baseline_neutral_variant_30</item> - <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_80</item> - <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> - <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_dark</item> - <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_dark</item> - <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_dark</item> - <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_dark</item> - <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_dark</item> - <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_dark</item> - <item name="colorOutline">@color/baseline_neutral_variant_60</item> - <item name="colorOutlineVariant">@color/baseline_neutral_variant_30</item> - <item name="colorError">@color/baseline_error_80</item> - </style> -</resources>
diff --git a/components/browser_ui/theme/android/templates/res/values-night/themes.xml b/components/browser_ui/theme/android/templates/res/values-night/themes.xml new file mode 100644 index 0000000..98173c6 --- /dev/null +++ b/components/browser_ui/theme/android/templates/res/values-night/themes.xml
@@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<!-- +Note: This is a jinja2 template, processed at build time into the final resources. +--> + +<resources> + <!-- Colors should be mirrored by Theme.BrowserUI.DialogWhenLarge.DayNight and + Theme.BrowserUI.AlertDialog.NoActionBar.DayNight. --> + <style name="Theme.BrowserUI.DayNight" parent="Theme.BrowserUI"> + {% macro common_color_night_attributes() %} + <!-- Color palettes --> + <item name="colorPrimary">@color/baseline_primary_80</item> + <item name="colorPrimaryInverse">@color/baseline_primary_40</item> + <item name="colorOnPrimary">@color/baseline_primary_20</item> + <item name="colorPrimaryContainer">@color/baseline_primary_30</item> + <item name="colorOnPrimaryContainer">@color/baseline_primary_90</item> + <item name="colorSecondaryContainer">@color/baseline_secondary_30</item> + <item name="colorOnSecondaryContainer">@color/baseline_secondary_90</item> + <item name="android:colorBackground">@color/baseline_neutral_10</item> + <item name="colorOnBackground">@color/baseline_neutral_90</item> + <item name="colorSurface">@color/gm3_baseline_surface_dark</item> + <item name="colorOnSurface">@color/baseline_neutral_90</item> + <item name="colorSurfaceVariant">@color/baseline_neutral_variant_30</item> + <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_80</item> + <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> + <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_dark</item> + <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_dark</item> + <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_dark</item> + <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_dark</item> + <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_dark</item> + <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_dark</item> + <item name="colorOutline">@color/baseline_neutral_variant_60</item> + <item name="colorOutlineVariant">@color/baseline_neutral_variant_30</item> + <item name="colorError">@color/baseline_error_80</item> + {% endmacro %} + {{ common_color_night_attributes() }} + </style> + + <style name="Theme.BrowserUI.DialogWhenLarge.DayNight" parent="Theme.BrowserUI.DialogWhenLarge"> + {{ common_color_night_attributes() }} + </style> + + <style name="Theme.BrowserUI.AlertDialog.NoActionBar.DayNight" parent="Theme.BrowserUI.AlertDialog.NoActionBar"> + {{ common_color_night_attributes() }} + </style> +</resources>
diff --git a/components/browser_ui/theme/android/java/res/values/themes.xml b/components/browser_ui/theme/android/templates/res/values/themes.xml similarity index 67% rename from components/browser_ui/theme/android/java/res/values/themes.xml rename to components/browser_ui/theme/android/templates/res/values/themes.xml index 5346551..ab6bd5e 100644 --- a/components/browser_ui/theme/android/java/res/values/themes.xml +++ b/components/browser_ui/theme/android/templates/res/values/themes.xml
@@ -1,16 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright 2022 The Chromium Authors +Copyright 2025 The Chromium Authors Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<!-- +Note: This is a jinja2 template, processed at build time into the final resources. +--> + <resources xmlns:tools="http://schemas.android.com/tools"> <!-- Colors should be mirrored by Theme.BrowserUI.DialogWhenLarge and Theme.BrowserUI.AlertDialog.NoActionBar. --> <style name="Base.V21.Theme.BrowserUI" parent="Theme.Material3.DayNight.NoActionBar"> <item name="dynamicColorThemeOverlay">@style/ThemeOverlay.BrowserUI.DynamicColors</item> + {% macro common_color_attributes() %} <!-- Color palettes --> <item name="colorPrimary">@color/baseline_primary_40</item> <item name="colorPrimaryDark">@android:color/black</item> @@ -66,6 +71,8 @@ <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item> <item name="globalLinkTextColor">?attr/colorPrimary</item> <item name="globalClickableSpanColor">?attr/colorPrimary</item> + {% endmacro %} + {{ common_color_attributes() }} <!-- Switches style workaround for UI that might use SwitchPreferenceCompat while not using the theme for SettingsActivity (e.g. PageInfoView) --> @@ -144,61 +151,7 @@ <style name="Theme.BrowserUI.DialogWhenLarge" parent="Theme.Material3.DayNight.DialogWhenLarge"> <item name="dynamicColorThemeOverlay">@style/ThemeOverlay.BrowserUI.DynamicColors</item> - <!-- Color palettes --> - <item name="colorPrimary">@color/baseline_primary_40</item> - <item name="colorPrimaryDark">@android:color/black</item> - <item name="colorPrimaryInverse">@color/baseline_primary_80</item> - <item name="colorOnPrimary">@color/baseline_primary_100</item> - <item name="colorPrimaryContainer">@color/baseline_primary_90</item> - <item name="colorOnPrimaryContainer">@color/baseline_primary_30</item> - <item name="colorSecondaryContainer">@color/baseline_secondary_90</item> - <item name="colorOnSecondaryContainer">@color/baseline_secondary_30</item> - <item name="colorAccent">@macro/default_control_color_active</item> - <item name="android:colorBackground">@color/baseline_neutral_100</item> - <item name="colorOnBackground">@color/baseline_neutral_10</item> - <item name="colorSurface">@color/gm3_baseline_surface_light</item> - <item name="colorOnSurface">@color/baseline_neutral_10</item> - <item name="colorSurfaceVariant">@color/baseline_neutral_variant_90</item> - <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_30</item> - <item name="colorOnSurfaceInverse">@color/baseline_neutral_95</item> - <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_light</item> - <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_light</item> - <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_light</item> - <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_light</item> - <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_light</item> - <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_light</item> - <item name="colorOutline">@color/baseline_neutral_variant_50</item> - <item name="colorOutlineVariant">@color/baseline_neutral_variant_80</item> - <item name="colorError">@color/baseline_error_40</item> - - <!-- Text colors--> - <item name="android:textColorPrimary">@color/default_text_color_list</item> - <item name="android:textColorSecondary">@color/default_text_color_secondary_list</item> - <item name="android:textColorHighlight">@color/text_highlight_color</item> - <item name="android:textColorHint">@color/default_text_color_hint_list</item> - - <!-- Widget colors: checkboxes, switches, buttons, etc. --> - <item name="colorControlNormal">@macro/default_control_color_normal</item> - <item name="colorControlActivated">@macro/default_control_color_active</item> - <item name="colorControlHighlight">@color/control_highlight_color</item> - - <!-- Elevation overlays --> - <item name="elevationOverlayEnabled">true</item> - <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> - <item name="elevationOverlayAccentColor">@android:color/transparent</item> - - <item name="android:listChoiceBackgroundIndicator">@drawable/list_item_ripple</item> - - <!-- Dynamic colors that are applied to the buttons and links. --> - <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item> - <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_list</item> - <item name="globalFilledTonalButtonBgColor">?attr/colorPrimaryContainer</item> - <item name="globalFilledTonalButtonTextColor">@color/default_text_color_on_accent1_container_list</item> - <item name="globalTextButtonTextColor">@color/default_text_color_accent1_tint_list</item> - <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list</item> - <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item> - <item name="globalLinkTextColor">?attr/colorPrimary</item> - <item name="globalClickableSpanColor">?attr/colorPrimary</item> + {{ common_color_attributes() }} <!-- Widgets style override--> <item name="materialSwitchStyle">@style/Widget.BrowserUI.Switch</item> @@ -236,61 +189,7 @@ <style name="Theme.BrowserUI.AlertDialog.NoActionBar" parent="Theme.Material3.DayNight.Dialog.Alert"> <item name="dynamicColorThemeOverlay">@style/ThemeOverlay.BrowserUI.DynamicColors</item> - <!-- Color palettes --> - <item name="colorPrimary">@color/baseline_primary_40</item> - <item name="colorPrimaryDark">@android:color/black</item> - <item name="colorPrimaryInverse">@color/baseline_primary_80</item> - <item name="colorOnPrimary">@color/baseline_primary_100</item> - <item name="colorPrimaryContainer">@color/baseline_primary_90</item> - <item name="colorOnPrimaryContainer">@color/baseline_primary_30</item> - <item name="colorSecondaryContainer">@color/baseline_secondary_90</item> - <item name="colorOnSecondaryContainer">@color/baseline_secondary_30</item> - <item name="colorAccent">@macro/default_control_color_active</item> - <item name="android:colorBackground">@color/baseline_neutral_100</item> - <item name="colorOnBackground">@color/baseline_neutral_10</item> - <item name="colorSurface">@color/gm3_baseline_surface_light</item> - <item name="colorOnSurface">@color/baseline_neutral_10</item> - <item name="colorSurfaceVariant">@color/baseline_neutral_variant_90</item> - <item name="colorSurfaceContainerLow">@color/gm3_baseline_surface_container_low_light</item> - <item name="colorSurfaceContainer">@color/gm3_baseline_surface_container_light</item> - <item name="colorSurfaceContainerHigh">@color/gm3_baseline_surface_container_high_light</item> - <item name="colorSurfaceContainerHighest">@color/gm3_baseline_surface_container_highest_light</item> - <item name="colorSurfaceBright">@color/gm3_baseline_surface_bright_light</item> - <item name="colorSurfaceDim">@color/gm3_baseline_surface_dim_light</item> - <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_30</item> - <item name="colorOnSurfaceInverse">@color/baseline_neutral_95</item> - <item name="colorOutline">@color/baseline_neutral_variant_50</item> - <item name="colorOutlineVariant">@color/baseline_neutral_variant_80</item> - <item name="colorError">@color/baseline_error_40</item> - - <!-- Text colors--> - <item name="android:textColorPrimary">@color/default_text_color_list</item> - <item name="android:textColorSecondary">@color/default_text_color_secondary_list</item> - <item name="android:textColorHighlight">@color/text_highlight_color</item> - <item name="android:textColorHint">@color/default_text_color_hint_list</item> - - <!-- Widget colors: checkboxes, switches, buttons, etc. --> - <item name="colorControlNormal">@macro/default_control_color_normal</item> - <item name="colorControlActivated">@macro/default_control_color_active</item> - <item name="colorControlHighlight">@color/control_highlight_color</item> - - <!-- Elevation overlays --> - <item name="elevationOverlayEnabled">true</item> - <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> - <item name="elevationOverlayAccentColor">@android:color/transparent</item> - - <item name="android:listChoiceBackgroundIndicator">@drawable/list_item_ripple</item> - - <!-- Dynamic colors that are applied to the buttons and links. --> - <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item> - <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_list</item> - <item name="globalFilledTonalButtonBgColor">?attr/colorPrimaryContainer</item> - <item name="globalFilledTonalButtonTextColor">@color/default_text_color_on_accent1_container_list</item> - <item name="globalTextButtonTextColor">@color/default_text_color_accent1_tint_list</item> - <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list</item> - <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item> - <item name="globalLinkTextColor">?attr/colorPrimary</item> - <item name="globalClickableSpanColor">?attr/colorPrimary</item> + {{ common_color_attributes() }} <item name="android:windowBackground">@drawable/dialog_bg_no_shadow</item> <item name="android:windowTitleStyle">@style/TextAppearance.AlertDialogTitleStyle</item>
diff --git a/components/commerce/core/BUILD.gn b/components/commerce/core/BUILD.gn index 142ec71..c88d327 100644 --- a/components/commerce/core/BUILD.gn +++ b/components/commerce/core/BUILD.gn
@@ -35,8 +35,8 @@ "//components/prefs", "//components/search", "//components/webui/flags", - "//third_party/re2:re2", - "//url:url", + "//third_party/re2", + "//url", ] } @@ -68,7 +68,7 @@ "//base/test:test_support", "//components/prefs:test_support", "//testing/gtest", - "//third_party/re2:re2", + "//third_party/re2", ] # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and @@ -172,7 +172,7 @@ deps = [ "//base", - "//third_party/re2:re2", + "//third_party/re2", ] } @@ -184,7 +184,7 @@ "//base", "//base/test:test_support", "//testing/gtest", - "//third_party/re2:re2", + "//third_party/re2", ] } @@ -200,9 +200,9 @@ "//base", "//components/resources:components_resources_grit", "//net", - "//third_party/re2:re2", + "//third_party/re2", "//ui/base", - "//url:url", + "//url", ] } @@ -244,7 +244,7 @@ "//base", "//components/bookmarks/browser", "//components/commerce/core/compare", - "//components/commerce/core/product_specifications:product_specifications", + "//components/commerce/core/product_specifications", "//components/history/core/browser", "//components/keyed_service/core", "//components/leveldb_proto", @@ -252,26 +252,26 @@ "//components/optimization_guide/proto:optimization_guide_proto", "//components/power_bookmarks/core", "//components/power_bookmarks/core:proto", - "//components/prefs:prefs", + "//components/prefs", "//components/resources:components_resources_grit", - "//components/search:search", + "//components/search", "//components/session_proto_db:core", "//components/sessions", - "//components/signin/public/identity_manager:identity_manager", + "//components/signin/public/identity_manager", "//components/strings:components_strings_grit", "//components/sync/service", "//components/unified_consent", "//services/metrics/public/cpp:metrics_cpp", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", "//ui/base", - "//url:url", + "//url", ] public_deps = [ ":account_checker", ":commerce_types", ":feature_utils", - "//components/commerce/core/subscriptions:subscriptions", + "//components/commerce/core/subscriptions", "//services/data_decoder/public/cpp", ] @@ -315,7 +315,7 @@ "//components/bookmarks/browser", "//components/bookmarks/test", "//components/commerce/core:proto", - "//components/commerce/core/compare:compare", + "//components/commerce/core/compare", "//components/commerce/core/product_specifications:test_support", "//components/commerce/core/subscriptions", "//components/optimization_guide/core", @@ -327,14 +327,14 @@ "//components/sessions:test_support", "//components/signin/public/identity_manager:test_support", "//components/sync:test_support", - "//components/unified_consent:unified_consent", + "//components/unified_consent", "//services/data_decoder/public/cpp:test_support", "//services/network:network_service", "//services/network:test_support", "//services/network/public/cpp", "//testing/gmock", "//testing/gtest", - "//url:url", + "//url", ] } @@ -407,16 +407,16 @@ ":pref_names", ":utils", "//base", - "//components/endpoint_fetcher:endpoint_fetcher", - "//components/prefs:prefs", - "//components/signin/public/identity_manager:identity_manager", + "//components/endpoint_fetcher", + "//components/prefs", + "//components/signin/public/identity_manager", "//components/sync/base", "//components/sync/service", "//components/unified_consent", - "//net/traffic_annotation:traffic_annotation", - "//services/network/public/cpp:cpp", + "//net/traffic_annotation", + "//services/network/public/cpp", "//ui/base", - "//url:url", + "//url", ] public_deps = [ "//services/data_decoder/public/cpp" ] @@ -438,7 +438,7 @@ "//components/prefs", "//components/prefs:test_support", "//components/sync/base", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", "//testing/gmock", ] } @@ -460,10 +460,10 @@ "//net/traffic_annotation:test_support", "//services/data_decoder/public/cpp:test_support", "//services/network:test_support", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", "//testing/gmock", "//testing/gtest", - "//url:url", + "//url", ] } @@ -494,9 +494,9 @@ ":commerce_types", ":feature_list", "//components/commerce/core:proto", - "//components/endpoint_fetcher:endpoint_fetcher", - "//components/optimization_guide/core:core", - "//net:net", + "//components/endpoint_fetcher", + "//components/optimization_guide/core", + "//net", ] } @@ -512,7 +512,7 @@ ":utils", "//base", "//base/test:test_support", - "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher", "//net/traffic_annotation:test_support", "//url", ]
diff --git a/components/commerce/core/compare/BUILD.gn b/components/commerce/core/compare/BUILD.gn index be8a563..a3653a0 100644 --- a/components/commerce/core/compare/BUILD.gn +++ b/components/commerce/core/compare/BUILD.gn
@@ -29,15 +29,15 @@ "//components/commerce/core:proto", "//components/commerce/core:utils", "//components/commerce/core/product_specifications", - "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher", "//components/leveldb_proto", - "//components/signin/public/identity_manager:identity_manager", + "//components/signin/public/identity_manager", "//components/sync/base:features", "//google_apis", - "//net:net", - "//net/traffic_annotation:traffic_annotation", + "//net", + "//net/traffic_annotation", "//services/data_decoder/public/cpp", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", "//url", ] } @@ -65,7 +65,7 @@ "//components/commerce/core:utils", "//components/commerce/core/product_specifications", "//components/commerce/core/product_specifications:test_support", - "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher", "//components/endpoint_fetcher:test_support", "//components/prefs:test_support", "//components/signin/public/identity_manager:test_support",
diff --git a/components/commerce/core/internals/BUILD.gn b/components/commerce/core/internals/BUILD.gn index 819867c..25311c2b 100644 --- a/components/commerce/core/internals/BUILD.gn +++ b/components/commerce/core/internals/BUILD.gn
@@ -15,12 +15,12 @@ "../:pref_names", "../:shopping_service", "//base", - "//components/bookmarks/browser:browser", - "//components/commerce/core/product_specifications:product_specifications", + "//components/bookmarks/browser", + "//components/commerce/core/product_specifications", "//components/payments/core:currency_formatter", - "//components/power_bookmarks/core:core", + "//components/power_bookmarks/core", "//components/prefs", - "//components/url_formatter:url_formatter", + "//components/url_formatter", "//mojo/public/cpp/bindings", "//ui/base", "//url",
diff --git a/components/commerce/core/subscriptions/BUILD.gn b/components/commerce/core/subscriptions/BUILD.gn index 3925a5d..acb11a0 100644 --- a/components/commerce/core/subscriptions/BUILD.gn +++ b/components/commerce/core/subscriptions/BUILD.gn
@@ -23,14 +23,14 @@ "//components/commerce/core:feature_list", "//components/commerce/core:feature_utils", "//components/commerce/core:utils", - "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher", "//components/leveldb_proto", - "//components/signin/public/identity_manager:identity_manager", + "//components/signin/public/identity_manager", "//components/sync/base:features", - "//net:net", - "//net/traffic_annotation:traffic_annotation", + "//net", + "//net/traffic_annotation", "//services/data_decoder/public/cpp", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", ] public_deps = [ "//components/session_proto_db:core" ] @@ -76,10 +76,10 @@ "//net/traffic_annotation:test_support", "//services/data_decoder/public/cpp:test_support", "//services/network:test_support", - "//services/network/public/cpp:cpp", + "//services/network/public/cpp", "//testing/gmock", "//testing/gtest", - "//url:url", + "//url", ] # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
diff --git a/components/commerce/core/webui/BUILD.gn b/components/commerce/core/webui/BUILD.gn index 2a57b9a..56b1680 100644 --- a/components/commerce/core/webui/BUILD.gn +++ b/components/commerce/core/webui/BUILD.gn
@@ -27,8 +27,8 @@ "//components/commerce/core:shopping_service", "//components/commerce/core:utils", "//components/feature_engagement/public", - "//components/history/core/browser:browser", - "//components/optimization_guide/core:core", + "//components/history/core/browser", + "//components/optimization_guide/core", "//components/payments/core:currency_formatter", "//components/power_bookmarks/core", "//components/prefs", @@ -66,7 +66,7 @@ "//mojo/public/cpp/bindings", "//services/metrics/public/cpp:ukm_builders", "//testing/gtest", - "//url:url", + "//url", ] # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
diff --git a/components/language_detection/OWNERS b/components/language_detection/OWNERS index 8f002d8c..1fd284f3 100644 --- a/components/language_detection/OWNERS +++ b/components/language_detection/OWNERS
@@ -1,4 +1,3 @@ file://components/translate/OWNERS -fergal@chromium.org memmott@chromium.org christinesm@chromium.org
diff --git a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java index 9d2efdc3..6ede3a0 100644 --- a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java +++ b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java
@@ -7,6 +7,7 @@ import android.text.TextUtils; import androidx.annotation.VisibleForTesting; +import androidx.collection.ArrayMap; import androidx.collection.ArraySet; import androidx.core.util.ObjectsCompat; @@ -30,6 +31,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; /** Container class with information about each omnibox suggestion item. */ @@ -83,7 +85,7 @@ private final @Nullable String mImageDominantColor; private final int mTransition; private final boolean mIsDeletable; - private @Nullable String mPostContentType; + private final Map<String, String> mExtraHeaders; private byte @Nullable [] mPostData; private final int mGroupId; private byte @Nullable [] mClipboardImageData; @@ -151,7 +153,7 @@ mImageUrl = imageUrl; mImageDominantColor = imageDominantColor; mIsDeletable = isDeletable; - mPostContentType = postContentType; + mExtraHeaders = new ArrayMap<>(); mPostData = postData; mGroupId = groupId; mClipboardImageData = clipboardImageData; @@ -168,6 +170,16 @@ assert false : "Parsing error for SuggestTemplateInfo"; } } + + updatePostContentType(postContentType); + } + + private void updatePostContentType(@Nullable String postContentType) { + if (TextUtils.isEmpty(postContentType)) { + mExtraHeaders.remove("Content-Type"); + } else { + mExtraHeaders.put("Content-Type", postContentType); + } } @CalledByNative @@ -280,8 +292,8 @@ byte @Nullable [] clipboardImageData) { mDisplayText = contents; mUrl = url; - mPostContentType = postContentType; mPostData = postData; + updatePostContentType(postContentType); mClipboardImageData = clipboardImageData; } @@ -391,8 +403,14 @@ return mIsDeletable; } - public @Nullable String getPostContentType() { - return mPostContentType; + /** + * Returns the extra HTTP headers associated with this autocomplete match. These headers should + * be included when navigating to the suggestion's URL. + * + * @return A map of header names to header values (may be empty). + */ + public Map<String, String> getExtraHeaders() { + return Collections.unmodifiableMap(mExtraHeaders); } public byte @Nullable [] getPostData() { @@ -476,7 +494,7 @@ && ObjectsCompat.equals( mDescriptionClassifications, suggestion.mDescriptionClassifications) && mIsDeletable == suggestion.mIsDeletable - && TextUtils.equals(mPostContentType, suggestion.mPostContentType) + && ObjectsCompat.equals(mExtraHeaders, suggestion.mExtraHeaders) && Arrays.equals(mPostData, suggestion.mPostData) && mGroupId == suggestion.mGroupId && mAnswerType == suggestion.mAnswerType @@ -626,7 +644,7 @@ "mImageDominatColor=" + mImageDominantColor, "mTransition=" + mTransition, "mIsDeletable=" + mIsDeletable, - "mPostContentType=" + mPostContentType, + "mExtraHeaders=" + mExtraHeaders, "mPostData=" + Arrays.toString(mPostData), "mGroupId=" + mGroupId, "mDisplayTextClassifications=" + mDisplayTextClassifications,
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index e76603e..1ce0db9 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -1050,8 +1050,7 @@ !encoded_search_terms.empty() && net::HttpUtil::IsValidHeaderValue(encoded_search_terms)) { DCHECK(net::HttpUtil::IsValidHeaderName(kOmniboxGeminiHeader)); - match->extra_headers = - base::StrCat({kOmniboxGeminiHeader, ":", encoded_search_terms}); + match->extra_headers.emplace(kOmniboxGeminiHeader, encoded_search_terms); } auto url = ComputeURLFromSearchTermsArgs(turl, *match->search_terms_args);
diff --git a/components/omnibox/browser/autocomplete_controller_unittest.cc b/components/omnibox/browser/autocomplete_controller_unittest.cc index 099c487..0b5af12 100644 --- a/components/omnibox/browser/autocomplete_controller_unittest.cc +++ b/components/omnibox/browser/autocomplete_controller_unittest.cc
@@ -42,6 +42,10 @@ #include "third_party/omnibox_proto/answer_type.pb.h" #include "third_party/omnibox_proto/rich_answer_template.pb.h" +using ::testing::ElementsAre; +using ::testing::Pair; +using ::testing::WhenSorted; + class AutocompleteControllerTest : public testing::Test { public: AutocompleteControllerTest() : controller_(&task_environment_) {} @@ -2183,7 +2187,9 @@ std::make_unique<TemplateURLRef::SearchTermsArgs>(u"search term"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, "X-Omnibox-Gemini:search%20term"); + EXPECT_THAT( + match.extra_headers, + WhenSorted(ElementsAre(Pair("X-Omnibox-Gemini", "search%20term")))); EXPECT_EQ(match.destination_url, expected_gemini_url); } { @@ -2200,7 +2206,9 @@ std::make_unique<TemplateURLRef::SearchTermsArgs>(u"search term?"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, "X-Omnibox-Gemini:search%20term%3F"); + EXPECT_THAT( + match.extra_headers, + WhenSorted(ElementsAre(Pair("X-Omnibox-Gemini", "search%20term%3F")))); EXPECT_EQ(match.destination_url, "https://example.com/"); } { @@ -2211,7 +2219,9 @@ std::make_unique<TemplateURLRef::SearchTermsArgs>(u"search term\n"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, "X-Omnibox-Gemini:search%20term%0A"); + EXPECT_THAT( + match.extra_headers, + WhenSorted(ElementsAre(Pair("X-Omnibox-Gemini", "search%20term%0A")))); EXPECT_EQ(match.destination_url, expected_gemini_url); } { @@ -2222,8 +2232,10 @@ u"what is http://example.com for?"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, - "X-Omnibox-Gemini:what%20is%20http%3A%2F%2Fexample.com%20for%3F"); + EXPECT_THAT(match.extra_headers, + WhenSorted(ElementsAre( + Pair("X-Omnibox-Gemini", + "what%20is%20http%3A%2F%2Fexample.com%20for%3F")))); EXPECT_EQ(match.destination_url, expected_gemini_url); } { @@ -2234,9 +2246,10 @@ std::make_unique<TemplateURLRef::SearchTermsArgs>(u"こんにちは\n"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ( - match.extra_headers, - "X-Omnibox-Gemini:%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%0A"); + EXPECT_THAT(match.extra_headers, + WhenSorted(ElementsAre( + Pair("X-Omnibox-Gemini", + "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%0A")))); EXPECT_EQ(match.destination_url, expected_gemini_url); } { @@ -2247,7 +2260,7 @@ std::make_unique<TemplateURLRef::SearchTermsArgs>(u"search term"); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, ""); + EXPECT_TRUE(match.extra_headers.empty()); EXPECT_EQ(match.destination_url, "chrome://bookmarks/?q=search+term"); } { @@ -2255,7 +2268,7 @@ auto match = CreateSearchMatch("search term", true, 1300); controller_.SetMatchDestinationURL(&match); - EXPECT_EQ(match.extra_headers, ""); + EXPECT_TRUE(match.extra_headers.empty()); EXPECT_EQ(match.destination_url, "https://google.com/search?q=search+term"); } }
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index 57ce289..4fa1b568 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -866,9 +866,10 @@ // `ComputeStrippedDestinationURL()` computation. GURL stripped_destination_url; - // Extra headers to add to the navigation. See `NavigateParams::extra_headers` - // for how headers should be represented. - std::string extra_headers; + // Extra headers to add to the navigation. Keys of the map represent the + // header name, and values represent header value, e.g. + // extra_headers["Content-Type"] = "application/json"; + std::map<std::string, std::string> extra_headers; // Optional image information. Used for some types of suggestions, such as // entity suggestions, that want to display an associated image, which will be
diff --git a/components/omnibox/composebox/composebox_metrics_recorder.cc b/components/omnibox/composebox/composebox_metrics_recorder.cc index b7543fe..5743756 100644 --- a/components/omnibox/composebox/composebox_metrics_recorder.cc +++ b/components/omnibox/composebox/composebox_metrics_recorder.cc
@@ -5,8 +5,12 @@ #include "components/omnibox/composebox/composebox_metrics_recorder.h" #include "base/metrics/histogram_functions.h" +#include "components/lens/lens_overlay_mime_type.h" +#include "components/omnibox/composebox/composebox_query.mojom.h" +#include "components/omnibox/composebox/composebox_query_controller.h" namespace { +const char kComposeboxFileDeleted[] = "Composebox.Session.File.DeletedCount"; const char kComposeboxSessionDuration[] = "Composebox.Session.Duration.Total"; const char kComposeboxSessionDurationQuerySubmitted[] = "Composebox.Session.Duration.QuerySubmitted"; @@ -27,6 +31,25 @@ const char kComposeboxQueryModality[] = "Composebox.Query.Modality"; const char kComposeboxQueryCount[] = "Composebox.Session.QueryCount"; const char kComposeboxFileSizePerType[] = "Composebox.File.Size."; + +std::string UploadStatusToString(FileUploadStatus status) { + switch (status) { + case FileUploadStatus::kNotUploaded: + return "NotUploaded"; + case FileUploadStatus::kProcessing: + return "Processing"; + case FileUploadStatus::kValidationFailed: + return "ValidationFailed"; + case FileUploadStatus::kUploadStarted: + return "UploadStarted"; + case FileUploadStatus::kUploadSuccessful: + return "UploadSuccessful"; + case FileUploadStatus::kUploadFailed: + return "UploadFailed"; + default: + return "Unknown"; + } +} } // namespace SessionMetrics::SessionMetrics() = default; @@ -126,6 +149,16 @@ file_size_bytes); } +void ComposeboxMetricsRecorder::RecordFileDeletedMetrics( + bool success, + lens::MimeType file_type, + FileUploadStatus file_status) { + base::UmaHistogramBoolean(metric_category_name_ + kComposeboxFileDeleted + + "." + MimeTypeToString(file_type) + "." + + UploadStatusToString(file_status), + success); +} + void ComposeboxMetricsRecorder::NotifySessionStarted() { session_metrics_->session_elapsed_timer = std::make_unique<base::ElapsedTimer>();
diff --git a/components/omnibox/composebox/composebox_metrics_recorder.h b/components/omnibox/composebox/composebox_metrics_recorder.h index de69fd9..aa4e971 100644 --- a/components/omnibox/composebox/composebox_metrics_recorder.h +++ b/components/omnibox/composebox/composebox_metrics_recorder.h
@@ -79,6 +79,11 @@ void RecordFileSizeMetric(lens::MimeType mime_type, uint64_t file_size_bytes); + // Should be called when a file has been deleted. + void RecordFileDeletedMetrics(bool success, + lens::MimeType file_type, + FileUploadStatus file_status); + private: // Called when the session starts to correctly track session // durations.
diff --git a/components/omnibox/composebox/composebox_metrics_recorder_unittest.cc b/components/omnibox/composebox/composebox_metrics_recorder_unittest.cc index 11c4c44..56eb3e0 100644 --- a/components/omnibox/composebox/composebox_metrics_recorder_unittest.cc +++ b/components/omnibox/composebox/composebox_metrics_recorder_unittest.cc
@@ -7,10 +7,13 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/unguessable_token.h" +#include "components/omnibox/composebox/composebox_query_controller.h" #include "testing/gtest/include/gtest/gtest.h" namespace { const char kTestMetricName[] = "Test."; +const char kComposeboxFileDeleted[] = + "Test.Composebox.Session.File.DeletedCount"; const char kComposeboxSessionDurationTotal[] = "Test.Composebox.Session.Duration.Total"; const char kComposeboxSessionAbandonedDuration[] = @@ -41,6 +44,25 @@ const char kComposeboxQueryModality[] = "Test.Composebox.Query.Modality"; const char kComposeboxQueryCount[] = "Test.Composebox.Session.QueryCount"; const char kComposeboxFileSizePdf[] = "Test.Composebox.File.Size.Pdf"; + +std::string UploadStatusToString(FileUploadStatus status) { + switch (status) { + case FileUploadStatus::kNotUploaded: + return "NotUploaded"; + case FileUploadStatus::kProcessing: + return "Processing"; + case FileUploadStatus::kValidationFailed: + return "ValidationFailed"; + case FileUploadStatus::kUploadStarted: + return "UploadStarted"; + case FileUploadStatus::kUploadSuccessful: + return "UploadSuccessful"; + case FileUploadStatus::kUploadFailed: + return "UploadFailed"; + default: + return "Unknown"; + } +} } // namespace class ComposeboxMetricsRecorderTest : public testing::Test { @@ -386,3 +408,50 @@ testing::Values(lens::MimeType::kPdf, lens::MimeType::kImage, lens::MimeType::kUnknown))); + +class MetricsRecorderFileDeletionTest + : public ComposeboxMetricsRecorderTest, + public testing::WithParamInterface< + std::tuple<lens::MimeType, FileUploadStatus>> { + public: + void SetUp() override { + ComposeboxMetricsRecorderTest::SetUp(); + mime_type_string_ = metrics().MimeTypeToString(mime_type_param()); + status_string_ = UploadStatusToString(status_param()); + } + + protected: + lens::MimeType mime_type_param() const { return std::get<0>(GetParam()); } + FileUploadStatus status_param() const { return std::get<1>(GetParam()); } + std::string mime_type_string() const { return mime_type_string_; } + std::string status_string() const { return status_string_; } + + private: + std::string mime_type_string_; + std::string status_string_; +}; + +TEST_P(MetricsRecorderFileDeletionTest, FileDeleted) { + std::string file_type = "." + mime_type_string(); + std::string file_status = "." + status_string(); + // Setup user flow. + metrics().RecordFileDeletedMetrics(true, mime_type_param(), status_param()); + + DestructMetricsRecorder(); + histogram_tester().ExpectTotalCount( + kComposeboxFileDeleted + file_type + file_status, 1); +} + +INSTANTIATE_TEST_SUITE_P( + All, + MetricsRecorderFileDeletionTest, + testing::Combine(testing::Values(lens::MimeType::kPdf, + lens::MimeType::kImage, + lens::MimeType::kUnknown), + testing::Values(FileUploadStatus::kNotUploaded, + FileUploadStatus::kProcessing, + FileUploadStatus::kValidationFailed, + FileUploadStatus::kUploadStarted, + FileUploadStatus::kUploadSuccessful, + FileUploadStatus::kUploadFailed, + FileUploadStatus::kUploadExpired)));
diff --git a/components/omnibox/composebox/composebox_query_controller.h b/components/omnibox/composebox/composebox_query_controller.h index 36e6168..86f54b4 100644 --- a/components/omnibox/composebox/composebox_query_controller.h +++ b/components/omnibox/composebox/composebox_query_controller.h
@@ -211,6 +211,9 @@ int num_files_in_request() { return num_files_in_request_; } + // Return the file from `active_files_` map or nullptr if not found. + virtual FileInfo* GetFileInfo(const base::UnguessableToken& file_token); + protected: // Returns the EndpointFetcher to use with the given params. Protected to // allow overriding in tests to mock server responses. @@ -319,9 +322,6 @@ const base::UnguessableToken& file_token, std::unique_ptr<endpoint_fetcher::EndpointResponse> response); - // Return the file from `active_files_` map or nullptr if not found. - FileInfo* GetFileInfo(const base::UnguessableToken& file_token); - // The last received cluster info. std::optional<lens::LensOverlayClusterInfo> cluster_info_ = std::nullopt;
diff --git a/components/omnibox/composebox/test_composebox_query_controller.h b/components/omnibox/composebox/test_composebox_query_controller.h index 6685084d..a1330a8a 100644 --- a/components/omnibox/composebox/test_composebox_query_controller.h +++ b/components/omnibox/composebox/test_composebox_query_controller.h
@@ -101,16 +101,6 @@ const GURL& last_sent_fetch_url() const { return last_sent_fetch_url_; } - // Gets the file info pointer for the given client token. - ComposeboxQueryController::FileInfo* GetFileInfo( - const base::UnguessableToken& client_token) { - auto it = active_files_.find(client_token); - if (it == active_files_.end()) { - return nullptr; - } - return it->second.get(); - } - // Gets the last sent file upload request. std::optional<lens::LensOverlayServerRequest> last_sent_file_upload_request() const {
diff --git a/components/optimization_guide/core/model_execution/model_broker_state.cc b/components/optimization_guide/core/model_execution/model_broker_state.cc index ea83c89..0af4478 100644 --- a/components/optimization_guide/core/model_execution/model_broker_state.cc +++ b/components/optimization_guide/core/model_execution/model_broker_state.cc
@@ -15,13 +15,15 @@ on_device_model::ServiceClient::LaunchFn launch_fn) : local_state_(local_state), service_client_(std::move(launch_fn)), - component_state_manager_(local_state, std::move(delegate)), - performance_classifier_(component_state_manager_.GetSafeRef(), - service_client_.GetSafeRef()) {} + performance_classifier_(local_state, service_client_.GetSafeRef()), + component_state_manager_(local_state, + performance_classifier_.GetSafeRef(), + std::move(delegate)) {} ModelBrokerState::~ModelBrokerState() = default; void ModelBrokerState::Init() { CHECK(!service_controller_); + performance_classifier_.Init(); component_state_manager_.OnStartup(); service_controller_ = std::make_unique<OnDeviceModelServiceController>( std::make_unique<OnDeviceModelAccessController>(*local_state_),
diff --git a/components/optimization_guide/core/model_execution/model_broker_state.h b/components/optimization_guide/core/model_execution/model_broker_state.h index 495d39e..d2f06f2 100644 --- a/components/optimization_guide/core/model_execution/model_broker_state.h +++ b/components/optimization_guide/core/model_execution/model_broker_state.h
@@ -40,6 +40,10 @@ return *service_controller_; } + on_device_model::Capabilities GetPossibleOnDeviceCapabilities() const { + return performance_classifier_.GetPossibleOnDeviceCapabilities(); + } + // Executes initialization steps. This is normally called immediately on // construction, but can be called later to allow tests to register // preferences and other state. @@ -52,8 +56,8 @@ private: raw_ptr<PrefService> local_state_; on_device_model::ServiceClient service_client_; - OnDeviceModelComponentStateManager component_state_manager_; PerformanceClassifier performance_classifier_; + OnDeviceModelComponentStateManager component_state_manager_; std::unique_ptr<OnDeviceModelServiceController> service_controller_; };
diff --git a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc index 933bb6d..1e0a8bf 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc
@@ -6,6 +6,7 @@ #include "base/files/file_util.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/task_environment.h" @@ -14,6 +15,7 @@ #include "components/optimization_guide/core/delivery/test_model_info_builder.h" #include "components/optimization_guide/core/delivery/test_optimization_guide_model_provider.h" #include "components/optimization_guide/core/model_execution/feature_keys.h" +#include "components/optimization_guide/core/model_execution/model_broker_state.h" #include "components/optimization_guide/core/model_execution/model_execution_features.h" #include "components/optimization_guide/core/model_execution/model_execution_prefs.h" #include "components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h" @@ -126,14 +128,16 @@ model_execution::prefs::RegisterLocalStatePrefs(local_state_.registry()); UpdatePerformanceClassPref(&local_state_, OnDeviceModelPerformanceClass::kHigh); + model_broker_state_.Init(); - on_device_component_state_manager_.get()->OnDeviceEligibleFeatureUsed( + model_broker_state_.component_state_manager().OnDeviceEligibleFeatureUsed( ModelBasedCapabilityKey::kTest); task_environment_.RunUntilIdle(); adaptation_loader_ = std::make_unique<OnDeviceModelAdaptationLoader>( ModelBasedCapabilityKey::kTest, &model_provider_, - on_device_component_state_manager_.get()->GetWeakPtr(), &local_state_, + model_broker_state_.component_state_manager().GetWeakPtr(), + &local_state_, base::BindRepeating( &OnDeviceModelAdaptationLoaderTest::OnModelAdaptationLoaded, base::Unretained(this))); @@ -145,7 +149,7 @@ } void SetBaseModelStateChanged(const FakeBaseModelAsset& base_model_asset) { - on_device_component_state_manager_.SetReady(base_model_asset); + base_model_asset.SetReadyIn(model_broker_state_.component_state_manager()); } void SendAdaptationModelUpdated( @@ -171,8 +175,9 @@ base::test::TaskEnvironment task_environment_; TestingPrefServiceSimple local_state_; base::ScopedTempDir temp_dir_; - TestOnDeviceModelComponentStateManager on_device_component_state_manager_{ - &local_state_}; + TestComponentState test_component_state_; + ModelBrokerState model_broker_state_{ + &local_state_, test_component_state_.CreateDelegate(), base::DoNothing()}; FakeOptimizationGuideModelProvider model_provider_; std::unique_ptr<OnDeviceModelAdaptationLoader> adaptation_loader_; MaybeAdaptationMetadata adaptation_metadata_{
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 f7189298..2af54d6 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
@@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/memory/ptr_util.h" +#include "base/memory/safe_ref.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_functions.h" @@ -46,16 +47,6 @@ return false; } -bool IsDeviceGPUCapable(const PrefService& local_state) { - return IsPerformanceClassCompatible( - features::kPerformanceClassListForOnDeviceModel.Get(), - PerformanceClassFromPref(local_state)); -} - -bool IsDeviceCapable(const PrefService& local_state) { - return IsDeviceGPUCapable(local_state) || on_device_model::IsCpuCapable(); -} - void LogInstallCriteria(std::string_view event_name, std::string_view criteria_name, bool criteria_value) { @@ -167,27 +158,6 @@ return debug; } -bool OnDeviceModelComponentStateManager::IsLowTierDevice() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return IsPerformanceClassCompatible( - features::kLowTierPerformanceClassListForOnDeviceModel.Get(), - PerformanceClassFromPref(*local_state_)); -} - -bool OnDeviceModelComponentStateManager::SupportsImageInput() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return IsPerformanceClassCompatible( - features::kPerformanceClassListForImageInput.Get(), - PerformanceClassFromPref(*local_state_)); -} - -bool OnDeviceModelComponentStateManager::SupportsAudioInput() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return IsPerformanceClassCompatible( - features::kPerformanceClassListForAudioInput.Get(), - PerformanceClassFromPref(*local_state_)); -} - void OnDeviceModelComponentStateManager::OnDeviceEligibleFeatureUsed( ModelBasedCapabilityKey feature) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -210,40 +180,20 @@ LogInstallCriteria(*registration_criteria_, "AtAttemptedUse"); } - BeginUpdateRegistration(base::DoNothing()); + BeginUpdateRegistration(); } -void OnDeviceModelComponentStateManager::DevicePerformanceClassChanged( - base::OnceClosure complete, - OnDeviceModelPerformanceClass performance_class) { +void OnDeviceModelComponentStateManager::OnPerformanceClassAvailable() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - UpdatePerformanceClassPref(local_state_, performance_class); - BeginUpdateRegistration(std::move(complete)); -} - -bool OnDeviceModelComponentStateManager::NeedsPerformanceClassUpdate() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return base::FeatureList::IsEnabled( - features::kOnDeviceModelFetchPerformanceClassEveryStartup) || - local_state_->GetString(model_execution::prefs::localstate:: - kOnDevicePerformanceClassVersion) != - version_info::GetVersionNumber(); + BeginUpdateRegistration(); } void OnDeviceModelComponentStateManager::OnStartup() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); model_execution::prefs::PruneOldUsagePrefs(local_state_); - if (auto model_path_override_switch = - switches::GetOnDeviceModelExecutionOverride()) { - is_model_allowed_ = true; - SetReady( - base::Version("override"), *model_path_override_switch, - base::Value::Dict().Set("BaseModelSpec", base::Value::Dict() - .Set("version", "override") - .Set("name", "override"))); - return; - } - BeginUpdateRegistration(base::DoNothing()); + performance_classifier_->ListenForPerformanceClassAvailable(base::BindOnce( + &OnDeviceModelComponentStateManager::OnPerformanceClassAvailable, + weak_ptr_factory_.GetWeakPtr())); } void OnDeviceModelComponentStateManager::InstallerRegistered() { @@ -259,19 +209,29 @@ return state_ != nullptr; } -void OnDeviceModelComponentStateManager::BeginUpdateRegistration( - base::OnceClosure complete) { +void OnDeviceModelComponentStateManager::BeginUpdateRegistration() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (switches::GetOnDeviceModelExecutionOverride()) { - std::move(complete).Run(); + if (!performance_classifier_->IsPerformanceClassAvailable()) { + // Still waiting for performance class. + return; + } + if (auto model_path_override_switch = + switches::GetOnDeviceModelExecutionOverride()) { + if (!state_) { + is_model_allowed_ = true; + SetReady(base::Version("override"), *model_path_override_switch, + base::Value::Dict().Set("BaseModelSpec", + base::Value::Dict() + .Set("version", "override") + .Set("name", "override"))); + } return; } delegate_->GetFreeDiskSpace( delegate_->GetInstallDirectory(), base::BindOnce( &OnDeviceModelComponentStateManager::CompleteUpdateRegistration, - GetWeakPtr()) - .Then(std::move(complete))); + GetWeakPtr())); } void OnDeviceModelComponentStateManager::CompleteUpdateRegistration( @@ -332,7 +292,7 @@ IsFreeDiskSpaceTooLowForOnDeviceModelInstall(disk_space_free_bytes); result.disk_space_available = optimization_guide::features:: IsFreeDiskSpaceSufficientForOnDeviceModelInstall(disk_space_free_bytes); - result.device_capable = IsDeviceCapable(*local_state_); + result.device_capable = performance_classifier_->IsDeviceCapable(); result.on_device_feature_recently_used = WasAnyOnDeviceEligibleFeatureRecentlyUsed(*local_state_); result.enabled_by_feature = features::IsOnDeviceExecutionEnabled(); @@ -358,8 +318,11 @@ OnDeviceModelComponentStateManager::OnDeviceModelComponentStateManager( PrefService* local_state, + base::SafeRef<PerformanceClassifier> performance_classifier, std::unique_ptr<Delegate> delegate) - : local_state_(local_state), delegate_(std::move(delegate)) { + : local_state_(local_state), + performance_classifier_(std::move(performance_classifier)), + delegate_(std::move(delegate)) { CHECK(local_state); // Useful to catch poor test setup. } @@ -457,7 +420,7 @@ supported_performance_hint_enum ? OnDeviceBaseModelSpec::PerformanceHints( {*supported_performance_hint_enum}) - : OnDeviceBaseModelSpec::PerformanceHints ({})); + : OnDeviceBaseModelSpec::PerformanceHints({})); } std::optional<proto::OnDeviceModelPerformanceHint> @@ -479,7 +442,7 @@ supported_hints.insert(*supported_performance_hint_int); } } - for (auto hint : GetPossibleHints()) { + for (auto hint : performance_classifier_->GetPossibleHints()) { if (supported_hints.contains(hint)) { return hint; } @@ -487,25 +450,6 @@ return std::nullopt; } -std::vector<proto::OnDeviceModelPerformanceHint> -OnDeviceModelComponentStateManager::GetPossibleHints() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::vector<proto::OnDeviceModelPerformanceHint> hints; - if (IsDeviceGPUCapable(*local_state_)) { - // Best option is highest quality for GPU device that is not low tier. - if (!IsLowTierDevice()) { - hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY); - } - // Other GPU capable devices get fastest inference. - hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE); - } - if (on_device_model::IsCpuCapable()) { - // Last option is CPU if the device is capable but not GPU capable. - hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU); - } - return hints; -} - OnDeviceModelComponentState::OnDeviceModelComponentState() = default; OnDeviceModelComponentState::~OnDeviceModelComponentState() = default;
diff --git a/components/optimization_guide/core/model_execution/on_device_model_component.h b/components/optimization_guide/core/model_execution/on_device_model_component.h index 9144401..ba16085 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_component.h +++ b/components/optimization_guide/core/model_execution/on_device_model_component.h
@@ -21,6 +21,7 @@ #include "base/types/pass_key.h" #include "base/values.h" #include "base/version.h" +#include "components/optimization_guide/core/model_execution/performance_class.h" #include "components/optimization_guide/core/optimization_guide_enums.h" #include "components/optimization_guide/proto/on_device_base_model_metadata.pb.h" @@ -184,8 +185,10 @@ } }; - OnDeviceModelComponentStateManager(PrefService* local_state, - std::unique_ptr<Delegate> delegate); + OnDeviceModelComponentStateManager( + PrefService* local_state, + base::SafeRef<PerformanceClassifier> performance_classifier, + std::unique_ptr<Delegate> delegate); ~OnDeviceModelComponentStateManager(); // Returns whether the component installation is valid. @@ -200,12 +203,7 @@ void OnDeviceEligibleFeatureUsed(ModelBasedCapabilityKey feature); // Should be called whenever the device performance class changes. - void DevicePerformanceClassChanged( - base::OnceClosure complete, - OnDeviceModelPerformanceClass performance_class); - - // Whether the performance class needs to be fetched. - bool NeedsPerformanceClassUpdate(); + void OnPerformanceClassAvailable(); // Returns the current state. Null if the component is not available. const OnDeviceModelComponentState* GetState(); @@ -247,14 +245,6 @@ return GetDebugState(); } - // Returns true if this is determined to be a low tier device. - bool IsLowTierDevice() const; - - // Returns true if the device supports image input. - bool SupportsImageInput() const; - // Returns true if the device supports audio input. - bool SupportsAudioInput() const; - // Returns the performance hint for this device based on the supported // performance hints in the manifest. std::optional<proto::OnDeviceModelPerformanceHint> @@ -284,7 +274,7 @@ DebugState GetDebugState(); // Installs the component installer if it needs installed. - void BeginUpdateRegistration(base::OnceClosure complete); + void BeginUpdateRegistration(); // Continuation of `UpdateRegistration()` after async work. void CompleteUpdateRegistration(int64_t disk_space_free_bytes); @@ -298,11 +288,9 @@ const std::optional<OnDeviceBaseModelSpec> ProcessBaseModelSpecFromManifest( const base::Value::Dict& manifest); - // Returns a list of performance hints this device supports in priority order, - // with highest priority first. - std::vector<proto::OnDeviceModelPerformanceHint> GetPossibleHints() const; - raw_ptr<PrefService> local_state_ GUARDED_BY_CONTEXT(sequence_checker_); + base::SafeRef<PerformanceClassifier> performance_classifier_ + GUARDED_BY_CONTEXT(sequence_checker_); std::unique_ptr<Delegate> delegate_ GUARDED_BY_CONTEXT(sequence_checker_); base::ObserverList<Observer> observers_ GUARDED_BY_CONTEXT(sequence_checker_); bool component_installer_registered_ GUARDED_BY_CONTEXT(sequence_checker_) = @@ -326,6 +314,8 @@ // State of the on-device model component. class OnDeviceModelComponentState { public: + OnDeviceModelComponentState(); + OnDeviceModelComponentState(const OnDeviceModelComponentState&); ~OnDeviceModelComponentState(); const base::FilePath& GetInstallDirectory() const { return install_dir_; } @@ -337,7 +327,6 @@ private: friend class OnDeviceModelAdaptationLoaderTest; - OnDeviceModelComponentState(); friend class OnDeviceModelComponentStateManager; base::FilePath install_dir_;
diff --git a/components/optimization_guide/core/model_execution/on_device_model_component_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_component_unittest.cc index 85b8f47..f11617ae 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_component_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_component_unittest.cc
@@ -6,20 +6,31 @@ #include <memory> +#include "base/check.h" +#include "base/command_line.h" +#include "base/functional/callback_helpers.h" #include "base/memory/weak_ptr.h" +#include "base/run_loop.h" #include "base/scoped_add_feature_flags.h" +#include "base/task/current_thread.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/thread_annotations.h" +#include "base/time/time.h" #include "base/types/cxx23_to_underlying.h" +#include "components/optimization_guide/core/model_execution/model_broker_state.h" #include "components/optimization_guide/core/model_execution/model_execution_prefs.h" +#include "components/optimization_guide/core/model_execution/performance_class.h" +#include "components/optimization_guide/core/model_execution/test/fake_model_assets.h" #include "components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h" #include "components/optimization_guide/core/optimization_guide_enums.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/prefs/testing_pref_service.h" #include "services/on_device_model/public/cpp/features.h" +#include "services/on_device_model/public/cpp/test_support/fake_service.h" +#include "services/on_device_model/public/mojom/on_device_model.mojom-data-view.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,32 +39,7 @@ using ::testing::UnorderedElementsAre; -const base::Value::Dict kTestManifest = base::Value::Dict().Set( - "BaseModelSpec", - base::Value::Dict().Set("version", "0.0.1").Set("name", "Test")); -const base::Value::Dict kTestManifestWithPerfHints = base::Value::Dict().Set( - "BaseModelSpec", - base::Value::Dict() - .Set("version", "0.0.1") - .Set("name", "Test") - .Set( - "supported_performance_hints", - base::Value::List() - .Append( - proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE) - .Append(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY) - .Append( - proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE) - .Append(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_UNSPECIFIED) - .Append(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU))); -const base::Value::Dict kTestManifestWithCPUPerfHints = base::Value::Dict().Set( - "BaseModelSpec", - base::Value::Dict() - .Set("version", "0.0.1") - .Set("name", "Test") - .Set("supported_performance_hints", - base::Value::List().Append( - proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU))); +using ::on_device_model::mojom::PerformanceClass; class StubObserver : public OnDeviceModelComponentStateManager::Observer { public: @@ -71,10 +57,7 @@ public: void SetUp() override { model_execution::prefs::RegisterLocalStatePrefs(local_state_.registry()); - - local_state_.SetInteger( - model_execution::prefs::localstate::kOnDevicePerformanceClass, - base::to_underlying(OnDeviceModelPerformanceClass::kLow)); + fake_settings_.performance_class = PerformanceClass::kLow; model_execution::prefs::RecordFeatureUsage( &local_state_, ModelBasedCapabilityKey::kCompose); @@ -90,25 +73,48 @@ void TearDown() override { // Try to detect mistakes in the tests. If any lingering tasks affect state, // the test may have not waited before asserting state. - bool uninstalled = - on_device_component_state_manager_.WasComponentUninstalled(); - bool installer_registered = - on_device_component_state_manager_.IsInstallerRegistered(); - WaitForStartup(); - ASSERT_EQ(uninstalled, - on_device_component_state_manager_.WasComponentUninstalled()); - ASSERT_EQ(installer_registered, - on_device_component_state_manager_.IsInstallerRegistered()); - } - - base::WeakPtr<OnDeviceModelComponentStateManager> manager() { - return on_device_component_state_manager_.get()->GetWeakPtr(); - } - - void WaitForStartup() { - // In the event we want to verify the installer is not installed, there's no - // event to quit a RunLoop. For now this works well enough. + bool uninstalled = test_component_state_.uninstall_called(); + bool installer_registered = test_component_state_.installer_registered(); task_environment_.FastForwardBy(base::Seconds(1)); + ASSERT_EQ(uninstalled, test_component_state_.uninstall_called()); + ASSERT_EQ(installer_registered, + test_component_state_.installer_registered()); + } + + void DoStartup() { + CHECK(!model_broker_state_); + model_broker_state_.emplace(&local_state_, + test_component_state_.CreateDelegate(), + fake_launcher_.LaunchFn()); + model_broker_state_->Init(); + task_environment_.FastForwardBy(base::Seconds(1)); + } + + void SimulateShutdown() { + model_broker_state_.reset(); + test_component_state_.SimulateShutdown(); + } + + PerformanceClassifier& classifier() { + return model_broker_state_->performance_classifier(); + } + + OnDeviceModelComponentStateManager& manager() { + return model_broker_state_->component_state_manager(); + } + + void EnsurePerformanceClassAvailable() { + model_broker_state_->performance_classifier() + .EnsurePerformanceClassAvailable(base::DoNothing()); + } + + bool WaitUntilInstallerRegistered() { + return test_component_state_.WaitForRegistration(); + } + + bool WaitForUnexpectedInstallerRegistered() { + task_environment_.FastForwardBy(base::Seconds(1)); + return test_component_state_.installer_registered(); } protected: @@ -116,17 +122,19 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; TestingPrefServiceSimple local_state_; base::test::ScopedFeatureList feature_list_; - TestOnDeviceModelComponentStateManager on_device_component_state_manager_{ - &local_state_}; + FakeBaseModelAsset fake_asset_; + TestComponentState test_component_state_; + on_device_model::FakeOnDeviceServiceSettings fake_settings_; + on_device_model::FakeServiceLauncher fake_launcher_{&fake_settings_}; + std::optional<ModelBrokerState> model_broker_state_; base::HistogramTester histograms_; }; TEST_F(OnDeviceModelComponentTest, InstallsWhenEligible) { const auto time_at_start = base::Time::Now(); - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); EXPECT_GE(local_state_.GetTime(model_execution::prefs::localstate:: kLastTimeEligibleForOnDeviceModelDownload), time_at_start); @@ -137,6 +145,11 @@ "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.DiskSpace", true, 1); + // Device has disk space. Histogram should not log. + histograms_.ExpectTotalCount( + "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." + "AtRegistration.DiskSpaceWhenNotEnoughAvailable", + 0); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.DeviceCapability", @@ -153,23 +166,13 @@ "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.All", true, 1); - // Device has disk space. Histogram should not log. - histograms_.ExpectTotalCount( - "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." - "AtRegistration.DiskSpaceWhenNotEnoughAvailable", - 0); } TEST_F(OnDeviceModelComponentTest, AlreadyInstalledFlow) { - manager()->OnStartup(); - WaitForStartup(); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - - manager()->InstallerRegistered(); - + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution." "OnDeviceModelInstalledAtRegistrationTime", @@ -177,11 +180,10 @@ } TEST_F(OnDeviceModelComponentTest, NotYetInstalledFlow) { - manager()->OnStartup(); - WaitForStartup(); - - manager()->InstallerRegistered(); - + // No test_component_state_.Install() call here. + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution." "OnDeviceModelInstalledAtRegistrationTime", @@ -195,13 +197,13 @@ &features::kOptimizationGuideOnDeviceModel}) { SCOPED_TRACE(feature->name); base::HistogramTester histograms; - on_device_component_state_manager_.Reset(); + SimulateShutdown(); base::test::ScopedFeatureList features; features.InitAndDisableFeature(*feature); - manager()->OnStartup(); - WaitForStartup(); - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); histograms.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.EnabledByFeature", @@ -219,11 +221,9 @@ static_cast<int>(model_execution::prefs:: GenAILocalFoundationalModelEnterprisePolicySettings:: kDisallowed)); - - on_device_component_state_manager_.Reset(); - manager()->OnStartup(); - WaitForStartup(); - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); histogram_tester.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.EnabledByEnterprisePolicy", @@ -232,13 +232,10 @@ TEST_F(OnDeviceModelComponentTest, NotEnoughDiskSpaceToInstall) { // 20gb is the default in `IsFreeDiskSpaceSufficientForOnDeviceModelInstall`. - on_device_component_state_manager_.SetFreeDiskSpace( - 20ll * 1024 * 1024 * 1024 - 1); - - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + test_component_state_.SetFreeDiskSpace(20ll * 1024 * 1024 * 1024 - 1); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.DiskSpace", @@ -256,11 +253,9 @@ TEST_F(OnDeviceModelComponentTest, NoEligibleFeatureUse) { local_state_.ClearPref( model_execution::prefs::localstate::kLastUsageByFeature); - - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.FeatureUse", @@ -269,11 +264,9 @@ TEST_F(OnDeviceModelComponentTest, EligibleFeatureUseTooOld) { task_environment_.FastForwardBy(base::Days(31)); - - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); // The usage should also get pruned from the pref. ASSERT_TRUE( local_state_ @@ -282,24 +275,16 @@ } TEST_F(OnDeviceModelComponentTest, NoPerformanceClass) { - local_state_.ClearPref( - model_execution::prefs::localstate::kOnDevicePerformanceClass); - - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + DoStartup(); + // No EnsurePerformanceClassAvailable() + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); } TEST_F(OnDeviceModelComponentTest, PerformanceClassTooLow) { - local_state_.SetInteger( - model_execution::prefs::localstate::kOnDevicePerformanceClass, - base::to_underlying(OnDeviceModelPerformanceClass::kVeryLow)); - - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + fake_settings_.performance_class = PerformanceClass::kVeryLow; + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); histograms_.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelInstallCriteria." "AtRegistration.DeviceCapability", @@ -317,17 +302,18 @@ model_execution::prefs::localstate::kLastUsageByFeature); // Should uninstall the first time, and skip uninstallation the next time. - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); - EXPECT_TRUE(on_device_component_state_manager_.WasComponentUninstalled()); + EXPECT_TRUE(base::test::RunUntil( + [&]() { return test_component_state_.uninstall_called(); })); - manager()->UninstallComplete(); + manager().UninstallComplete(); - manager()->OnStartup(); - WaitForStartup(); + SimulateShutdown(); + DoStartup(); - EXPECT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); } TEST_F(OnDeviceModelComponentTest, UninstallNeededDueToDiskSpace) { @@ -336,213 +322,158 @@ base::Time::Now()); // 10gb is the default in `IsFreeDiskSpaceTooLowForOnDeviceModelInstall`. - on_device_component_state_manager_.SetFreeDiskSpace( - 10ll * 1024 * 1024 * 1024 - 1); + test_component_state_.SetFreeDiskSpace(10ll * 1024 * 1024 * 1024 - 1); // Should uninstall right away. Unlike most install requirements, the disk // space requirement is not subject to `GetOnDeviceModelRetentionTime()`. - manager()->OnStartup(); - WaitForStartup(); - - EXPECT_TRUE(on_device_component_state_manager_.WasComponentUninstalled()); + DoStartup(); + EnsurePerformanceClassAvailable(); + EXPECT_TRUE(base::test::RunUntil( + [&]() { return test_component_state_.uninstall_called(); })); } TEST_F(OnDeviceModelComponentTest, KeepInstalledWhileNotEligible) { // If the model is already installed, we don't uninstall right away. // Trigger installer registration. - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); + EXPECT_TRUE(WaitUntilInstallerRegistered()); + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>()); + SimulateShutdown(); - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - - // Simulate a restart, and clear feature recently used pref so that the model - // is no longer eligible for download. - on_device_component_state_manager_.Reset(); + // Clear usage prefs so that the model is no longer eligible for download. local_state_.ClearPref( model_execution::prefs::localstate::kLastUsageByFeature); - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); - // The installer is still registered. Even if the component is ready, it's not - // exposed via GetState(). - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - + // The installer is still registered. + EXPECT_TRUE(WaitUntilInstallerRegistered()); // The model is still available. - EXPECT_TRUE(manager()->GetState()); -} - -TEST_F(OnDeviceModelComponentTest, NeedsPerformanceClassUpdateEveryStartup) { - base::test::ScopedFeatureList feature_list( - features::kOnDeviceModelFetchPerformanceClassEveryStartup); - manager()->OnStartup(); - WaitForStartup(); - EXPECT_TRUE(manager()->NeedsPerformanceClassUpdate()); - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kVeryLow); - EXPECT_TRUE(manager()->NeedsPerformanceClassUpdate()); -} - -TEST_F(OnDeviceModelComponentTest, NeedsPerformanceClassUpdate) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - features::kOnDeviceModelFetchPerformanceClassEveryStartup); - manager()->OnStartup(); - WaitForStartup(); - EXPECT_TRUE(manager()->NeedsPerformanceClassUpdate()); - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kVeryLow); - EXPECT_FALSE(manager()->NeedsPerformanceClassUpdate()); + EXPECT_TRUE(manager().GetState()); } TEST_F(OnDeviceModelComponentTest, KeepInstalledWhileNotAllowed) { // Same test as KeepInstalledWhileNotEligible, but in this case the model // should not be used (because performance class is not supported) even though // it's installed. - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); + EXPECT_TRUE(WaitUntilInstallerRegistered()); + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>()); + SimulateShutdown(); - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - on_device_component_state_manager_.Reset(); - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kVeryLow); - manager()->OnStartup(); - WaitForStartup(); + local_state_.SetString( + model_execution::prefs::localstate::kOnDevicePerformanceClassVersion, + "0.0.0.1"); + fake_settings_.performance_class = PerformanceClass::kVeryLow; + DoStartup(); + EnsurePerformanceClassAvailable(); - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - - EXPECT_FALSE(manager()->GetState()) + EXPECT_TRUE(WaitUntilInstallerRegistered()); + EXPECT_FALSE(manager().GetState()) << "state available even though performance class is not supported"; } +TEST_F(OnDeviceModelComponentTest, NeedsPerformanceClassUpdateEveryStartup) { + base::test::ScopedFeatureList feature_list( + features::kOnDeviceModelFetchPerformanceClassEveryStartup); + fake_settings_.performance_class = PerformanceClass::kVeryHigh; + DoStartup(); + EXPECT_FALSE(classifier().IsPerformanceClassAvailable()); + base::RunLoop run_loop; + classifier().EnsurePerformanceClassAvailable(run_loop.QuitClosure()); + run_loop.Run(); + EXPECT_TRUE(fake_launcher_.did_launch_service()); + EXPECT_TRUE(classifier().IsPerformanceClassAvailable()); + EXPECT_EQ(classifier().GetPerformanceClass(), + OnDeviceModelPerformanceClass::kVeryHigh); + SimulateShutdown(); + + fake_launcher_.clear_did_launch_service(); + fake_settings_.performance_class = PerformanceClass::kVeryLow; + DoStartup(); + EXPECT_FALSE(classifier().IsPerformanceClassAvailable()); + base::RunLoop run_loop2; + classifier().EnsurePerformanceClassAvailable(run_loop2.QuitClosure()); + run_loop2.Run(); + EXPECT_TRUE(fake_launcher_.did_launch_service()); + EXPECT_TRUE(classifier().IsPerformanceClassAvailable()); + EXPECT_EQ(classifier().GetPerformanceClass(), + OnDeviceModelPerformanceClass::kVeryLow); +} + +TEST_F(OnDeviceModelComponentTest, NeedsPerformanceClassUpdate) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + features::kOnDeviceModelFetchPerformanceClassEveryStartup); + fake_settings_.performance_class = PerformanceClass::kVeryHigh; + DoStartup(); + EXPECT_FALSE(classifier().IsPerformanceClassAvailable()); + base::RunLoop run_loop; + classifier().EnsurePerformanceClassAvailable(run_loop.QuitClosure()); + run_loop.Run(); + EXPECT_TRUE(fake_launcher_.did_launch_service()); + EXPECT_TRUE(classifier().IsPerformanceClassAvailable()); + EXPECT_EQ(classifier().GetPerformanceClass(), + OnDeviceModelPerformanceClass::kVeryHigh); + SimulateShutdown(); + + fake_launcher_.clear_did_launch_service(); + fake_settings_.performance_class = PerformanceClass::kVeryLow; + DoStartup(); + EXPECT_TRUE(classifier().IsPerformanceClassAvailable()); + EXPECT_EQ(classifier().GetPerformanceClass(), + OnDeviceModelPerformanceClass::kVeryHigh); + base::RunLoop run_loop2; + classifier().EnsurePerformanceClassAvailable(run_loop2.QuitClosure()); + run_loop2.Run(); + EXPECT_FALSE(fake_launcher_.did_launch_service()); + EXPECT_EQ(classifier().GetPerformanceClass(), + OnDeviceModelPerformanceClass::kVeryHigh); +} + TEST_F(OnDeviceModelComponentTest, GetStateInitiallyNull) { - EXPECT_EQ(manager()->GetState(), nullptr); + DoStartup(); + EXPECT_EQ(manager().GetState(), nullptr); } TEST_F(OnDeviceModelComponentTest, SetReady) { - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); + EXPECT_TRUE(WaitUntilInstallerRegistered()); StubObserver observer; - manager()->AddObserver(&observer); - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); + manager().AddObserver(&observer); + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>()); - const OnDeviceModelComponentState* state = manager()->GetState(); + const OnDeviceModelComponentState* state = manager().GetState(); ASSERT_TRUE(state); - EXPECT_EQ(state->GetInstallDirectory(), - base::FilePath(FILE_PATH_LITERAL("/some/path"))); - EXPECT_EQ(state->GetComponentVersion(), base::Version("0.1.1")); + EXPECT_FALSE(state->GetInstallDirectory().empty()); + EXPECT_EQ(state->GetComponentVersion(), base::Version("0.0.1")); ASSERT_EQ(observer.GetState(), state); } -TEST_F(OnDeviceModelComponentTest, InstallAfterPerformanceClassChanges) { - // This sequence would happen on first run. - local_state_.ClearPref( - model_execution::prefs::localstate::kOnDevicePerformanceClass); - - StubObserver observer; - manager()->AddObserver(&observer); - manager()->OnStartup(); - WaitForStartup(); - - ASSERT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); - EXPECT_FALSE(manager()->GetState()); - - manager()->DevicePerformanceClassChanged(base::DoNothing(), - OnDeviceModelPerformanceClass::kLow); - WaitForStartup(); - - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - - EXPECT_TRUE(manager()->GetState()); - EXPECT_TRUE(observer.GetState()); -} - -TEST_F(OnDeviceModelComponentTest, PerformanceClassChangesAfterInstall) { - // Start 1: registers the component as device is eligible. - StubObserver observer; - manager()->AddObserver(&observer); - manager()->OnStartup(); - WaitForStartup(); - ASSERT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - - // Start 2: device is no longer eligible, but component is registered because - // it's already installed. - on_device_component_state_manager_.Reset(); - manager()->AddObserver(&observer); - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kServiceCrash); - manager()->OnStartup(); - WaitForStartup(); - ASSERT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - - // State is not available, because device is not eligible. - EXPECT_FALSE(manager()->GetState()); - EXPECT_FALSE(observer.GetState()); - - // Device is now eligible - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kHigh); - task_environment_.RunUntilIdle(); - EXPECT_TRUE(manager()->GetState()); - EXPECT_TRUE(observer.GetState()); -} - -TEST_F(OnDeviceModelComponentTest, DontUninstallAfterPerformanceClassChanges) { - manager()->OnStartup(); - WaitForStartup(); - - ASSERT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - - manager()->DevicePerformanceClassChanged(base::DoNothing(), - OnDeviceModelPerformanceClass::kLow); - WaitForStartup(); - - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); - EXPECT_FALSE(on_device_component_state_manager_.WasComponentUninstalled()); -} - TEST_F(OnDeviceModelComponentTest, InstallAfterEligibleFeatureWasUsed) { local_state_.ClearPref( model_execution::prefs::localstate::kLastUsageByFeature); - manager()->OnStartup(); - WaitForStartup(); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_FALSE(WaitForUnexpectedInstallerRegistered()); - ASSERT_FALSE(on_device_component_state_manager_.IsInstallerRegistered()); - - manager()->OnDeviceEligibleFeatureUsed(ModelBasedCapabilityKey::kCompose); - WaitForStartup(); - EXPECT_TRUE(on_device_component_state_manager_.IsInstallerRegistered()); + manager().OnDeviceEligibleFeatureUsed(ModelBasedCapabilityKey::kCompose); + EXPECT_TRUE(WaitUntilInstallerRegistered()); } TEST_F(OnDeviceModelComponentTest, LogsStatusOnUse) { - manager()->OnStartup(); - WaitForStartup(); + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>()); + DoStartup(); + EnsurePerformanceClassAvailable(); + EXPECT_TRUE(WaitUntilInstallerRegistered()); - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); - - manager()->InstallerRegistered(); - - manager()->OnDeviceEligibleFeatureUsed(ModelBasedCapabilityKey::kCompose); + manager().OnDeviceEligibleFeatureUsed(ModelBasedCapabilityKey::kCompose); histograms_.ExpectBucketCount( "OptimizationGuide.ModelExecution.OnDeviceModelStatusAtUseTime", @@ -569,128 +500,118 @@ true, 1); } -TEST_F(OnDeviceModelComponentTest, SetPrefsWhenManifestContainsBaseModelSpec) { - manager()->OnStartup(); - WaitForStartup(); - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifest); // manifest is populated with test data. - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); +TEST_F(OnDeviceModelComponentTest, SetStateWhenManifestContainsBaseModelSpec) { + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>( + std::vector<proto::OnDeviceModelPerformanceHint>{})); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "Test"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "0.0.1"); EXPECT_TRUE(manager() - ->GetState() + .GetState() ->GetBaseModelSpec() .supported_performance_hints.empty()); } TEST_F(OnDeviceModelComponentTest, SetStateWhenModelOverridden) { + FakeBaseModelAsset asset; base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - switches::kOnDeviceModelExecutionOverride, "/some/path"); - manager()->OnStartup(); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "override"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, - "override"); + switches::kOnDeviceModelExecutionOverride, asset.path().MaybeAsASCII()); + DoStartup(); + EnsurePerformanceClassAvailable(); + task_environment_.FastForwardBy(base::Seconds(1)); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "override"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "override"); } TEST_F(OnDeviceModelComponentTest, SetReadyManifestContainsPerformanceHints) { - manager()->OnStartup(); - WaitForStartup(); - - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kHigh); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifestWithPerfHints); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); + fake_settings_.performance_class = PerformanceClass::kHigh; + std::vector<proto::OnDeviceModelPerformanceHint> hints{ + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_UNSPECIFIED, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU, + }; + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>(hints)); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "Test"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "0.0.1"); EXPECT_THAT( - manager()->GetState()->GetBaseModelSpec().supported_performance_hints, + manager().GetState()->GetBaseModelSpec().supported_performance_hints, UnorderedElementsAre( proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY)); } TEST_F(OnDeviceModelComponentTest, SetReadyManifestContainsPerformanceHintsLowTierDevice) { - manager()->OnStartup(); - WaitForStartup(); - - manager()->DevicePerformanceClassChanged(base::DoNothing(), - OnDeviceModelPerformanceClass::kLow); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifestWithPerfHints); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); + fake_settings_.performance_class = PerformanceClass::kLow; + std::vector<proto::OnDeviceModelPerformanceHint> hints{ + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_UNSPECIFIED, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU, + }; + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>(hints)); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "Test"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "0.0.1"); EXPECT_THAT( - manager()->GetState()->GetBaseModelSpec().supported_performance_hints, + manager().GetState()->GetBaseModelSpec().supported_performance_hints, UnorderedElementsAre( proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE)); } -TEST_F(OnDeviceModelComponentTest, - SetReadyManifestContainsPerformanceHintsCPUNotEnabled) { - manager()->OnStartup(); - WaitForStartup(); - - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kVeryLow); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifestWithPerfHints); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); - EXPECT_TRUE(manager() - ->GetState() - ->GetBaseModelSpec() - .supported_performance_hints.empty()); -} - -TEST_F(OnDeviceModelComponentTest, - SetReadyManifestContainsPerformanceHintsCPU) { +TEST_F(OnDeviceModelComponentTest, ManifestContainsPerformanceHintsCPU) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeatureWithParameters( on_device_model::features::kOnDeviceModelCpuBackend, {{"on_device_cpu_ram_threshold_mb", "0"}, {"on_device_cpu_processor_count_threshold", "0"}}); - manager()->OnStartup(); - WaitForStartup(); - - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kVeryLow); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifestWithPerfHints); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); + fake_settings_.performance_class = PerformanceClass::kVeryLow; + std::vector<proto::OnDeviceModelPerformanceHint> hints{ + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_UNSPECIFIED, + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU, + }; + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>(hints)); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); + ASSERT_TRUE(manager().GetState()); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "Test"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "0.0.1"); EXPECT_THAT( - manager()->GetState()->GetBaseModelSpec().supported_performance_hints, + manager().GetState()->GetBaseModelSpec().supported_performance_hints, UnorderedElementsAre(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU)); } -TEST_F(OnDeviceModelComponentTest, - SetReadyManifestContainsPerformanceHintsCPUOnly) { +TEST_F(OnDeviceModelComponentTest, ManifestContainsPerformanceHintsCPUOnly) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeatureWithParameters( on_device_model::features::kOnDeviceModelCpuBackend, {{"on_device_cpu_ram_threshold_mb", "0"}, {"on_device_cpu_processor_count_threshold", "0"}}); - manager()->OnStartup(); - WaitForStartup(); - - manager()->DevicePerformanceClassChanged( - base::DoNothing(), OnDeviceModelPerformanceClass::kHigh); - - manager()->SetReady(base::Version("0.1.1"), - base::FilePath(FILE_PATH_LITERAL("/some/path")), - kTestManifestWithCPUPerfHints); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_name, "Test"); - EXPECT_EQ(manager()->GetState()->GetBaseModelSpec().model_version, "0.0.1"); + fake_settings_.performance_class = PerformanceClass::kHigh; + std::vector<proto::OnDeviceModelPerformanceHint> hints{ + proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU, + }; + test_component_state_.Install(std::make_unique<FakeBaseModelAsset>(hints)); + DoStartup(); + EnsurePerformanceClassAvailable(); + ASSERT_TRUE(WaitUntilInstallerRegistered()); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_name, "Test"); + EXPECT_EQ(manager().GetState()->GetBaseModelSpec().model_version, "0.0.1"); EXPECT_THAT( - manager()->GetState()->GetBaseModelSpec().supported_performance_hints, + manager().GetState()->GetBaseModelSpec().supported_performance_hints, UnorderedElementsAre(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU)); }
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc index 9acd661..e5bc588 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
@@ -13,6 +13,7 @@ #include "base/functional/callback_helpers.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" @@ -167,9 +168,8 @@ model_execution::prefs::RegisterLocalStatePrefs(pref_service_.registry()); // Fake the requirements to install the model. - pref_service_.SetInteger( - model_execution::prefs::localstate::kOnDevicePerformanceClass, - base::to_underlying(OnDeviceModelPerformanceClass::kHigh)); + UpdatePerformanceClassPref(&pref_service_, + OnDeviceModelPerformanceClass::kVeryHigh); model_execution::prefs::RecordFeatureUsage( &pref_service_, ModelBasedCapabilityKey::kCompose); } @@ -187,7 +187,7 @@ component_state_.CreateDelegate(), fake_launcher_.LaunchFn()); model_broker_state_->Init(); - task_environment_.FastForwardBy(base::Seconds(1)); + component_state_.WaitForRegistration(); if (params.base_model) { params.base_model->SetReadyIn( model_broker_state_->component_state_manager()); @@ -605,6 +605,9 @@ TEST_F(OnDeviceModelServiceControllerTest, SessionCreationFailsWhenExecutionNotEnabled) { + // Mark another feature used so registration still happens. + model_execution::prefs::RecordFeatureUsage( + &pref_service_, ModelBasedCapabilityKey::kPromptApi); base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures( {}, {features::kOptimizationGuideComposeOnDeviceEval}); @@ -2037,8 +2040,16 @@ TEST_F(OnDeviceModelServiceControllerTest, ShutsDownServiceAfterPerformanceCheck) { - Initialize(standard_assets_); base::HistogramTester histogram_tester; + pref_service_.SetString( + model_execution::prefs::localstate::kOnDevicePerformanceClassVersion, + "0.0.0.1"); + model_broker_state_.emplace(&pref_service_, component_state_.CreateDelegate(), + fake_launcher_.LaunchFn()); + model_broker_state_->Init(); + EXPECT_FALSE(model_broker_state_->performance_classifier() + .IsPerformanceClassAvailable()); + fake_launcher_.clear_did_launch_service(); base::RunLoop run_loop; model_broker_state_->performance_classifier().EnsurePerformanceClassAvailable( run_loop.QuitClosure()); @@ -2046,8 +2057,9 @@ histogram_tester.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", OnDeviceModelPerformanceClass::kVeryHigh, 1); - task_environment_.RunUntilIdle(); - EXPECT_FALSE(fake_launcher_.is_service_running()); + EXPECT_TRUE(fake_launcher_.did_launch_service()); + EXPECT_TRUE(base::test::RunUntil( + [&]() { return !fake_launcher_.is_service_running(); })); } TEST_F(OnDeviceModelServiceControllerTest, RedactedField) { @@ -3161,68 +3173,6 @@ OnDeviceModelValidationResult::kServiceCrash, 1); } -TEST_F(OnDeviceModelServiceControllerTest, - PerformanceCheckDoesNotInterruptModelValidation) { - fake_settings_.set_execute_delay(base::Seconds(10)); - - FakeBaseModelAsset base_model(WillPassValidationConfig()); - FakeAdaptationAsset compose_asset({.config = UnsafeComposeConfig()}); - - base::HistogramTester histogram_tester; - Initialize({.base_model = &base_model, .adaptations = {&compose_asset}}); - task_environment_.RunUntilIdle(); - - base::RunLoop run_loop; - model_broker_state_->performance_classifier().EnsurePerformanceClassAvailable( - run_loop.QuitClosure()); - run_loop.Run(); - task_environment_.RunUntilIdle(); - - // Performance check sh;ould not shut down service. - EXPECT_TRUE(fake_launcher_.is_service_running()); - histogram_tester.ExpectTotalCount( - "OptimizationGuide.ModelExecution.OnDeviceModelValidationResult", 0); - - task_environment_.FastForwardBy(base::Seconds(10) + base::Milliseconds(1)); - task_environment_.RunUntilIdle(); - EXPECT_FALSE(fake_launcher_.is_service_running()); - - histogram_tester.ExpectUniqueSample( - "OptimizationGuide.ModelExecution.OnDeviceModelValidationResult", - OnDeviceModelValidationResult::kSuccess, 1); -} - -TEST_F(OnDeviceModelServiceControllerTest, - ModelValidationDoesNotInterruptPerformanceCheck) { - fake_settings_.set_estimated_performance_delay(base::Seconds(10)); - fake_settings_.set_execute_delay(base::Seconds(1)); - - FakeBaseModelAsset base_model(WillPassValidationConfig()); - FakeAdaptationAsset compose_asset({.config = UnsafeComposeConfig()}); - - base::HistogramTester histogram_tester; - Initialize({.base_model = &base_model, .adaptations = {&compose_asset}}); - task_environment_.RunUntilIdle(); - - base::RunLoop run_loop; - model_broker_state_->performance_classifier().EnsurePerformanceClassAvailable( - run_loop.QuitClosure()); - - task_environment_.FastForwardBy(base::Seconds(1) + base::Milliseconds(1)); - task_environment_.RunUntilIdle(); - // Still connected since the performance estimator is running. - EXPECT_TRUE(fake_launcher_.is_service_running()); - - histogram_tester.ExpectUniqueSample( - "OptimizationGuide.ModelExecution.OnDeviceModelValidationResult", - OnDeviceModelValidationResult::kSuccess, 1); - - EXPECT_FALSE(run_loop.AnyQuitCalled()); - run_loop.Run(); - task_environment_.RunUntilIdle(); - EXPECT_FALSE(fake_launcher_.is_service_running()); -} - TEST_F(OnDeviceModelServiceControllerTest, SendsPerformanceHint) { FakeBaseModelAsset base_model( {.supported_performance_hint = @@ -3718,6 +3668,10 @@ base::HistogramTester histogram_tester; mojo::PendingReceiver<mojom::ModelBroker> pending_broker; + pref_service_.SetString( + model_execution::prefs::localstate::kOnDevicePerformanceClassVersion, + "0.0.0.1"); + ModelBrokerClient broker_client( pending_broker.InitWithNewPipeAndPassRemote(), CreateSessionArgs(logger_.GetWeakPtr(), FailOnRemoteFallback())); @@ -3727,10 +3681,11 @@ broker_client.CreateSession(mojom::ModelBasedCapabilityKey::kCompose, std::nullopt, session_future.GetCallback()); - Initialize(standard_assets_); + model_broker_state_.emplace(&pref_service_, component_state_.CreateDelegate(), + fake_launcher_.LaunchFn()); + model_broker_state_->Init(); controller().BindBroker(std::move(pending_broker)); - - ASSERT_TRUE(session_future.Take()); + component_state_.WaitForRegistration(); histogram_tester.ExpectUniqueSample( "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", OnDeviceModelPerformanceClass::kVeryHigh, 1);
diff --git a/components/optimization_guide/core/model_execution/performance_class.cc b/components/optimization_guide/core/model_execution/performance_class.cc index 65b43c64..0dfb8f3 100644 --- a/components/optimization_guide/core/model_execution/performance_class.cc +++ b/components/optimization_guide/core/model_execution/performance_class.cc
@@ -8,18 +8,65 @@ #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_functions.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/types/cxx23_to_underlying.h" #include "base/version_info/version_info.h" #include "components/optimization_guide/core/model_execution/model_execution_prefs.h" #include "components/optimization_guide/core/optimization_guide_enums.h" #include "components/optimization_guide/core/optimization_guide_features.h" +#include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/prefs/pref_service.h" #include "components/variations/synthetic_trials.h" #include "mojo/public/cpp/bindings/callback_helpers.h" +#include "services/on_device_model/public/cpp/cpu.h" namespace optimization_guide { +namespace { + +// Commandline switch to force a particular performance class. +const char kOverridePerformanceClassSwitch[] = + "optimization-guide-performance-class"; + +bool NeedsPerformanceClassUpdate(const PrefService& local_state) { + if (!features::CanLaunchOnDeviceModelService()) { + return false; + } + if (base::FeatureList::IsEnabled( + features::kOnDeviceModelFetchPerformanceClassEveryStartup)) { + return true; + } + return local_state.GetString(model_execution::prefs::localstate:: + kOnDevicePerformanceClassVersion) != + version_info::GetVersionNumber(); +} + +// Convert a number to a performance class. +OnDeviceModelPerformanceClass AsPerformanceClass(int value) { + if (value < 0 || + value > static_cast<int>(OnDeviceModelPerformanceClass::kMaxValue)) { + return OnDeviceModelPerformanceClass::kUnknown; + } + return static_cast<OnDeviceModelPerformanceClass>(value); +} + +OnDeviceModelPerformanceClass GetPerformanceClassSwitch() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(kOverridePerformanceClassSwitch)) { + return OnDeviceModelPerformanceClass::kUnknown; + } + int value = 0; + if (!base::StringToInt( + command_line->GetSwitchValueASCII(kOverridePerformanceClassSwitch), + &value)) { + return OnDeviceModelPerformanceClass::kUnknown; + } + return AsPerformanceClass(value); +} + +} // namespace + OnDeviceModelPerformanceClass ConvertToOnDeviceModelPerformanceClass( on_device_model::mojom::PerformanceClass performance_class) { switch (performance_class) { @@ -104,29 +151,51 @@ } PerformanceClassifier::PerformanceClassifier( - base::SafeRef<OnDeviceModelComponentStateManager> - on_device_component_state_manager, + PrefService* local_state, base::SafeRef<on_device_model::ServiceClient> service_client) - : on_device_component_state_manager_( - std::move(on_device_component_state_manager)), - service_client_(std::move(service_client)) {} + : local_state_(local_state), service_client_(std::move(service_client)) {} PerformanceClassifier::~PerformanceClassifier() = default; +void PerformanceClassifier::Init() { + CHECK_EQ(performance_class_state_, PerformanceClassState::kNotStarted); + CHECK(performance_class_callbacks_.empty()); + // TODO: crbug.com/432041523 - Update integration tests to force performance + // class explicitly. + if (switches::GetOnDeviceValidationWriteToFile()) { + UpdatePerformanceClassPref(local_state_, + OnDeviceModelPerformanceClass::kVeryHigh); + } + OnDeviceModelPerformanceClass override_class = GetPerformanceClassSwitch(); + if (override_class != OnDeviceModelPerformanceClass::kUnknown) { + UpdatePerformanceClassPref(local_state_, override_class); + performance_class_state_ = PerformanceClassState::kComplete; + return; + } + if (!NeedsPerformanceClassUpdate(*local_state_)) { + performance_class_state_ = PerformanceClassState::kComplete; + } +} + +void PerformanceClassifier::ScheduleEvaluation() { + base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&PerformanceClassifier::EnsurePerformanceClassAvailable, + weak_ptr_factory_.GetWeakPtr(), base::DoNothing()), + optimization_guide::features::GetOnDeviceStartupMetricDelay()); +} + void PerformanceClassifier::EnsurePerformanceClassAvailable( base::OnceClosure complete) { - if (!features::CanLaunchOnDeviceModelService()) { - std::move(complete).Run(); - return; - } - if (ListenForPerformanceClassAvailable(std::move(complete))) { return; } - if (performance_class_state_ == PerformanceClassState::kComputing) { + if (performance_class_state_ != PerformanceClassState::kNotStarted) { return; } + CHECK(features::CanLaunchOnDeviceModelService()); + performance_class_state_ = PerformanceClassState::kComputing; service_client_->Get()->GetDevicePerformanceInfo( base::BindOnce([](on_device_model::mojom::DevicePerformanceInfoPtr info) { @@ -135,19 +204,14 @@ .Then(base::BindOnce(&ConvertToOnDeviceModelPerformanceClass) .Then(mojo::WrapCallbackWithDefaultInvokeIfNotRun( base::BindOnce( - &PerformanceClassifier::PerformanceClassUpdated, + &PerformanceClassifier::PerformanceClassEvaluated, weak_ptr_factory_.GetWeakPtr()), OnDeviceModelPerformanceClass::kServiceCrash)))); } bool PerformanceClassifier::ListenForPerformanceClassAvailable( base::OnceClosure available) { - if (!on_device_component_state_manager_->NeedsPerformanceClassUpdate()) { - std::move(available).Run(); - return true; - } - - if (performance_class_state_ == PerformanceClassState::kComplete) { + if (IsPerformanceClassAvailable()) { std::move(available).Run(); return true; } @@ -157,20 +221,76 @@ return false; } -void PerformanceClassifier::PerformanceClassUpdated( +OnDeviceModelPerformanceClass PerformanceClassifier::GetPerformanceClass() + const { + CHECK(IsPerformanceClassAvailable()); + return PerformanceClassFromPref(*local_state_); +} + +bool PerformanceClassifier::IsDeviceGPUCapable() const { + return IsPerformanceClassCompatible( + features::kPerformanceClassListForOnDeviceModel.Get(), + GetPerformanceClass()); +} + +bool PerformanceClassifier::IsDeviceCapable() const { + return IsDeviceGPUCapable() || on_device_model::IsCpuCapable(); +} + +bool PerformanceClassifier::IsLowTierDevice() const { + return IsPerformanceClassCompatible( + features::kLowTierPerformanceClassListForOnDeviceModel.Get(), + GetPerformanceClass()); +} + +bool PerformanceClassifier::SupportsImageInput() const { + return IsPerformanceClassCompatible( + features::kPerformanceClassListForImageInput.Get(), + GetPerformanceClass()); +} + +bool PerformanceClassifier::SupportsAudioInput() const { + return IsPerformanceClassCompatible( + features::kPerformanceClassListForAudioInput.Get(), + GetPerformanceClass()); +} + +std::vector<proto::OnDeviceModelPerformanceHint> +PerformanceClassifier::GetPossibleHints() const { + std::vector<proto::OnDeviceModelPerformanceHint> hints; + if (IsDeviceGPUCapable()) { + // Best option is highest quality for GPU device that is not low tier. + if (!IsLowTierDevice()) { + hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY); + } + // Other GPU capable devices get fastest inference. + hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_FASTEST_INFERENCE); + } + if (on_device_model::IsCpuCapable()) { + // Last option is CPU if the device is capable but not GPU capable. + hints.push_back(proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_CPU); + } + return hints; +} + +on_device_model::Capabilities +PerformanceClassifier::GetPossibleOnDeviceCapabilities() const { + on_device_model::Capabilities capabilities; + if (SupportsImageInput()) { + capabilities.Put(on_device_model::CapabilityFlags::kImageInput); + } + if (SupportsAudioInput()) { + capabilities.Put(on_device_model::CapabilityFlags::kAudioInput); + } + return capabilities; +} + +void PerformanceClassifier::PerformanceClassEvaluated( OnDeviceModelPerformanceClass perf_class) { base::UmaHistogramEnumeration( "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", perf_class); - - auto complete = - base::BindOnce(&PerformanceClassifier::NotifyPerformanceClassAvailable, - weak_ptr_factory_.GetWeakPtr()); - on_device_component_state_manager_->DevicePerformanceClassChanged( - std::move(complete), perf_class); -} - -void PerformanceClassifier::NotifyPerformanceClassAvailable() { + UpdatePerformanceClassPref(local_state_, perf_class); performance_class_state_ = PerformanceClassState::kComplete; performance_class_callbacks_.Notify(); }
diff --git a/components/optimization_guide/core/model_execution/performance_class.h b/components/optimization_guide/core/model_execution/performance_class.h index e63c2e7..5bb0c117 100644 --- a/components/optimization_guide/core/model_execution/performance_class.h +++ b/components/optimization_guide/core/model_execution/performance_class.h
@@ -7,8 +7,8 @@ #include "base/callback_list.h" #include "base/component_export.h" -#include "components/optimization_guide/core/model_execution/on_device_model_component.h" #include "components/optimization_guide/core/optimization_guide_enums.h" +#include "components/optimization_guide/proto/on_device_base_model_metadata.pb.h" #include "components/prefs/pref_service.h" #include "services/on_device_model/public/cpp/service_client.h" #include "services/on_device_model/public/mojom/on_device_model.mojom-shared.h" @@ -42,17 +42,16 @@ class PerformanceClassifier final { public: PerformanceClassifier( - base::SafeRef<OnDeviceModelComponentStateManager> - on_device_component_state_manager, + PrefService* local_state, base::SafeRef<on_device_model::ServiceClient> service_client); ~PerformanceClassifier(); base::SafeRef<PerformanceClassifier> GetSafeRef() { return weak_ptr_factory_.GetSafeRef(); } - base::WeakPtr<PerformanceClassifier> GetWeakPtr() { - return weak_ptr_factory_.GetWeakPtr(); - } + + // Do deferred initialization, like reading prefs / checking features. + void Init(); // Ensures the performance class will be up to date and available when // `complete` runs. @@ -63,25 +62,50 @@ // available. bool ListenForPerformanceClassAvailable(base::OnceClosure available); + // Schedules a call to EnsurePerformanceClassAvailable after a delay. + void ScheduleEvaluation(); + + // Whether the performance class has been determined yet. + bool IsPerformanceClassAvailable() const { + return performance_class_state_ == PerformanceClassState::kComplete; + } + + // The below methods all require PerformanceClassAvailable and may give a + // stale value otherwise. + + // Returns the latest performance class. + OnDeviceModelPerformanceClass GetPerformanceClass() const; + // Returns true if this device can run any foundational model. + bool IsDeviceCapable() const; + // Returns true if this device can run any GPU foundational model. + bool IsDeviceGPUCapable() const; + // Returns true if this is determined to be a low tier device. + bool IsLowTierDevice() const; + // Returns true if the device supports image input. + bool SupportsImageInput() const; + // Returns true if the device supports audio input. + bool SupportsAudioInput() const; + // Returns a list of performance hints this device supports in priority order, + // with highest priority first. + std::vector<proto::OnDeviceModelPerformanceHint> GetPossibleHints() const; + + on_device_model::Capabilities GetPossibleOnDeviceCapabilities() const; + private: - // Called when performance class has finished updating. - void PerformanceClassUpdated(OnDeviceModelPerformanceClass perf_class); + // Called when performance class has finished evaluating. + void PerformanceClassEvaluated(OnDeviceModelPerformanceClass perf_class); - // Notify observers that the performance class is available. - void NotifyPerformanceClassAvailable(); - - base::SafeRef<OnDeviceModelComponentStateManager> - on_device_component_state_manager_; + raw_ptr<PrefService> local_state_; base::SafeRef<on_device_model::ServiceClient> service_client_; enum class PerformanceClassState { - kNotSet, + kNotStarted, kComputing, kComplete, }; PerformanceClassState performance_class_state_ = - PerformanceClassState::kNotSet; + PerformanceClassState::kNotStarted; // Callbacks waiting for performance class to finish computing. base::OnceClosureList performance_class_callbacks_;
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_assets.cc b/components/optimization_guide/core/model_execution/test/fake_model_assets.cc index 6826908..f48f3360 100644 --- a/components/optimization_guide/core/model_execution/test/fake_model_assets.cc +++ b/components/optimization_guide/core/model_execution/test/fake_model_assets.cc
@@ -25,12 +25,21 @@ FakeBaseModelAsset::FakeBaseModelAsset() : FakeBaseModelAsset(FakeBaseModelAsset::Content{}) {} FakeBaseModelAsset::FakeBaseModelAsset(Content&& content) - : version_(content.version), - supported_performance_hint_(content.supported_performance_hint) { + : version_(content.version) { CHECK(temp_dir_.CreateUniqueTempDir()); + supported_performance_hints_.Append(content.supported_performance_hint); Write(std::move(content)); } FakeBaseModelAsset::FakeBaseModelAsset( + std::vector<proto::OnDeviceModelPerformanceHint> hints) + : version_("0.0.1") { + CHECK(temp_dir_.CreateUniqueTempDir()); + for (auto hint : hints) { + supported_performance_hints_.Append(hint); + } + Write({}); +} +FakeBaseModelAsset::FakeBaseModelAsset( proto::OnDeviceModelValidationConfig&& validation_config) : FakeBaseModelAsset(Content{ .config = ExecutionConfigWithValidation(std::move(validation_config)), @@ -51,12 +60,11 @@ base::Value::Dict FakeBaseModelAsset::Manifest() const { return base::Value::Dict().Set( - "BaseModelSpec", - base::Value::Dict() - .Set("version", "0.0.1") - .Set("name", "Test") - .Set("supported_performance_hints", - base::Value::List().Append(supported_performance_hint_))); + "BaseModelSpec", base::Value::Dict() + .Set("version", "0.0.1") + .Set("name", "Test") + .Set("supported_performance_hints", + supported_performance_hints_.Clone())); } void FakeBaseModelAsset::SetReadyIn(
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_assets.h b/components/optimization_guide/core/model_execution/test/fake_model_assets.h index 71f311e..0405bf5 100644 --- a/components/optimization_guide/core/model_execution/test/fake_model_assets.h +++ b/components/optimization_guide/core/model_execution/test/fake_model_assets.h
@@ -11,6 +11,7 @@ #include "base/containers/flat_set.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "base/values.h" #include "components/optimization_guide/core/delivery/model_info.h" #include "components/optimization_guide/core/model_execution/feature_keys.h" #include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h" @@ -31,12 +32,14 @@ proto::OnDeviceModelExecutionConfig config; std::string version = "0.0.1"; uint32_t cache_weight = 0; - int supported_performance_hint = + proto::OnDeviceModelPerformanceHint supported_performance_hint = proto::ON_DEVICE_MODEL_PERFORMANCE_HINT_HIGHEST_QUALITY; }; FakeBaseModelAsset(); explicit FakeBaseModelAsset(Content&& content); explicit FakeBaseModelAsset( + std::vector<proto::OnDeviceModelPerformanceHint> hints); + explicit FakeBaseModelAsset( proto::OnDeviceModelValidationConfig&& validation_config); ~FakeBaseModelAsset(); @@ -55,7 +58,7 @@ private: std::string version_; - int supported_performance_hint_; + base::Value::List supported_performance_hints_; base::ScopedTempDir temp_dir_; };
diff --git a/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.cc b/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.cc index dcd21d91..83fd51d 100644 --- a/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.cc +++ b/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.cc
@@ -28,8 +28,12 @@ base::WeakPtr<OnDeviceModelComponentStateManager> state_manager, bool is_already_installing) override { if (state_) { - state_->installer_registered_ = true; + state_->registered_manager_ = state_manager; + if (state_->installed_asset_) { + state_->installed_asset_->SetReadyIn(*state_manager); + } } + state_manager->InstallerRegistered(); } void Uninstall(base::WeakPtr<OnDeviceModelComponentStateManager> state_manager) override { @@ -48,7 +52,6 @@ } private: - friend class TestOnDeviceModelComponentStateManager; base::WeakPtr<TestComponentState> state_; }; @@ -60,48 +63,11 @@ return std::make_unique<DelegateImpl>(weak_ptr_factory_.GetWeakPtr()); } -TestOnDeviceModelComponentStateManager::TestOnDeviceModelComponentStateManager( - PrefService* local_state) - : local_state_(local_state), - state_(std::make_unique<TestComponentState>()) {} - -TestOnDeviceModelComponentStateManager:: - ~TestOnDeviceModelComponentStateManager() { - Reset(); -} - -base::WeakPtr<OnDeviceModelComponentStateManager> -TestOnDeviceModelComponentStateManager::get() { - // Note that we create the instance lazily to allow tests time to register - // prefs. - if (!manager_) { - manager_ = std::make_unique<OnDeviceModelComponentStateManager>( - local_state_, state_->CreateDelegate()); +void TestComponentState::Install(std::unique_ptr<FakeBaseModelAsset> asset) { + installed_asset_ = std::move(asset); + if (registered_manager_) { + installed_asset_->SetReadyIn(*registered_manager_); } - return manager_->GetWeakPtr(); -} - -void TestOnDeviceModelComponentStateManager::Reset() { - manager_ = nullptr; - state_ = std::make_unique<TestComponentState>(); -} - -bool TestOnDeviceModelComponentStateManager::IsInstallerRegistered() const { - return state_->installer_registered(); -} - -bool TestOnDeviceModelComponentStateManager::WasComponentUninstalled() const { - return state_->uninstall_called(); -} - -void TestOnDeviceModelComponentStateManager::SetFreeDiskSpace( - int64_t free_space_bytes) { - state_->SetFreeDiskSpace(free_space_bytes); -} - -void TestOnDeviceModelComponentStateManager::SetReady( - const FakeBaseModelAsset& asset) { - asset.SetReadyIn(*get()); } } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h b/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h index b9264f2f1..1f53820 100644 --- a/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h +++ b/components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h
@@ -9,10 +9,9 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/task/current_thread.h" #include "components/optimization_guide/core/model_execution/on_device_model_component.h" -class PrefService; - namespace optimization_guide { class FakeBaseModelAsset; @@ -29,43 +28,29 @@ void SetFreeDiskSpace(int64_t free_space_bytes) { free_disk_space_ = free_space_bytes; } - bool installer_registered() const { return installer_registered_; } + bool installer_registered() const { return !!registered_manager_; } bool uninstall_called() const { return uninstall_called_; } + void Install(std::unique_ptr<FakeBaseModelAsset> asset); + void SimulateShutdown() { + registered_manager_.reset(); + uninstall_called_ = false; + } + + bool WaitForRegistration() const { + return base::test::RunUntil([&]() { return installer_registered(); }); + } + private: class DelegateImpl; int64_t free_disk_space_ = 100 * 1024ll * 1024 * 1024; - bool installer_registered_ = false; + base::WeakPtr<OnDeviceModelComponentStateManager> registered_manager_; bool uninstall_called_ = false; + std::unique_ptr<FakeBaseModelAsset> installed_asset_; base::WeakPtrFactory<TestComponentState> weak_ptr_factory_{this}; }; -// Provides scoped creation and destruction of -// OnDeviceModelComponentStateManager. Checks to make sure only one instance is -// used at a time. -class TestOnDeviceModelComponentStateManager { - public: - explicit TestOnDeviceModelComponentStateManager(PrefService* local_state); - ~TestOnDeviceModelComponentStateManager(); - - base::WeakPtr<OnDeviceModelComponentStateManager> get(); - - void Reset(); - - bool IsInstallerRegistered() const; - bool WasComponentUninstalled() const; - - void SetFreeDiskSpace(int64_t free_space_bytes); - - void SetReady(const FakeBaseModelAsset& asset); - - private: - raw_ptr<PrefService> local_state_; - std::unique_ptr<OnDeviceModelComponentStateManager> manager_; - std::unique_ptr<TestComponentState> state_; -}; - } // namespace optimization_guide #endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_EXECUTION_TEST_TEST_ON_DEVICE_MODEL_COMPONENT_STATE_MANAGER_H_
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 34545b5..538702b 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 34545b579229b4993a3f0ea5a1046b34e305a2aa +Subproject commit 538702b238a5c0dc92d77496aa35f55382cf936b
diff --git a/components/password_manager/core/browser/affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/affiliation/affiliated_match_helper_unittest.cc index 0a90c43..edd64fe 100644 --- a/components/password_manager/core/browser/affiliation/affiliated_match_helper_unittest.cc +++ b/components/password_manager/core/browser/affiliation/affiliated_match_helper_unittest.cc
@@ -20,9 +20,7 @@ #include "base/test/gmock_callback_support.h" #include "base/test/gmock_move_support.h" #include "base/test/mock_callback.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/test/task_environment.h" -#include "base/test/test_mock_time_task_runner.h" #include "components/affiliations/core/browser/affiliation_utils.h" #include "components/affiliations/core/browser/mock_affiliation_service.h" #include "services/network/test/test_shared_url_loader_factory.h" @@ -136,12 +134,7 @@ AffiliatedMatchHelperTest() = default; protected: - void RunUntilIdle() { - // TODO(gab): Add support for base::RunLoop().RunUntilIdle() in scope of - // ScopedMockTimeMessageLoopTaskRunner and use it instead of this helper - // method. - mock_time_task_runner_->RunUntilIdle(); - } + void RunUntilIdle() { task_environment_.RunUntilIdle(); } MockAffiliationService* mock_affiliation_service() { return mock_affiliation_service_.get(); @@ -165,8 +158,8 @@ RunUntilIdle(); } - base::test::SingleThreadTaskEnvironment task_environment_; - base::ScopedMockTimeMessageLoopTaskRunner mock_time_task_runner_; + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<MockAffiliationService> mock_affiliation_service_; std::unique_ptr<AffiliatedMatchHelper> match_helper_;
diff --git a/components/sync/service/sync_prefs.cc b/components/sync/service/sync_prefs.cc index 4aa09a0..18f2437 100644 --- a/components/sync/service/sync_prefs.cc +++ b/components/sync/service/sync_prefs.cc
@@ -827,7 +827,7 @@ kMigratedPart2AndFullyDone); return false; } - case SyncAccountState::kSignedInNotSyncing: { + case SyncAccountState::kSignedInWithoutSyncConsent: { pref_service_->SetInteger(prefs::internal::kSyncToSigninMigrationState, kMigratedPart1ButNot2); CHECK(!gaia_id.empty());
diff --git a/components/sync/service/sync_prefs.h b/components/sync/service/sync_prefs.h index 72c7771b..c6f980ad 100644 --- a/components/sync/service/sync_prefs.h +++ b/components/sync/service/sync_prefs.h
@@ -46,10 +46,13 @@ class SyncPrefs { public: enum class SyncAccountState { - kNotSignedIn = 0, - // In transport mode. - kSignedInNotSyncing = 1, - kSyncing = 2 + kNotSignedIn, + kSignedInWithoutSyncConsent, + // Note that kSyncing is also used for local sync (an enterprise feature + // known as roaming profiles) as well as in some advanced transport-mode + // scenarios such as the advanced sync setup flow interrupted case or, on + // ChromeOS, after sync is reset from the sync dashboard. + kSyncing, }; // `pref_service` must not be null and must outlive this object.
diff --git a/components/sync/service/sync_prefs_unittest.cc b/components/sync/service/sync_prefs_unittest.cc index 01433ca8..d50a63f 100644 --- a/components/sync/service/sync_prefs_unittest.cc +++ b/components/sync/service/sync_prefs_unittest.cc
@@ -1105,7 +1105,7 @@ // Both methods are called. No migration should run. EXPECT_FALSE(prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_)); EXPECT_FALSE(prefs.MaybeMigratePrefsForSyncToSigninPart2( gaia_id_, /*is_using_explicit_passphrase=*/true)); @@ -1123,7 +1123,7 @@ // The user is signed-in non-syncing, so part 1 runs. The user also has an // explicit passphrase, so part 2 runs too. EXPECT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_)); EXPECT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart2( gaia_id_, /*is_using_explicit_passphrase=*/true)); @@ -1139,7 +1139,7 @@ // Since the feature is disabled now, no migration runs. EXPECT_FALSE(prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_)); EXPECT_FALSE(prefs.MaybeMigratePrefsForSyncToSigninPart2( gaia_id_, /*is_using_explicit_passphrase=*/true)); @@ -1154,7 +1154,7 @@ // Since it was disabled in between, the migration should run again. EXPECT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_)); EXPECT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart2( gaia_id_, /*is_using_explicit_passphrase=*/true)); @@ -1174,7 +1174,7 @@ SyncPrefs prefs(&pref_service_); ASSERT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_)); ASSERT_TRUE(prefs.MaybeMigratePrefsForSyncToSigninPart2( gaia_id_, /*is_using_explicit_passphrase=*/true)); @@ -1198,7 +1198,7 @@ // Run the migration for a pre-existing signed-in non-syncing user. prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // Preferences should've been turned off in the account-scoped settings. EXPECT_FALSE(prefs.GetSelectedTypesForAccount(gaia_id_).Has( @@ -1246,7 +1246,7 @@ UserSelectableType::kReadingList)); prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // Bookmarks and ReadingList should still be enabled. EXPECT_TRUE(prefs.GetSelectedTypesForAccount(gaia_id_).Has( @@ -1288,7 +1288,7 @@ // Run the migration! prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // After the migration, the types should be disabled. EXPECT_FALSE(prefs.GetSelectedTypesForAccount(gaia_id_).Has( @@ -1310,7 +1310,7 @@ // Run the first phase of the migration. prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // Autofill should still be unaffected for now, since the passphrase state // wasn't known yet. @@ -1343,7 +1343,7 @@ // Run the first phase of the migration. prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // The types should still be unaffected for now, since the passphrase state // wasn't known yet. @@ -1379,7 +1379,7 @@ // Run the first phase of the migration. prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); // The account-scoped settings should still be unaffected for now, since the // passphrase state wasn't known yet. @@ -1393,7 +1393,7 @@ // The first phase runs again. This should effectively do nothing. prefs.MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_); + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, gaia_id_); ASSERT_TRUE(prefs.GetSelectedTypesForAccount(gaia_id_).Has( UserSelectableType::kAutofill)); @@ -1599,10 +1599,10 @@ // After the GlobalToAccount migration has run, the SyncToSignin migration // should not have any effect anymore. - EXPECT_FALSE( - SyncPrefs(&pref_service_) - .MaybeMigratePrefsForSyncToSigninPart1( - SyncPrefs::SyncAccountState::kSignedInNotSyncing, gaia_id_)); + EXPECT_FALSE(SyncPrefs(&pref_service_) + .MaybeMigratePrefsForSyncToSigninPart1( + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, + gaia_id_)); } TEST_F(SyncPrefsTest, IsTypeDisabledByUserForAccount) {
diff --git a/components/sync/service/sync_service_impl.cc b/components/sync/service/sync_service_impl.cc index 046c649a..8252cec 100644 --- a/components/sync/service/sync_service_impl.cc +++ b/components/sync/service/sync_service_impl.cc
@@ -1322,7 +1322,7 @@ if (!sync_prefs_.GetCachedPassphraseType().has_value() && IsExplicitPassphrase(passphrase_type) && GetSyncAccountStateForPrefs() == - SyncPrefs::SyncAccountState::kSignedInNotSyncing && + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent && sync_prefs_.DoesTypeHaveDefaultValueForAccount( UserSelectableType::kAutofill, GetAccountInfo().gaia) && base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos)) { @@ -1365,8 +1365,9 @@ } // This doesn't check IsSyncFeatureEnabled() so it covers the case of advanced // sync setup, where IsInitialSyncFeatureSetupComplete() is not true yet. - return HasSyncConsent() ? SyncPrefs::SyncAccountState::kSyncing - : SyncPrefs::SyncAccountState::kSignedInNotSyncing; + return HasSyncConsent() + ? SyncPrefs::SyncAccountState::kSyncing + : SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent; } CoreAccountInfo SyncServiceImpl::GetSyncAccountInfoForPrefs() const {
diff --git a/components/sync/service/sync_stopped_reporter_unittest.cc b/components/sync/service/sync_stopped_reporter_unittest.cc index e36927d..91a857464 100644 --- a/components/sync/service/sync_stopped_reporter_unittest.cc +++ b/components/sync/service/sync_stopped_reporter_unittest.cc
@@ -7,7 +7,6 @@ #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "components/sync/protocol/sync.pb.h" @@ -38,7 +37,14 @@ SyncStoppedReporterTest& operator=(const SyncStoppedReporterTest&) = delete; protected: - SyncStoppedReporterTest() = default; + SyncStoppedReporterTest() + : SyncStoppedReporterTest( + base::test::TaskEnvironment::TimeSource::SYSTEM_TIME) {} + + explicit SyncStoppedReporterTest( + base::test::TaskEnvironment::TimeSource time_source) + : task_environment_(time_source) {} + ~SyncStoppedReporterTest() override = default; void SetUp() override { @@ -63,8 +69,9 @@ return test_shared_loader_factory_; } - private: base::test::SingleThreadTaskEnvironment task_environment_; + + private: network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; }; @@ -160,10 +167,15 @@ histogram_tester.ExpectTotalCount("Sync.SyncStoppedURLFetchTimedOut", 0); } -TEST_F(SyncStoppedReporterTest, Timeout) { +class MockTimeSyncStoppedReporterTest : public SyncStoppedReporterTest { + protected: + MockTimeSyncStoppedReporterTest() + : SyncStoppedReporterTest( + base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} +}; + +TEST_F(MockTimeSyncStoppedReporterTest, Timeout) { base::HistogramTester histogram_tester; - // Mock the underlying loop's clock to trigger the timer at will. - base::ScopedMockTimeMessageLoopTaskRunner mock_main_runner; // No TestURLLoaderFactory::AddResponse(), so the request stays pending. SyncStoppedReporter ssr(test_url(), user_agent(), @@ -173,8 +185,7 @@ ssr.ReportSyncStopped(kAuthToken, kCacheGuid, kBirthday); // Trigger the timeout, 30 seconds should be more than enough. - ASSERT_TRUE(mock_main_runner->HasPendingTask()); - mock_main_runner->FastForwardBy(base::Seconds(30)); + task_environment_.FastForwardBy(base::Seconds(30)); histogram_tester.ExpectUniqueSample("Sync.SyncStoppedURLFetchTimedOut", true, 1); }
diff --git a/components/sync/service/sync_user_settings_impl.cc b/components/sync/service/sync_user_settings_impl.cc index ac78423..7353830 100644 --- a/components/sync/service/sync_user_settings_impl.cc +++ b/components/sync/service/sync_user_settings_impl.cc
@@ -129,7 +129,7 @@ case SyncPrefs::SyncAccountState::kNotSignedIn: { return UserSelectableTypeSet(); } - case SyncPrefs::SyncAccountState::kSignedInNotSyncing: { + case SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent: { types = prefs_->GetSelectedTypesForAccount( delegate_->GetSyncAccountInfoForPrefs().gaia); break; @@ -158,7 +158,7 @@ SyncUserSettingsImpl::GetTypePrefStateForAccount( UserSelectableType type) const { if (delegate_->GetSyncAccountStateForPrefs() != - SyncPrefs::SyncAccountState::kSignedInNotSyncing) { + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent) { return SyncUserSettings::UserSelectableTypePrefState::kNotApplicable; } if (prefs_->IsTypeDisabledByUserForAccount( @@ -178,7 +178,7 @@ switch (delegate_->GetSyncAccountStateForPrefs()) { case SyncPrefs::SyncAccountState::kNotSignedIn: NOTREACHED(); - case SyncPrefs::SyncAccountState::kSignedInNotSyncing: + case SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent: for (UserSelectableType type : registered_types) { SetSelectedType(type, types.Has(type) || sync_everything); } @@ -198,7 +198,7 @@ switch (delegate_->GetSyncAccountStateForPrefs()) { case SyncPrefs::SyncAccountState::kNotSignedIn: NOTREACHED(); - case SyncPrefs::SyncAccountState::kSignedInNotSyncing: { + case SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent: { prefs_->SetSelectedTypeForAccount( type, is_type_on, delegate_->GetSyncAccountInfoForPrefs().gaia); break; @@ -215,7 +215,7 @@ } void SyncUserSettingsImpl::ResetSelectedType(UserSelectableType type) { - CHECK_EQ(SyncPrefs::SyncAccountState::kSignedInNotSyncing, + CHECK_EQ(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent, delegate_->GetSyncAccountStateForPrefs()); prefs_->ResetSelectedTypeForAccount( type, delegate_->GetSyncAccountInfoForPrefs().gaia);
diff --git a/components/sync/service/sync_user_settings_impl_unittest.cc b/components/sync/service/sync_user_settings_impl_unittest.cc index ce7a69d4..d223f4e8 100644 --- a/components/sync/service/sync_user_settings_impl_unittest.cc +++ b/components/sync/service/sync_user_settings_impl_unittest.cc
@@ -130,7 +130,7 @@ .WillByDefault(Return(sync_account_state)); #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) if (sync_account_state == - SyncPrefs::SyncAccountState::kSignedInNotSyncing) { + SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent) { pref_service_.SetBoolean(prefs::kExplicitBrowserSignin, true); } #endif @@ -180,7 +180,7 @@ TEST_F(SyncUserSettingsImplTest, GetSelectedTypesWhileSignedOut) { // Sanity check: signed-in there are selected types. - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); ASSERT_FALSE( MakeSyncUserSettings(GetUserTypes())->GetSelectedTypes().empty()); @@ -206,7 +206,7 @@ std::unique_ptr<SyncUserSettingsImpl> sync_user_settings = MakeSyncUserSettings(GetUserTypes()); - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); UserSelectableTypeSet expected_types = {UserSelectableType::kPasswords, UserSelectableType::kAutofill, @@ -249,7 +249,7 @@ std::unique_ptr<SyncUserSettingsImpl> sync_user_settings = MakeSyncUserSettings(GetUserTypes()); - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); const UserSelectableTypeSet registered_types = sync_user_settings->GetRegisteredSelectableTypes(); @@ -272,7 +272,7 @@ } TEST_F(SyncUserSettingsImplTest, SetSelectedTypeInTransportMode) { - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); std::unique_ptr<SyncUserSettingsImpl> sync_user_settings = MakeSyncUserSettings(GetUserTypes()); const UserSelectableTypeSet default_types = @@ -643,7 +643,7 @@ } TEST_F(SyncUserSettingsImplTest, EncryptionBootstrapTokenPerAccount) { - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); std::unique_ptr<SyncUserSettingsImpl> sync_user_settings = MakeSyncUserSettings(GetUserTypes()); ASSERT_TRUE(sync_user_settings->GetEncryptionBootstrapToken().empty()); @@ -654,7 +654,7 @@ } TEST_F(SyncUserSettingsImplTest, ClearEncryptionBootstrapTokenPerAccount) { - SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInNotSyncing); + SetSyncAccountState(SyncPrefs::SyncAccountState::kSignedInWithoutSyncConsent); std::unique_ptr<SyncUserSettingsImpl> sync_user_settings = MakeSyncUserSettings(GetUserTypes()); ASSERT_TRUE(sync_user_settings->GetEncryptionBootstrapToken().empty());
diff --git a/components/user_data_importer/utility/zip_ffi_glue.rs b/components/user_data_importer/utility/zip_ffi_glue.rs index 367fd8f..c9d31e1 100644 --- a/components/user_data_importer/utility/zip_ffi_glue.rs +++ b/components/user_data_importer/utility/zip_ffi_glue.rs
@@ -61,7 +61,7 @@ type SafariHistoryCallbackFromRust; #[cxx_name = "ImportHistoryEntries"] - fn ImportHistoryEntries( + fn ImportSafariHistoryEntries( self: Pin<&mut SafariHistoryCallbackFromRust>, history_entries: UniquePtr<CxxVector<SafariHistoryEntry>>, completed: bool, @@ -263,6 +263,68 @@ } } +// A trait for history callbacks to allow for generic implementation of +// batching. +trait HistoryCallback<T: cxx::vector::VectorElement> { + fn import_entries(self: Pin<&mut Self>, entries: cxx::UniquePtr<CxxVector<T>>, completed: bool); +} + +impl HistoryCallback<ffi::SafariHistoryEntry> for ffi::SafariHistoryCallbackFromRust { + fn import_entries( + self: Pin<&mut Self>, + entries: cxx::UniquePtr<CxxVector<ffi::SafariHistoryEntry>>, + completed: bool, + ) { + self.ImportSafariHistoryEntries(entries, completed); + } +} + +impl HistoryCallback<ffi::StablePortabilityHistoryEntry> + for ffi::StablePortabilityHistoryCallbackFromRust +{ + fn import_entries( + self: Pin<&mut Self>, + entries: cxx::UniquePtr<CxxVector<ffi::StablePortabilityHistoryEntry>>, + completed: bool, + ) { + self.ImportStablePortabilityHistoryEntries(entries, completed); + } +} + +// Adds an item to a history batch, sending a batch if the threshold is reached. +// +// Type Parameters: +// +// - `T`: The type of the history item to be added to the batch. For example, +// `SafariHistoryJSONEntry` or `StablePortabilityHistoryJSONEntry`. +// - `U`: The type of the element stored in the C++ vector. This is the same as +// `T` but with the `cxx::ExternType` trait. +// - `C`: The type of the callback object, which must implement +// `HistoryCallback<U>`. +// +// Arguments: +// +// - `item`: The history item to add to the batch. +// - `history`: The vector where history items are accumulated. +// - `threshold`: The size at which the batch is sent to the callback. +// - `callback`: The C++ callback to invoke with the batch of history items. +fn batch_and_send<T, U, C>( + item: T, + history: &mut cxx::UniquePtr<CxxVector<U>>, + threshold: usize, + callback: Pin<&mut C>, +) where + T: Into<U>, + U: 'static + cxx::vector::VectorElement + cxx::ExternType<Kind = cxx::kind::Trivial>, + C: HistoryCallback<U> + ?Sized, +{ + history.as_mut().unwrap().push(item.into()); + if history.len() >= threshold { + let batch_to_send = std::mem::replace(history, CxxVector::<U>::new()); + callback.import_entries(batch_to_send, /* completed= */ false); + } +} + // Returns the expected extension for the provided file type. fn expected_extension(file_type: ffi::FileType) -> Result<&'static str> { match file_type { @@ -484,29 +546,22 @@ let path_str = std::str::from_utf8(json_filename)?; let file = fs::File::open(path_str)?; let stream_reader = BufReader::with_capacity(STREAM_BUFFER_SIZE, file); - deserialize_top_level::<StablePortabilityHistoryJSONEntry, std::fs::File>( stream_reader, ffi::FileType::StablePortabilityHistory, |history_item| { - history.pin_mut().push(history_item.into()); - if history.len() >= history_size_threshold { - let batch_to_send = std::mem::replace( - &mut history, - CxxVector::<ffi::StablePortabilityHistoryEntry>::new(), - ); - history_callback.as_mut().unwrap().ImportStablePortabilityHistoryEntries( - batch_to_send, - /* completed= */ false, - ); - } + batch_and_send( + history_item, + &mut history, + history_size_threshold, + history_callback.as_mut().unwrap(), + ); }, /* metadata_only= */ false, ) })(); - // Send final batch if any, and completion signal. - history_callback.as_mut().unwrap().ImportStablePortabilityHistoryEntries(history, true); + history_callback.as_mut().unwrap().import_entries(history, true); return result.is_ok(); } @@ -695,25 +750,17 @@ if has_extension(outpath, ffi::FileType::SafariHistory) { let stream_reader = ZipEntryBufReader::new(file); parse_history_file(stream_reader, |history_item| { - history.as_mut().unwrap().push(history_item.into()); - if history.len() >= history_size_threshold { - let batch_to_send = std::mem::replace( - &mut history, - CxxVector::<ffi::SafariHistoryEntry>::new(), - ); - history_callback - .as_mut() - .unwrap() - .ImportHistoryEntries(batch_to_send, /* completed= */ false); - } + batch_and_send( + history_item, + &mut history, + history_size_threshold, + history_callback.as_mut().unwrap(), + ); }); } }); - history_callback - .as_mut() - .unwrap() - .ImportHistoryEntries(history, /* completed= */ true); + history_callback.as_mut().unwrap().import_entries(history, /* completed= */ true); } fn parse_payment_cards(
diff --git a/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc b/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc index a067a8d0..71b9d9c3 100644 --- a/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc +++ b/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc
@@ -83,12 +83,13 @@ EXPECT_THAT(Pending(), testing::IsEmpty()); } -// The promo registry orders by key; ensure this is preserved. +// The promo registry maintains registration order. Ensure this is preserved, +// in the absence of other ordering criteria. TEST_F(NtpPromoOrderTest, PendingStableOrder) { RegisterPromo("c", {}, 0, 0, base::Time()); RegisterPromo("b", {}, 0, 0, base::Time()); RegisterPromo("a", {}, 0, 0, base::Time()); - EXPECT_THAT(Pending(), ElementsAre("a", "b", "c")); + EXPECT_THAT(Pending(), ElementsAre("c", "b", "a")); } TEST_F(NtpPromoOrderTest, PendingCircularDependency) {
diff --git a/components/user_education/common/ntp_promo/ntp_promo_registry.cc b/components/user_education/common/ntp_promo/ntp_promo_registry.cc index 66a35b0..6daf77a 100644 --- a/components/user_education/common/ntp_promo/ntp_promo_registry.cc +++ b/components/user_education/common/ntp_promo/ntp_promo_registry.cc
@@ -19,29 +19,27 @@ const NtpPromoSpecification* NtpPromoRegistry::GetNtpPromoSpecification( const NtpPromoIdentifier& id) const { - auto pair = ntp_promo_registry_.find(id); - if (pair == ntp_promo_registry_.end()) { + auto pair = registry_.find(id); + if (pair == registry_.end()) { return nullptr; } return &pair->second; } -std::vector<NtpPromoIdentifier> NtpPromoRegistry::GetNtpPromoIdentifiers() - const { - std::vector<NtpPromoIdentifier> id_strings; - std::ranges::transform(ntp_promo_registry_, std::back_inserter(id_strings), - &Registry::value_type::first); - return id_strings; +const std::vector<NtpPromoIdentifier>& +NtpPromoRegistry::GetNtpPromoIdentifiers() const { + return identifiers_; } void NtpPromoRegistry::AddPromo(NtpPromoSpecification specification) { auto [it, inserted] = - ntp_promo_registry_.emplace(specification.id(), std::move(specification)); + registry_.emplace(specification.id(), std::move(specification)); CHECK(inserted); + identifiers_.push_back(it->first); } bool NtpPromoRegistry::AreAnyPromosRegistered() const { - return ntp_promo_registry_.size() > 0; + return registry_.size() > 0; } } // namespace user_education
diff --git a/components/user_education/common/ntp_promo/ntp_promo_registry.h b/components/user_education/common/ntp_promo/ntp_promo_registry.h index ec272e2..c93c55b 100644 --- a/components/user_education/common/ntp_promo/ntp_promo_registry.h +++ b/components/user_education/common/ntp_promo/ntp_promo_registry.h
@@ -18,7 +18,7 @@ NtpPromoRegistry& operator=(const NtpPromoRegistry&) = delete; // Returns a list of registered NtpPromoIdentifiers. - std::vector<NtpPromoIdentifier> GetNtpPromoIdentifiers() const; + const std::vector<NtpPromoIdentifier>& GetNtpPromoIdentifiers() const; // Gets the requested NtpPromoSpecification from the registry, or nullptr // if the promo is not registered. @@ -33,7 +33,10 @@ private: using Registry = std::map<NtpPromoIdentifier, NtpPromoSpecification>; - Registry ntp_promo_registry_; + // Keep both a map of ID to specification, and a vector of IDs. This gives + // easy lookups while preserving promo registration order. + Registry registry_; + std::vector<NtpPromoIdentifier> identifiers_; }; } // namespace user_education
diff --git a/components/user_education/common/ntp_promo/ntp_promo_registry_unittest.cc b/components/user_education/common/ntp_promo/ntp_promo_registry_unittest.cc index d5c416d..ec56d75d 100644 --- a/components/user_education/common/ntp_promo/ntp_promo_registry_unittest.cc +++ b/components/user_education/common/ntp_promo/ntp_promo_registry_unittest.cc
@@ -64,11 +64,13 @@ EXPECT_THAT(spec->show_after(), testing::ElementsAre(kShowFirstPromoId)); } +// The registry must maintain registration order, independent of ID. TEST_F(NtpPromoRegistryTest, GetIdentifiers) { + registry_.AddPromo(CreateTestPromoSpec("Promo3")); registry_.AddPromo(CreateTestPromoSpec("Promo1")); registry_.AddPromo(CreateTestPromoSpec("Promo2")); EXPECT_THAT(registry_.GetNtpPromoIdentifiers(), - testing::ElementsAre("Promo1", "Promo2")); + testing::ElementsAre("Promo3", "Promo1", "Promo2")); } TEST_F(NtpPromoRegistryTest, DuplicateEntry) {
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc index b07c875..5687925 100644 --- a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc +++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
@@ -96,8 +96,7 @@ // Create a native GMB handle first. gfx::GpuMemoryBufferHandle buffer_handle = gpu_memory_buffer_factory_->CreateNativeGmbHandle( - gpu::MappableSIClientGmbId::kGmbVideoFramePoolContext, size, - gpu::ToBufferFormat(si_format), buffer_usage); + size, gpu::ToBufferFormat(si_format), buffer_usage); if (buffer_handle.is_null()) { return nullptr; }
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 12514a5e..e3647bc0 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -1277,9 +1277,7 @@ auto size = gfx::Size(2, 2); return !gpu_memory_buffer_factory_ - ->CreateNativeGmbHandle( - gpu::MappableSIClientGmbId::kGpuServiceImpl, size, - buffer_format, buffer_usage) + ->CreateNativeGmbHandle(size, buffer_format, buffer_usage) .is_null(); } #endif
diff --git a/content/browser/android/java/java_type_unittest.cc b/content/browser/android/java/java_type_unittest.cc index 68af5ad..fcab248 100644 --- a/content/browser/android/java/java_type_unittest.cc +++ b/content/browser/android/java/java_type_unittest.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/342213636): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - #include "content/browser/android/java/java_type.h" #include <stddef.h> @@ -21,33 +16,32 @@ }; TEST_F(JavaTypeTest, ScalarTypes) { - struct { + const struct { const char* binary_type; JavaType::Type java_type; const char* jni_name; const char* jni_signature; - } scalar_types[] = { - {"boolean", JavaType::TypeBoolean, "Z", "Z"}, - {"byte", JavaType::TypeByte, "B", "B"}, - {"char", JavaType::TypeChar, "C", "C"}, - {"short", JavaType::TypeShort, "S", "S"}, - {"int", JavaType::TypeInt, "I", "I"}, - {"long", JavaType::TypeLong, "J", "J"}, - {"float", JavaType::TypeFloat, "F", "F"}, - {"double", JavaType::TypeDouble, "D", "D"}, - {"void", JavaType::TypeVoid, "V", "V"}, - {"java.lang.String", JavaType::TypeString, "java/lang/String", - "Ljava/lang/String;"}, - {"java.lang.Object", JavaType::TypeObject, "java/lang/Object", - "Ljava/lang/Object;"}, - {"my.nested.Type$Foo", JavaType::TypeObject, "my/nested/Type$Foo", - "Lmy/nested/Type$Foo;"}}; - for (size_t i = 0; i < std::size(scalar_types); ++i) { - JavaType jt = JavaType::CreateFromBinaryName(scalar_types[i].binary_type); - EXPECT_EQ(scalar_types[i].java_type, jt.type); + } kScalarTypes[] = {{"boolean", JavaType::TypeBoolean, "Z", "Z"}, + {"byte", JavaType::TypeByte, "B", "B"}, + {"char", JavaType::TypeChar, "C", "C"}, + {"short", JavaType::TypeShort, "S", "S"}, + {"int", JavaType::TypeInt, "I", "I"}, + {"long", JavaType::TypeLong, "J", "J"}, + {"float", JavaType::TypeFloat, "F", "F"}, + {"double", JavaType::TypeDouble, "D", "D"}, + {"void", JavaType::TypeVoid, "V", "V"}, + {"java.lang.String", JavaType::TypeString, + "java/lang/String", "Ljava/lang/String;"}, + {"java.lang.Object", JavaType::TypeObject, + "java/lang/Object", "Ljava/lang/Object;"}, + {"my.nested.Type$Foo", JavaType::TypeObject, + "my/nested/Type$Foo", "Lmy/nested/Type$Foo;"}}; + for (const auto& scalar_type : kScalarTypes) { + JavaType jt = JavaType::CreateFromBinaryName(scalar_type.binary_type); + EXPECT_EQ(scalar_type.java_type, jt.type); EXPECT_FALSE(jt.inner_type); - EXPECT_EQ(scalar_types[i].jni_name, jt.JNIName()); - EXPECT_EQ(scalar_types[i].jni_signature, jt.JNISignature()); + EXPECT_EQ(scalar_type.jni_name, jt.JNIName()); + EXPECT_EQ(scalar_type.jni_signature, jt.JNISignature()); } }
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc index 480b8b8..fa86c17 100644 --- a/content/browser/back_forward_cache_internal_browsertest.cc +++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -16,6 +16,7 @@ #include "content/browser/renderer_host/back_forward_cache_impl.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/content_navigation_policy.h" #include "content/common/features.h" @@ -2211,8 +2212,8 @@ #if BUILDFLAG(IS_ANDROID) IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ChildImportanceTestForBackForwardCachedPagesTest) { - web_contents()->SetPrimaryMainFrameImportance( - ChildProcessImportance::MODERATE); + web_contents()->SetPrimaryPageImportance( + ChildProcessImportance::MODERATE, ChildProcessImportance::NORMAL); ASSERT_TRUE(embedded_test_server()->Start()); GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); @@ -2240,8 +2241,152 @@ EXPECT_EQ(ChildProcessImportance::MODERATE, rfh_a->GetProcess()->GetEffectiveImportance()); } + +class BackForwardCacheInternalSubframeImportanceBrowserTest + : public BackForwardCacheBrowserTest { + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + BackForwardCacheBrowserTest::SetUpCommandLine(command_line); + feature_list_.InitWithFeatures( + /* enabled_features= */ {features::kSubframePriorityContribution, + features::kSubframeImportance}, + /* disabled_features= */ {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + BackForwardCacheInternalSubframeImportanceBrowserTest, + ChildImportanceTestForBackForwardCachedPagesWithSubframeTest) { + IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + GURL url_b(embedded_test_server()->GetURL("c.com", "/title1.html")); + + // 1) Navigate to A. + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_main = current_frame_host(); + RenderFrameHostImpl* rfh_child = web_contents() + ->GetPrimaryFrameTree() + .root() + ->child_at(0) + ->current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_main(rfh_main); + RenderFrameDeletedObserver delete_observer_rfh_child(rfh_child); + + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::IMPORTANT, + ChildProcessImportance::MODERATE); + + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + rfh_main->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ(ChildProcessImportance::MODERATE, + rfh_child->GetProcess()->GetEffectiveImportance()); + + // 2) Navigate to B. + EXPECT_TRUE(NavigateToURL(shell(), url_b)); + ASSERT_FALSE(delete_observer_rfh_main.deleted()); + ASSERT_FALSE(delete_observer_rfh_child.deleted()); + + // 3) Verify the importance of page after entering back-forward cache to be + // "NORMAL". + EXPECT_EQ(ChildProcessImportance::NORMAL, + rfh_main->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ(ChildProcessImportance::NORMAL, + rfh_child->GetProcess()->GetEffectiveImportance()); + + // 4) Go back to A. + ASSERT_TRUE(HistoryGoBack(web_contents())); + + // 5) Verify the importance was restored correctly after page leaves + // back-forward cache. + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + rfh_main->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ(ChildProcessImportance::MODERATE, + rfh_child->GetProcess()->GetEffectiveImportance()); + + // 6) Navigate to B again. + EXPECT_TRUE(NavigateToURL(shell(), url_b)); + ASSERT_FALSE(delete_observer_rfh_main.deleted()); + ASSERT_FALSE(delete_observer_rfh_child.deleted()); + + // Change the importance while the page is in back-forward cache. + web_contents()->SetPrimaryPageImportance( + ChildProcessImportance::MODERATE, ChildProcessImportance::NORMAL); + + // 4) Go back to A. + ASSERT_TRUE(HistoryGoBack(web_contents())); + + // 5) Verify the importance was restored correctly after page leaves + // back-forward cache. + EXPECT_EQ(ChildProcessImportance::MODERATE, + rfh_main->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ(ChildProcessImportance::NORMAL, + rfh_child->GetProcess()->GetEffectiveImportance()); +} #endif +class BackForwardCacheInternalSubframePriorityBrowserTest + : public BackForwardCacheBrowserTest { + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + BackForwardCacheBrowserTest::SetUpCommandLine(command_line); + feature_list_.InitAndEnableFeature(features::kSubframePriorityContribution); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(BackForwardCacheInternalSubframePriorityBrowserTest, + FrameDepthInBackForwardCache) { + IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + + FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); + RenderFrameHostImpl* rfh_a = root->current_frame_host(); + RenderWidgetHostImpl* rwh_a = rfh_a->GetRenderWidgetHost(); + + FrameTreeNode* child = root->child_at(0); + RenderFrameHostImpl* rfh_b = child->current_frame_host(); + RenderWidgetHostImpl* rwh_b = rfh_b->GetRenderWidgetHost(); + + // Check initial frame depths. + EXPECT_EQ(0u, rfh_a->GetFrameDepth()); + EXPECT_EQ(0u, rwh_a->GetPriority().frame_depth); + EXPECT_EQ(1u, rfh_b->GetFrameDepth()); + EXPECT_EQ(1u, rwh_b->GetPriority().frame_depth); + + // Navigate away to put the first page into the back-forward cache. + GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), url_c)); + + // Check that page A is in the back-forward cache. + EXPECT_TRUE(rfh_a->IsInBackForwardCache()); + EXPECT_TRUE(rfh_b->IsInBackForwardCache()); + + // Check that the frame depths of the widgets in the back-forward cached + // page are now `RenderProcessHostImpl::kMaxFrameDepthForPriority`. + EXPECT_EQ(RenderProcessHostImpl::kMaxFrameDepthForPriority, + rwh_a->GetPriority().frame_depth); + EXPECT_EQ(RenderProcessHostImpl::kMaxFrameDepthForPriority, + rwh_b->GetPriority().frame_depth); + + // Navigate back to the first page. + EXPECT_TRUE(HistoryGoBack(web_contents())); + + // Check that the frame depths of the widgets back from the back-forward cache + // are recovered. + EXPECT_EQ(0u, rwh_a->GetPriority().frame_depth); + EXPECT_EQ(1u, rwh_b->GetPriority().frame_depth); +} + IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, PageshowMetrics) { // TODO(crbug.com/40702446): Do not check for unexpected messages // because the input task queue is not currently frozen, causing flakes in
diff --git a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc index 868f738..d2f2009 100644 --- a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc +++ b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
@@ -5,11 +5,15 @@ #include <iostream> #include "base/compiler_specific.h" +#include "base/containers/span.h" #include "base/hash/hash.h" #include "device/bluetooth/public/cpp/bluetooth_uuid.h" int main(int argc, char** argv) { - if (argc <= 2) { + // SAFETY: The OS guarantees argv length is argc. + const base::span<const char* const> args = + UNSAFE_BUFFERS(base::span(argv, static_cast<size_t>(argc))); + if (args.size() <= 2) { std::cout << "Generates hash values given UUIDs using the same method\n" << "as in bluetooth_metrics.cc.\n" << "\n" @@ -17,11 +21,11 @@ << "Note that tools/metrics/histograms/pretty_print.py will\n" << "sort enum entries for you.\n" << "\n" - << "Usage: " << argv[0] << " <uuid> <label> [uuid2 label2...]\n" + << "Usage: " << args[0] << " <uuid> <label> [uuid2 label2...]\n" << " The UUIDs may be short UUIDs, and will be made\n" << " canonical before being hashed.\n" << "\n" - << "Example: " << argv[0] << " FEFF foo FEFE bar\n" + << "Example: " << args[0] << " FEFF foo FEFE bar\n" << " <int value=\"62669585\" " "label=\"foo; 0000feff-0000-1000-8000-00805f9b34fb\"/>\n" << " <int value=\"643543662\" " @@ -29,9 +33,9 @@ return 1; } - for (int i = 1; i < argc; i = i + 2) { - std::string uuid_string(UNSAFE_TODO(argv[i])); - std::string label_string((i + 1 < argc) ? UNSAFE_TODO(argv[i + 1]) : ""); + for (size_t i = 1; i < args.size(); i = i + 2) { + std::string uuid_string(args[i]); + std::string label_string((i + 1 < args.size()) ? args[i + 1] : ""); device::BluetoothUUID uuid(uuid_string); std::string uuid_canonical_string = uuid.canonical_value(); uint32_t hash = base::PersistentHash(uuid_canonical_string);
diff --git a/content/browser/devtools/protocol/preload_handler.cc b/content/browser/devtools/protocol/preload_handler.cc index 5031ddb..58b5d03 100644 --- a/content/browser/devtools/protocol/preload_handler.cc +++ b/content/browser/devtools/protocol/preload_handler.cc
@@ -191,6 +191,8 @@ return Preload::PrerenderFinalStatusEnum::PrerenderFailedDuringPrefetch; case PrerenderFinalStatus::kBrowsingDataRemoved: return Preload::PrerenderFinalStatusEnum::BrowsingDataRemoved; + case PrerenderFinalStatus::kPrerenderHostReused: + return Preload::PrerenderFinalStatusEnum::PrerenderHostReused; } }
diff --git a/content/browser/loader/cached_navigation_url_loader.cc b/content/browser/loader/cached_navigation_url_loader.cc index eeef39dd..c294292 100644 --- a/content/browser/loader/cached_navigation_url_loader.cc +++ b/content/browser/loader/cached_navigation_url_loader.cc
@@ -82,9 +82,9 @@ } void CachedNavigationURLLoader::FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) { + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) { NOTREACHED(); }
diff --git a/content/browser/loader/cached_navigation_url_loader.h b/content/browser/loader/cached_navigation_url_loader.h index 3d5f574a..eb69d199 100644 --- a/content/browser/loader/cached_navigation_url_loader.h +++ b/content/browser/loader/cached_navigation_url_loader.h
@@ -33,9 +33,9 @@ // NavigationURLLoader implementation. void Start() override; void FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) override; + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) override; bool SetNavigationTimeout(base::TimeDelta timeout) override; void CancelNavigationTimeout() override;
diff --git a/content/browser/loader/navigation_url_loader.h b/content/browser/loader/navigation_url_loader.h index a3e5b2d..7d2d4ba 100644 --- a/content/browser/loader/navigation_url_loader.h +++ b/content/browser/loader/navigation_url_loader.h
@@ -106,9 +106,9 @@ // Called in response to OnRequestRedirected to continue processing the // request. virtual void FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) = 0; + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) = 0; // Sets an overall request timeout for this navigation, which will cause the // navigation to fail if it expires before the navigation commits. This is
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index c95e4498..1a7d072 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -771,16 +771,7 @@ resource_request_->navigation_redirect_chain [resource_request_->navigation_redirect_chain.size() - 2]))) { - if (loader_holder_.url_loader()) { - loader_holder_.url_loader()->ResetForFollowRedirect( - *resource_request_.get(), url_loader_removed_headers_, - url_loader_modified_headers_, - url_loader_modified_cors_exempt_headers_); - url_loader_removed_headers_.clear(); - url_loader_modified_headers_.Clear(); - url_loader_modified_cors_exempt_headers_.Clear(); - } - loader_holder_.ResetLoader(); + loader_holder_.ResetForFollowRedirect(*resource_request_.get()); } received_response_ = false; head_update_params_ = ResponseHeadUpdateParams(); @@ -846,15 +837,7 @@ // If `url_loader_` already exists, this means we are following a redirect // using an interceptor. In this case we should make sure to reset the // loader, similar to what is done in Restart(). - if (loader_holder_.url_loader()) { - loader_holder_.url_loader()->ResetForFollowRedirect( - *resource_request_.get(), url_loader_removed_headers_, - url_loader_modified_headers_, url_loader_modified_cors_exempt_headers_); - url_loader_removed_headers_.clear(); - url_loader_modified_headers_.Clear(); - url_loader_modified_cors_exempt_headers_.Clear(); - } - loader_holder_.ResetLoader(); + loader_holder_.ResetForFollowRedirect(*resource_request_.get()); CreateThrottlingLoaderAndStart(std::move(single_request_factory), std::move(additional_throttles)); @@ -902,6 +885,50 @@ } } +NavigationURLLoaderImpl::LoaderHolder::ModifiedHeadersOnRedirect:: + ModifiedHeadersOnRedirect( + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) + : removed_headers_(std::move(removed_headers)), + modified_headers_(std::move(modified_headers)), + modified_cors_exempt_headers_(std::move(modified_cors_exempt_headers)) {} + +NavigationURLLoaderImpl::LoaderHolder::ModifiedHeadersOnRedirect:: + ~ModifiedHeadersOnRedirect() = default; + +void NavigationURLLoaderImpl::LoaderHolder::SetModifiedHeadersOnRedirect( + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) { + modified_headers_on_redirect_.emplace( + std::move(removed_headers), std::move(modified_headers), + std::move(modified_cors_exempt_headers)); +} + +void NavigationURLLoaderImpl::LoaderHolder::ResetForFollowRedirect( + network::ResourceRequest& resource_request) { + if (url_loader_) { + CHECK(modified_headers_on_redirect_); + url_loader_->ResetForFollowRedirect( + resource_request, modified_headers_on_redirect_->removed_headers_, + modified_headers_on_redirect_->modified_headers_, + modified_headers_on_redirect_->modified_cors_exempt_headers_); + modified_headers_on_redirect_.reset(); + } + // TODO(https://crbug.com/40943077): Call `Reset()` instead. + ResetLoader(); +} + +void NavigationURLLoaderImpl::LoaderHolder::FollowRedirect() { + CHECK(url_loader_); + CHECK(modified_headers_on_redirect_); + url_loader_->FollowRedirect( + std::move(modified_headers_on_redirect_->removed_headers_), + std::move(modified_headers_on_redirect_->modified_headers_), + std::move(modified_headers_on_redirect_->modified_cors_exempt_headers_)); +} + void NavigationURLLoaderImpl::StartNonInterceptedRequest( ResponseHeadUpdateParams head_update_params) { // If we already have the default `url_loader_` we must come here after a @@ -909,10 +936,7 @@ // so let the loader just follow the redirect. if (loader_holder_.url_loader()) { DCHECK(!redirect_info_.new_url.is_empty()); - loader_holder_.url_loader()->FollowRedirect( - std::move(url_loader_removed_headers_), - std::move(url_loader_modified_headers_), - std::move(url_loader_modified_cors_exempt_headers_)); + loader_holder_.FollowRedirect(); return; } @@ -1924,12 +1948,22 @@ } void NavigationURLLoaderImpl::FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) { + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!redirect_info_.new_url.is_empty()); + // Don't send Accept: application/signed-exchange for fallback redirects. + // This is also applied to `resource_request_->headers` via + // `net::RedirectUtil::UpdateHttpRequest()`. + if (redirect_info_.is_signed_exchange_fallback_redirect) { + modified_headers.SetHeader( + net::HttpRequestHeaders::kAccept, + FrameAcceptHeaderValue(/*allow_sxg_responses=*/false, + browser_context_)); + } + // Update `resource_request_` and call Restart to give our `interceptors_` a // chance at handling the new location. If no interceptor wants to take // over, we'll use the existing url_loader to follow the redirect, see @@ -1965,19 +1999,9 @@ // Need to cache modified headers for `url_loader_` since it doesn't use // `resource_request_` during redirect. - url_loader_removed_headers_ = removed_headers; - url_loader_modified_headers_ = modified_headers; - url_loader_modified_cors_exempt_headers_ = modified_cors_exempt_headers; - - // Don't send Accept: application/signed-exchange for fallback redirects. - if (redirect_info_.is_signed_exchange_fallback_redirect) { - std::string header_value = - FrameAcceptHeaderValue(/*allow_sxg_responses=*/false, browser_context_); - url_loader_modified_headers_.SetHeader(net::HttpRequestHeaders::kAccept, - header_value); - resource_request_->headers.SetHeader(net::HttpRequestHeaders::kAccept, - header_value); - } + loader_holder_.SetModifiedHeadersOnRedirect( + std::move(removed_headers), std::move(modified_headers), + std::move(modified_cors_exempt_headers)); Restart(); }
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h index 6541d067..a8d4359 100644 --- a/content/browser/loader/navigation_url_loader_impl.h +++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -269,9 +269,9 @@ // Sets `started_` true. void Start() override; void FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) override; + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) override; bool SetNavigationTimeout(base::TimeDelta timeout) override; void CancelNavigationTimeout() override; @@ -303,12 +303,6 @@ scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_; - // Caches the modified request headers provided by clients during redirect, - // will be consumed by next `url_loader_->FollowRedirect()`. - std::vector<std::string> url_loader_removed_headers_; - net::HttpRequestHeaders url_loader_modified_headers_; - net::HttpRequestHeaders url_loader_modified_cors_exempt_headers_; - SubresourceLoaderParams subresource_loader_params_; std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_; @@ -389,6 +383,35 @@ // `URLLoaderClientEndpointsPtr` (transitioning to `kUnbound`). [[nodiscard]] network::mojom::URLLoaderClientEndpointsPtr Unbind(); + // Redirect handling: the expected sequence is: + // 1. `NavigationURLLoaderImpl::OnReceiveRedirect()` + // 2. `LoaderHolder::SetModifiedHeadersOnRedirect()` + // 3. Either: + // - `LoaderHolder::FollowRedirect()`, when we want and can continue + // using the current `url_loader` for the next redirect leg, or + // - `LoaderHolder::ResetForFollowRedirect()` then + // `LoaderHolder::SetLoader()`, when we start the next redirect leg + // with a new loader. + // Also `LoaderHolder::Reset()` can be called at any time during this to + // cancel loading. + // TODO(https://crbug.com/434182226): Add `CHECK()`s to confirm these + // sequences. + + // Cache the modified request headers provided by clients during redirect. + // They will be consumed by next `FollowRedirect()` or + // `ResetForFollowRedirect()`. + void SetModifiedHeadersOnRedirect( + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers); + + // Follows the redirect using the current `url_loader_`. + void FollowRedirect(); + + // Similar to `ResetLoader()`, but also calls + // `URLLoader::ResetForFollowRedirect()` if needed. + void ResetForFollowRedirect(network::ResourceRequest& resource_request); + private: // `NavigationURLLoaderImpl`'s `URLLoaderClient` methods are called either // via `url_loader_` or `response_loader_receiver_`. @@ -404,6 +427,21 @@ // `MaybeCreateLoaderForResponse()` (at least within Chromium codesearch). // For now this is kept here as-is but probably can be removed. mojo::PendingRemote<network::mojom::URLLoader> response_url_loader_; + + struct ModifiedHeadersOnRedirect final { + ModifiedHeadersOnRedirect( + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers); + ModifiedHeadersOnRedirect(const ModifiedHeadersOnRedirect&) = delete; + ModifiedHeadersOnRedirect(ModifiedHeadersOnRedirect&&) = delete; + ~ModifiedHeadersOnRedirect(); + + std::vector<std::string> removed_headers_; + net::HttpRequestHeaders modified_headers_; + net::HttpRequestHeaders modified_cors_exempt_headers_; + }; + std::optional<ModifiedHeadersOnRedirect> modified_headers_on_redirect_; }; LoaderHolder loader_holder_{this};
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc index 0106065..2f62a35 100644 --- a/content/browser/preloading/preloading_decider.cc +++ b/content/browser/preloading/preloading_decider.cc
@@ -705,29 +705,6 @@ return suitable_candidates; } -std::optional<std::pair<PreloadingDecider::SpeculationCandidateKey, - blink::mojom::SpeculationCandidatePtr>> -PreloadingDecider::GetMatchedPreloadingCandidateByNoVarySearchHint( - const PreloadingDecider::SpeculationCandidateKey& lookup_key, - const PreloadingPredictor& enacting_predictor, - PreloadingConfidence confidence) const { - std::optional< - std::pair<SpeculationCandidateKey, blink::mojom::SpeculationCandidatePtr>> - result; - - // Check all URLs that might match via NVS hint. - // If there are multiple candidates that match the first one. - EnumerateNoVarySearchMatchedCandidates( - lookup_key, enacting_predictor, confidence, - [&](const SpeculationCandidateKey& standby_key, - const blink::mojom::SpeculationCandidatePtr& candidate) { - result = std::make_pair(standby_key, candidate.Clone()); - return true; // Stop enumeration after the first match. - }); - - return result; -} - bool PreloadingDecider::ShouldWaitForPrefetchResult(const GURL& url) { // TODO(liviutinta): Don't implement any No-Vary-Search hint matching here // for now. It is not clear how to match `url` with a `processed_candidate`.
diff --git a/content/browser/preloading/preloading_decider.h b/content/browser/preloading/preloading_decider.h index edca8ca..2da955fc 100644 --- a/content/browser/preloading/preloading_decider.h +++ b/content/browser/preloading/preloading_decider.h
@@ -193,13 +193,6 @@ PreloadingConfidence confidence, Visitor&& visitor) const; - std::optional< - std::pair<SpeculationCandidateKey, blink::mojom::SpeculationCandidatePtr>> - GetMatchedPreloadingCandidateByNoVarySearchHint( - const SpeculationCandidateKey& lookup_key, - const PreloadingPredictor& enacting_predictor, - PreloadingConfidence confidence) const; - // |on_standby_candidates_| stores preloading candidates for each target URL, // action pairs that are safe to perform but are not marked as |kImmediate| // and should be performed when we are confident enough that the user will
diff --git a/content/browser/preloading/prerender/prerender_final_status.h b/content/browser/preloading/prerender/prerender_final_status.h index 0bd38350..0b1d634 100644 --- a/content/browser/preloading/prerender/prerender_final_status.h +++ b/content/browser/preloading/prerender/prerender_final_status.h
@@ -177,8 +177,11 @@ // Prerendering canceled by clearing cache from browsing data removal. kBrowsingDataRemoved = 87, + // Prerendering cancelled but the PrerenderHost is reused for future + // navigation. + kPrerenderHostReused = 88, - kMaxValue = kBrowsingDataRemoved, + kMaxValue = kPrerenderHostReused, }; // LINT.ThenChange(//third_party/blink/public/devtools_protocol/browser_protocol.pdl)
diff --git a/content/browser/preloading/prerender/prerender_handle_impl.cc b/content/browser/preloading/prerender/prerender_handle_impl.cc index 360c9a1..017fc45e 100644 --- a/content/browser/preloading/prerender/prerender_handle_impl.cc +++ b/content/browser/preloading/prerender/prerender_handle_impl.cc
@@ -141,6 +141,9 @@ // option or with Clear-Site-Data response headers. case PrerenderFinalStatus::kBrowsingDataRemoved: return false; + // The PrerenderHost is reused by another prerender request. + case PrerenderFinalStatus::kPrerenderHostReused: + return false; } } @@ -166,6 +169,10 @@ } PrerenderHandleImpl::~PrerenderHandleImpl() { + // GetPrerenderHost() fetches the PrerenderHost by the frame_tree_node_id_. + // If the underlying PrerenderHost is reused, frame_tree_node_id_ will + // be reset and prerender_host will be nullptr. The reused host will + // not be cancelled. PrerenderHost* prerender_host = GetPrerenderHost(); if (!prerender_host) { return; @@ -264,6 +271,14 @@ } } +void PrerenderHandleImpl::OnHostReused() { + // Since the frame_tree_node_id_ is reused by the new PrerenderHost, we will + // stop tracking the FrameTree and reset frame_tree_node_id_. + // TODO(crbug.com/434826191): Add a new unique identifier for the + // PrerenderHost. + frame_tree_node_id_ = FrameTreeNodeId(); +} + PrerenderHost* PrerenderHandleImpl::GetPrerenderHost() { auto* prerender_frame_tree_node = FrameTreeNode::GloballyFindByID(frame_tree_node_id_);
diff --git a/content/browser/preloading/prerender/prerender_handle_impl.h b/content/browser/preloading/prerender/prerender_handle_impl.h index 724379af..3a61f9a3 100644 --- a/content/browser/preloading/prerender/prerender_handle_impl.h +++ b/content/browser/preloading/prerender/prerender_handle_impl.h
@@ -42,6 +42,7 @@ // PrerenderHost::Observer: void OnActivated() override; void OnFailed(PrerenderFinalStatus status) override; + void OnHostReused() override; FrameTreeNodeId frame_tree_node_id_for_testing() const { return frame_tree_node_id_; @@ -55,7 +56,7 @@ base::WeakPtr<PrerenderHostRegistry> prerender_host_registry_; // `frame_tree_node_id_` is the root FrameTreeNode id of the prerendered // page. - const FrameTreeNodeId frame_tree_node_id_; + FrameTreeNodeId frame_tree_node_id_; const GURL prerendering_url_; const std::optional<net::HttpNoVarySearchData> no_vary_search_hint_;
diff --git a/content/browser/preloading/prerender/prerender_host.cc b/content/browser/preloading/prerender/prerender_host.cc index e73c23ce..ba477986 100644 --- a/content/browser/preloading/prerender/prerender_host.cc +++ b/content/browser/preloading/prerender/prerender_host.cc
@@ -375,6 +375,8 @@ SetTriggeringOutcome(PreloadingTriggeringOutcome::kTriggeredButPending); if (reuse_host) { + reuse_host->RecordFailedFinalStatusImpl(PrerenderCancellationReason( + PrerenderFinalStatus::kPrerenderHostReused)); if (reuse_host->frame_tree_delegate_->on_wait_loading_finished_) { std::move(reuse_host->frame_tree_delegate_->on_wait_loading_finished_) .Run(PrerenderHost::LoadingOutcome::kPrerenderingCancelled); @@ -1261,7 +1263,8 @@ // propagated to `attempt_`. Most values should be propagated, but we // explicitly do not propagate failure reasons if: // 1. prerender was successfully prepared but then destroyed because it - // wasn't needed for a subsequent navigation (kTriggerDestroyed). + // wasn't needed for a subsequent navigation (kTriggerDestroyed and + // kPrerenderHostReused). // 2. the prerender was still pending for its initial navigation when it was // activated (kActivatedBeforeStarted). case PrerenderFinalStatus::kTriggerDestroyed: @@ -1270,6 +1273,7 @@ case PrerenderFinalStatus::kTabClosedWithoutUserGesture: case PrerenderFinalStatus::kSpeculationRuleRemoved: case PrerenderFinalStatus::kOtherPrerenderedPageActivated: + case PrerenderFinalStatus::kPrerenderHostReused: return; case PrerenderFinalStatus::kDestroyed: case PrerenderFinalStatus::kLowEndDevice: @@ -1722,4 +1726,10 @@ } } +void PrerenderHost::NotifyReused() { + for (auto& observer : observers_) { + observer.OnHostReused(); + } +} + } // namespace content
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h index 0d1b6b5..b7b89c6 100644 --- a/content/browser/preloading/prerender/prerender_host.h +++ b/content/browser/preloading/prerender/prerender_host.h
@@ -156,6 +156,10 @@ // Called from the PrerenderHost's destructor. The observer should drop any // reference to the host. virtual void OnHostDestroyed(PrerenderFinalStatus status) {} + + // Called when the PrerenderHost is reused for another prerender. The + // observer shall not cancel the host if OnHostReused is called. + virtual void OnHostReused() {} }; // Returns the PrerenderHost that the given `frame_tree_node` is in, if it is @@ -419,6 +423,8 @@ void AddAdditionalRequestHeaders(net::HttpRequestHeaders& headers, FrameTreeNode& navigating_frame_tree_node); + void NotifyReused(); + private: // The helper class to make the frame tree movable among different // PrerenderHosts. When moving the prerender host to the new owner, we need to
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc index 0aff665..a899af1 100644 --- a/content/browser/preloading/prerender/prerender_host_registry.cc +++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -337,6 +337,8 @@ case PrerenderFinalStatus::kPrerenderFailedDuringPrefetch: case PrerenderFinalStatus::kBrowsingDataRemoved: NOTREACHED(); + case PrerenderFinalStatus::kPrerenderHostReused: + NOTREACHED(); } NOTREACHED(); @@ -803,7 +805,7 @@ std::unique_ptr<PrerenderHost> reuse_host; std::unique_ptr<PrerenderHost> prerender_host; if (base::FeatureList::IsEnabled(features::kPrerender2ReuseHost)) { - reuse_host = FindPrerenderHostToReuse(attributes); + reuse_host = FindAndTakePrerenderHostToReuse(attributes); } base::UmaHistogramBoolean("Prerender.Experimental.FoundReusePrerenderHost", reuse_host != nullptr); @@ -2101,7 +2103,8 @@ base::UmaHistogramEnumeration(kPrerenderProcessReuseUMAName, availability); } -std::unique_ptr<PrerenderHost> PrerenderHostRegistry::FindPrerenderHostToReuse( +std::unique_ptr<PrerenderHost> +PrerenderHostRegistry::FindAndTakePrerenderHostToReuse( const PrerenderAttributes& attributes) { const GURL prerender_url = attributes.prerendering_url; auto iter = std::find_if(prerender_host_by_frame_tree_node_id_.begin(), @@ -2112,8 +2115,8 @@ }); if (iter != prerender_host_by_frame_tree_node_id_.end()) { std::unique_ptr<PrerenderHost> reuse_host = std::move(iter->second); - // TODO(crbug.com/402626324): add a new reason and notify about cancellation prerender_host_by_frame_tree_node_id_.erase(iter); + reuse_host->NotifyReused(); return reuse_host; } return nullptr;
diff --git a/content/browser/preloading/prerender/prerender_host_registry.h b/content/browser/preloading/prerender/prerender_host_registry.h index d4bc203..9268864d 100644 --- a/content/browser/preloading/prerender/prerender_host_registry.h +++ b/content/browser/preloading/prerender/prerender_host_registry.h
@@ -369,7 +369,7 @@ // Find a prerender host that is marked as reusable and under the // same site as attributes.prerendering_url. - std::unique_ptr<PrerenderHost> FindPrerenderHostToReuse( + std::unique_ptr<PrerenderHost> FindAndTakePrerenderHostToReuse( const PrerenderAttributes& attributes); scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner();
diff --git a/content/browser/renderer_host/navigation_policy_container_builder.cc b/content/browser/renderer_host/navigation_policy_container_builder.cc index a7212c5..2832813 100644 --- a/content/browser/renderer_host/navigation_policy_container_builder.cc +++ b/content/browser/renderer_host/navigation_policy_container_builder.cc
@@ -107,6 +107,12 @@ delivered_policies_.ip_address_space = address_space; } +void NavigationPolicyContainerBuilder:: + SetLocalNetworkAccessNonSecureContextAllowed(bool allowed) { + DCHECK(!HasComputedPolicies()); + delivered_policies_.allow_non_secure_local_network_access = allowed; +} + void NavigationPolicyContainerBuilder::SetIsOriginPotentiallyTrustworthy( bool value) { DCHECK(!HasComputedPolicies());
diff --git a/content/browser/renderer_host/navigation_policy_container_builder.h b/content/browser/renderer_host/navigation_policy_container_builder.h index 3da4e8b..b4ff97b 100644 --- a/content/browser/renderer_host/navigation_policy_container_builder.h +++ b/content/browser/renderer_host/navigation_policy_container_builder.h
@@ -113,6 +113,12 @@ // This must be called before `ComputePolicies()`. void SetIPAddressSpace(network::mojom::IPAddressSpace address_space); + // Sets whether the origin is allowed to issue Local Network Access requests + // even if it is not a secure context. If not set, this defaults to false. + // + // If set, this must be called before `ComputePolicies()`. + void SetLocalNetworkAccessNonSecureContextAllowed(bool allowed); + // Sets whether the origin of the document being navigated to is // potentially-trustworthy, as defined in: // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy.
diff --git a/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc b/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc index eee703c..b125da6 100644 --- a/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc +++ b/content/browser/renderer_host/navigation_policy_container_builder_unittest.cc
@@ -47,6 +47,7 @@ return PolicyContainerPolicies( network::mojom::ReferrerPolicy::kAlways, network::mojom::IPAddressSpace::kPublic, + /*allow_non_secure_local_network_access*/ true, /*is_web_secure_context=*/true, std::move(csp_list), network::CrossOriginOpenerPolicy(), network::CrossOriginEmbedderPolicy(), network::DocumentIsolationPolicy(), network::IntegrityPolicy(), @@ -107,6 +108,20 @@ EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); } +// Verifies that SetLocalNetworkAccessNonSecureContextAllowed sets +// allow_non_secure_local_network_access in the builder's +// delivered policies. +TEST_F(NavigationPolicyContainerBuilderTest, SetLNANonSecureContextAllowed) { + NavigationPolicyContainerBuilder builder( + nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); + builder.SetLocalNetworkAccessNonSecureContextAllowed(true); + + PolicyContainerPolicies expected_policies; + expected_policies.allow_non_secure_local_network_access = true; + + EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); +} + // Verifies that SetIsOriginPotentiallyTrustworthy sets the secure context bit // in the builder's delivered policies. TEST_F(NavigationPolicyContainerBuilderTest,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 525eedb5..69048bd1 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -8500,8 +8500,6 @@ return; } - bool lna_secure_context_override = false; - // Deprecation trial is to allow http sites to run LNA requests assuming the // user grants the permission to the web site. // @@ -8509,34 +8507,25 @@ // supported, for the same reasons as in the previous PNA trial: // https://developer.chrome.com/blog/private-network-access-update#register-deprecation-trial if (!policies.is_web_secure_context && + policies.allow_non_secure_local_network_access && base::FeatureList::IsEnabled( - network::features::kLocalNetworkAccessChecks) && - // If there is no response or no headers in the response, there are - // definitely no trial token headers. - response_head_ && response_head_->headers && - blink::TrialTokenValidator().RequestEnablesDeprecatedFeature( - common_params_->url, response_head_->headers.get(), - "LocalNetworkAccessNonSecureContextAllowed", base::Time::Now())) { + network::features::kLocalNetworkAccessChecks)) { web_features_to_log_.push_back( blink::mojom::WebFeature:: kLocalNetworkAccessNonSecureContextAllowedDeprecationTrial); - lna_secure_context_override = true; } // TODO(crbug.com/433300380): The lna_secure_context_overide check needs to be // done in all other policy derivation points. This boolean should probably be // put into PolicyContainerPolicies. private_network_request_policy_ = DerivePrivateNetworkRequestPolicy( - policies.ip_address_space, - policies.is_web_secure_context || lna_secure_context_override, - PrivateNetworkRequestContext::kSubresource); + policies, PrivateNetworkRequestContext::kSubresource); if (policy_override == ContentBrowserClient::PrivateNetworkRequestPolicyOverride:: kBlockInsteadOfWarn) { private_network_request_policy_ = - OverrideBlockWithWarn(DerivePrivateNetworkRequestPolicy( - policies, PrivateNetworkRequestContext::kSubresource)); + OverrideBlockWithWarn(private_network_request_policy_); } } @@ -10052,7 +10041,7 @@ client_security_state->private_network_request_policy = DerivePrivateNetworkRequestPolicy( client_security_state->ip_address_space, - client_security_state->is_web_secure_context, + client_security_state->is_web_secure_context, false, PrivateNetworkRequestContext::kNavigation); return client_security_state; @@ -10298,6 +10287,24 @@ GetContentClient()->browser()); policy_container_builder_->SetIPAddressSpace(response_address_space); + // Deprecation trial is to allow http sites to run LNA requests assuming the + // user grants the permission to the web site. + // + // We don't set the use counter here yet because we only want to count the + // number of times this is actually included on a non-secure context, and + // whether a context is secure or not is computed later. + if (base::FeatureList::IsEnabled( + network::features::kLocalNetworkAccessChecks) && + // If there is no response or no headers in the response, there are + // definitely no trial token headers. + response_head_ && response_head_->headers && + blink::TrialTokenValidator().RequestEnablesDeprecatedFeature( + common_params_->url, response_head_->headers.get(), + "LocalNetworkAccessNonSecureContextAllowed", base::Time::Now())) { + policy_container_builder_->SetLocalNetworkAccessNonSecureContextAllowed( + true); + } + if (!devtools_instrumentation::ShouldBypassCSP(*this)) { if (response_head_) { policy_container_builder_->AddContentSecurityPolicies(
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager.cc b/content/browser/renderer_host/page_lifecycle_state_manager.cc index dae70bf..ca11316 100644 --- a/content/browser/renderer_host/page_lifecycle_state_manager.cc +++ b/content/browser/renderer_host/page_lifecycle_state_manager.cc
@@ -4,8 +4,6 @@ #include "content/browser/renderer_host/page_lifecycle_state_manager.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_macros.h" @@ -99,8 +97,7 @@ } void PageLifecycleStateManager::SetBackForwardCacheEntered( - BackForwardCacheEntered entered, - char context_for_bug_427316606) { + BackForwardCacheEntered entered) { static const base::NoDestructor< base::StateTransitions<BackForwardCacheEntered>> transitions(base::StateTransitions<BackForwardCacheEntered>({ @@ -109,26 +106,10 @@ {BackForwardCacheEntered::kNo, BackForwardCacheEntered::kEntered}}, {BackForwardCacheEntered::kEntered, {BackForwardCacheEntered::kNo}}, })); - // TODO(https://crbug.com/427316606): Remove this when we understand how this - // transition sometimes occurs. - back_forward_cache_state_tracker_.append( - base::StringPrintf("%c%d", context_for_bug_427316606, entered)); - - if (back_forward_cache_entered_ == BackForwardCacheEntered::kNo && - entered == BackForwardCacheEntered::kEntered) { - DumpWithoutCrashForBug427316606(); - } else { - CHECK_STATE_TRANSITION(transitions, back_forward_cache_entered_, entered); - } + CHECK_STATE_TRANSITION(transitions, back_forward_cache_entered_, entered); back_forward_cache_entered_ = entered; } -void PageLifecycleStateManager::DumpWithoutCrashForBug427316606() { - SCOPED_CRASH_KEY_STRING64("bfcache", "tracker", - back_forward_cache_state_tracker_); - base::debug::DumpWithoutCrashing(); -} - void PageLifecycleStateManager::SetIsInBackForwardCache( bool is_in_back_forward_cache, blink::mojom::PageRestoreParamsPtr page_restore_params) { @@ -141,7 +122,7 @@ !last_acknowledged_state_->eviction_enabled); eviction_enabled_ = is_in_back_forward_cache; if (is_in_back_forward_cache) { - SetBackForwardCacheEntered(BackForwardCacheEntered::kEntering, 'S'); + SetBackForwardCacheEntered(BackForwardCacheEntered::kEntering); // When a page is put into BackForwardCache, the page can run a busy loop. // Set a timeout monitor to check that the transition finishes within the // time limit. @@ -155,7 +136,7 @@ // When a page is restored from the back-forward cache, we should reset this // state so that it behaves correctly next time navigation occurs. pagehide_dispatch_ = blink::mojom::PagehideDispatch::kNotDispatched; - SetBackForwardCacheEntered(BackForwardCacheEntered::kNo, 'S'); + SetBackForwardCacheEntered(BackForwardCacheEntered::kNo); } SendUpdatesToRendererIfNeeded(std::move(page_restore_params), @@ -187,8 +168,7 @@ blink::mojom::PageVisibilityState::kHidden); DCHECK_NE(acknowledged_state->pagehide_dispatch, blink::mojom::PagehideDispatch::kNotDispatched); - OnPageLifecycleStateChanged(std::move(acknowledged_state), - /*set_page_lifecycle_state_response=*/false); + OnPageLifecycleStateChanged(std::move(acknowledged_state)); } void PageLifecycleStateManager::SetIsLeavingBackForwardCache( @@ -227,13 +207,6 @@ // has not. } - back_forward_cache_state_tracker_.append(base::StringPrintf( - "U%d%d%d%d%d%d", last_acknowledged_state_->is_in_back_forward_cache, - last_acknowledged_state_->is_frozen, - last_state_sent_to_renderer_->is_in_back_forward_cache, - last_state_sent_to_renderer_->is_frozen, - new_state->is_in_back_forward_cache, new_state->is_frozen)); - last_state_sent_to_renderer_ = new_state.Clone(); auto state = new_state.Clone(); @@ -267,13 +240,7 @@ } void PageLifecycleStateManager::OnPageLifecycleStateChanged( - blink::mojom::PageLifecycleStatePtr acknowledged_state, - bool set_page_lifecycle_state_response) { - back_forward_cache_state_tracker_.append(base::StringPrintf( - "O%d%d%d%d", last_acknowledged_state_->is_in_back_forward_cache, - last_acknowledged_state_->is_frozen, - last_state_sent_to_renderer_->is_in_back_forward_cache, - last_state_sent_to_renderer_->is_frozen)); + blink::mojom::PageLifecycleStatePtr acknowledged_state) { blink::mojom::PageLifecycleStatePtr old_state = std::move(last_acknowledged_state_); @@ -285,18 +252,7 @@ // `is_in_back_forward_cache` state. if (!old_state->is_in_back_forward_cache && last_acknowledged_state_->is_in_back_forward_cache) { - CHECK(set_page_lifecycle_state_response); - SCOPED_CRASH_KEY_NUMBER("bfcache", "current_entered_", - static_cast<int>(back_forward_cache_entered_)); - SCOPED_CRASH_KEY_NUMBER("bfcache", "splsr", - set_page_lifecycle_state_response); - SetBackForwardCacheEntered(BackForwardCacheEntered::kEntered, - set_page_lifecycle_state_response ? 'R' : 'C'); - // TODO(https://crbug.com/427316606): Remove this. - // This should only happen during a response to SetPageLifecycleState. - if (!set_page_lifecycle_state_response) { - DumpWithoutCrashForBug427316606(); - } + SetBackForwardCacheEntered(BackForwardCacheEntered::kEntered); // TODO(crbug.com/41494183): currently after the navigation, the old // RenderViewHost is marked as inactive. @@ -357,8 +313,7 @@ void PageLifecycleStateManager::OnSetPageLifecycleStateResponse( blink::mojom::PageLifecycleStatePtr acknowledged_state, base::OnceClosure done_cb) { - OnPageLifecycleStateChanged(std::move(acknowledged_state), - /*set_page_lifecycle_state_response=*/true); + OnPageLifecycleStateChanged(std::move(acknowledged_state)); if (done_cb) std::move(done_cb).Run(); }
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager.h b/content/browser/renderer_host/page_lifecycle_state_manager.h index dcca589..0437ca6 100644 --- a/content/browser/renderer_host/page_lifecycle_state_manager.h +++ b/content/browser/renderer_host/page_lifecycle_state_manager.h
@@ -98,15 +98,10 @@ blink::mojom::PageRestoreParamsPtr page_restore_params, base::OnceClosure done_cb); - // TODO(https://crbug.com/427316606): Remove this. - void DumpWithoutCrashForBug427316606(); - // Called when a new acknowledged state is available. This new state can come // from several paths. void OnPageLifecycleStateChanged( - blink::mojom::PageLifecycleStatePtr acknowledged_state, - // TODO(https://crbug.com/427316606): Remove this. - bool set_page_lifecycle_state_response); + blink::mojom::PageLifecycleStatePtr acknowledged_state); void OnSetPageLifecycleStateResponse( blink::mojom::PageLifecycleStatePtr acknowledged_state, base::OnceClosure done_cb); @@ -126,10 +121,7 @@ friend std::ostream& operator<<(std::ostream&, const BackForwardCacheEntered&); - // TODO(https://crbug.com/427316606): Remove `context_for_bug_427316606` after - // debugging. - void SetBackForwardCacheEntered(BackForwardCacheEntered entered, - char context_for_bug_427316606); + void SetBackForwardCacheEntered(BackForwardCacheEntered entered); BackForwardCacheEntered back_forward_cache_entered_ = BackForwardCacheEntered::kNo; @@ -160,9 +152,6 @@ raw_ptr<TestDelegate> test_delegate_{nullptr}; - // TODO(https://crbug.com/427316606): Remove this after debugging. - std::string back_forward_cache_state_tracker_; - // NOTE: This must be the last member. base::WeakPtrFactory<PageLifecycleStateManager> weak_ptr_factory_{this}; };
diff --git a/content/browser/renderer_host/policy_container_host.cc b/content/browser/renderer_host/policy_container_host.cc index 5b9977d..0e7b5822 100644 --- a/content/browser/renderer_host/policy_container_host.cc +++ b/content/browser/renderer_host/policy_container_host.cc
@@ -114,6 +114,7 @@ PolicyContainerPolicies::PolicyContainerPolicies( network::mojom::ReferrerPolicy referrer_policy, network::mojom::IPAddressSpace ip_address_space, + bool allow_non_secure_local_network_access, bool is_web_secure_context, std::vector<network::mojom::ContentSecurityPolicyPtr> content_security_policies, @@ -128,6 +129,8 @@ bool cross_origin_isolation_enabled_by_dip) : referrer_policy(referrer_policy), ip_address_space(ip_address_space), + allow_non_secure_local_network_access( + allow_non_secure_local_network_access), is_web_secure_context(is_web_secure_context), content_security_policies(std::move(content_security_policies)), cross_origin_opener_policy(cross_origin_opener_policy), @@ -147,6 +150,7 @@ bool is_web_secure_context) : PolicyContainerPolicies(policies.referrer_policy, policies.ip_address_space, + /*allow_non_secure_local_network_access=*/false, is_web_secure_context, mojo::Clone(policies.content_security_policies), network::CrossOriginOpenerPolicy(), @@ -166,6 +170,7 @@ : PolicyContainerPolicies( network::mojom::ReferrerPolicy::kDefault, CalculateIPAddressSpace(url, response_head, client), + /*allow_non_secure_local_network_access=*/false, network::IsUrlPotentiallyTrustworthy(url), mojo::Clone(response_head->parsed_headers->content_security_policy), response_head->parsed_headers->cross_origin_opener_policy, @@ -193,11 +198,12 @@ PolicyContainerPolicies PolicyContainerPolicies::Clone() const { return PolicyContainerPolicies( - referrer_policy, ip_address_space, is_web_secure_context, - mojo::Clone(content_security_policies), cross_origin_opener_policy, - cross_origin_embedder_policy, mojo::Clone(document_isolation_policy), - integrity_policy, integrity_policy_report_only, sandbox_flags, - is_credentialless, can_navigate_top_without_user_gesture, + referrer_policy, ip_address_space, allow_non_secure_local_network_access, + is_web_secure_context, mojo::Clone(content_security_policies), + cross_origin_opener_policy, cross_origin_embedder_policy, + mojo::Clone(document_isolation_policy), integrity_policy, + integrity_policy_report_only, sandbox_flags, is_credentialless, + can_navigate_top_without_user_gesture, cross_origin_isolation_enabled_by_dip); } @@ -215,6 +221,11 @@ blink::mojom::PolicyContainerPoliciesPtr PolicyContainerPolicies::ToMojoPolicyContainerPolicies() const { + // TODO(crbug.com/395895368): add allow_non_secure_local_network_access to the + // mojo container in + // third_party/blink/public/mojom/frame/policy_container.mojom if it is + // necessary for Service workers (see https://crrev.com/c/3885147 for how it + // was done in PNA). return blink::mojom::PolicyContainerPolicies::New( cross_origin_embedder_policy, integrity_policy, integrity_policy_report_only, referrer_policy,
diff --git a/content/browser/renderer_host/policy_container_host.h b/content/browser/renderer_host/policy_container_host.h index 8771bbc6..67d3c1f 100644 --- a/content/browser/renderer_host/policy_container_host.h +++ b/content/browser/renderer_host/policy_container_host.h
@@ -38,6 +38,7 @@ PolicyContainerPolicies( network::mojom::ReferrerPolicy referrer_policy, network::mojom::IPAddressSpace ip_address_space, + bool allow_non_secure_local_network_access, bool is_web_secure_context, std::vector<network::mojom::ContentSecurityPolicyPtr> content_security_policies, @@ -100,6 +101,14 @@ network::mojom::IPAddressSpace ip_address_space = network::mojom::IPAddressSpace::kUnknown; + // Whether non-secure contexts are allowed to issue Local Network Access + // requests. Even if allowed, they are still bound by permission + // requirements. + // + // Only relevant if network::features::kLocalNetworkAccessChecks is enabled + // and blocking. + bool allow_non_secure_local_network_access = false; + // Whether the document is a secure context. // // See: https://html.spec.whatwg.org/C/#secure-contexts.
diff --git a/content/browser/renderer_host/policy_container_host_unittest.cc b/content/browser/renderer_host/policy_container_host_unittest.cc index 1e0b5c74..984e3609 100644 --- a/content/browser/renderer_host/policy_container_host_unittest.cc +++ b/content/browser/renderer_host/policy_container_host_unittest.cc
@@ -94,6 +94,7 @@ PolicyContainerPolicies policies( network::mojom::ReferrerPolicy::kAlways, network::mojom::IPAddressSpace::kUnknown, + /*allow_non_secure_local_network_access=*/true, /*is_web_secure_context=*/true, std::move(csps), coop, coep, std::move(dip), ip, network::IntegrityPolicy(), sandbox_flags, /*is_credentialless=*/true,
diff --git a/content/browser/renderer_host/private_network_access_util.cc b/content/browser/renderer_host/private_network_access_util.cc index d3cfad1e..bf04610 100644 --- a/content/browser/renderer_host/private_network_access_util.cc +++ b/content/browser/renderer_host/private_network_access_util.cc
@@ -73,9 +73,10 @@ // LNA blocks all local network access requests coming from non-secure // contexts. // See: https://wicg.github.io/local-network-access/ - return network::features::kLocalNetworkAccessChecksWarn.Get() - ? Policy::kPermissionWarn - : Policy::kBlock; + if (network::features::kLocalNetworkAccessChecksWarn.Get()) { + return Policy::kPermissionWarn; + } + return Policy::kBlock; } switch (ip_address_space) { @@ -166,6 +167,7 @@ Policy DerivePrivateNetworkRequestPolicy( AddressSpace ip_address_space, bool is_web_secure_context, + bool allow_on_non_secure_context, RequestContext private_network_request_context) { // Disable PNA checks entirely when running with `--disable-web-security`. if (base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -179,8 +181,11 @@ FeatureState feature_state = FeatureStateForContext(private_network_request_context); + // For LNA, if allow_on_non_secure_context is true, derive the policy as if it + // is a secure context. Policy policy = - is_web_secure_context + is_web_secure_context || (local_network_access_checks_enabled && + allow_on_non_secure_context) ? DerivePolicyForSecureContext(ip_address_space, local_network_access_checks_enabled) : DerivePolicyForNonSecureContext( @@ -196,9 +201,10 @@ Policy DerivePrivateNetworkRequestPolicy( const PolicyContainerPolicies& policies, RequestContext private_network_request_context) { - return DerivePrivateNetworkRequestPolicy(policies.ip_address_space, - policies.is_web_secure_context, - private_network_request_context); + return DerivePrivateNetworkRequestPolicy( + policies.ip_address_space, policies.is_web_secure_context, + policies.allow_non_secure_local_network_access, + private_network_request_context); } network::mojom::ClientSecurityStatePtr DeriveClientSecurityState(
diff --git a/content/browser/renderer_host/private_network_access_util.h b/content/browser/renderer_host/private_network_access_util.h index 4e97465..db87e31 100644 --- a/content/browser/renderer_host/private_network_access_util.h +++ b/content/browser/renderer_host/private_network_access_util.h
@@ -28,13 +28,19 @@ // `ip_address_space` identifies the IP address space of the request client. // `is_web_secure_context` specifies whether the request client is a secure // context or not. -// `private_network_request_context` specifies what this request is about. For -// example, requests made from workers can have different policies from normal -// subresource requests. +// `allow_on_non_secure_context` specifies whether we allow local network +// requests on non-secure contexts. Note: this only applies to local network +// access requests, not private network access requests, and having this be true +// means that while we still allow the requests, they still need to pass +// permissions checks. +// `private_network_request_context` specifies what this +// request is about. For example, requests made from workers can have different +// policies from normal subresource requests. network::mojom::PrivateNetworkRequestPolicy CONTENT_EXPORT DerivePrivateNetworkRequestPolicy( network::mojom::IPAddressSpace ip_address_space, bool is_web_secure_context, + bool allow_on_non_secure_context, PrivateNetworkRequestContext private_network_request_context); // Convenience overload to directly compute this from the client's `policies`.
diff --git a/content/browser/renderer_host/private_network_access_util_unittest.cc b/content/browser/renderer_host/private_network_access_util_unittest.cc index b2bf536..6439fa8f 100644 --- a/content/browser/renderer_host/private_network_access_util_unittest.cc +++ b/content/browser/renderer_host/private_network_access_util_unittest.cc
@@ -35,15 +35,21 @@ constexpr bool kNonSecure = false; constexpr bool kSecure = true; +// Self-descriptive constants for `allow_on_non_secure_context`. +constexpr bool kDisallowNonSecure = false; +constexpr bool kAllowNonSecure = true; + // Input arguments to `DerivePrivateNetworkRequestPolicy()`. struct DerivePolicyInput { bool is_web_secure_context; + bool allow_on_non_secure_context; AddressSpace address_space; RequestContext request_context; // Helper for comparison operators. - std::tuple<bool, AddressSpace, RequestContext> ToTuple() const { - return {is_web_secure_context, address_space, request_context}; + std::tuple<bool, bool, AddressSpace, RequestContext> ToTuple() const { + return {is_web_secure_context, allow_on_non_secure_context, address_space, + request_context}; } bool operator==(const DerivePolicyInput& other) const { @@ -71,12 +77,16 @@ std::ostream& operator<<(std::ostream& out, const DerivePolicyInput& input) { return out << "{ " << input.address_space << ", " << (input.is_web_secure_context ? "secure" : "non-secure") << ", " - << RequestContextToStringPiece(input.request_context) << " }"; + << (input.allow_on_non_secure_context ? "allow-non-secure" + : "disallow-non-secure") + << ", " << RequestContextToStringPiece(input.request_context) + << " }"; } Policy DerivePolicy(DerivePolicyInput input) { return DerivePrivateNetworkRequestPolicy( - input.address_space, input.is_web_secure_context, input.request_context); + input.address_space, input.is_web_secure_context, + input.allow_on_non_secure_context, input.request_context); } // Maps inputs to their default output (all feature flags left untouched). @@ -86,105 +96,189 @@ // `RequestContext::kSubresource` // { - {kNonSecure, AddressSpace::kUnknown, RequestContext::kSubresource}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kSubresource}, Policy::kAllow, }, { - {kNonSecure, AddressSpace::kPublic, RequestContext::kSubresource}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kSubresource}, Policy::kWarn, }, { - {kNonSecure, AddressSpace::kLocal, RequestContext::kSubresource}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kSubresource}, Policy::kWarn, }, { - {kNonSecure, AddressSpace::kLoopback, RequestContext::kSubresource}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kSubresource}, Policy::kWarn, }, { - {kSecure, AddressSpace::kUnknown, RequestContext::kSubresource}, + {kNonSecure, kAllowNonSecure, AddressSpace::kUnknown, + RequestContext::kSubresource}, Policy::kAllow, }, { - {kSecure, AddressSpace::kPublic, RequestContext::kSubresource}, + {kNonSecure, kAllowNonSecure, AddressSpace::kPublic, + RequestContext::kSubresource}, + Policy::kWarn, + }, + { + {kNonSecure, kAllowNonSecure, AddressSpace::kLocal, + RequestContext::kSubresource}, + Policy::kWarn, + }, + { + {kNonSecure, kAllowNonSecure, AddressSpace::kLoopback, + RequestContext::kSubresource}, + Policy::kWarn, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kSubresource}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLocal, RequestContext::kSubresource}, + {kSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kSubresource}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLoopback, RequestContext::kSubresource}, + {kSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kSubresource}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kSubresource}, Policy::kAllow, }, // // `RequestContext::kWorker` // { - {kNonSecure, AddressSpace::kUnknown, RequestContext::kWorker}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kWorker}, Policy::kAllow, }, { - {kNonSecure, AddressSpace::kPublic, RequestContext::kWorker}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kWorker}, Policy::kWarn, }, { - {kNonSecure, AddressSpace::kLocal, RequestContext::kWorker}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kWorker}, Policy::kWarn, }, { - {kNonSecure, AddressSpace::kLoopback, RequestContext::kWorker}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kWorker}, Policy::kWarn, }, { - {kSecure, AddressSpace::kUnknown, RequestContext::kWorker}, + {kNonSecure, kAllowNonSecure, AddressSpace::kUnknown, + RequestContext::kWorker}, Policy::kAllow, }, { - {kSecure, AddressSpace::kPublic, RequestContext::kWorker}, + {kNonSecure, kAllowNonSecure, AddressSpace::kPublic, + RequestContext::kWorker}, + Policy::kWarn, + }, + { + {kNonSecure, kAllowNonSecure, AddressSpace::kLocal, + RequestContext::kWorker}, + Policy::kWarn, + }, + { + {kNonSecure, kAllowNonSecure, AddressSpace::kLoopback, + RequestContext::kWorker}, + Policy::kWarn, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kWorker}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLocal, RequestContext::kWorker}, + {kSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kWorker}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLoopback, RequestContext::kWorker}, + {kSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kWorker}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kWorker}, Policy::kAllow, }, // // `RequestContext::kNavigation` // { - {kNonSecure, AddressSpace::kUnknown, RequestContext::kNavigation}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kNonSecure, AddressSpace::kPublic, RequestContext::kNavigation}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kNonSecure, AddressSpace::kLocal, RequestContext::kNavigation}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kNonSecure, AddressSpace::kLoopback, RequestContext::kNavigation}, + {kNonSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kSecure, AddressSpace::kUnknown, RequestContext::kNavigation}, + {kNonSecure, kAllowNonSecure, AddressSpace::kUnknown, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kSecure, AddressSpace::kPublic, RequestContext::kNavigation}, + {kNonSecure, kAllowNonSecure, AddressSpace::kPublic, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLocal, RequestContext::kNavigation}, + {kNonSecure, kAllowNonSecure, AddressSpace::kLocal, + RequestContext::kNavigation}, Policy::kAllow, }, { - {kSecure, AddressSpace::kLoopback, RequestContext::kNavigation}, + {kNonSecure, kAllowNonSecure, AddressSpace::kLoopback, + RequestContext::kNavigation}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kUnknown, + RequestContext::kNavigation}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kPublic, + RequestContext::kNavigation}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kLocal, + RequestContext::kNavigation}, + Policy::kAllow, + }, + { + {kSecure, kDisallowNonSecure, AddressSpace::kLoopback, + RequestContext::kNavigation}, Policy::kAllow, }, }; @@ -225,8 +319,10 @@ std::map<DerivePolicyInput, Policy> expected = DefaultPolicyMap(); for (auto& entry : expected) { - entry.second = entry.first.is_web_secure_context ? Policy::kPermissionBlock - : Policy::kBlock; + entry.second = (entry.first.is_web_secure_context || + entry.first.allow_on_non_secure_context) + ? Policy::kPermissionBlock + : Policy::kBlock; } TestPolicyMap(expected); }
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 378e3eb..a94a7423 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1825,6 +1825,23 @@ ukm_builder->Record(ukm::UkmRecorder::Get()); } } + +bool ShouldContributePriorityToProcess( + RenderFrameHostImpl::LifecycleStateImpl state) { + // The frame should not contribute to the process priority while the frame is + // in BFCache or being deleted. + switch (state) { + case RenderFrameHostImpl::LifecycleStateImpl::kSpeculative: + case RenderFrameHostImpl::LifecycleStateImpl::kPendingCommit: + case RenderFrameHostImpl::LifecycleStateImpl::kPrerendering: + case RenderFrameHostImpl::LifecycleStateImpl::kActive: + case RenderFrameHostImpl::LifecycleStateImpl::kRunningUnloadHandlers: + return true; + case RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache: + case RenderFrameHostImpl::LifecycleStateImpl::kReadyToBeDeleted: + return false; + } +} } // namespace class RenderFrameHostImpl::SubresourceLoaderFactoriesConfig { @@ -2536,6 +2553,10 @@ if (is_main_frame()) GetLocalRenderWidgetHost()->SetIntersectsViewport(true); GetLocalRenderWidgetHost()->SetFrameDepth(depth_); + if (base::FeatureList::IsEnabled(features::kSubframePriorityContribution)) { + GetLocalRenderWidgetHost()->SetShouldContributePriorityToProcess( + ShouldContributePriorityToProcess(lifecycle_state_)); + } } // Verify is_local_root() now indicates whether this frame is a local root or // not. It is safe to use this method anywhere beyond this point. @@ -3985,6 +4006,7 @@ network::mojom::ReferrerPolicy::kDefault, IsFencedFrameRoot() ? network::mojom::IPAddressSpace::kPublic : network::mojom::IPAddressSpace::kUnknown, + /*allow_non_secure_local_network_access=*/false, /*is_web_secure_context=*/false, std::vector<network::mojom::ContentSecurityPolicyPtr>(), parent_policies.cross_origin_opener_policy, @@ -14710,10 +14732,15 @@ RenderFrameHostImpl::BuildClientSecurityStateForWorkers() const { auto client_security_state = BuildClientSecurityState(); + bool allow_non_secure_local_network_access = + policy_container_host_ && + policy_container_host_->policies().allow_non_secure_local_network_access; + client_security_state->private_network_request_policy = DerivePrivateNetworkRequestPolicy( client_security_state->ip_address_space, client_security_state->is_web_secure_context, + allow_non_secure_local_network_access, PrivateNetworkRequestContext::kWorker); return client_security_state; @@ -18076,6 +18103,24 @@ LifecycleStateImpl old_state = lifecycle_state_; lifecycle_state_ = new_state; + if (base::FeatureList::IsEnabled(features::kSubframePriorityContribution)) { + auto* local_render_widget_host = GetLocalRenderWidgetHost(); + if (local_render_widget_host) { + // The priority contribution of the main frame is controlled also by + // RenderViewHostImpl::IsMainFrameActive. The main purpose of + // RenderViewHostImpl::IsMainFrameActive is to prevent RWH owned by RVH of + // subframes from contributing to the process priority and allow RWH owned + // by RVM of a main frame to contribute. IsMainFrameActive() of RVH of a + // main frame also returns false while the main frame is in BFCache, which + // is the same as here. But we explicitly + // SetShouldContributePriorityToProcess() for the main frame here to make + // the priority contribution of the main frame more readable and be robust + // to future changes (e.g. for the case we want to disallow other states). + local_render_widget_host->SetShouldContributePriorityToProcess( + ShouldContributePriorityToProcess(new_state)); + } + } + // If the state changes from or to kActive, update the active document count. if (old_state == LifecycleStateImpl::kActive && new_state != LifecycleStateImpl::kActive) {
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 595e637..87c448c0 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -651,6 +651,9 @@ void RenderViewHostImpl::SetMainFrameRoutingId(int routing_id) { main_frame_routing_id_ = routing_id; render_widget_host_->ClearVisualProperties(); + // RenderWidgetHostImpl changes its contribution to the process priority based + // on whether the main frame is active. UpdatePriority() to reflect the + // change. GetWidget()->UpdatePriority(); // TODO(crbug.com/40387047): If a local main frame is no longer attached to // this `blink::WebView` then the RenderWidgetHostImpl owned by this class
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc index bab7b50..d2fa600c 100644 --- a/content/browser/renderer_host/render_widget_host_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -720,10 +720,11 @@ run_loop_.Quit(); } - void DidCreatePopupWidget(RenderWidgetHostImpl* render_widget_host) { + void DidCreatePopupWidget(RenderWidgetHost* render_widget_host) { process_id_ = render_widget_host->GetProcess()->GetDeprecatedID(); routing_id_ = render_widget_host->GetRoutingID(); - std::ignore = render_widget_host->popup_widget_host_receiver_for_testing() + std::ignore = static_cast<RenderWidgetHostImpl*>(render_widget_host) + ->popup_widget_host_receiver_for_testing() .SwapImplForTesting(this); }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index fb8a955d..ddb682e 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -706,6 +706,17 @@ UpdatePriority(); } +void RenderWidgetHostImpl::SetShouldContributePriorityToProcess( + bool should_contribute_priority_to_process) { + if (should_contribute_priority_to_process_ == + should_contribute_priority_to_process) { + return; + } + should_contribute_priority_to_process_ = + should_contribute_priority_to_process; + UpdatePriority(); +} + void RenderWidgetHostImpl::UpdatePriority() { if (!destroyed_) { GetProcess()->UpdateClientPriority(this); @@ -2105,8 +2116,24 @@ importance_, #endif }; - if (owner_delegate_ && - !owner_delegate_->ShouldContributePriorityToProcess()) { + bool should_contribute = false; + if (base::FeatureList::IsEnabled(features::kSubframePriorityContribution)) { + should_contribute = should_contribute_priority_to_process_; + if (owner_delegate_ && !owner_delegate_->IsMainFrameActive()) { + // If this RenderWidgetHost is owned by a RenderViewHost which does not + // have an active main frame, it should not contribute to the priority of + // the process. This can happen for an OOPIF which not only has its own + // RenderWidgetHost, but also has an inactive RenderViewHost in its + // SiteInstance, and that RenderViewHost owns another unused + // RenderWidgetHost which is what's being excluded here. + should_contribute = false; + } + } else { + should_contribute = !owner_delegate_ || + owner_delegate_->ShouldContributePriorityToProcess(); + } + + if (!should_contribute) { priority.is_hidden = true; priority.frame_depth = RenderProcessHostImpl::kMaxFrameDepthForPriority; #if BUILDFLAG(IS_ANDROID)
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 1e5164c..d9375e5 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -459,6 +459,8 @@ void SetFrameDepth(unsigned int depth); void SetIntersectsViewport(bool intersects); void UpdatePriority(); + void SetShouldContributePriorityToProcess( + bool should_contribute_priority_to_process); // Tells the renderer to die and optionally delete |this|. void ShutdownAndDestroyWidget(bool also_delete); @@ -1316,6 +1318,9 @@ // RenderFrame/View, assume false. bool intersects_viewport_ = false; + // Indicates whether this widget contributes to the priority of the process. + bool should_contribute_priority_to_process_ = true; + // Determines whether the page is mobile optimized or not. bool is_mobile_optimized_ = false;
diff --git a/content/browser/renderer_host/render_widget_host_owner_delegate.h b/content/browser/renderer_host/render_widget_host_owner_delegate.h index 3fe4efa..b1e6ee8 100644 --- a/content/browser/renderer_host/render_widget_host_owner_delegate.h +++ b/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -53,7 +53,8 @@ // the renderer's background is forced to be opaque. virtual void SetBackgroundOpaque(bool opaque) = 0; - // Returns true if the main frame is active, false if it is swapped out. + // Returns true if the main frame is active, false if the widget is not for + // the main frame. virtual bool IsMainFrameActive() = 0; // Returns the WebkitPreferences for the page. The preferences are shared
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 01758ea5..c115028 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -2149,12 +2149,15 @@ } const PolicyContainerPolicies& policies = policy_container_host_->policies(); + // TODO(crbug.com/395895368): try replacing the below with + // DeriveClientSecurityState return network::mojom::ClientSecurityState::New( policies.cross_origin_embedder_policy, policies.is_web_secure_context, policies.ip_address_space, - DerivePrivateNetworkRequestPolicy(policies.ip_address_space, - policies.is_web_secure_context, - PrivateNetworkRequestContext::kWorker), + DerivePrivateNetworkRequestPolicy( + policies.ip_address_space, policies.is_web_secure_context, + policies.allow_non_secure_local_network_access, + PrivateNetworkRequestContext::kWorker), policies.document_isolation_policy); }
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index eeb6a0f..03143f0 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -6504,9 +6504,9 @@ void ResumeShowPopupWidget() { show_interceptor_->ResumeShowPopupWidget(); } private: - void DidCreatePopupWidget(RenderWidgetHostImpl* widget) { + void DidCreatePopupWidget(RenderWidgetHost* widget) { show_interceptor_ = std::make_unique<ShowCreatedPopupWidgetInterceptor>( - widget, std::move(test_callback_)); + static_cast<RenderWidgetHostImpl*>(widget), std::move(test_callback_)); } CreateNewPopupWidgetInterceptor create_new_popup_widget_interceptor_; @@ -9525,9 +9525,117 @@ EXPECT_FALSE(mock_handler_speculative.did_receive_event()); } -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TestChildProcessImportance) { - web_contents()->SetPrimaryMainFrameImportance( - ChildProcessImportance::MODERATE); +class SitePerProcessBrowserTestWithSubframePriority + : public SitePerProcessBrowserTest { + public: + SitePerProcessBrowserTestWithSubframePriority() { + scoped_feature_list_.InitWithFeatures( + /* enabled_features= */ {features::kSubframePriorityContribution, + features::kSubframeImportance}, + /* disabled_features= */ {}); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSubframePriority, + TestChildProcessImportance) { + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::IMPORTANT, + ChildProcessImportance::MODERATE); + + // Construct root page with one child in different domain. + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)"))); + FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); + ASSERT_EQ(1u, root->child_count()); + FrameTreeNode* child = root->child_at(0); + + // Importance should survive initial navigation. + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ( + ChildProcessImportance::MODERATE, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + // Setting NORMAL importance for child frame. + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::MODERATE, + ChildProcessImportance::NORMAL); + EXPECT_EQ(ChildProcessImportance::MODERATE, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ( + ChildProcessImportance::NORMAL, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + // Check setting the same importance for main frame and subframe. + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::MODERATE, + ChildProcessImportance::MODERATE); + EXPECT_EQ(ChildProcessImportance::MODERATE, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ( + ChildProcessImportance::MODERATE, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + // Check setting importance. + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::NORMAL, + ChildProcessImportance::NORMAL); + EXPECT_EQ(ChildProcessImportance::NORMAL, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ( + ChildProcessImportance::NORMAL, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::IMPORTANT, + ChildProcessImportance::MODERATE); + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ( + ChildProcessImportance::MODERATE, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + // Check importance is maintained if child navigates to new domain. + int old_child_process_id = + child->current_frame_host()->GetProcess()->GetDeprecatedID(); + EXPECT_TRUE(NavigateToURLFromRenderer( + root->child_at(0), + embedded_test_server()->GetURL("foo.com", "/title2.html"))); + int new_child_process_id = + child->current_frame_host()->GetProcess()->GetDeprecatedID(); + EXPECT_NE(old_child_process_id, new_child_process_id); + EXPECT_EQ( + ChildProcessImportance::MODERATE, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + // Check importance is maintained if root navigates to new domain. + int old_root_process_id = + root->current_frame_host()->GetProcess()->GetDeprecatedID(); + EXPECT_TRUE(NavigateToURLFromRenderer( + root, embedded_test_server()->GetURL( + "b.com", "/cross_site_iframe_factory.html?b(a)"))); + int new_root_process_id = + root->current_frame_host()->GetProcess()->GetDeprecatedID(); + EXPECT_NE(old_root_process_id, new_root_process_id); + EXPECT_EQ(ChildProcessImportance::IMPORTANT, + root->current_frame_host()->GetProcess()->GetEffectiveImportance()); + + ASSERT_EQ(1u, root->child_count()); + child = root->child_at(0); + int new_child_process_id_2 = + child->current_frame_host()->GetProcess()->GetDeprecatedID(); + EXPECT_NE(new_child_process_id, new_child_process_id_2); + EXPECT_EQ( + ChildProcessImportance::MODERATE, + child->current_frame_host()->GetProcess()->GetEffectiveImportance()); +} + +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, + TestChildProcessImportanceWithNormalSubframes) { + // In this test case, subframe importance is always NORMAL. With that + // WebContents never updates subframe importance. + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::MODERATE, + ChildProcessImportance::NORMAL); // Construct root page with one child in different domain. GURL main_url(embedded_test_server()->GetURL( @@ -9537,8 +9645,7 @@ ASSERT_EQ(1u, root->child_count()); FrameTreeNode* child = root->child_at(0); - // Importance should survive initial navigation. Note importance only affect - // main frame, so sub frame process should remain NORMAL throughout. + // Importance should survive initial navigation. EXPECT_EQ(ChildProcessImportance::MODERATE, root->current_frame_host()->GetProcess()->GetEffectiveImportance()); EXPECT_EQ( @@ -9546,14 +9653,15 @@ child->current_frame_host()->GetProcess()->GetEffectiveImportance()); // Check setting importance. - web_contents()->SetPrimaryMainFrameImportance(ChildProcessImportance::NORMAL); + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::NORMAL, + ChildProcessImportance::NORMAL); EXPECT_EQ(ChildProcessImportance::NORMAL, root->current_frame_host()->GetProcess()->GetEffectiveImportance()); EXPECT_EQ( ChildProcessImportance::NORMAL, child->current_frame_host()->GetProcess()->GetEffectiveImportance()); - web_contents()->SetPrimaryMainFrameImportance( - ChildProcessImportance::IMPORTANT); + web_contents()->SetPrimaryPageImportance(ChildProcessImportance::IMPORTANT, + ChildProcessImportance::NORMAL); EXPECT_EQ(ChildProcessImportance::IMPORTANT, root->current_frame_host()->GetProcess()->GetEffectiveImportance()); EXPECT_EQ( @@ -14594,6 +14702,9 @@ INSTANTIATE_TEST_SUITE_P(All, AndroidInputBrowserTest, testing::ValuesIn(RenderDocumentFeatureLevelValues())); +INSTANTIATE_TEST_SUITE_P(All, + SitePerProcessBrowserTestWithSubframePriority, + testing::ValuesIn(RenderDocumentFeatureLevelValues())); #endif // BUILDFLAG(IS_ANDROID) INSTANTIATE_TEST_SUITE_P(All, SitePerProcessAndProcessPerSiteBrowserTest,
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index 855cbd36..3b8b5b68 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc
@@ -497,10 +497,12 @@ web_contents_->ResumeLoadingCreatedWebContents(); } -void WebContentsAndroid::SetPrimaryMainFrameImportance(JNIEnv* env, - jint importance) { - web_contents_->SetPrimaryMainFrameImportance( - static_cast<ChildProcessImportance>(importance)); +void WebContentsAndroid::SetPrimaryPageImportance(JNIEnv* env, + jint main_frame_importance, + jint subframe_importance) { + web_contents_->SetPrimaryPageImportance( + static_cast<ChildProcessImportance>(main_frame_importance), + static_cast<ChildProcessImportance>(subframe_importance)); } void WebContentsAndroid::SuspendAllMediaPlayers(JNIEnv* env) {
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h index 9181081..9a955ed 100644 --- a/content/browser/web_contents/web_contents_android.h +++ b/content/browser/web_contents/web_contents_android.h
@@ -98,7 +98,9 @@ void ResumeLoadingCreatedWebContents(JNIEnv* env); - void SetPrimaryMainFrameImportance(JNIEnv* env, jint importance); + void SetPrimaryPageImportance(JNIEnv* env, + jint main_frame_importance, + jint subframe_importance); void SuspendAllMediaPlayers(JNIEnv* env); void SetAudioMuted(JNIEnv* env, jboolean mute); jboolean IsAudioMuted(JNIEnv* env);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 5c319d0b..4e63b4b 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3124,16 +3124,51 @@ return GetPrimaryMainFrame()->GetRenderWidgetHost()->importance(); } -void WebContentsImpl::SetPrimaryMainFrameImportance( - ChildProcessImportance importance) { - OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::SetMainFrameImportance", - "importance", static_cast<int>(importance)); +ChildProcessImportance +WebContentsImpl::GetPrimaryPageSubframeImportanceForTesting() { + return primary_subframe_importance_; +} + +void WebContentsImpl::SetPrimaryPageImportance( + ChildProcessImportance main_frame_importance, + ChildProcessImportance subframe_importance) { + OPTIONAL_TRACE_EVENT2( + "content", "WebContentsImpl::SetPrimaryPageImportance", + "main_frame_importance", static_cast<int>(main_frame_importance), + "subframe_importance", static_cast<int>(subframe_importance)); CHECK(IsPerceptibleImportanceSupported() || - importance != ChildProcessImportance::PERCEPTIBLE) + (main_frame_importance != ChildProcessImportance::PERCEPTIBLE && + subframe_importance != ChildProcessImportance::PERCEPTIBLE)) << "Setter of ChildProcessImportance::PERCEPTIBLE should be aware of the " "support and avoid using PERCEPTIBLE if " "IsPerceptibleImportanceSupported() is false"; - GetPrimaryMainFrame()->GetRenderWidgetHost()->SetImportance(importance); + CHECK(main_frame_importance >= subframe_importance); + + if (base::FeatureList::IsEnabled(features::kSubframeImportance)) { + CHECK( + base::FeatureList::IsEnabled(features::kSubframePriorityContribution)); + if (subframe_importance != primary_subframe_importance_) { + primary_subframe_importance_ = subframe_importance; + ApplyPrimaryPageSubframeImportance(); + } + } + + GetPrimaryMainFrame()->GetRenderWidgetHost()->SetImportance( + main_frame_importance); +} + +void WebContentsImpl::ApplyPrimaryPageSubframeImportance() { + OPTIONAL_TRACE_EVENT1( + "content", "WebContentsImpl::ApplyPrimaryPageSubframeImportance", + "importance", static_cast<int>(primary_subframe_importance_)); + for (FrameTreeNode* node : primary_frame_tree_.Nodes()) { + if (node->IsMainFrame()) { + continue; + } + if (auto* rwh = node->current_frame_host()->GetLocalRenderWidgetHost()) { + rwh->SetImportance(primary_subframe_importance_); + } + } } #endif @@ -8583,6 +8618,16 @@ if (safe_area_insets_host_) { safe_area_insets_host_->RenderFrameCreated(render_frame_host); } + +#if BUILDFLAG(IS_ANDROID) + if (base::FeatureList::IsEnabled(features::kSubframeImportance) && + render_frame_host->GetParent() && + render_frame_host->frame_tree()->is_primary()) { + if (auto* rwh = render_frame_host->GetLocalRenderWidgetHost()) { + rwh->SetImportance(primary_subframe_importance_); + } + } +#endif } void WebContentsImpl::RenderFrameDeleted( @@ -11757,6 +11802,16 @@ DCHECK_EQ(&page, &GetPrimaryPage()); +#if BUILDFLAG(IS_ANDROID) + // Apply the cached subframe importance if it is set. This is needed for + // pages restored from back/forward cache. Note that we don't need to clear + // importance for non-primary pages because the importance is ignored at + // RenderWidgetHostImpl::GetPriority() and updated when it becomes inactive. + if (base::FeatureList::IsEnabled(features::kSubframeImportance)) { + ApplyPrimaryPageSubframeImportance(); + } +#endif + // Clear |save_package_| since the primary page changed. if (save_package_) { save_package_->ClearPage();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 1d413c5..a191e257 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -628,8 +628,10 @@ void RequestFindMatchRects(int current_version) override; service_manager::InterfaceProvider* GetJavaInterfaces() override; ChildProcessImportance GetPrimaryMainFrameImportanceForTesting() override; - void SetPrimaryMainFrameImportance( - ChildProcessImportance importance) override; + ChildProcessImportance GetPrimaryPageSubframeImportanceForTesting() override; + void SetPrimaryPageImportance( + ChildProcessImportance main_frame_importance, + ChildProcessImportance subframe_importance) override; #endif bool HasRecentInteraction() override; [[nodiscard]] ScopedIgnoreInputEvents IgnoreInputEvents( @@ -2198,6 +2200,11 @@ void RecursivelyConstructAXTree(ui::AXNode* node, std::vector<ui::AXNodeData>& nodes); +#if BUILDFLAG(IS_ANDROID) + // Apply the cached primary subframe importance to the primary frame tree. + void ApplyPrimaryPageSubframeImportance(); +#endif + // Data for core operation --------------------------------------------------- // Delegate for notifying our owner about stuff. Not owned by us. @@ -2252,6 +2259,11 @@ #if BUILDFLAG(IS_ANDROID) std::unique_ptr<WebContentsAndroid> web_contents_android_; + // Caches the importance of subframes in the primary frame tree. + // WebContentsImpl::RenderFrameCreated() sets the importance to a new + // RenderWidgetHost for new subframes. + ChildProcessImportance primary_subframe_importance_ = + ChildProcessImportance::NORMAL; #endif // Manages the embedder state for browser plugins, if this WebContents is an
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 9a95e1f..1b4730b 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -446,10 +446,18 @@ worker_client_security_state_->is_web_secure_context = network::IsUrlPotentiallyTrustworthy(result->final_response_url) && creator_client_security_state_->is_web_secure_context; + // Deprecation trial status allowing LNA requests on non-http + bool allow_non_secure_local_network_access = + ancestor_render_frame_host->policy_container_host() && + ancestor_render_frame_host->policy_container_host() + ->policies() + .allow_non_secure_local_network_access; + worker_client_security_state_->private_network_request_policy = DerivePrivateNetworkRequestPolicy( worker_client_security_state_->ip_address_space, worker_client_security_state_->is_web_secure_context, + allow_non_secure_local_network_access, PrivateNetworkRequestContext::kWorker); } else { // Preserve incorrect functionality if PNA is not enabled.
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 364d6f1a..f281627 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -598,12 +598,17 @@ } @Override - public void setPrimaryMainFrameImportance(@ChildProcessImportance int importance) { + public void setPrimaryPageImportance( + @ChildProcessImportance int mainFrameImportance, + @ChildProcessImportance int subframeImportance) { checkNotDestroyed(); assert ChildProcessConnection.supportNotPerceptibleBinding() - || importance != ChildProcessImportance.PERCEPTIBLE; + || (mainFrameImportance != ChildProcessImportance.PERCEPTIBLE + && subframeImportance != ChildProcessImportance.PERCEPTIBLE); + assert mainFrameImportance >= subframeImportance; WebContentsImplJni.get() - .setPrimaryMainFrameImportance(mNativeWebContentsAndroid, importance); + .setPrimaryPageImportance( + mNativeWebContentsAndroid, mainFrameImportance, subframeImportance); } @Override @@ -1320,7 +1325,8 @@ void collapseSelection(long nativeWebContentsAndroid); - void setPrimaryMainFrameImportance(long nativeWebContentsAndroid, int importance); + void setPrimaryPageImportance( + long nativeWebContentsAndroid, int mainFrameImportance, int subframeImportance); void suspendAllMediaPlayers(long nativeWebContentsAndroid);
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index c792324..0a7d06f 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -246,12 +246,17 @@ /** * ChildProcessImportance on Android allows controls of the renderer process bindings - * independent of visibility. Note this does not affect importance of subframe processes or main - * frames processeses for non-primary pages. + * independent of visibility. Note this does not affect importance of processes for non-primary + * pages. * - * @param importance importance of the primary page's main frame process. + * <p>The subframeImportance must be less than or equal to the mainFrameImportance. + * + * @param mainFrameImportance importance of the primary page's main frame process. + * @param subframeImportance importance of the primary page's subframes process. */ - void setPrimaryMainFrameImportance(@ChildProcessImportance int importance); + void setPrimaryPageImportance( + @ChildProcessImportance int mainFrameImportance, + @ChildProcessImportance int subframeImportance); /** * Suspends all media players for this WebContents. Note: There may still be activities
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java index 660f7ec..ca02eed 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java
@@ -26,9 +26,11 @@ import org.jni_zero.JNINamespace; import org.jni_zero.NativeMethods; +import org.chromium.base.ThreadUtils; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.WindowAndroid; import java.nio.ByteBuffer; @@ -101,7 +103,7 @@ private static final ConditionVariable sLatch = new ConditionVariable(false); // Holds the pointer to the C++ side object. The C++ side has the ownership of the Java side. - private long mNativeDesktopCapturerAndroid; + private volatile long mNativeDesktopCapturerAndroid; private final Handler mHandler; private final ImageHandlerFactory mImageHandlerFactory; @@ -116,6 +118,7 @@ private final ArrayList<ImageHandler> mImageHandlerQueue = new ArrayList<>(); private @Nullable WebContents mWebContents; + private volatile @Nullable WebContentsObserver mWebContentsObserver; private ScreenCapture(long nativeDesktopCapturerAndroid) { this(nativeDesktopCapturerAndroid, ImageHandler::new); @@ -155,8 +158,17 @@ sNextPickState.set(null); } + /** + * Gets the `Context` for the `Activity` the `WebContents` is associated with. + * + * <p>This can be called on either the UI thread or the desktop capture thread. If called on the + * desktop capture thread, callers must only read values from the Context and not perform any + * modifications. Reads may theoretically return stale values, so callers on the desktop capture + * thread must be ok with receiving potentially old values. + */ private @Nullable Context maybeGetContext() { - final WindowAndroid window = assumeNonNull(mWebContents).getTopLevelNativeWindow(); + if (mWebContents == null) return null; + final WindowAndroid window = mWebContents.getTopLevelNativeWindow(); if (window == null) return null; return window.getContext().get(); } @@ -179,7 +191,23 @@ sLatch.block(); mWebContents = pickState.mWebContents; - // TODO(crbug.com/352187279): Update the context if the WebContents is reparented. + + // `WebContentsObserver` modifies `WebContents` by adding an observer, and that observer + // list is not thread safe to use. So, we do this on the UI thread. We also run this + // as blocking so we know that we are observing before creating the listener - this + // guarantees that we won't miss any updates. + ThreadUtils.runOnUiThreadBlocking( + () -> { + mWebContentsObserver = + new WebContentsObserver(mWebContents) { + @Override + public void onTopLevelNativeWindowChanged( + @Nullable WindowAndroid windowAndroid) { + mHandler.post(() -> updateContext()); + } + }; + }); + final Context context = maybeGetContext(); if (context == null) return false; @@ -212,6 +240,16 @@ void destroy() { mNativeDesktopCapturerAndroid = 0; + // No need to block here since `updateContext` will early exit since + // `mNativeDesktopCapturerAndroid` is now 0. + ThreadUtils.runOnUiThread( + () -> { + if (mWebContentsObserver != null) { + mWebContentsObserver.observe(null); + mWebContentsObserver = null; + } + }); + if (mMediaProjection != null) { mMediaProjection.stop(); mMediaProjection = null; @@ -233,6 +271,25 @@ } } + private void updateContext() { + assert mHandler.getLooper().isCurrentThread(); + if (mNativeDesktopCapturerAndroid == 0) return; + if (mImageHandlerQueue.isEmpty()) return; + + final Context context = maybeGetContext(); + // It's possible to not have a Context if the WebContents is not attached to a window. + if (context == null) return; + + final CaptureState captureState = + mImageHandlerQueue.get(mImageHandlerQueue.size() - 1).getCaptureState(); + recreateListener( + new CaptureState( + captureState.width, + captureState.height, + context.getResources().getConfiguration().densityDpi, + captureState.format)); + } + private class MediaProjectionCallback extends MediaProjection.Callback { @Override public void onCapturedContentResize(int width, int height) {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java index 870c172..b739b42 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
@@ -1190,42 +1190,49 @@ @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionAnnotate() { performAriaTest("supplemental-description-annotate.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionButtonLabel() { performAriaTest("supplemental-description-button-label.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionImageButton() { performAriaTest("supplemental-description-image-button.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionLinks() { performAriaTest("supplemental-description-links.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionNav() { performAriaTest("supplemental-description-nav.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionRegion() { performAriaTest("supplemental-description-region.html"); } @Test @SmallTest + @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionSelect() { performAriaTest("supplemental-description-select.html"); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java index 57b834d6..76fb3f1 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
@@ -432,7 +432,9 @@ "Failed to remove moderate binding"); ThreadUtils.runOnUiThreadBlocking( - () -> webContents.setPrimaryMainFrameImportance(ChildProcessImportance.MODERATE)); + () -> + webContents.setPrimaryPageImportance( + ChildProcessImportance.MODERATE, ChildProcessImportance.NORMAL)); ChildProcessLauncherTestUtils.runOnLauncherThreadBlocking( () -> Assert.assertTrue(connection.isVisibleBindingBound())); }
diff --git a/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ScreenCaptureTest.java b/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ScreenCaptureTest.java index d4eaef8..33d5b94 100644 --- a/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ScreenCaptureTest.java +++ b/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ScreenCaptureTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.content.Context; @@ -39,6 +40,7 @@ import android.media.projection.MediaProjectionManager; import android.os.Build; import android.os.Handler; +import android.os.Looper; import android.util.DisplayMetrics; import android.view.Surface; import android.view.WindowMetrics; @@ -61,7 +63,8 @@ import org.robolectric.annotation.Resetter; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; +import org.chromium.content_public.browser.test.mock.MockWebContents; import org.chromium.ui.base.WindowAndroid; import java.lang.ref.WeakReference; @@ -88,7 +91,7 @@ private static final int NEW_HEIGHT_PX = 500; private static final long NATIVE_POINTER = 1L; - @Mock private WebContents mWebContents; + @Mock private MockWebContents mWebContents; @Mock private WindowAndroid mWindowAndroid; @Mock private MediaProjection mMediaProjection; @Mock private VirtualDisplay mVirtualDisplay; @@ -750,4 +753,39 @@ pendingReleases.remove().run(); verify(image).close(); } + + @Test + public void testOnTopLevelNativeWindowChanged() { + final ActivityResult activityResult = new ActivityResult(Activity.RESULT_OK, new Intent()); + ScreenCapture.onPick(mWebContents, activityResult); + ScreenCapture.onForegroundServiceRunning(true); + + assertTrue(mScreenCapture.startCapture()); + assertEquals(1, mImageHandlerStates.size()); + + final ArgumentCaptor<WebContentsObserver> observerCaptor = + ArgumentCaptor.forClass(WebContentsObserver.class); + verify(mWebContents).addObserver(observerCaptor.capture()); + final WebContentsObserver observer = observerCaptor.getValue(); + assertNotNull(observer); + + // Simulate a DPI change. + final int newDpi = TEST_DPI + 100; + updateConfiguration(mContext, TEST_WIDTH_DP, TEST_HEIGHT_DP, newDpi); + + // Simulate a window change. + observer.onTopLevelNativeWindowChanged(mWindowAndroid); + shadowOf(Looper.myLooper()).idle(); + + // Verify a new ImageHandler was created with the new DPI. + assertEquals(2, mImageHandlerStates.size()); + final var handler = mImageHandlerStates.get(1).imageHandler; + assertEquals(newDpi, handler.getCaptureState().dpi); + + // Verify VirtualDisplay was updated. The width/height in pixels should not change. + final int widthPx = mImageHandlerStates.get(0).imageHandler.getCaptureState().width; + final int heightPx = mImageHandlerStates.get(0).imageHandler.getCaptureState().height; + verify(mVirtualDisplay).resize(widthPx, heightPx, newDpi); + verify(mVirtualDisplay).setSurface(handler.getSurface()); + } }
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 07165bf2..17cf4554 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -1502,12 +1502,27 @@ // Returns the primary main frame importance. This is for testing only. virtual ChildProcessImportance GetPrimaryMainFrameImportanceForTesting() = 0; - // Set an importance of the page to the primary main frame. + // Returns the primary page's subframe importance cached. This is for testing + // only. + virtual ChildProcessImportance + GetPrimaryPageSubframeImportanceForTesting() = 0; + + // Set importance for main frame and subframes of the page in the primary + // frame tree. // - // Note this does not affect importance of subframe processes or main frames - // processeses for non-primary pages. - virtual void SetPrimaryMainFrameImportance( - ChildProcessImportance importance) = 0; + // The subframe importance will be set to new subframes in the primary frame + // tree when they are created as well. Also the subframe importance will be + // set to subframes when they are restored (e.g. from BFCache) to the primary + // frame tree. + // + // SubframePriorityContribution and SubframeImportance features are required + // to set subframe importance to other than NORMAL. + // + // The subframe_importance must be less than or equal to the + // main_frame_importance. + virtual void SetPrimaryPageImportance( + ChildProcessImportance main_frame_importance, + ChildProcessImportance subframe_importance) = 0; #endif // BUILDFLAG(IS_ANDROID) // Returns true if the WebContents has completed its first meaningful paint
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index fe709f1..f4eadeee 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -738,6 +738,14 @@ "Prerender2ReuseHost", base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, the feature parameter allows all the prerender hosts for +// DSE search results to be reused. +BASE_FEATURE_PARAM(bool, + kPrerender2ReuseSearchResultHost, + &features::kPrerender2ReuseHost, + "reuse_search_host", + false); + // If enabled, browser-initiated prefetch is allowed. // Please see crbug.com/40946257 for more details. BASE_FEATURE(kPrefetchBrowserInitiatedTriggers, @@ -1203,6 +1211,12 @@ &kSubframeProcessReuseThresholds, "SubframeProcessReuseMemoryThreshold", 512 * 1024 * 1024u}; +// When enabled, RenderWidgetHost in BFCache doesn't contribute to the priority +// of the renderer process. +BASE_FEATURE(kSubframePriorityContribution, + "SubframePriorityContribution", + base::FEATURE_DISABLED_BY_DEFAULT); + // Disallows window.{alert, prompt, confirm} if triggered inside a subframe that // is not same origin with the main frame. BASE_FEATURE(kSuppressDifferentOriginSubframeJSDialogs, @@ -1507,6 +1521,11 @@ // enables the associated UI. BASE_FEATURE(kSmartZoom, "SmartZoom", base::FEATURE_DISABLED_BY_DEFAULT); +// Enables setting the importance for subframes in WebContents. +BASE_FEATURE(kSubframeImportance, + "SubframeImportance", + base::FEATURE_DISABLED_BY_DEFAULT); + // Skips clearing objects on main document ready. Only has an impact // when gin java bridge is enabled. BASE_FEATURE(kGinJavaBridgeMojoSkipClearObjectsOnMainDocumentReady,
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index be94bcb..f3c03a2 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -190,6 +190,8 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchPrerenderIntegration); CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchProxy); CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrerender2ReuseHost); +CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(bool, + kPrerender2ReuseSearchResultHost); CONTENT_EXPORT BASE_DECLARE_FEATURE(kFeaturePolicyHeader); CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchBrowserInitiatedTriggers); CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrivacySandboxAdsAPIsOverride); @@ -275,6 +277,7 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kSubframeProcessReuseThresholds); CONTENT_EXPORT extern const base::FeatureParam<double> kSubframeProcessReuseMemoryThreshold; +CONTENT_EXPORT BASE_DECLARE_FEATURE(kSubframePriorityContribution); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSuppressDifferentOriginSubframeJSDialogs); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSyntheticPointerActions); CONTENT_EXPORT BASE_DECLARE_FEATURE(kTouchDragAndContextMenu); @@ -343,6 +346,7 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kGroupRebindingForGroupImportance); CONTENT_EXPORT BASE_DECLARE_FEATURE(kReduceGpuPriorityOnBackground); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSmartZoom); +CONTENT_EXPORT BASE_DECLARE_FEATURE(kSubframeImportance); CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaScreenCapturing); #endif // BUILDFLAG(IS_ANDROID)
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java index 5d5b538..76d2548 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
@@ -169,7 +169,7 @@ public void stop() {} @Override - public void setPrimaryMainFrameImportance(int importance) {} + public void setPrimaryPageImportance(int mainFrameImportance, int subframeImportance) {} @Override public void suspendAllMediaPlayers() {}
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index 06bf33a2..2d7658c 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -58,6 +58,7 @@ #include "content/browser/renderer_host/render_frame_metadata_provider_impl.h" #include "content/browser/renderer_host/render_frame_proxy_host.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_factory.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" #include "content/browser/screen_orientation/screen_orientation_provider.h" @@ -4902,4 +4903,164 @@ return observer.Wait(); } +CreateNewPopupWidgetInterceptor::CreateNewPopupWidgetInterceptor( + RenderFrameHost* rfh, + base::OnceCallback<void(RenderWidgetHost*)> did_create_callback) + : swapped_impl_(static_cast<RenderFrameHostImpl*>(rfh) + ->local_frame_host_receiver_for_testing(), + this), + did_create_callback_(std::move(did_create_callback)) {} + +CreateNewPopupWidgetInterceptor::~CreateNewPopupWidgetInterceptor() = default; + +void CreateNewPopupWidgetInterceptor::CreateNewPopupWidget( + mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost> + blink_popup_widget_host, + mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost> blink_widget_host, + mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget) { + class PopupWidgetCreationObserver : public RenderWidgetHostFactory { + public: + PopupWidgetCreationObserver() { RegisterFactory(this); } + + ~PopupWidgetCreationObserver() override { UnregisterFactory(); } + + // RenderWidgetHostFactory overrides: + RenderWidgetHostImpl* CreateSelfOwnedRenderWidgetHost( + FrameTree* frame_tree, + RenderWidgetHostDelegate* delegate, + base::SafeRef<SiteInstanceGroup> site_instance_group, + int32_t routing_id, + bool hidden) override { + CHECK(!last_created_widget_); + last_created_widget_ = + RenderWidgetHostFactory::CreateSelfOwnedRenderWidgetHost( + frame_tree, delegate, std::move(site_instance_group), routing_id, + hidden); + return last_created_widget_; + } + + RenderWidgetHostImpl* TakeLastCreatedWidget() { + return std::exchange(last_created_widget_, nullptr); + } + + private: + raw_ptr<RenderWidgetHostImpl> last_created_widget_; + }; + + PopupWidgetCreationObserver creation_observer; + + GetForwardingInterface()->CreateNewPopupWidget( + std::move(blink_popup_widget_host), std::move(blink_widget_host), + std::move(blink_widget)); + + if (!did_create_callback_) { + return; + } + + if (auto* widget = creation_observer.TakeLastCreatedWidget(); widget) { + std::move(did_create_callback_).Run(widget); + } +} + +blink::mojom::LocalFrameHost* +CreateNewPopupWidgetInterceptor::GetForwardingInterface() { + return swapped_impl_.old_impl(); +} + +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) +ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::ShowPopupMenuInterceptor( + RenderFrameHost* rfh, + base::OnceCallback<void(const gfx::Rect&)> did_show_popup_menu_callback) + : swapped_impl_(static_cast<RenderFrameHostImpl*>(rfh) + ->local_frame_host_receiver_for_testing(), + this), + did_show_popup_menu_callback_(std::move(did_show_popup_menu_callback)) {} + +ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::~ShowPopupMenuInterceptor() = + default; + +void ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::ShowPopupMenu( + mojo::PendingRemote<blink::mojom::PopupMenuClient> popup_client, + const gfx::Rect& bounds, + double font_size, + int32_t selected_item, + std::vector<blink::mojom::MenuItemPtr> menu_items, + bool right_aligned, + bool allow_multiple_selection) { + if (did_show_popup_menu_callback_) { + std::move(did_show_popup_menu_callback_).Run(bounds); + mojo::Remote<blink::mojom::PopupMenuClient>(std::move(popup_client)) + ->DidCancel(); + return; + } + + GetForwardingInterface()->ShowPopupMenu( + std::move(popup_client), bounds, font_size, selected_item, + std::move(menu_items), right_aligned, allow_multiple_selection); +} + +blink::mojom::LocalFrameHost* +ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::GetForwardingInterface() { + return swapped_impl_.old_impl(); +} +#endif + +ShowPopupWidgetWaiter::ShowPopupWidgetWaiter(WebContents* web_contents, + RenderFrameHost* frame_host) + : create_new_popup_widget_interceptor_( + static_cast<RenderFrameHostImpl*>(frame_host), + base::BindOnce(&ShowPopupWidgetWaiter::DidCreatePopupWidget, + base::Unretained(this))), +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) + show_popup_menu_interceptor_( + frame_host, + base::BindOnce(&ShowPopupWidgetWaiter::DidShowPopupMenu, + base::Unretained(this))), +#endif + + frame_host_(frame_host) { +} + +ShowPopupWidgetWaiter::~ShowPopupWidgetWaiter() { + if (auto* rwhi = RenderWidgetHostImpl::FromID(process_id_, routing_id_)) { + std::ignore = + rwhi->popup_widget_host_receiver_for_testing().SwapImplForTesting(rwhi); + } +} + +void ShowPopupWidgetWaiter::Wait() { + run_loop_.Run(); +} + +blink::mojom::PopupWidgetHost* ShowPopupWidgetWaiter::GetForwardingInterface() { + DCHECK_NE(IPC::mojom::kRoutingIdNone, routing_id_); + return RenderWidgetHostImpl::FromID(process_id_, routing_id_); +} + +void ShowPopupWidgetWaiter::ShowPopup(const gfx::Rect& initial_rect, + const gfx::Rect& initial_anchor_rect, + ShowPopupCallback callback) { + GetForwardingInterface()->ShowPopup(initial_rect, initial_anchor_rect, + std::move(callback)); + initial_rect_ = initial_rect; + run_loop_.Quit(); +} + +void ShowPopupWidgetWaiter::DidCreatePopupWidget( + RenderWidgetHost* render_widget_host) { + process_id_ = render_widget_host->GetProcess()->GetDeprecatedID(); + routing_id_ = render_widget_host->GetRoutingID(); + // Swapped back in destructor from process_id_ and routing_id_ lookup. + std::ignore = static_cast<RenderWidgetHostImpl*>(render_widget_host) + ->popup_widget_host_receiver_for_testing() + .SwapImplForTesting(this); +} + +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) +void ShowPopupWidgetWaiter::DidShowPopupMenu(const gfx::Rect& bounds) { + initial_rect_ = bounds; + run_loop_.Quit(); +} +#endif + } // namespace content
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 9922a00..1452fc56 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -67,9 +67,12 @@ #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom-test-utils.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" +#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h" #include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h" #include "third_party/blink/public/mojom/keyboard_lock/keyboard_lock.mojom-shared.h" #include "third_party/blink/public/mojom/navigation/navigation_params.mojom-shared.h" +#include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h" +#include "third_party/blink/public/mojom/page/widget.mojom.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_tree_update.h" @@ -2615,6 +2618,106 @@ // call. [[nodiscard]] bool WaitForDOMContentLoaded(RenderFrameHost* rfh); +// One-shot helper that listens for creation of a new popup widget. +class CreateNewPopupWidgetInterceptor + : public blink::mojom::LocalFrameHostInterceptorForTesting { + public: + explicit CreateNewPopupWidgetInterceptor( + RenderFrameHost* rfh, + base::OnceCallback<void(RenderWidgetHost*)> did_create_callback); + + ~CreateNewPopupWidgetInterceptor() override; + + // LocalFrameHost overrides: + void CreateNewPopupWidget( + mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost> + blink_popup_widget_host, + mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost> + blink_widget_host, + mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget) + override; + + // LocalFrameHostInterceptorForTesting overrides: + blink::mojom::LocalFrameHost* GetForwardingInterface() override; + + private: + mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost> + swapped_impl_; + base::OnceCallback<void(RenderWidgetHost*)> did_create_callback_; +}; + +class ShowPopupWidgetWaiter + : public blink::mojom::PopupWidgetHostInterceptorForTesting { + public: + ShowPopupWidgetWaiter(WebContents* web_contents, RenderFrameHost* frame_host); + + ShowPopupWidgetWaiter(const ShowPopupWidgetWaiter&) = delete; + ShowPopupWidgetWaiter& operator=(const ShowPopupWidgetWaiter&) = delete; + + ~ShowPopupWidgetWaiter() override; + + gfx::Rect last_initial_rect() const { return initial_rect_; } + + int last_routing_id() const { return routing_id_; } + + // Waits until a popup request is received. + void Wait(); + + private: +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) + // Helper that waits for a `ShowPopupMenu()` call and then invokes the + // observer callback with the requested bounds. The actual call to show the + // popup menu is treated as if it were cancelled. + class ShowPopupMenuInterceptor + : public blink::mojom::LocalFrameHostInterceptorForTesting { + public: + explicit ShowPopupMenuInterceptor(RenderFrameHost* rfh, + base::OnceCallback<void(const gfx::Rect&)> + did_show_popup_menu_callback); + ~ShowPopupMenuInterceptor() override; + + // LocalFrameHost overrides: + void ShowPopupMenu( + mojo::PendingRemote<blink::mojom::PopupMenuClient> popup_client, + const gfx::Rect& bounds, + double font_size, + int32_t selected_item, + std::vector<blink::mojom::MenuItemPtr> menu_items, + bool right_aligned, + bool allow_multiple_selection) override; + + // LocalFrameHostInterceptorForTesting overrides: + blink::mojom::LocalFrameHost* GetForwardingInterface() override; + + private: + mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost> + swapped_impl_; + base::OnceCallback<void(const gfx::Rect&)> did_show_popup_menu_callback_; + }; + + void DidShowPopupMenu(const gfx::Rect& bounds); +#endif + + // Callback bound for creating a popup widget. + void DidCreatePopupWidget(RenderWidgetHost* render_widget_host); + + // blink::mojom::PopupWidgetHostInterceptorForTesting: + blink::mojom::PopupWidgetHost* GetForwardingInterface() override; + void ShowPopup(const gfx::Rect& initial_rect, + const gfx::Rect& initial_anchor_rect, + ShowPopupCallback callback) override; + + CreateNewPopupWidgetInterceptor create_new_popup_widget_interceptor_; +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) + ShowPopupMenuInterceptor show_popup_menu_interceptor_; +#endif + base::RunLoop run_loop_; + gfx::Rect initial_rect_; + int32_t routing_id_ = IPC::mojom::kRoutingIdNone; + int32_t process_id_ = 0; + const raw_ptr<RenderFrameHost> frame_host_; +}; + } // namespace content #endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
diff --git a/content/public/test/local_network_access_util.cc b/content/public/test/local_network_access_util.cc index a36425a1..9e640abb 100644 --- a/content/public/test/local_network_access_util.cc +++ b/content/public/test/local_network_access_util.cc
@@ -19,8 +19,25 @@ bool DeprecationTrialURLLoaderInterceptor::HandleRequest( RequestParams* request_params) const { const GURL& url = request_params->url_request.url; - if (url == EnabledHttpUrl()) { - HandleEnabledHttpUrlRequest(*request_params); + if (url == EnabledHttpUrl() || url == EnabledHttpWorkerUrl()) { + HandleEnabledHttpUrlRequest(*request_params, url == EnabledHttpWorkerUrl()); + return true; + } + + if (url == enabled_http_worker_js_url_) { + // Served off of the http://enabled.test domain, but no origin trial token + // served. This is needed because the worker html hosting will request the + // JS based on the worker hosting domain which isn't mapped to the right + // port for the embedded test server, and so needs to be served from this + // interceptor. + // + // TODO(crbug.com/395895368): remove this functionality when we move away + // from using this interceptor for browser tests and use a library function + // like in https://crbug.com/40860522#comment8. + URLLoaderInterceptor::WriteResponse( + "chrome/test/data/private_network_access/" + "fetch-from-worker-as-public-address.js", + request_params->client.get()); return true; } @@ -38,8 +55,9 @@ } void DeprecationTrialURLLoaderInterceptor::HandleEnabledHttpUrlRequest( - RequestParams& request_params) const { - constexpr char kHeaders[] = // + RequestParams& request_params, + bool use_worker_html) const { + std::string headers = // "HTTP/1.1 200 OK\n" // "Content-Type: text/html\n" // // Use CSP to make the page `public`, even though it is served with no @@ -61,8 +79,15 @@ "kxvY2FsTmV0d29ya0FjY2Vzc05vblNlY3VyZUNvbnRleHRBbGxvd2VkIiwgImV4cGlyeSI6I" "DE4MzkxOTU4NTZ9" "\n\n"; - URLLoaderInterceptor::WriteResponse(kHeaders, "", - request_params.client.get()); + if (use_worker_html) { + URLLoaderInterceptor::WriteResponse( + "chrome/test/data/private_network_access/" + "fetch-from-worker-as-public-address.html", + request_params.client.get(), &headers); + } else { + URLLoaderInterceptor::WriteResponse(headers, "", + request_params.client.get()); + } } void DeprecationTrialURLLoaderInterceptor::HandleEnabledHttpsUrlRequest(
diff --git a/content/public/test/local_network_access_util.h b/content/public/test/local_network_access_util.h index f41d7a06..1043e177 100644 --- a/content/public/test/local_network_access_util.h +++ b/content/public/test/local_network_access_util.h
@@ -32,6 +32,7 @@ // Returns the URL of a document that bears a valid trial token. GURL EnabledHttpUrl() const { return enabled_http_url_; } GURL EnabledHttpsUrl() const { return enabled_https_url_; } + GURL EnabledHttpWorkerUrl() const { return enabled_http_worker_url_; } // Returns the URL of a document that does not bear a valid trial token. GURL DisabledHttpUrl() const { return disabled_http_url_; } @@ -41,7 +42,8 @@ using RequestParams = URLLoaderInterceptor::RequestParams; bool HandleRequest(RequestParams* request_params) const; - void HandleEnabledHttpUrlRequest(RequestParams& request_params) const; + void HandleEnabledHttpUrlRequest(RequestParams& request_params, + bool use_worker_html) const; void HandleEnabledHttpsUrlRequest(RequestParams& request_params) const; void HandleDisabledUrlRequest(RequestParams& request_params) const; @@ -49,6 +51,9 @@ const GURL disabled_http_url_{"http://disabled.test/"}; const GURL enabled_https_url_{"https://enabled.test/"}; const GURL disabled_https_url_{"https://disabled.test/"}; + const GURL enabled_http_worker_url_{"http://enabled.test/worker"}; + const GURL enabled_http_worker_js_url_{ + "http://enabled.test/fetch-from-worker-as-public-address.js"}; URLLoaderInterceptor interceptor_; };
diff --git a/content/public/test/prerender_test_util.cc b/content/public/test/prerender_test_util.cc index 953a859..e9249041 100644 --- a/content/public/test/prerender_test_util.cc +++ b/content/public/test/prerender_test_util.cc
@@ -382,6 +382,10 @@ bool was_activated() const { return was_activated_; } + bool WasHostReused() const { + return last_status_ == PrerenderFinalStatus::kPrerenderHostReused; + } + private: void OnTrigger(WebContents& web_contents, const GURL& url) { PrerenderHost* host = @@ -441,6 +445,10 @@ return impl_->was_activated(); } +bool PrerenderHostObserver::WasHostReused() const { + return impl_->WasHostReused(); +} + PrerenderHostCreationWaiter::PrerenderHostCreationWaiter() { PrerenderHost::SetHostCreationCallbackForTesting( base::BindLambdaForTesting([&](FrameTreeNodeId host_id) {
diff --git a/content/public/test/prerender_test_util.h b/content/public/test/prerender_test_util.h index fe562d4e..5c5ec2c 100644 --- a/content/public/test/prerender_test_util.h +++ b/content/public/test/prerender_test_util.h
@@ -89,6 +89,9 @@ // True if the PrerenderHost was activated to be the primary page. bool was_activated() const; + // Returns true if the PrerenderHost is reused. + bool WasHostReused() const; + private: std::unique_ptr<PrerenderHostObserverImpl> impl_; };
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc index 51cb2352..a8615d2c 100644 --- a/content/test/content_browser_test_utils_internal.cc +++ b/content/test/content_browser_test_utils_internal.cc
@@ -615,161 +615,6 @@ return static_cast<bad_message::BadMessageReason>(internal_result.value()); } -CreateNewPopupWidgetInterceptor::CreateNewPopupWidgetInterceptor( - RenderFrameHostImpl* rfh, - base::OnceCallback<void(RenderWidgetHostImpl*)> did_create_callback) - : swapped_impl_(rfh->local_frame_host_receiver_for_testing(), this), - did_create_callback_(std::move(did_create_callback)) {} - -CreateNewPopupWidgetInterceptor::~CreateNewPopupWidgetInterceptor() = default; - -void CreateNewPopupWidgetInterceptor::CreateNewPopupWidget( - mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost> - blink_popup_widget_host, - mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost> blink_widget_host, - mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget) { - class PopupWidgetCreationObserver : public RenderWidgetHostFactory { - public: - PopupWidgetCreationObserver() { RegisterFactory(this); } - - ~PopupWidgetCreationObserver() override { UnregisterFactory(); } - - // RenderWidgetHostFactory overrides: - RenderWidgetHostImpl* CreateSelfOwnedRenderWidgetHost( - FrameTree* frame_tree, - RenderWidgetHostDelegate* delegate, - base::SafeRef<SiteInstanceGroup> site_instance_group, - int32_t routing_id, - bool hidden) override { - CHECK(!last_created_widget_); - last_created_widget_ = - RenderWidgetHostFactory::CreateSelfOwnedRenderWidgetHost( - frame_tree, delegate, std::move(site_instance_group), routing_id, - hidden); - return last_created_widget_; - } - - RenderWidgetHostImpl* TakeLastCreatedWidget() { - return std::exchange(last_created_widget_, nullptr); - } - - private: - raw_ptr<RenderWidgetHostImpl> last_created_widget_; - }; - - PopupWidgetCreationObserver creation_observer; - - GetForwardingInterface()->CreateNewPopupWidget( - std::move(blink_popup_widget_host), std::move(blink_widget_host), - std::move(blink_widget)); - - if (!did_create_callback_) { - return; - } - - if (auto* widget = creation_observer.TakeLastCreatedWidget(); widget) { - std::move(did_create_callback_).Run(widget); - } -} - -blink::mojom::LocalFrameHost* -CreateNewPopupWidgetInterceptor::GetForwardingInterface() { - return swapped_impl_.old_impl(); -} - -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) -ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::ShowPopupMenuInterceptor( - RenderFrameHostImpl* rfh, - base::OnceCallback<void(const gfx::Rect&)> did_show_popup_menu_callback) - : swapped_impl_(rfh->local_frame_host_receiver_for_testing(), this), - did_show_popup_menu_callback_(std::move(did_show_popup_menu_callback)) {} - -ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::~ShowPopupMenuInterceptor() = - default; - -void ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::ShowPopupMenu( - mojo::PendingRemote<blink::mojom::PopupMenuClient> popup_client, - const gfx::Rect& bounds, - double font_size, - int32_t selected_item, - std::vector<blink::mojom::MenuItemPtr> menu_items, - bool right_aligned, - bool allow_multiple_selection) { - if (did_show_popup_menu_callback_) { - std::move(did_show_popup_menu_callback_).Run(bounds); - mojo::Remote<blink::mojom::PopupMenuClient>(std::move(popup_client)) - ->DidCancel(); - return; - } - - GetForwardingInterface()->ShowPopupMenu( - std::move(popup_client), bounds, font_size, selected_item, - std::move(menu_items), right_aligned, allow_multiple_selection); -} - -blink::mojom::LocalFrameHost* -ShowPopupWidgetWaiter::ShowPopupMenuInterceptor::GetForwardingInterface() { - return swapped_impl_.old_impl(); -} -#endif - -ShowPopupWidgetWaiter::ShowPopupWidgetWaiter(WebContentsImpl* web_contents, - RenderFrameHostImpl* frame_host) - : create_new_popup_widget_interceptor_( - frame_host, - base::BindOnce(&ShowPopupWidgetWaiter::DidCreatePopupWidget, - base::Unretained(this))), -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) - show_popup_menu_interceptor_( - frame_host, - base::BindOnce(&ShowPopupWidgetWaiter::DidShowPopupMenu, - base::Unretained(this))), -#endif - - frame_host_(frame_host) { -} - -ShowPopupWidgetWaiter::~ShowPopupWidgetWaiter() { - if (auto* rwhi = RenderWidgetHostImpl::FromID(process_id_, routing_id_)) { - std::ignore = - rwhi->popup_widget_host_receiver_for_testing().SwapImplForTesting(rwhi); - } -} - -void ShowPopupWidgetWaiter::Wait() { - run_loop_.Run(); -} - -blink::mojom::PopupWidgetHost* ShowPopupWidgetWaiter::GetForwardingInterface() { - DCHECK_NE(IPC::mojom::kRoutingIdNone, routing_id_); - return RenderWidgetHostImpl::FromID(process_id_, routing_id_); -} - -void ShowPopupWidgetWaiter::ShowPopup(const gfx::Rect& initial_rect, - const gfx::Rect& initial_anchor_rect, - ShowPopupCallback callback) { - GetForwardingInterface()->ShowPopup(initial_rect, initial_anchor_rect, - std::move(callback)); - initial_rect_ = initial_rect; - run_loop_.Quit(); -} - -void ShowPopupWidgetWaiter::DidCreatePopupWidget( - RenderWidgetHostImpl* render_widget_host) { - process_id_ = render_widget_host->GetProcess()->GetDeprecatedID(); - routing_id_ = render_widget_host->GetRoutingID(); - // Swapped back in destructor from process_id_ and routing_id_ lookup. - std::ignore = render_widget_host->popup_widget_host_receiver_for_testing() - .SwapImplForTesting(this); -} - -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) -void ShowPopupWidgetWaiter::DidShowPopupMenu(const gfx::Rect& bounds) { - initial_rect_ = bounds; - run_loop_.Quit(); -} -#endif - UnresponsiveRendererObserver::UnresponsiveRendererObserver( WebContents* web_contents) : WebContentsObserver(web_contents) {}
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h index b2138941..01aa771 100644 --- a/content/test/content_browser_test_utils_internal.h +++ b/content/test/content_browser_test_utils_internal.h
@@ -45,7 +45,6 @@ class FrameTreeNode; class RenderFrameHost; class RenderFrameHostImpl; -class RenderWidgetHostImpl; class Shell; class SiteInstance; class SiteInstanceGroup; @@ -328,107 +327,6 @@ RenderProcessHostKillWaiter internal_waiter_; }; -// One-shot helper that listens for creation of a new popup widget. -class CreateNewPopupWidgetInterceptor - : public blink::mojom::LocalFrameHostInterceptorForTesting { - public: - explicit CreateNewPopupWidgetInterceptor( - RenderFrameHostImpl* rfh, - base::OnceCallback<void(RenderWidgetHostImpl*)> did_create_callback); - - ~CreateNewPopupWidgetInterceptor() override; - - // LocalFrameHost overrides: - void CreateNewPopupWidget( - mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost> - blink_popup_widget_host, - mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost> - blink_widget_host, - mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget) - override; - - // LocalFrameHostInterceptorForTesting overrides: - blink::mojom::LocalFrameHost* GetForwardingInterface() override; - - private: - mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost> - swapped_impl_; - base::OnceCallback<void(RenderWidgetHostImpl*)> did_create_callback_; -}; - -class ShowPopupWidgetWaiter - : public blink::mojom::PopupWidgetHostInterceptorForTesting { - public: - ShowPopupWidgetWaiter(WebContentsImpl* web_contents, - RenderFrameHostImpl* frame_host); - - ShowPopupWidgetWaiter(const ShowPopupWidgetWaiter&) = delete; - ShowPopupWidgetWaiter& operator=(const ShowPopupWidgetWaiter&) = delete; - - ~ShowPopupWidgetWaiter() override; - - gfx::Rect last_initial_rect() const { return initial_rect_; } - - int last_routing_id() const { return routing_id_; } - - // Waits until a popup request is received. - void Wait(); - - private: -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) - // Helper that waits for a `ShowPopupMenu()` call and then invokes the - // observer callback with the requested bounds. The actual call to show the - // popup menu is treated as if it were cancelled. - class ShowPopupMenuInterceptor - : public blink::mojom::LocalFrameHostInterceptorForTesting { - public: - explicit ShowPopupMenuInterceptor(RenderFrameHostImpl* rfh, - base::OnceCallback<void(const gfx::Rect&)> - did_show_popup_menu_callback); - ~ShowPopupMenuInterceptor() override; - - // LocalFrameHost overrides: - void ShowPopupMenu( - mojo::PendingRemote<blink::mojom::PopupMenuClient> popup_client, - const gfx::Rect& bounds, - double font_size, - int32_t selected_item, - std::vector<blink::mojom::MenuItemPtr> menu_items, - bool right_aligned, - bool allow_multiple_selection) override; - - // LocalFrameHostInterceptorForTesting overrides: - blink::mojom::LocalFrameHost* GetForwardingInterface() override; - - private: - mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost> - swapped_impl_; - base::OnceCallback<void(const gfx::Rect&)> did_show_popup_menu_callback_; - }; - - void DidShowPopupMenu(const gfx::Rect& bounds); -#endif - - // Callback bound for creating a popup widget. - void DidCreatePopupWidget(RenderWidgetHostImpl* render_widget_host); - - // blink::mojom::PopupWidgetHostInterceptorForTesting: - blink::mojom::PopupWidgetHost* GetForwardingInterface() override; - void ShowPopup(const gfx::Rect& initial_rect, - const gfx::Rect& initial_anchor_rect, - ShowPopupCallback callback) override; - - CreateNewPopupWidgetInterceptor create_new_popup_widget_interceptor_; -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) - ShowPopupMenuInterceptor show_popup_menu_interceptor_; -#endif - base::RunLoop run_loop_; - gfx::Rect initial_rect_; - int32_t routing_id_ = IPC::mojom::kRoutingIdNone; - int32_t process_id_ = 0; - const raw_ptr<RenderFrameHostImpl> frame_host_; -}; - // This observer waits until WebContentsObserver::OnRendererUnresponsive // notification. class UnresponsiveRendererObserver : public WebContentsObserver {
diff --git a/content/test/data/accessibility/aria/supplemental-description-button-label-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-button-label-expected-android-external.txt index 785ddfd..b4a71e3a 100644 --- a/content/test/data/accessibility/aria/supplemental-description-button-label-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-button-label-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++Button text:"Submit form" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", roleDescription="button"] +++++Button contentDescription:"Submit form" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", roleDescription="button"]
diff --git a/content/test/data/accessibility/aria/supplemental-description-image-button-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-image-button-expected-android-external.txt index 594d1b1..f38ae84 100644 --- a/content/test/data/accessibility/aria/supplemental-description-image-button-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-image-button-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++Button text:"Close" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", roleDescription="button"] +++++Button contentDescription:"Close" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", roleDescription="button"]
diff --git a/content/test/data/accessibility/aria/supplemental-description-links-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-links-expected-android-external.txt index fd038d3..1fdb981 100644 --- a/content/test/data/accessibility/aria/supplemental-description-links-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-links-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++TextView text:"Seminole tax hike: Seminole city managers are proposing a 75% increase in property taxes for the coming fiscal year. " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++View text:"null" contentDescription:"Read more about Seminole tax hike" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/aria/taxhike.html"] +++++View text:"taxhike" contentDescription:"Read more about Seminole tax hike" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/aria/taxhike.html"] ++++++TextView text:"[Read more...]" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"]
diff --git a/content/test/data/accessibility/aria/supplemental-description-nav-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-nav-expected-android-external.txt index 5cb7fdf..c410e77 100644 --- a/content/test/data/accessibility/aria/supplemental-description-nav-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-nav-expected-android-external.txt
@@ -1,6 +1,6 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"The nav element defines a set of navigation links:" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] -++NavigationView text:"programming languages" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="navigation", roleDescription="navigation"] +++NavigationView containerTitle:"programming languages" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="navigation", roleDescription="navigation"] ++++View text:"null" contentDescription:"HTML" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///html/"] ++++++TextView text:"HTML" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"] ++++TextView text:" | " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
diff --git a/content/test/data/accessibility/aria/supplemental-description-region-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-region-expected-android-external.txt index f17adbbe..37eece3 100644 --- a/content/test/data/accessibility/aria/supplemental-description-region-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-region-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++View text:"Example" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="region", roleDescription="region"] +++++View containerTitle:"Example" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="region", roleDescription="region"] ++++++TextView text:"The region role should be reserved for sections of content sufficiently important that users will likely want to navigate to the section easily and to have it listed in a summary of the page." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/aria/supplemental-description-select-expected-android-external.txt b/content/test/data/accessibility/aria/supplemental-description-select-expected-android-external.txt index a71620d..83fa0f6 100644 --- a/content/test/data/accessibility/aria/supplemental-description-select-expected-android-external.txt +++ b/content/test/data/accessibility/aria/supplemental-description-select-expected-android-external.txt
@@ -1,6 +1,6 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++View text:"Volvo" hint:"choose a car" viewIdResName:"cars" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", hint="choose a car", roleDescription="menu pop up button"] +++++View text:"Volvo" viewIdResName:"cars" supplementalDescription:"choose a car" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"] ++++++View notVisibleToUser CollectionInfo:[selection_mode_single, rows=4, cols=1] actions:[AX_FOCUS] bundle:[chromeRole="menuListPopup"] ++++++++View text:"Volvo" clickable focusable selected CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"] ++++++++View text:"Saab" clickable focusable notVisibleToUser CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="menuListOption", clickableScore="300"]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index cf1f5ff3..a405b3e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -501,7 +501,9 @@ crbug.com/415830130 [ android android-chromium ] Pixel_ViewTransitionsCapture_TreesInViz [ RetryOnFailure ] crbug.com/415830130 [ android android-chromium ] Pixel_WebGLGreenTriangle_AA_Alpha_TreesInViz [ RetryOnFailure ] crbug.com/415830130 [ android android-chromium ] Pixel_SolidColorBackground_TreesInViz [ Failure ] -crbug.com/415830130 [ fuchsia ] Pixel_SolidColorBackground_TreesInViz [ Failure ] +crbug.com/415830130 [ angle-swiftshader fuchsia fuchsia-board-qemu-x64 google-0xc0de ] Pixel_SolidColorBackground_TreesInViz [ Failure ] +crbug.com/415830130 [ angle-vulkan arm fuchsia fuchsia-board-astro no-asan no-clang-coverage ] Pixel_SolidColorBackground_TreesInViz [ Failure ] +crbug.com/415830130 [ angle-vulkan arm fuchsia fuchsia-board-sherlock no-asan no-clang-coverage ] Pixel_SolidColorBackground_TreesInViz [ Failure ] crbug.com/415830130 [ mac ] Pixel_RenderPasses_TreesInViz [ Failure ] crbug.com/415830130 [ linux ] Pixel_RenderPasses_TreesInViz [ Failure ] crbug.com/415830130 [ chromeos chromeos-board-amd64-generic ] Pixel_RenderPasses_TreesInViz [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt index 871e49a..3f6f1fb3 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -134,21 +134,17 @@ crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_Encode_offscreen_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_Encode_sw_decoder_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_arraybuffer_av01.0.04M.08 [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_arraybuffer_avc1.42001E [ Failure ] +crbug.com/430338387 [ nvidia-0x2783 win11 ] WebCodecs_D3D12_EncodeDecode_arraybuffer_avc1.42001E [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_camera_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_capture_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_hw_decoder_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_offscreen_av01.0.04M.08 [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_offscreen_avc1.42001E [ Failure ] +crbug.com/430338387 [ nvidia-0x2783 win11 ] WebCodecs_D3D12_EncodeDecode_offscreen_avc1.42001E [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodeDecode_sw_decoder_av01.0.04M.08 [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodingModes_offscreen_av01.0.04M.08_constant_quality [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodingModes_offscreen_av01.0.04M.08_constant_realtime [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodingModes_offscreen_av01.0.04M.08_variable_quality [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_EncodingModes_offscreen_av01.0.04M.08_variable_realtime [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_FrameSizeChange_av01.0.04M.08_arraybuffer [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_FrameSizeChange_av01.0.04M.08_camera [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_FrameSizeChange_av01.0.04M.08_capture [ Failure ] -crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_FrameSizeChange_av01.0.04M.08_sw_decoder [ Failure ] crbug.com/430338387 [ win11 nvidia ] WebCodecs_D3D12_MixedSourceEncoding_av01.0.04M.08 [ Failure ] @@ -246,7 +242,7 @@ # Flaky failures that started when upgrading to Mac 15.4 crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_*hvc*prefer-hardware* [ Failure ] crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_detail [ Failure ] -crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_motion [ Failure ] +crbug.com/416294710 [ angle-metal intel-0x3e9b sequoia ] WebCodecs_ContentHint_hvc1.1.6.L123.00_motion [ Failure ] crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_text [ Failure ] crbug.com/416294710 [ graphite-disabled intel-0x3e9b sequoia ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_arraybuffer [ Failure ] crbug.com/416294710 [ graphite-disabled intel-0x3e9b sequoia ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_capture [ Failure ]
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc index a71f61b..9d6a07b 100644 --- a/content/test/test_navigation_url_loader.cc +++ b/content/test/test_navigation_url_loader.cc
@@ -37,9 +37,9 @@ } void TestNavigationURLLoader::FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) { + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) { DCHECK_EQ(loader_type_, NavigationURLLoader::LoaderType::kRegular); redirect_count_++; }
diff --git a/content/test/test_navigation_url_loader.h b/content/test/test_navigation_url_loader.h index 6eef45c..63cff21 100644 --- a/content/test/test_navigation_url_loader.h +++ b/content/test/test_navigation_url_loader.h
@@ -32,9 +32,9 @@ // NavigationURLLoader implementation. void Start() override; void FollowRedirect( - const std::vector<std::string>& removed_headers, - const net::HttpRequestHeaders& modified_headers, - const net::HttpRequestHeaders& modified_cors_exempt_headers) override; + std::vector<std::string> removed_headers, + net::HttpRequestHeaders modified_headers, + net::HttpRequestHeaders modified_cors_exempt_headers) override; bool SetNavigationTimeout(base::TimeDelta timeout) override; void CancelNavigationTimeout() override;
diff --git a/content/web_test/browser/web_test_browser_main_platform_support_win.cc b/content/web_test/browser/web_test_browser_main_platform_support_win.cc index 6058d52..6b253f7 100644 --- a/content/web_test/browser/web_test_browser_main_platform_support_win.cc +++ b/content/web_test/browser/web_test_browser_main_platform_support_win.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/342213636): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - #include "content/web_test/browser/web_test_browser_main_platform_support.h" #include <windows.h> @@ -64,13 +59,15 @@ bool success = !!::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); PCHECK(success); - LOGFONTW* system_fonts[] = {&metrics.lfStatusFont, &metrics.lfMenuFont, - &metrics.lfSmCaptionFont}; - const wchar_t required_font[] = L"Segoe UI"; + const std::wstring_view required_font = L"Segoe UI"; int required_font_size = -12; - for (size_t i = 0; i < std::size(system_fonts); ++i) { - if (system_fonts[i]->lfHeight != required_font_size || - wcscmp(required_font, system_fonts[i]->lfFaceName)) { + for (const LOGFONTW* font : { + &metrics.lfStatusFont, + &metrics.lfMenuFont, + &metrics.lfSmCaptionFont, + }) { + if (font->lfHeight != required_font_size || + font->lfFaceName != required_font) { errors.push_back( "Must use either the Aero or Basic theme. Or change display language " "to English.");
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothSocket.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothSocket.java index 028dca5..8042dfa 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothSocket.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothSocket.java
@@ -30,8 +30,7 @@ public class ChromeBluetoothSocket { private static final String TAG = "Bluetooth"; - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - final BluetoothSocketWrapper mSocket; + @VisibleForTesting final BluetoothSocketWrapper mSocket; private final InputStream mInputStream; private final OutputStream mOutputStream;
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/wrapper/BluetoothAdapterWrapper.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/wrapper/BluetoothAdapterWrapper.java index 29ad6dc..6436164 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/wrapper/BluetoothAdapterWrapper.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/wrapper/BluetoothAdapterWrapper.java
@@ -97,7 +97,7 @@ } } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + @VisibleForTesting public BluetoothAdapterWrapper( BluetoothAdapter adapter, Context context,
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index d73dced..833ad79 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn
@@ -499,6 +499,7 @@ "state_store_test_observer.h", "suggest_permission_util.cc", "suggest_permission_util.h", + "supervised_user_extensions_delegate.cc", "supervised_user_extensions_delegate.h", "task_queue_util.cc", "task_queue_util.h",
diff --git a/extensions/browser/content_verifier/content_verify_job.cc b/extensions/browser/content_verifier/content_verify_job.cc index a36da24e..fbdd9f3a 100644 --- a/extensions/browser/content_verifier/content_verify_job.cc +++ b/extensions/browser/content_verifier/content_verify_job.cc
@@ -16,8 +16,7 @@ #include "base/task/thread_pool.h" #include "base/timer/elapsed_timer.h" #include "content/public/browser/browser_thread.h" -#include "crypto/secure_hash.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" #include "extensions/browser/content_hash_reader.h" #include "extensions/browser/content_verifier/content_hash.h" #include "extensions/browser/content_verifier/content_verifier.h" @@ -257,14 +256,19 @@ if (!current_hash_) { current_hash_byte_count_ = 0; - current_hash_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256); + current_hash_ = crypto::hash::Hasher(crypto::hash::kSha256); } // Compute how many bytes we should hash, and add them to the current hash. int bytes_to_hash = std::min(hash_reader_->block_size() - current_hash_byte_count_, count - bytes_added); DCHECK_GT(bytes_to_hash, 0); - current_hash_->Update(&data[bytes_added], bytes_to_hash); + auto bytes_span = base::as_byte_span(data).subspan( + // TODO(https://crbug.com/434977723): get rid of these checked casts + // when this code uses size_t throughout. + base::checked_cast<size_t>(bytes_added), + base::checked_cast<size_t>(bytes_to_hash)); + current_hash_->Update(bytes_span); bytes_added += bytes_to_hash; current_hash_byte_count_ += bytes_to_hash; total_bytes_read_ += bytes_to_hash; @@ -291,10 +295,10 @@ if (!current_hash_) { // This happens when we fail to read the resource. Compute empty content's // hash in this case. - current_hash_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256); + current_hash_ = crypto::hash::Hasher(crypto::hash::kSha256); } - std::string final(crypto::kSHA256Length, 0); - current_hash_->Finish(std::data(final), final.size()); + std::string final(crypto::hash::kSha256Size, 0); + current_hash_->Finish(base::as_writable_byte_span(final)); current_hash_.reset(); current_hash_byte_count_ = 0;
diff --git a/extensions/browser/content_verifier/content_verify_job.h b/extensions/browser/content_verifier/content_verify_job.h index 0a25a99..859d3c8 100644 --- a/extensions/browser/content_verifier/content_verify_job.h +++ b/extensions/browser/content_verifier/content_verify_job.h
@@ -17,6 +17,7 @@ #include "base/synchronization/lock.h" #include "base/time/time.h" #include "base/version.h" +#include "crypto/hash.h" #include "extensions/browser/content_verifier/content_verifier_key.h" #include "extensions/common/extension_id.h" #include "mojo/public/c/system/types.h" @@ -25,10 +26,6 @@ class FilePath; } -namespace crypto { -class SecureHash; -} - namespace extensions { class ContentHash; @@ -169,7 +166,7 @@ int current_block_ = 0; // The hash we're building up for the bytes of `current_block_`. - std::unique_ptr<crypto::SecureHash> current_hash_; + std::optional<crypto::hash::Hasher> current_hash_; // The number of bytes we've already input into `current_hash_`. int current_hash_byte_count_ = 0;
diff --git a/extensions/browser/supervised_user_extensions_delegate.cc b/extensions/browser/supervised_user_extensions_delegate.cc new file mode 100644 index 0000000..c25ea83 --- /dev/null +++ b/extensions/browser/supervised_user_extensions_delegate.cc
@@ -0,0 +1,72 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/supervised_user_extensions_delegate.h" + +#include "base/notimplemented.h" + +namespace extensions { + +void SupervisedUserExtensionsDelegate::UpdateManagementPolicyRegistration() { + NOTIMPLEMENTED(); +} + +bool SupervisedUserExtensionsDelegate::IsChild() const { + NOTIMPLEMENTED(); + return false; +} + +bool SupervisedUserExtensionsDelegate::IsExtensionAllowedByParent( + const extensions::Extension& extension) const { + NOTIMPLEMENTED(); + return false; +} + +void SupervisedUserExtensionsDelegate::RequestToAddExtensionOrShowError( + const extensions::Extension& extension, + content::WebContents* web_contents, + const gfx::ImageSkia& icon, + SupervisedUserExtensionParentApprovalEntryPoint + extension_approval_entry_point, + ExtensionApprovalDoneCallback extension_approval_callback) { + NOTIMPLEMENTED(); + std::move(extension_approval_callback).Run(ExtensionApprovalResult::kBlocked); +} + +void SupervisedUserExtensionsDelegate::RequestToEnableExtensionOrShowError( + const extensions::Extension& extension, + content::WebContents* web_contents, + SupervisedUserExtensionParentApprovalEntryPoint + extension_approval_entry_point, + ExtensionApprovalDoneCallback extension_approval_callback) { + NOTIMPLEMENTED(); + std::move(extension_approval_callback).Run(ExtensionApprovalResult::kBlocked); +} + +bool SupervisedUserExtensionsDelegate::CanInstallExtensions() const { + NOTIMPLEMENTED(); + return false; +} + +void SupervisedUserExtensionsDelegate::AddExtensionApproval( + const extensions::Extension& extension) { + NOTIMPLEMENTED(); +} + +void SupervisedUserExtensionsDelegate::MaybeRecordPermissionsIncreaseMetrics( + const extensions::Extension& extension) { + NOTIMPLEMENTED(); +} + +void SupervisedUserExtensionsDelegate::RemoveExtensionApproval( + const extensions::Extension& extension) { + NOTIMPLEMENTED(); +} + +void SupervisedUserExtensionsDelegate::RecordExtensionEnablementUmaMetrics( + bool enabled) const { + NOTIMPLEMENTED(); +} + +} // namespace extensions
diff --git a/extensions/browser/supervised_user_extensions_delegate.h b/extensions/browser/supervised_user_extensions_delegate.h index 4c208917..35c5218 100644 --- a/extensions/browser/supervised_user_extensions_delegate.h +++ b/extensions/browser/supervised_user_extensions_delegate.h
@@ -42,6 +42,8 @@ namespace extensions { +// Interface for the supervised user extensions delegate. The interface has +// stub implementations so it can be used in test code. class SupervisedUserExtensionsDelegate { public: // Result of the extension approval flow. @@ -55,17 +57,18 @@ using ExtensionApprovalDoneCallback = base::OnceCallback<void(ExtensionApprovalResult)>; + SupervisedUserExtensionsDelegate() = default; virtual ~SupervisedUserExtensionsDelegate() = default; // Updates registration of management policy provider for supervised users. - virtual void UpdateManagementPolicyRegistration() = 0; + virtual void UpdateManagementPolicyRegistration(); // Returns true if the primary account is a supervised child. - virtual bool IsChild() const = 0; + virtual bool IsChild() const; // Returns true if the parent has already approved the `extension`. virtual bool IsExtensionAllowedByParent( - const extensions::Extension& extension) const = 0; + const extensions::Extension& extension) const; // If the current user is a child, the child user has a custodian/parent, and // the parent has enabled the "Permissions for sites, apps and extensions" @@ -82,7 +85,7 @@ const gfx::ImageSkia& icon, SupervisedUserExtensionParentApprovalEntryPoint extension_approval_entry_point, - ExtensionApprovalDoneCallback extension_approval_callback) = 0; + ExtensionApprovalDoneCallback extension_approval_callback); // Similar to RequestToAddExtensionOrShowError except for enabling already // installed extensions. The icon is fetched from local resources. @@ -91,27 +94,26 @@ content::WebContents* web_contents, SupervisedUserExtensionParentApprovalEntryPoint extension_approval_entry_point, - ExtensionApprovalDoneCallback extension_approval_callback) = 0; + ExtensionApprovalDoneCallback extension_approval_callback); // Returns true if the primary account represents a supervised child account // who may install extensions with parent permission. - virtual bool CanInstallExtensions() const = 0; + virtual bool CanInstallExtensions() const; // Updates the set of approved extensions to add approval for `extension`. - virtual void AddExtensionApproval(const extensions::Extension& extension) = 0; + virtual void AddExtensionApproval(const extensions::Extension& extension); // Checks if the given `extension` escalated permissions and records the // corresponding metrics. virtual void MaybeRecordPermissionsIncreaseMetrics( - const extensions::Extension& extension) = 0; + const extensions::Extension& extension); // Updates the set of approved extensions to remove approval for `extension`. - virtual void RemoveExtensionApproval( - const extensions::Extension& extension) = 0; + virtual void RemoveExtensionApproval(const extensions::Extension& extension); // Records when an extension has been enabled or disabled by parental // controls. - virtual void RecordExtensionEnablementUmaMetrics(bool enabled) const = 0; + virtual void RecordExtensionEnablementUmaMetrics(bool enabled) const; }; } // namespace extensions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 37c59f4..3276ac92 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -1130,13 +1130,20 @@ auto it = service_workers_paused_for_on_loaded_message_.find(extension->id()); if (it != service_workers_paused_for_on_loaded_message_.end()) { - scoped_refptr<base::SingleThreadTaskRunner> task_runner = - std::move(it->second->task_runner); - // Using base::Unretained() should be fine as this won't get destructed. - task_runner->PostTask( - FROM_HERE, - base::BindOnce(&Dispatcher::ResumeEvaluationOnWorkerThread, - base::Unretained(this), extension->id())); + // It's possible that LoadExtensions is called multiple times for the + // same extension before the worker thread has a chance to run the + // ResumeEvaluationOnWorkerThread task. In that case, the task_runner + // will have already been moved, so we need to check if it's valid. + if (it->second->task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + std::move(it->second->task_runner); + // Using base::Unretained() should be fine as this won't get + // destructed. + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&Dispatcher::ResumeEvaluationOnWorkerThread, + base::Unretained(this), extension->id())); + } } } }
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index e1b0c53..fbf16aa 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1443,7 +1443,21 @@ if (descriptor != nullptr) { desc = *reinterpret_cast<const wgpu::DeviceDescriptor*>(descriptor); } - DCHECK_EQ(desc.nextInChain, nullptr); + + // Check that the only chained struct allowed is DawnConsumeAdapterDescriptor. + for (auto* chain = desc.nextInChain; chain != nullptr; + chain = chain->nextInChain) { + switch (chain->sType) { + case wgpu::SType::DawnConsumeAdapterDescriptor: + break; + default: + callback_info.callback( + WGPURequestDeviceStatus_Error, nullptr, + MakeStringView("Disallowed chained struct requested."), + callback_info.userdata1, callback_info.userdata2); + return {}; + } + } std::vector<wgpu::FeatureName> required_features;
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc index 2140478..335c3a7 100644 --- a/gpu/ipc/service/gpu_channel.cc +++ b/gpu/ipc/service/gpu_channel.cc
@@ -454,7 +454,7 @@ if (IsNativeBufferSupported(buffer_format, buffer_usage)) { handle = gpu_memory_buffer_factory_->CreateNativeGmbHandle( - MappableSIClientGmbId::kGpuChannel, size, buffer_format, buffer_usage); + size, buffer_format, buffer_usage); } else { if (SharedMemoryImageBackingFactory::IsBufferUsageSupported(buffer_usage) && SharedMemoryImageBackingFactory::IsSizeValidForFormat(size, format)) {
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.cc b/gpu/ipc/service/gpu_memory_buffer_factory.cc index 482a3c78..a58380c 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory.cc
@@ -36,12 +36,10 @@ ~GpuMemoryBufferFactoryStub() override = default; // GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) override { + gfx::BufferUsage usage) override { return gfx::GpuMemoryBufferHandle(); } bool FillSharedMemoryRegionWithBufferContents( @@ -77,14 +75,4 @@ #endif } -gfx::GpuMemoryBufferHandle GpuMemoryBufferFactory::CreateNativeGmbHandle( - MappableSIClientGmbId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage) { - auto handle = CreateGpuMemoryBuffer(size, /*framebuffer_size=*/size, format, - usage, gpu::kNullSurfaceHandle); - return handle; -} - } // namespace gpu
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.h b/gpu/ipc/service/gpu_memory_buffer_factory.h index 1e220c85..9d0a4d9 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory.h
@@ -22,16 +22,6 @@ namespace gpu { -// This enums will be used by clients when creating native gmb handles via -// GpuMemoryBufferFactory::CreateNativeGmbHandle(). This ensure each client uses -// a unique id. -enum class MappableSIClientGmbId : int { - kGpuChannel = 1, - kGmbVideoFramePoolContext = 2, - kGpuServiceImpl = 3, - kLast = 2 -}; - class GPU_IPC_SERVICE_EXPORT GpuMemoryBufferFactory { public: GpuMemoryBufferFactory(const GpuMemoryBufferFactory&) = delete; @@ -45,29 +35,11 @@ viz::VulkanContextProvider* vulkan_context_provider, scoped_refptr<base::SingleThreadTaskRunner> io_runner = nullptr); - // Creates a native GpuMemoryBufferHandle for MappableSI work. Note that - // every client should use a different |id| here otherwise it can result in - // errors due to multiple clients creating and destroying GMBs with same |id| - // from multiple threads. Using MappableSIClientGmbId here ensures that every - // client uses unique id assigned to it and also makes it easier to track. - gfx::GpuMemoryBufferHandle CreateNativeGmbHandle(MappableSIClientGmbId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage); - - // Creates a new GPU memory buffer instance. A valid handle is returned on - // success. This method is thread-safe but it should not be called on the IO - // thread as it can lead to deadlocks (see https://crbug.com/981721). Instead - // use the asynchronous version on the IO thread. |framebuffer_size| specifies - // the size used to create a framebuffer when the |usage| requires it and the - // particular GpuMemoryBufferFactory implementation supports it (for example, - // when creating a buffer for scanout using the Ozone/DRM backend). - virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + // Creates a native GpuMemoryBufferHandle for MappableSI. + virtual gfx::GpuMemoryBufferHandle CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) = 0; + gfx::BufferUsage usage) = 0; // Fills |shared_memory| with the contents of the provided |buffer_handle| virtual bool FillSharedMemoryRegionWithBufferContents(
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc index b85c1de..11278ba 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
@@ -91,12 +91,9 @@ } gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryDXGI::CreateGpuMemoryBufferOnIO( - const gfx::Size& size, - const gfx::Size& framebuffer_size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) { +GpuMemoryBufferFactoryDXGI::CreateNativeGmbHandleOnIO(const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage) { DCHECK(io_runner_); gfx::GpuMemoryBufferHandle result; @@ -108,35 +105,29 @@ [](gfx::GpuMemoryBufferHandle* out_gmb_handle, base::WaitableEvent* waitable_event, GpuMemoryBufferFactoryDXGI* factory, const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, SurfaceHandle surface_handle) { - *out_gmb_handle = factory->CreateGpuMemoryBuffer( - size, framebuffer_size, format, usage, surface_handle); + gfx::BufferFormat format, gfx::BufferUsage usage) { + *out_gmb_handle = + factory->CreateNativeGmbHandle(size, format, usage); waitable_event->Signal(); }, - &result, &event, this, size, framebuffer_size, format, usage, - surface_handle)); + &result, &event, this, size, format, usage)); event.Wait(); return result; } -gfx::GpuMemoryBufferHandle GpuMemoryBufferFactoryDXGI::CreateGpuMemoryBuffer( +gfx::GpuMemoryBufferHandle GpuMemoryBufferFactoryDXGI::CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) { + gfx::BufferUsage usage) { if (io_runner_ && !io_runner_->BelongsToCurrentThread()) { // Thread-hop is required! - return CreateGpuMemoryBufferOnIO(size, framebuffer_size, format, usage, - surface_handle); + return CreateNativeGmbHandleOnIO(size, format, usage); } - TRACE_EVENT0("gpu", "GpuMemoryBufferFactoryDXGI::CreateGpuMemoryBuffer"); - DCHECK_EQ(framebuffer_size, size); + TRACE_EVENT0("gpu", "GpuMemoryBufferFactoryDXGI::CreateNativeGmbHandle"); gfx::GpuMemoryBufferHandle handle;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h index 72f75555d..93ad11f8 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
@@ -36,12 +36,10 @@ delete; // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) override; + gfx::BufferUsage usage) override; bool FillSharedMemoryRegionWithBufferContents( gfx::GpuMemoryBufferHandle buffer_handle, base::UnsafeSharedMemoryRegion shared_memory) override; @@ -49,12 +47,9 @@ private: Microsoft::WRL::ComPtr<ID3D11Device> GetOrCreateD3D11Device(); - gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferOnIO( - const gfx::Size& size, - const gfx::Size& framebuffer_size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle); + gfx::GpuMemoryBufferHandle CreateNativeGmbHandleOnIO(const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage); Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_ GUARDED_BY_CONTEXT(thread_checker_);
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc index 1b9786b..d62899fc 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
@@ -22,14 +22,9 @@ GpuMemoryBufferFactoryIOSurface::~GpuMemoryBufferFactoryIOSurface() = default; gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer( - const gfx::Size& size, - const gfx::Size& framebuffer_size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) { - DCHECK_EQ(framebuffer_size, size); - +GpuMemoryBufferFactoryIOSurface::CreateNativeGmbHandle(const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage) { bool should_clear = true; base::apple::ScopedCFTypeRef<IOSurfaceRef> io_surface = gfx::CreateIOSurface(size, format, should_clear);
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h index 2a254ad..7175192 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
@@ -22,12 +22,10 @@ ~GpuMemoryBufferFactoryIOSurface() override; // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) override; + gfx::BufferUsage usage) override; bool FillSharedMemoryRegionWithBufferContents( gfx::GpuMemoryBufferHandle buffer_handle, base::UnsafeSharedMemoryRegion shared_memory) override;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc index c600495..6e278a21 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -33,18 +33,16 @@ default; gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBuffer( +GpuMemoryBufferFactoryNativePixmap::CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) { + gfx::BufferUsage usage) { scoped_refptr<gfx::NativePixmap> pixmap = ui::OzonePlatform::GetInstance() ->GetSurfaceFactoryOzone() - ->CreateNativePixmap(surface_handle, GetVulkanDeviceQueue(), size, - format, usage, framebuffer_size); - return CreateGpuMemoryBufferFromNativePixmap(size, format, usage, + ->CreateNativePixmap(gpu::kNullSurfaceHandle, GetVulkanDeviceQueue(), + size, format, usage, size); + return CreateNativeGmbHandleFromNativePixmap(size, format, usage, std::move(pixmap)); } @@ -65,7 +63,7 @@ } gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferFromNativePixmap( +GpuMemoryBufferFactoryNativePixmap::CreateNativeGmbHandleFromNativePixmap( const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h index 749051c63..f48cfb61 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -30,18 +30,16 @@ ~GpuMemoryBufferFactoryNativePixmap() override; // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle CreateNativeGmbHandle( const gfx::Size& size, - const gfx::Size& framebuffer_size, gfx::BufferFormat format, - gfx::BufferUsage usage, - SurfaceHandle surface_handle) override; + gfx::BufferUsage usage) override; bool FillSharedMemoryRegionWithBufferContents( gfx::GpuMemoryBufferHandle buffer_handle, base::UnsafeSharedMemoryRegion shared_memory) override; private: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromNativePixmap( + gfx::GpuMemoryBufferHandle CreateNativeGmbHandleFromNativePixmap( const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h index c215d56..895bfc09 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
@@ -76,9 +76,8 @@ } gfx::GpuMemoryBufferHandle handle = - TestFixture::factory_.CreateNativeGmbHandle( - gpu::MappableSIClientGmbId::kGpuServiceImpl, gfx::Size(2, 2), - format, usage); + TestFixture::factory_.CreateNativeGmbHandle(gfx::Size(2, 2), format, + usage); EXPECT_NE(handle.type, gfx::EMPTY_BUFFER); } }
diff --git a/gpu/vulkan/vulkan_image_unittest.cc b/gpu/vulkan/vulkan_image_unittest.cc index f076a5c8..252c5e6 100644 --- a/gpu/vulkan/vulkan_image_unittest.cc +++ b/gpu/vulkan/vulkan_image_unittest.cc
@@ -161,9 +161,8 @@ }; for (const auto format : formats) { gfx::BufferUsage buffer_usage = gfx::BufferUsage::SCANOUT; - auto gmb_handle = factory->CreateNativeGmbHandle( - gpu::MappableSIClientGmbId::kGpuServiceImpl, size, format.buffer, - buffer_usage); + auto gmb_handle = + factory->CreateNativeGmbHandle(size, format.buffer, buffer_usage); EXPECT_TRUE(!gmb_handle.is_null()); EXPECT_EQ(gmb_handle.type, gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER);
diff --git a/infra/config/PACKAGE.lock b/infra/config/PACKAGE.lock index 02df67c..727238e 100644 --- a/infra/config/PACKAGE.lock +++ b/infra/config/PACKAGE.lock
@@ -31,7 +31,7 @@ "name": "@chromium-luci", "source": { "repo": "https://chromium.googlesource.com/infra/chromium/+/refs/heads/main", - "revision": "7af22527170d64d84dac041cc2028c11f8bb121d", + "revision": "5e6d4b3392677bd2e947f0098229d0555e220eef", "path": "starlark-libs/chromium-luci" }, "lucicfg": "1.45.0"
diff --git a/infra/config/PACKAGE.star b/infra/config/PACKAGE.star index 30dab12..cc0a6af 100644 --- a/infra/config/PACKAGE.star +++ b/infra/config/PACKAGE.star
@@ -29,7 +29,7 @@ repo = "infra/chromium", ref = "refs/heads/main", path = "starlark-libs/chromium-luci", - revision = "7af22527170d64d84dac041cc2028c11f8bb121d", + revision = "5e6d4b3392677bd2e947f0098229d0555e220eef", ), )
diff --git a/infra/config/generated/builder-owners/chops-security-core@google.com.txt b/infra/config/generated/builder-owners/chops-security-core@google.com.txt deleted file mode 100644 index c2bd6ccf..0000000 --- a/infra/config/generated/builder-owners/chops-security-core@google.com.txt +++ /dev/null
@@ -1 +0,0 @@ -ci/linux-3p-licenses \ No newline at end of file
diff --git a/infra/config/generated/health-specs/health-specs.json b/infra/config/generated/health-specs/health-specs.json index 487480d..280bdaf 100644 --- a/infra/config/generated/health-specs/health-specs.json +++ b/infra/config/generated/health-specs/health-specs.json
@@ -9058,27 +9058,6 @@ } ] }, - "linux-3p-licenses": { - "contact_team_email": "chops-security-core@google.com", - "problem_specs": [ - { - "name": "Unhealthy", - "period_days": 7, - "score": 5, - "thresholds": { - "_default": "_default" - } - }, - { - "name": "Low Value", - "period_days": 90, - "score": 1, - "thresholds": { - "_default": "_default" - } - } - ] - }, "linux-angle-chromium-builder": { "contact_team_email": "angle-team@google.com", "problem_specs": [
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 26a0db5..d1407f5 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -50856,101 +50856,6 @@ } } builders { - name: "linux-3p-licenses" - swarming_host: "chromium-swarm.appspot.com" - dimensions: "builderless:1" - dimensions: "cpu:x86-64" - dimensions: "free_space:standard" - dimensions: "os:Ubuntu-22.04" - dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" - exe { - cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" - cipd_version: "refs/heads/main" - cmd: "luciexe" - } - properties: - '{' - ' "$recipe_engine/resultdb/test_presentation": {' - ' "column_keys": [],' - ' "grouping_keys": [' - ' "status",' - ' "v.test_suite"' - ' ]' - ' },' - ' "recipe": "chromium_licenses/scan"' - '}' - execution_timeout_secs: 10800 - build_numbers: YES - service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - experiments { - key: "chromium.use_per_builder_build_dir_name" - value: 100 - } - experiments { - key: "luci.recipes.use_python3" - value: 100 - } - resultdb { - enable: true - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "ci_test_results" - test_results {} - } - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "gpu_ci_test_results" - test_results { - predicate { - test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+" - } - } - } - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "blink_web_tests_ci_test_results" - test_results { - predicate { - test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)" - } - } - } - history_options { - use_invocation_timestamp: true - } - } - description_html: "Weekly scan for third party license errors.<br/>Builder owner: <a href=mailto:chops-security-core@google.com>chops-security-core@google.com</a>" - shadow_builder_adjustments { - service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" - pool: "luci.chromium.try" - dimensions: "free_space:" - dimensions: "pool:luci.chromium.try" - } - contact_team_email: "chops-security-core@google.com" - custom_metric_definitions { - name: "/chrome/infra/browser/builds/cached_count" - predicates: "has(build.output.properties.is_cached)" - predicates: "string(build.output.properties.is_cached) == \"true\"" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" - predicates: "has(build.output.properties.ran_tests_retry_shard)" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" - predicates: "has(build.output.properties.ran_tests_without_patch)" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/uncached_count" - predicates: "has(build.output.properties.is_cached)" - predicates: "string(build.output.properties.is_cached) == \"false\"" - } - } - builders { name: "linux-angle-chromium-builder" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 57d16462..8533964 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -5601,11 +5601,6 @@ refs: "regexp:refs/heads/main" manifest_name: "REVISION" builders { - name: "buildbucket/luci.chromium.ci/linux-3p-licenses" - category: "3p-licenses" - short_name: "linux" - } - builders { name: "buildbucket/luci.chromium.ci/linux-presubmit" category: "presubmit" short_name: "linux"
diff --git a/infra/config/generated/luci/luci-notify.cfg b/infra/config/generated/luci/luci-notify.cfg index f9845141..8a0be2c1 100644 --- a/infra/config/generated/luci/luci-notify.cfg +++ b/infra/config/generated/luci/luci-notify.cfg
@@ -3113,21 +3113,6 @@ } notifiers { notifications { - on_occurrence: FAILURE - on_new_status: SUCCESS - on_new_status: INFRA_FAILURE - email { - recipients: "chops-security-core+ssci-alert@google.com" - } - template: "build_with_step_summary_template" - } - builders { - bucket: "ci" - name: "linux-3p-licenses" - } -} -notifiers { - notifications { on_new_status: FAILURE email { recipients: "chiav@chromium.org"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index b1d8116..45a9660f 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -4279,16 +4279,6 @@ } } job { - id: "linux-3p-licenses" - realm: "ci" - schedule: "15 22 * * 1" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "ci" - builder: "linux-3p-licenses" - } -} -job { id: "linux-angle-chromium-builder" realm: "ci" buildbucket {
diff --git a/infra/config/recipes.star b/infra/config/recipes.star index d33e93f..0b3e4fa 100644 --- a/infra/config/recipes.star +++ b/infra/config/recipes.star
@@ -194,10 +194,6 @@ ) build_recipe( - name = "recipe:chromium_licenses/scan", -) - -build_recipe( name = "recipe:chromium_polymorphic/launcher", )
diff --git a/infra/config/subprojects/chromium/ci/checks.star b/infra/config/subprojects/chromium/ci/checks.star index ea52273..a65c7f9 100644 --- a/infra/config/subprojects/chromium/ci/checks.star +++ b/infra/config/subprojects/chromium/ci/checks.star
@@ -69,20 +69,3 @@ "repo_name": "chromium", }, ) - -ci.builder( - name = "linux-3p-licenses", - description_html = "Weekly scan for third party license errors.", - executable = "recipe:chromium_licenses/scan", - schedule = "15 22 * * 1", # Once a week 10:15pm UTC / 8:15am AEST / 1:15am PST - triggered_by = None, - os = os.LINUX_DEFAULT, - console_view_entry = consoles.console_view_entry( - console_view = "checks", - category = "3p-licenses", - short_name = "linux", - ), - contact_team_email = "chops-security-core@google.com", - execution_timeout = ci_constants.DEFAULT_EXECUTION_TIMEOUT, - notifies = ["peeps-security-core-ssci"], -)
diff --git a/internal b/internal index 5ca7704..3cadbbd 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 5ca7704be6a2e84bf875773ab2009dffe3a98afa +Subproject commit 3cadbbd673e1d93353480c197bfb1d0a968b787e
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm index 367ba4a..0fad7a88 100644 --- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm +++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm
@@ -21,6 +21,7 @@ #import "ios/chrome/browser/shared/ui/util/rtl_geometry.h" #import "ios/chrome/browser/shared/ui/util/util_swift.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" +#import "ios/chrome/common/ui/elements/form_input_accessory_view.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" using autofill::FillingProduct; @@ -269,7 +270,7 @@ UIView* wrapperContainer = [[UIView alloc] init]; wrapperContainer.translatesAutoresizingMaskIntoConstraints = NO; UIView* separator = [[UIView alloc] init]; - separator.backgroundColor = [UIColor colorNamed:kSeparatorColor]; + separator.backgroundColor = [UIColor colorNamed:kTextSecondaryColor]; separator.translatesAutoresizingMaskIntoConstraints = NO; [wrapperContainer addSubview:separator]; [NSLayoutConstraint activateConstraints:@[ @@ -291,6 +292,16 @@ if (idx > 0) { [self.stackView addArrangedSubview:[self createSeparatorView]]; } + + // This constraint is added to ensure that the keyboard accessory's + // suggestion label maintains its height when a hardware keyboard is + // connected and the keyboard accessory is located at the bottom of the + // screen. Without this constraint, the label's height is reduced and looks + // squeezed. + [label.heightAnchor + constraintEqualToConstant:kLargeKeyboardAccessoryHeight - + (2 * kSuggestionVerticalMargin)] + .active = YES; } [self.stackView addArrangedSubview:label];
diff --git a/ios/chrome/browser/omnibox/eg_tests/omnibox_popup_egtest.mm b/ios/chrome/browser/omnibox/eg_tests/omnibox_popup_egtest.mm index 92fc941..09dd929 100644 --- a/ios/chrome/browser/omnibox/eg_tests/omnibox_popup_egtest.mm +++ b/ios/chrome/browser/omnibox/eg_tests/omnibox_popup_egtest.mm
@@ -721,38 +721,4 @@ [ChromeEarlGrey clearPasteboard]; } -- (void)testHardwareKeyboardSelectLinkYouCopiedAsFirstElement { - // Start a server to be able to navigate to a web page. - self.testServer->RegisterRequestHandler( - base::BindRepeating(&omnibox::OmniboxHTTPResponses)); - GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); - const GURL pageURL = self.testServer->GetURL(omnibox::PageURL(1)); - // Copy link in clipboard. - [ChromeEarlGrey - copyLinkAsURLToPasteBoard:[NSString cr_fromString:pageURL.spec()]]; - - // Focus the fake omnibox. - [[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()] - performAction:grey_tap()]; - [ChromeEarlGrey - waitForSufficientlyVisibleElementWithMatcher:chrome_test_util::Omnibox()]; - - // Wait for the clipboard suggestion to show. - [ChromeEarlGrey waitForUIElementToAppearWithMatcher:LinkYouCopiedRow()]; - - // The omnibox popup may update multiple times. Don't downArrow until this - // is done. - base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(1)); - - // Highlight the text you copied row. Accept with Return. - [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"downArrow" flags:0]; - base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.1)); - [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"\r" flags:0]; - - // The web page should load. - [ChromeEarlGrey waitForWebStateContainingText:omnibox::PageContent(1)]; - - [ChromeEarlGrey clearPasteboard]; -} - @end
diff --git a/ios/chrome/browser/omnibox/ui/omnibox_view_controller.mm b/ios/chrome/browser/omnibox/ui/omnibox_view_controller.mm index ad25993..45f4715 100644 --- a/ios/chrome/browser/omnibox/ui/omnibox_view_controller.mm +++ b/ios/chrome/browser/omnibox/ui/omnibox_view_controller.mm
@@ -461,7 +461,6 @@ !!self.view.thumbnailImage || [self.popupKeyboardDelegate canPerformKeyboardAction:OmniboxKeyboardAction::kReturnKey]; - [self.textField reloadInputViews]; } - (void)setPlaceholderText:(NSString*)placeholderText {
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm index fa66650..0bc02936 100644 --- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm +++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm
@@ -2027,8 +2027,9 @@ [pinnedView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:kPinnedViewMaxWidthInPercent], - [pinnedView.topAnchor - constraintEqualToAnchor:self.bottomToolbar.topAnchor], + [pinnedView.bottomAnchor + constraintEqualToAnchor:self.view.bottomAnchor + constant:-kPinnedViewBottomPadding], ]]; }
diff --git a/ios/chrome/common/ui/elements/form_input_accessory_view.h b/ios/chrome/common/ui/elements/form_input_accessory_view.h index 6b339fb..6909530 100644 --- a/ios/chrome/common/ui/elements/form_input_accessory_view.h +++ b/ios/chrome/common/ui/elements/form_input_accessory_view.h
@@ -7,6 +7,9 @@ #import <UIKit/UIKit.h> +// Large height for the keyboard accessory. +extern const CGFloat kLargeKeyboardAccessoryHeight; + @class FormInputAccessoryView; @class FormInputAccessoryViewTextData;
diff --git a/ios/chrome/common/ui/elements/form_input_accessory_view.mm b/ios/chrome/common/ui/elements/form_input_accessory_view.mm index a0f48f53..d09c6b88 100644 --- a/ios/chrome/common/ui/elements/form_input_accessory_view.mm +++ b/ios/chrome/common/ui/elements/form_input_accessory_view.mm
@@ -27,15 +27,6 @@ // Default height for the keyboard accessory. constexpr CGFloat kDefaultAccessoryHeight = 44; -// Large height for the keyboard accessory. -constexpr CGFloat kLargeAccessoryHeight = 59; - -// Bottom padding for the large keyboard accessory on iOS 26.0+. -constexpr CGFloat kBottomAccessoryPadding = 12; - -// Side padding for the large keyboard accessory on iOS 26.0+. -constexpr CGFloat kSideAccessoryPadding = 4; - // Button target area for the large keyboard accessory. constexpr CGFloat kLargeButtonTargetArea = 44; @@ -46,9 +37,6 @@ // Only applies to the iPad version of this button. constexpr CGFloat kManualFillTitlePadding = 4; -// Width for the small keyboard accessory. -constexpr CGFloat kSmallAccessoryWidth = 3 * kLargeButtonTargetArea + 4; - // The font size used for the title of the manual fill button. // Only applies to the iPad version of this button. constexpr CGFloat kManualFillTitleFontSize = 18; @@ -56,11 +44,14 @@ // The spacing between the items in the navigation view. constexpr CGFloat ManualFillNavigationItemSpacing = 4; -// The left content inset for the close button. -constexpr CGFloat ManualFillCloseButtonLeftInset = 7; +// The leading content inset for the close button. +constexpr CGFloat ManualFillCloseButtonLeadingInset = 7; -// The right content inset for the close button. -constexpr CGFloat ManualFillCloseButtonRightInset = 15; +// The trailing content inset for the close button. +constexpr CGFloat ManualFillCloseButtonTrailingInset = 15; + +// The trailing content inset for the close button when using liquid glass. +constexpr CGFloat LiquidGlassCloseButtonTrailingInset = 24; // The bottom content inset for the close button. constexpr CGFloat ManualFillCloseButtonBottomInset = 4; @@ -84,20 +75,33 @@ #if defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_26_0 +// Padding around the keyboard accessory on iOS 26.0+. +constexpr CGFloat kSurroundingPadding = 12; + +// Corner radius of the keyboard accessory on iOS 26.0+. +constexpr CGFloat kCornerRadius = 24; + +// Width for the small keyboard accessory. Only when liquid glass effect is +// enabled. +constexpr CGFloat kSmallAccessoryWidth = 3 * kLargeButtonTargetArea + 4; + // Alpha of the tint color for the glass effect. A lower alpha will produce a // more pronounced glass effect. constexpr CGFloat kGlassTintAlpha = 0.5; // Shadow parameters. Used when the liquid glass effect is enabled. -constexpr CGFloat kShadowRadius = 0.5; -constexpr CGFloat kShadowVerticalOffset = 2.0; -constexpr CGFloat kShadowOpacity = 1.0; +constexpr CGFloat kShadowRadius = 16.0; +constexpr CGFloat kShadowVerticalOffset = 4.0; +constexpr CGFloat kShadowOpacity = 0.12; #endif // defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= // __IPHONE_26_0 } // namespace +// Large height for the keyboard accessory. +const CGFloat kLargeKeyboardAccessoryHeight = 59; + NSString* const kFormInputAccessoryViewAccessibilityID = @"kFormInputAccessoryViewAccessibilityID"; @@ -329,37 +333,25 @@ self.addressManualFillSymbol = addressManualFillSymbol; self.closeButtonSymbol = closeButtonSymbol; - _contentView = [[UIView alloc] init]; - _contentView.translatesAutoresizingMaskIntoConstraints = NO; - if (_largeAccessoryViewEnabled || [self isLiquidGlassEffectEnabled]) { - _backgroundView = [self backgroundEffectView]; - _backgroundView.translatesAutoresizingMaskIntoConstraints = NO; - [_contentView addSubview:_backgroundView]; - AddSameConstraints(_backgroundView, _contentView); - } else { - _contentView.backgroundColor = [UIColor colorNamed:kBackgroundColor]; - } - [self addSubview:_contentView]; - [self.trailingAnchor constraintEqualToAnchor:_contentView.trailingAnchor - constant:[self sidePadding]] - .active = YES; - // Lower the top constraint as the omniboxTypingShield can be above it. - NSLayoutConstraint* topConstraint = - [self.topAnchor constraintEqualToAnchor:_contentView.topAnchor]; - topConstraint.priority = UILayoutPriorityRequired - 1; - topConstraint.active = YES; + // Attempt to set up the liquid glass effect, otherwise, use the non liquid + // glass accessory. + if (![self setupLiquidGlassEffect]) { + _contentView = [[UIView alloc] init]; + _contentView.translatesAutoresizingMaskIntoConstraints = NO; + if (_largeAccessoryViewEnabled) { + _backgroundView = PrimaryBackgroundBlurView(); + _backgroundView.translatesAutoresizingMaskIntoConstraints = NO; + [_contentView addSubview:_backgroundView]; + AddSameConstraints(_backgroundView, _contentView); + } else { + _contentView.backgroundColor = [UIColor colorNamed:kBackgroundColor]; + } + [self addSubview:_contentView]; + AddSameConstraintsToSides( + self, _contentView, + LayoutSides::kBottom | LayoutSides::kLeading | LayoutSides::kTrailing); - [self.bottomAnchor constraintEqualToAnchor:_contentView.bottomAnchor - constant:[self bottomPadding]] - .active = YES; - - if (_smallWidthAccessoryViewEnabled) { - [_contentView.widthAnchor constraintEqualToConstant:kSmallAccessoryWidth] - .active = YES; - } else { - [self.leadingAnchor constraintEqualToAnchor:_contentView.leadingAnchor - constant:-[self sidePadding]] - .active = YES; + [self setOmniboxSafeTopConstraint:_contentView]; } leadingView = leadingView ?: [[UIView alloc] init]; @@ -385,27 +377,32 @@ UIView* leadingViewContainer = [[UIView alloc] init]; leadingViewContainer.translatesAutoresizingMaskIntoConstraints = NO; + [self clipToLiquidGlassEffectBounds:leadingViewContainer]; [_contentView addSubview:leadingViewContainer]; [leadingViewContainer addSubview:leadingView]; - AddSameConstraints(leadingViewContainer, leadingView); + if ([self isLiquidGlassEffectEnabled]) { + AddSameConstraintsToSides( + leadingViewContainer, leadingView, + LayoutSides::kTop | LayoutSides::kLeading | LayoutSides::kTrailing); + [self setBottomAnchorForView:leadingView]; + } else { + AddSameConstraints(leadingViewContainer, leadingView); + } trailingView.translatesAutoresizingMaskIntoConstraints = NO; - [self addSubview:trailingView]; + [self addTrailingView:trailingView]; - CGFloat desiredHeight = [self accessoryHeight]; - NSLayoutConstraint* defaultHeightConstraint = - [_contentView.heightAnchor constraintEqualToConstant:desiredHeight]; - defaultHeightConstraint.priority = UILayoutPriorityDefaultHigh; + [self setDefaultHeightConstraint:_contentView]; id<LayoutGuideProvider> layoutGuide = self.safeAreaLayoutGuide; [NSLayoutConstraint activateConstraints:@[ - defaultHeightConstraint, [leadingViewContainer.topAnchor constraintEqualToAnchor:_contentView.topAnchor], [leadingViewContainer.leadingAnchor - constraintEqualToAnchor:layoutGuide.leadingAnchor], + constraintEqualToAnchor:[self isLiquidGlassEffectEnabled] + ? _contentView.leadingAnchor + : layoutGuide.leadingAnchor], [trailingView.topAnchor constraintEqualToAnchor:_contentView.topAnchor], - ]]; [self setBottomAnchorForView:leadingViewContainer]; @@ -428,7 +425,7 @@ // in height. This is only relevant on tablets. [self.topAnchor constraintLessThanOrEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor - constant:-desiredHeight] + constant:-[self accessoryHeight]] .active = YES; [self setHorizontalConstraints]; @@ -439,7 +436,7 @@ } // When using the blur effect background, do not add top and bottom lines. - if (!_largeAccessoryViewEnabled) { + if (!_largeAccessoryViewEnabled && ![self isLiquidGlassEffectEnabled]) { UIView* topGrayLine = [[UIView alloc] init]; topGrayLine.backgroundColor = [UIColor colorNamed:kGrey50Color]; topGrayLine.translatesAutoresizingMaskIntoConstraints = NO; @@ -473,6 +470,54 @@ [self createOmniboxTypingShield]; } +// If the liquid glass effect is enabled, clip the contents of the leading view +// to the liquid glass effect's bounds. +- (void)clipToLiquidGlassEffectBounds:(UIView*)leadingViewContainer { +#if defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_26_0 + if (@available(iOS 26, *)) { + if ([self isLiquidGlassEffectEnabled]) { + // Set leading view container bounds to match the glass effect. + leadingViewContainer.clipsToBounds = YES; + leadingViewContainer.cornerConfiguration = [UICornerConfiguration + configurationWithRadius: + [UICornerRadius + containerConcentricRadiusWithMinimum:kCornerRadius]]; + leadingViewContainer.layer.maskedCorners = + kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner; + } + } +#endif // defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= + // __IPHONE_26_0 +} + +// Adds the trailing view in the accessory's view hierarchy. +- (void)addTrailingView:(UIView*)trailingView { + // When the liquid glass effect is enabled, all views must be subviews of the + // content view so that the glass effect can apply properly to all views. + if ([self isLiquidGlassEffectEnabled]) { + [_contentView addSubview:trailingView]; + } else { + [self addSubview:trailingView]; + } +} + +// Sets a top constraint which is bottom omnibox safe. +- (void)setOmniboxSafeTopConstraint:(UIView*)view { + // Lower the top constraint as the omniboxTypingShield can be above it. + NSLayoutConstraint* topConstraint = + [self.topAnchor constraintEqualToAnchor:view.topAnchor]; + topConstraint.priority = UILayoutPriorityRequired - 1; + topConstraint.active = YES; +} + +// Sets the height constraint of the entire keyboard accessory. +- (void)setDefaultHeightConstraint:(UIView*)view { + NSLayoutConstraint* defaultHeightConstraint = + [view.heightAnchor constraintEqualToConstant:[self accessoryHeight]]; + defaultHeightConstraint.priority = UILayoutPriorityDefaultHigh; + defaultHeightConstraint.active = YES; +} + // Returns a view that shows navigation buttons. - (UIView*)viewForNavigationButtons { FormInputAccessoryViewTextData* textData = @@ -564,6 +609,11 @@ // The image should always be set, whether or not there's a title. buttonConfiguration.image = self.manualFillSymbol; + if ([self isLiquidGlassEffectEnabled]) { + buttonConfiguration.contentInsets = NSDirectionalEdgeInsetsMake( + 0, 0, 0, LiquidGlassCloseButtonTrailingInset); + } + if (!_isCompact) { // Set the button title with a custom sized font. FormInputAccessoryViewTextData* textData = @@ -704,12 +754,11 @@ } } - if (![self isLiquidGlassEffectEnabled]) { - buttonConfiguration.contentInsets = NSDirectionalEdgeInsetsMake( - 0, ManualFillCloseButtonLeftInset, - self.closeButtonSymbol ? ManualFillCloseButtonBottomInset : 0, - ManualFillCloseButtonRightInset); - } + buttonConfiguration.contentInsets = NSDirectionalEdgeInsetsMake( + 0, ManualFillCloseButtonLeadingInset, + self.closeButtonSymbol ? ManualFillCloseButtonBottomInset : 0, + [self isLiquidGlassEffectEnabled] ? LiquidGlassCloseButtonTrailingInset + : ManualFillCloseButtonTrailingInset); closeButton.configuration = buttonConfiguration; [closeButton setAccessibilityLabel:textData.closeButtonAccessibilityLabel]; @@ -751,52 +800,84 @@ // Returns the height of the accessory. Returns a larger height when using the // large accessory view. - (CGFloat)accessoryHeight { - return ((_largeAccessoryViewEnabled || [self isLiquidGlassEffectEnabled]) - ? kLargeAccessoryHeight - : kDefaultAccessoryHeight) - - [self bottomPadding]; + return (_largeAccessoryViewEnabled || [self isLiquidGlassEffectEnabled]) + ? kLargeKeyboardAccessoryHeight + : kDefaultAccessoryHeight; } -- (UIView*)backgroundEffectView { +// Sets up the liquid glass effect for the accessory. Returns whether liquid +// glass is enabled. +- (BOOL)setupLiquidGlassEffect { #if defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_26_0 if ([self isLiquidGlassEffectEnabled]) { - // Set content view bounds to match the glass effect. - _contentView.clipsToBounds = true; - _contentView.layer.cornerRadius = [self accessoryHeight] / 2.0; - _contentView.layer.shadowRadius = kShadowRadius; - _contentView.layer.shadowOffset = CGSizeMake(0, kShadowVerticalOffset); - _contentView.layer.shadowOpacity = kShadowOpacity; - _contentView.layer.shadowColor = - [UIColor colorNamed:kBackgroundShadowColor].CGColor; - _contentView.layer.masksToBounds = NO; - if (@available(iOS 26, *)) { // Create glass effect UIGlassEffect* glassEffect = [[UIGlassEffect alloc] init]; glassEffect.interactive = YES; glassEffect.tintColor = [[UIColor colorNamed:kSecondaryBackgroundColor] colorWithAlphaComponent:kGlassTintAlpha]; - return [[UIVisualEffectView alloc] initWithEffect:glassEffect]; - } else { - static constexpr std::string_view errorMessage = - "iOS 26 should always be available when the liquid glass effect is " - "enabled."; - NOTREACHED() << errorMessage; + + UIVisualEffectView* effectView = + [[UIVisualEffectView alloc] initWithEffect:nil]; + effectView.effect = glassEffect; + effectView.cornerConfiguration = [UICornerConfiguration + configurationWithRadius: + [UICornerRadius + containerConcentricRadiusWithMinimum:kCornerRadius]]; + + [self addSubview:effectView]; + + effectView.translatesAutoresizingMaskIntoConstraints = NO; + [self setOmniboxSafeTopConstraint:effectView]; + + // Add padding under and on the sides of the keyboard accessory. + [self.bottomAnchor constraintEqualToAnchor:effectView.bottomAnchor + constant:kSurroundingPadding] + .active = YES; + + [self.trailingAnchor constraintEqualToAnchor:effectView.trailingAnchor + constant:kSurroundingPadding] + .active = YES; + + // For showing a smaller accessory, the width anchor is set instead of the + // leading anchor. + if (_smallWidthAccessoryViewEnabled) { + [effectView.widthAnchor constraintEqualToConstant:kSmallAccessoryWidth] + .active = YES; + } else { + [self.leadingAnchor constraintEqualToAnchor:effectView.leadingAnchor + constant:-kSurroundingPadding] + .active = YES; + } + + _contentView = effectView.contentView; + AddSameConstraints(effectView, _contentView); + [self setDefaultHeightConstraint:effectView]; + + // Add shadow around the glass effect. + self.layer.shadowRadius = kShadowRadius; + self.layer.shadowOffset = CGSizeMake(0, kShadowVerticalOffset); + self.layer.shadowOpacity = kShadowOpacity; + self.layer.shadowColor = + [UIColor colorNamed:kBackgroundShadowColor].CGColor; + self.layer.masksToBounds = NO; + + return YES; } } #endif // defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= - // __IPHONE_26_0 + // __IPHONE_26_0 - return PrimaryBackgroundBlurView(); + return NO; } +// Sets the bottom anchor depending on whether the liquid glass effect is +// enabled. - (void)setBottomAnchorForView:(UIView*)view { if ([self isLiquidGlassEffectEnabled]) { - [view.bottomAnchor - constraintGreaterThanOrEqualToAnchor:self.safeAreaLayoutGuide - .bottomAnchor - constant:-[self bottomPadding]] - .active = YES; + // When using liquid glass, to ensure a constant height, we use the height + // constraints, instead of the bottom constraint. + [self setDefaultHeightConstraint:view]; } else { [view.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor] @@ -804,16 +885,6 @@ } } -// Returns the bottom padding of the accessory. -- (CGFloat)bottomPadding { - return [self isLiquidGlassEffectEnabled] ? kBottomAccessoryPadding : 0; -} - -// Returns the leading and trailing padding of the accessory. -- (CGFloat)sidePadding { - return [self isLiquidGlassEffectEnabled] ? kSideAccessoryPadding : 0; -} - // Applies the proper horizontal padding, depending on whether the keyboard // accessory is in compact mode (tablet only). - (void)setHorizontalConstraints {
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index cfb45c12..954f7c5 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -c26b9b68912804c7dab128431caf4f4e28fb158f \ No newline at end of file +b85d5717b513f04505c17f05b868a0593e7345ae \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index a506bbdb..99909365 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -bf0e8c218a3c3a26942e4e0397b8bb8f19e57b28 \ No newline at end of file +de33e3da4223aedb2f8467ed78d76a3543ce5e5e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index 770f98b79..f1aa726 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -f593c24eaaed2905d207f6a68885d443648ef08e \ No newline at end of file +1cd5a60354e135cf9a763c349658c1b60d165af0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 86b2b21..cdf6159d 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -b01f339dbb8878cc01b2293089c017a5c7137a82 \ No newline at end of file +c5455431f781a42746627f73f76661112c728d96 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 386d7251..b40e257 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -a2e173c831b9a7359c92687120418cbfad38e18d \ No newline at end of file +4091582d5389ff9314a58a2d9a8359b98e356365 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index fb35988..8c8b2063 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -6510b59b87094d5ad124ca32085d8346ecc1099d \ No newline at end of file +b12c04e60675e3e0a048033193391e2ffcccba5d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index 350afb4..9c90be6 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -10c72e95dff8ac43e9e84bb75c670ab3722fb8d1 \ No newline at end of file +8cf4bbd248f7b1b04ab3092ea5001351a944f3d6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index 36109b94..cd1cee7a 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -8ab62e2396653b9d815c438a404b7fc364094300 \ No newline at end of file +c48d1c138738ce5b2bc1766f046bc0149a358730 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index bf7b788..840be82b 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -d7dba46a08bca6c2dd8f25e4c98bd7af98737b58 \ No newline at end of file +2386f465ead61d3838a43f716cb874e4a1b7cbd2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 1a53b59..b55f01e 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -1a5b59714e963f631102ddc282e6df42fa6b471d \ No newline at end of file +065599099acb3b4a1007d6c03931d91bc56f6d9d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index f94e5c6..fc937ce 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -bfeeed4d420bffdf0e23a39ebb8efcdb4f942e2b \ No newline at end of file +e244cd3de6f58a26cbe315d23967e2fa0a7b29f1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index 0c54c5a..cc293a7 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -700dbb4f88f49e1e8643a0294046d88850be0c96 \ No newline at end of file +729e05c31f50caf0f909c762e83067fe9093ba35 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 40698ac..cda3e25 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -57ce7de86299fba51b2fd88634b536d83a755a04 \ No newline at end of file +0f0f1c8a1908a04e840a15ab26aab84e1c4679f6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 0262323..8da002c9 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -fe8c2a14ecb9de13a83bd5f4e8996033a94d3313 \ No newline at end of file +707f0bd7f20ef05cb56d925b41caa15d385ea6a7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 28a7c7f..ce3d968 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -db9d9171c9caef635a3dfcc0000399d99454f31a \ No newline at end of file +cb63e843f4eeaa7453ce73a05c0830457d543ecd \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index 1c6b567..1589180 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -e6247a2ab6491868b434335434eee486027756e9 \ No newline at end of file +0a3ca74a827ae00b523d0e0b631c406dab69672f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 1e3e9ea..db9a834fc 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -ff4911a6c532100a44496e8c3ca9b11abb0fb9a2 \ No newline at end of file +c4b73a50e3e216a4276717a2bb3551d763ef8dbd \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 9dde8c1..3ff1655c 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -bcce77eb2e221a4a7ff02d3cfdd9ca3649af2004 \ No newline at end of file +9d91195beca8c66b8dba12784952fa09ae3855e4 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index c5de915..3e0d291b 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -6d1de83744f3d84db19d7c72ac5fc9126a66443e \ No newline at end of file +8f7167c3b36ea4162b6fe366f196d70dffb5ed42 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index bbca019..9af2154b4 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -cc371071531dbedb97dc06281946766122386938 \ No newline at end of file +d4169908d42b910ecc78fb5647640acf02a8f9a1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index e5d4bb8..6b05331 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -687a533646a8f0eabc75e630a7e26b9086e0d3d0 \ No newline at end of file +108ae8b2c0e797abe2ad6b73a51e9b286b813fef \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 index 31214a9..808bf39 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -21dfb7a27cd1e3ba0193020020dcd6566b6613ef \ No newline at end of file +0ee875880ad325d8e2d63da178e674a14a20d39d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 7024081..5f6d5d3 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -ebb5e2651a2855282639497a8d5529aaff373b8e \ No newline at end of file +88d2e8e297839b5eb4dc5e082263710b0280ebc9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 8d8271da..aa0d5ca 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -40ec0a3f19f211488a2a516e700105b786420d83 \ No newline at end of file +f87b413bf603f1367d4c72c3c7ef00726c9b6579 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index b26b431e..9a8b223 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -a1ad983101f194b232e9900f547e055f67fbad82 \ No newline at end of file +c0b15b5a06a31846a0bda9323496845cb684838a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 0964cc2f..77e0b7d 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -8e1d3423c7d4477fc83bd493027bbabfbd57d9e2 \ No newline at end of file +5d1c680a9f849a23845997fa500a4f262809d2f9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 26249db7..8c3bb1d 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -25d62251d9382a8451cff5bcbe3636bfab90f602 \ No newline at end of file +ac38812d4ab5c00b6a02115e439b3bba5f2ff5d8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index e5b38896..3f2a1915 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -fdb10eff3966dfafcea5778af57c9a9fa33bb23d \ No newline at end of file +013a44e2f3e48289efaae69bea315475e68f1cba \ No newline at end of file
diff --git a/ios/third_party/edo/src b/ios/third_party/edo/src index 5030b6a..d228369 160000 --- a/ios/third_party/edo/src +++ b/ios/third_party/edo/src
@@ -1 +1 @@ -Subproject commit 5030b6a79c86f3b0787061f9c933b7476631efe3 +Subproject commit d228369931f0872e32743ca2cbfea72eaf2e44bc
diff --git a/ios_internal b/ios_internal index b4ec3b0..25a37b7 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit b4ec3b01aa013126eb9a2de9f7c99ea44da5ac39 +Subproject commit 25a37b7335a2cd2fe671e0c85e716fd794c8648c
diff --git a/media/audio/audio_features.cc b/media/audio/audio_features.cc index c4f2106..1bb8a86c 100644 --- a/media/audio/audio_features.cc +++ b/media/audio/audio_features.cc
@@ -10,6 +10,14 @@ namespace features { +#if BUILDFLAG(IS_WIN) +// Enables application audio capture for getDisplayMedia (gDM) window capture in +// Windows. +BASE_FEATURE(kApplicationAudioCaptureWin, + "ApplicationAudioCaptureWin", + base::FEATURE_DISABLED_BY_DEFAULT); +#endif + #if BUILDFLAG(IS_ANDROID) // Enables loading and using AAudio instead of OpenSLES on compatible devices, // for audio output streams. This feature is disabled on ATV HDMI dongle devices @@ -52,3 +60,14 @@ } // namespace features +namespace media { + +bool IsApplicationAudioCaptureSupported() { +#if BUILDFLAG(IS_WIN) + return base::FeatureList::IsEnabled(features::kApplicationAudioCaptureWin); +#else + return false; +#endif // BUILDFLAG(IS_WIN) +} + +} // namespace media
diff --git a/media/audio/audio_features.h b/media/audio/audio_features.h index c7bb658d..b82ca012 100644 --- a/media/audio/audio_features.h +++ b/media/audio/audio_features.h
@@ -11,6 +11,10 @@ namespace features { +#if BUILDFLAG(IS_WIN) +MEDIA_EXPORT BASE_DECLARE_FEATURE(kApplicationAudioCaptureWin); +#endif + #if BUILDFLAG(IS_ANDROID) MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseAAudioDriver); MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseAAudioInput); @@ -21,4 +25,11 @@ } // namespace features +namespace media { + +// Returns true if application audio capture is implemented for the current OS. +MEDIA_EXPORT bool IsApplicationAudioCaptureSupported(); + +} // namespace media + #endif // MEDIA_AUDIO_AUDIO_FEATURES_H_
diff --git a/media/capture/video/win/gpu_memory_buffer_tracker_win.h b/media/capture/video/win/gpu_memory_buffer_tracker_win.h index 0062830..d7b2bc6 100644 --- a/media/capture/video/win/gpu_memory_buffer_tracker_win.h +++ b/media/capture/video/win/gpu_memory_buffer_tracker_win.h
@@ -64,7 +64,6 @@ gfx::DXGIHandle dxgi_handle_; gfx::Size dimensions_; - gfx::GpuMemoryBufferId handle_id_; int stride_; scoped_refptr<DXGIDeviceManager> dxgi_device_manager_; Microsoft::WRL::ComPtr<ID3D11Device> d3d_device_;
diff --git a/media/gpu/chromeos/native_pixmap_frame_resource.cc b/media/gpu/chromeos/native_pixmap_frame_resource.cc index cb6d04b..12e75cf4 100644 --- a/media/gpu/chromeos/native_pixmap_frame_resource.cc +++ b/media/gpu/chromeos/native_pixmap_frame_resource.cc
@@ -5,6 +5,7 @@ #include "media/gpu/chromeos/native_pixmap_frame_resource.h" #include <atomic> +#include <limits> #include <utility> #include "base/feature_list.h" @@ -26,10 +27,11 @@ namespace { gfx::GenericSharedMemoryId GetNextSharedMemoryId() { - // This uses the same ID generator that is used for creating ID's for GPU - // memory buffers. Doing so avoids overlapping ID's. No cast is necessary - // since gfx::GpuMemoryBufferId is an alias of gfx::GenericSharedMemoryId. - return GetNextGpuMemoryBufferId(); + static base::NoDestructor<base::Lock> id_lock; + static int next_id = 0; + base::AutoLock lock(*id_lock); + CHECK_LT(next_id, std::numeric_limits<int>::max()); + return gfx::GenericSharedMemoryId(next_id++); } // IsValidSize() performs size validity checks similar to those in
diff --git a/media/gpu/chromeos/native_pixmap_frame_resource.h b/media/gpu/chromeos/native_pixmap_frame_resource.h index 34277dd..e71a0ba 100644 --- a/media/gpu/chromeos/native_pixmap_frame_resource.h +++ b/media/gpu/chromeos/native_pixmap_frame_resource.h
@@ -92,9 +92,7 @@ scoped_refptr<const gfx::NativePixmapDmaBuf> GetNativePixmapDmaBuf() const override; // CreateGpuMemoryBufferHandle() will duplicate file descriptors to make a - // gfx::GpuMemoryBufferHandle. The GpuMemoryBufferId will be set to a - // consistent value in subsequent calls for |this| or for any wrapping frame - // of |this|. + // gfx::GpuMemoryBufferHandle. gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle() const override; // Always returns nullptr. std::unique_ptr<VideoFrame::ScopedMapping> MapGMBOrSharedImage()
diff --git a/media/gpu/chromeos/platform_video_frame_utils.cc b/media/gpu/chromeos/platform_video_frame_utils.cc index 3cc6ae5..e0658ff 100644 --- a/media/gpu/chromeos/platform_video_frame_utils.cc +++ b/media/gpu/chromeos/platform_video_frame_utils.cc
@@ -380,14 +380,6 @@ metadata.tracking_token = GenerateToken(); } -gfx::GpuMemoryBufferId GetNextGpuMemoryBufferId() { - static base::NoDestructor<base::Lock> id_lock; - static int next_gpu_memory_buffer_id = 0; - base::AutoLock lock(*id_lock); - CHECK_LT(next_gpu_memory_buffer_id, std::numeric_limits<int>::max()); - return gfx::GpuMemoryBufferId(next_gpu_memory_buffer_id++); -} - scoped_refptr<VideoFrame> CreateMappableVideoFrame( VideoPixelFormat pixel_format, const gfx::Size& coded_size,
diff --git a/media/gpu/chromeos/platform_video_frame_utils.h b/media/gpu/chromeos/platform_video_frame_utils.h index 7e6b400..cc53abf4 100644 --- a/media/gpu/chromeos/platform_video_frame_utils.h +++ b/media/gpu/chromeos/platform_video_frame_utils.h
@@ -60,10 +60,6 @@ std::set<base::UnguessableToken> tokens_; }; -// Returns a GpuMemoryBufferId that's guaranteed to be different from those -// returned by previous calls. This function is thread safe. -MEDIA_GPU_EXPORT gfx::GpuMemoryBufferId GetNextGpuMemoryBufferId(); - // Creates a GpuMemoryBufferHandle. This function is thread safe. gfx::GpuMemoryBufferHandle AllocateGpuMemoryBufferHandle( VideoPixelFormat pixel_format,
diff --git a/media/gpu/chromeos/vd_video_decode_accelerator.cc b/media/gpu/chromeos/vd_video_decode_accelerator.cc index 0f8c3527..08975be 100644 --- a/media/gpu/chromeos/vd_video_decode_accelerator.cc +++ b/media/gpu/chromeos/vd_video_decode_accelerator.cc
@@ -583,8 +583,7 @@ CHECK(res.second); // |wrapped_frame| is used to keep |origin_frame| alive until everyone - // released |wrapped_frame|. Then GpuMemoryBufferId will be available at - // OnFrameReleased(). + // released |wrapped_frame|. scoped_refptr<FrameResource> wrapped_frame = origin_frame->CreateWrappingFrame(); wrapped_frame->AddDestructionObserver(
diff --git a/net/test/embedded_test_server/connection_tracker.cc b/net/test/embedded_test_server/connection_tracker.cc index e2d28411..bd76029 100644 --- a/net/test/embedded_test_server/connection_tracker.cc +++ b/net/test/embedded_test_server/connection_tracker.cc
@@ -77,8 +77,8 @@ // expects the server will not accept more than |num_connections| connections. // |num_connections| must be greater than 0. void ConnectionTracker::WaitForAcceptedConnections(size_t num_connections) { - CHECK(!num_accepted_connections_loop_); - CHECK_GT(num_connections, 0u); + DCHECK(!num_accepted_connections_loop_); + DCHECK_GT(num_connections, 0u); base::RunLoop run_loop; EXPECT_GE(num_connections, num_connected_sockets_); num_accepted_connections_loop_ = &run_loop; @@ -97,8 +97,8 @@ void ConnectionTracker::CheckAccepted() { // |num_accepted_connections_loop_| null implies // |num_accepted_connections_needed_| == 0. - CHECK(num_accepted_connections_loop_ || - num_accepted_connections_needed_ == 0); + DCHECK(num_accepted_connections_loop_ || + num_accepted_connections_needed_ == 0); if (!num_accepted_connections_loop_ || num_accepted_connections_needed_ != num_connected_sockets_) { return;
diff --git a/net/test/embedded_test_server/create_websocket_handler.cc b/net/test/embedded_test_server/create_websocket_handler.cc index fda0d07..96af1ea 100644 --- a/net/test/embedded_test_server/create_websocket_handler.cc +++ b/net/test/embedded_test_server/create_websocket_handler.cc
@@ -36,8 +36,8 @@ auto error_response = std::make_unique<BasicHttpResponse>(); error_response->set_code(code); error_response->set_content(content); - VLOG(3) << "Error response created. Code: " << static_cast<int>(code) - << ", Content: " << content; + DVLOG(3) << "Error response created. Code: " << static_cast<int>(code) + << ", Content: " << content; return error_response; } @@ -47,7 +47,7 @@ EmbeddedTestServer* server, const HttpRequest& request, HttpConnection* connection) { - VLOG(3) << "Handling WebSocket upgrade for path: " << handle_path; + DVLOG(3) << "Handling WebSocket upgrade for path: " << handle_path; std::string_view request_path = StripQuery(request.relative_url); @@ -66,14 +66,14 @@ auto host_header = request.headers.find("Host"); if (host_header == request.headers.end()) { - VLOG(1) << "Host header is missing."; + DVLOG(1) << "Host header is missing."; return base::unexpected(MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Host header is missing.")); } HostPortPair host_port = HostPortPair::FromString(host_header->second); if (!IsCanonicalizedHostCompliant(host_port.host())) { - VLOG(1) << "Host header is invalid: " << host_port.host(); + DVLOG(1) << "Host header is invalid: " << host_port.host(); return base::unexpected(MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Host header is invalid.")); } @@ -81,8 +81,8 @@ auto upgrade_header = request.headers.find("Upgrade"); if (upgrade_header == request.headers.end() || !base::EqualsCaseInsensitiveASCII(upgrade_header->second, "websocket")) { - VLOG(1) << "Upgrade header is missing or invalid: " - << upgrade_header->second; + DVLOG(1) << "Upgrade header is missing or invalid: " + << upgrade_header->second; return base::unexpected( MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Upgrade header is missing or invalid.")); @@ -90,7 +90,7 @@ auto connection_header = request.headers.find("Connection"); if (connection_header == request.headers.end()) { - VLOG(1) << "Connection header is missing."; + DVLOG(1) << "Connection header is missing."; return base::unexpected(MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Connection header is missing.")); } @@ -101,8 +101,8 @@ if (!std::ranges::any_of(tokens, [](std::string_view token) { return base::EqualsCaseInsensitiveASCII(token, "Upgrade"); })) { - VLOG(1) << "Connection header does not contain 'Upgrade'. Tokens: " - << connection_header->second; + DVLOG(1) << "Connection header does not contain 'Upgrade'. Tokens: " + << connection_header->second; return base::unexpected( MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Connection header does not contain 'Upgrade'.")); @@ -111,15 +111,15 @@ auto websocket_version_header = request.headers.find("Sec-WebSocket-Version"); if (websocket_version_header == request.headers.end() || websocket_version_header->second != "13") { - VLOG(1) << "Invalid or missing Sec-WebSocket-Version: " - << websocket_version_header->second; + DVLOG(1) << "Invalid or missing Sec-WebSocket-Version: " + << websocket_version_header->second; return base::unexpected(MakeErrorResponse( HttpStatusCode::HTTP_BAD_REQUEST, "Sec-WebSocket-Version must be 13.")); } auto sec_websocket_key_iter = request.headers.find("Sec-WebSocket-Key"); if (sec_websocket_key_iter == request.headers.end()) { - VLOG(1) << "Sec-WebSocket-Key header is missing."; + DVLOG(1) << "Sec-WebSocket-Key header is missing."; return base::unexpected( MakeErrorResponse(HttpStatusCode::HTTP_BAD_REQUEST, "Sec-WebSocket-Key header is missing.")); @@ -127,7 +127,7 @@ auto decoded = base::Base64Decode(sec_websocket_key_iter->second); if (!decoded || decoded->size() != 16) { - VLOG(1) << "Sec-WebSocket-Key is invalid or has incorrect length."; + DVLOG(1) << "Sec-WebSocket-Key is invalid or has incorrect length."; return base::unexpected(MakeErrorResponse( HttpStatusCode::HTTP_BAD_REQUEST, "Sec-WebSocket-Key is invalid or has incorrect length."));
diff --git a/net/test/embedded_test_server/default_handlers.cc b/net/test/embedded_test_server/default_handlers.cc index 5dcdfd6d..f46cfda6 100644 --- a/net/test/embedded_test_server/default_handlers.cc +++ b/net/test/embedded_test_server/default_handlers.cc
@@ -849,7 +849,7 @@ // /gzip-body?<body> // Returns a response with a gzipped body of "<body>". Attempts to allocate -// enough memory to contain the body, but CHECKs if that fails. +// enough memory to contain the body, but DCHECKs if that fails. std::unique_ptr<HttpResponse> HandleGzipBody(const HttpRequest& request) { std::string uncompressed_body = request.GetURL().query(); auto compressed_body = CompressGzip(uncompressed_body); @@ -927,7 +927,7 @@ } void SendNextChunk() { - CHECK_GT(remaining_chunks_, 0); + DCHECK_GT(remaining_chunks_, 0); remaining_chunks_--; delegate_->SendContents(
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc index 871a47e..f23f5c1 100644 --- a/net/test/embedded_test_server/embedded_test_server.cc +++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -286,9 +286,9 @@ EmbeddedTestServer::EmbeddedTestServer(Type type, HttpConnection::Protocol protocol) : is_using_ssl_(type == TYPE_HTTPS), protocol_(protocol) { - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); // HTTP/2 is only valid by negotiation via TLS ALPN - CHECK(protocol_ != HttpConnection::Protocol::kHttp2 || type == TYPE_HTTPS); + DCHECK(protocol_ != HttpConnection::Protocol::kHttp2 || type == TYPE_HTTPS); if (!is_using_ssl_) return; @@ -296,7 +296,7 @@ } EmbeddedTestServer::~EmbeddedTestServer() { - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); if (Started()) CHECK(ShutdownAndWaitUntilComplete()); @@ -317,7 +317,7 @@ void EmbeddedTestServer::SetConnectionListener( EmbeddedTestServerConnectionListener* listener) { - CHECK(!io_thread_) + DCHECK(!io_thread_) << "ConnectionListener must be set before starting the server."; connection_listener_ = listener; } @@ -336,7 +336,7 @@ bool EmbeddedTestServer::InitializeAndListen(int port, std::string_view address) { - CHECK(!Started()); + DCHECK(!Started()); const int max_tries = 5; int num_tries = 0; @@ -344,8 +344,8 @@ do { if (++num_tries > max_tries) { - LOG(ERROR) << "Failed to listen on a valid port after " << max_tries - << " attempts."; + DVLOG(1) << "Failed to listen on a valid port after " << max_tries + << " attempts."; listen_socket_.reset(); return false; } @@ -355,14 +355,14 @@ int result = listen_socket_->ListenWithAddressAndPort(address.data(), port, 10); if (result) { - LOG(ERROR) << "Listen failed: " << ErrorToString(result); + DVLOG(1) << "Listen failed: " << ErrorToString(result); listen_socket_.reset(); return false; } result = listen_socket_->GetLocalAddress(&local_endpoint_); if (result != OK) { - LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); + DVLOG(1) << "GetLocalAddress failed: " << ErrorToString(result); listen_socket_.reset(); return false; } @@ -385,7 +385,7 @@ listen_socket_->DetachFromThread(); if (is_using_ssl_ && !InitializeSSLServerContext()) { - LOG(ERROR) << "Unable to initialize SSL"; + DVLOG(1) << "Unable to initialize SSL"; return false; } @@ -583,12 +583,12 @@ bool EmbeddedTestServer::InitializeSSLServerContext() { if (UsingStaticCert()) { if (!InitializeCertAndKeyFromFile()) { - LOG(ERROR) << "Unable to initialize cert and key from file"; + DVLOG(1) << "Unable to initialize cert and key from file"; return false; } } else { if (!GenerateCertAndKey()) { - LOG(ERROR) << "Unable to generate cert and key"; + DVLOG(1) << "Unable to generate cert and key"; return false; } } @@ -626,7 +626,7 @@ } spdy::SpdySerializedFrame serialized_frame = builder.take(); - CHECK_EQ(frame_size, serialized_frame.size()); + DCHECK_EQ(frame_size, serialized_frame.size()); std::string_view serialized_frame_view(serialized_frame); ssl_config_.application_settings[NextProto::kProtoHTTP2] = @@ -667,8 +667,8 @@ } void EmbeddedTestServer::StartAcceptingConnections() { - CHECK(Started()); - CHECK(!io_thread_) << "Server must not be started while server is running"; + DCHECK(Started()); + DCHECK(!io_thread_) << "Server must not be started while server is running"; if (aia_http_server_) aia_http_server_->StartAcceptingConnections(); @@ -685,7 +685,7 @@ } bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); if (!io_thread_) { // Can't stop a server that never started. @@ -712,7 +712,7 @@ } void EmbeddedTestServer::ShutdownOnIOThread() { - CHECK(io_thread_->task_runner()->BelongsToCurrentThread()); + DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); weak_factory_.InvalidateWeakPtrs(); shutdown_closures_.Notify(); listen_socket_.reset(); @@ -733,7 +733,7 @@ base::WeakPtr<HttpResponseDelegate> delegate, std::unique_ptr<HttpRequest> request, const StreamSocket* socket) { - CHECK(io_thread_->task_runner()->BelongsToCurrentThread()); + DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); request->base_url = base_url_; for (const auto& monitor : request_monitors_) @@ -798,7 +798,7 @@ } if (!response) { - VLOG(2) << "Request not handled. Returning 404: " << request->relative_url; + DVLOG(2) << "Request not handled. Returning 404: " << request->relative_url; auto not_found_response = std::make_unique<BasicHttpResponse>(); not_found_response->set_code(HTTP_NOT_FOUND); response = std::move(not_found_response); @@ -808,8 +808,8 @@ } GURL EmbeddedTestServer::GetURL(std::string_view relative_url) const { - CHECK(Started()) << "You must start the server first."; - CHECK(relative_url.starts_with("/")) << relative_url; + DCHECK(Started()) << "You must start the server first."; + DCHECK(relative_url.starts_with("/")) << relative_url; return base_url_.Resolve(relative_url); } @@ -841,9 +841,9 @@ ServerCertificate cert, const ServerCertificateConfig* cert_config, const SSLServerConfig& ssl_config) { - CHECK(!Started()); + DCHECK(!Started()); cert_ = cert; - CHECK(!cert_config || cert == CERT_AUTO); + DCHECK(!cert_config || cert == CERT_AUTO); cert_config_ = cert_config ? *cert_config : ServerCertificateConfig(); x509_cert_ = nullptr; private_key_ = nullptr; @@ -895,7 +895,7 @@ } std::string EmbeddedTestServer::GetCertificateName() const { - CHECK(is_using_ssl_); + DCHECK(is_using_ssl_); switch (cert_) { case CERT_OK: case CERT_MISMATCHED_NAME: @@ -928,7 +928,7 @@ } scoped_refptr<X509Certificate> EmbeddedTestServer::GetCertificate() { - CHECK(is_using_ssl_); + DCHECK(is_using_ssl_); if (!x509_cert_) { // Some tests want to get the certificate before the server has been // initialized, so load it now if necessary. This is only possible if using @@ -944,13 +944,13 @@ } scoped_refptr<X509Certificate> EmbeddedTestServer::GetGeneratedIntermediate() { - CHECK(is_using_ssl_); - CHECK(!UsingStaticCert()); + DCHECK(is_using_ssl_); + DCHECK(!UsingStaticCert()); return intermediate_; } scoped_refptr<X509Certificate> EmbeddedTestServer::GetRoot() { - CHECK(is_using_ssl_); + DCHECK(is_using_ssl_); return root_; } @@ -992,7 +992,7 @@ CHECK(!io_thread_) << "Handlers must be registered before starting the server."; if (auth_handler_) { - VLOG(2) << "Overwriting existing Auth handler."; + DVLOG(2) << "Overwriting existing Auth handler."; } auth_handler_ = callback; } @@ -1018,28 +1018,28 @@ void EmbeddedTestServer::RegisterRequestHandler( const HandleRequestCallback& callback) { - CHECK(!io_thread_) + DCHECK(!io_thread_) << "Handlers must be registered before starting the server."; request_handlers_.push_back(callback); } void EmbeddedTestServer::RegisterRequestMonitor( const MonitorRequestCallback& callback) { - CHECK(!io_thread_) + DCHECK(!io_thread_) << "Monitors must be registered before starting the server."; request_monitors_.push_back(callback); } void EmbeddedTestServer::RegisterDefaultHandler( const HandleRequestCallback& callback) { - CHECK(!io_thread_) + DCHECK(!io_thread_) << "Handlers must be registered before starting the server."; default_request_handlers_.push_back(callback); } std::unique_ptr<SSLServerSocket> EmbeddedTestServer::DoSSLUpgrade( std::unique_ptr<StreamSocket> connection) { - CHECK(io_thread_->task_runner()->BelongsToCurrentThread()); + DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); return context_->CreateSSLServerSocket(std::move(connection)); } @@ -1078,7 +1078,7 @@ } void EmbeddedTestServer::OnAcceptCompleted(int rv) { - CHECK_NE(ERR_IO_PENDING, rv); + DCHECK_NE(ERR_IO_PENDING, rv); HandleAcceptResult(std::move(accepted_socket_)); DoAcceptLoop(); } @@ -1093,7 +1093,7 @@ void EmbeddedTestServer::HandleAcceptResult( std::unique_ptr<StreamSocket> socket_ptr) { - CHECK(io_thread_->task_runner()->BelongsToCurrentThread()); + DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); if (connection_listener_) socket_ptr = connection_listener_->AcceptedSocket(std::move(socket_ptr)); @@ -1128,9 +1128,9 @@ void EmbeddedTestServer::RemoveConnection( HttpConnection* connection, EmbeddedTestServerConnectionListener* listener) { - CHECK(io_thread_->task_runner()->BelongsToCurrentThread()); - CHECK(connection); - CHECK_EQ(1u, connections_.count(connection->Socket())); + DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); + DCHECK(connection); + DCHECK_EQ(1u, connections_.count(connection->Socket())); StreamSocket* raw_socket = connection->Socket(); std::unique_ptr<StreamSocket> socket = connection->TakeSocket();
diff --git a/net/test/embedded_test_server/http2_connection.cc b/net/test/embedded_test_server/http2_connection.cc index 7b7a3c29..eba9897 100644 --- a/net/test/embedded_test_server/http2_connection.cc +++ b/net/test/embedded_test_server/http2_connection.cc
@@ -242,7 +242,7 @@ } // Any frames and data sources will be queued up and sent all at once below - CHECK(!processing_responses_); + DCHECK(!processing_responses_); processing_responses_ = true; while (!ready_streams_.empty()) { StreamId stream_id = ready_streams_.front(); @@ -310,8 +310,8 @@ } void Http2Connection::SendInternal() { - CHECK(socket_); - CHECK(write_buf_); + DCHECK(socket_); + DCHECK(write_buf_); while (write_buf_->BytesRemaining() > 0) { int rv = socket_->Write(write_buf_.get(), write_buf_->BytesRemaining(), base::BindOnce(&Http2Connection::OnSendInternalDone, @@ -331,7 +331,7 @@ } void Http2Connection::OnSendInternalDone(int rv) { - CHECK(write_buf_); + DCHECK(write_buf_); if (rv < 0) { embedded_test_server_->RemoveConnection(this); write_buf_ = nullptr; @@ -385,7 +385,7 @@ request->has_content = false; SSLInfo ssl_info; - CHECK(socket_->GetSSLInfo(&ssl_info)); + DCHECK(socket_->GetSSLInfo(&ssl_info)); request->ssl_info = ssl_info; request_map_[stream_id] = std::move(request);
diff --git a/net/test/embedded_test_server/http_connect_proxy_handler.cc b/net/test/embedded_test_server/http_connect_proxy_handler.cc index 4d605146..239e53e 100644 --- a/net/test/embedded_test_server/http_connect_proxy_handler.cc +++ b/net/test/embedded_test_server/http_connect_proxy_handler.cc
@@ -70,7 +70,7 @@ // If unable to connect, write a bad gateway error to `socket_` before // deleting `this`. if (result != OK) { - VLOG(1) << "Failed to establish tunnel connection."; + DVLOG(1) << "Failed to establish tunnel connection."; BasicHttpResponse response; response.set_code(HttpStatusCode::HTTP_BAD_GATEWAY);
diff --git a/net/test/embedded_test_server/http_request.cc b/net/test/embedded_test_server/http_request.cc index eca44bc..ab036c04 100644 --- a/net/test/embedded_test_server/http_request.cc +++ b/net/test/embedded_test_server/http_request.cc
@@ -51,13 +51,13 @@ void HttpRequestParser::ProcessChunk(std::string_view data) { buffer_.append(data); - CHECK_LE(buffer_.size() + data.size(), kRequestSizeLimit) - << "The HTTP request is too large."; + DCHECK_LE(buffer_.size() + data.size(), kRequestSizeLimit) << + "The HTTP request is too large."; } std::string HttpRequestParser::ShiftLine() { size_t eoln_position = buffer_.find("\r\n", buffer_position_); - CHECK_NE(std::string::npos, eoln_position); + DCHECK_NE(std::string::npos, eoln_position); const int line_length = eoln_position - buffer_position_; std::string result = buffer_.substr(buffer_position_, line_length); buffer_position_ += line_length + 2; @@ -65,7 +65,7 @@ } HttpRequestParser::ParseResult HttpRequestParser::ParseRequest() { - CHECK_NE(STATE_ACCEPTED, state_); + DCHECK_NE(STATE_ACCEPTED, state_); // Parse the request from beginning. However, entire request may not be // available in the buffer. if (state_ == STATE_HEADERS) { @@ -94,7 +94,7 @@ http_request_->all_headers += header_line + "\r\n"; std::vector<std::string> header_line_tokens = base::SplitString( header_line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - CHECK_EQ(3u, header_line_tokens.size()); + DCHECK_EQ(3u, header_line_tokens.size()); // Method. http_request_->method_string = header_line_tokens[0]; http_request_->method = GetMethodType(http_request_->method_string); @@ -151,7 +151,7 @@ } else { // New header. size_t delimiter_pos = header_line.find(":"); - CHECK_NE(std::string::npos, delimiter_pos) << "Syntax error."; + DCHECK_NE(std::string::npos, delimiter_pos) << "Syntax error."; header_name = Trim(header_line.substr(0, delimiter_pos)); std::string header_value = Trim(header_line.substr( delimiter_pos + 1, @@ -236,7 +236,7 @@ } std::unique_ptr<HttpRequest> HttpRequestParser::GetRequest() { - CHECK_EQ(STATE_ACCEPTED, state_); + DCHECK_EQ(STATE_ACCEPTED, state_); std::unique_ptr<HttpRequest> result = std::move(http_request_); // Prepare for parsing a new request.
diff --git a/net/test/embedded_test_server/install_default_websocket_handlers.cc b/net/test/embedded_test_server/install_default_websocket_handlers.cc index e4d14bc..6850185 100644 --- a/net/test/embedded_test_server/install_default_websocket_handlers.cc +++ b/net/test/embedded_test_server/install_default_websocket_handlers.cc
@@ -50,8 +50,8 @@ GURL GetWebSocketURL(const EmbeddedTestServer& server, std::string_view relative_url) { - CHECK(server.Started()) << "Server must be started to get WebSocket URL"; - CHECK(relative_url.starts_with("/")) << "Relative URL should start with '/'"; + DCHECK(server.Started()) << "Server must be started to get WebSocket URL"; + DCHECK(relative_url.starts_with("/")) << "Relative URL should start with '/'"; GURL base_url = server.base_url().Resolve(relative_url); return ToWebSocketUrl(base_url); @@ -60,8 +60,8 @@ GURL GetWebSocketURL(const EmbeddedTestServer& server, std::string_view hostname, std::string_view relative_url) { - CHECK(server.Started()) << "Server must be started to get WebSocket URL"; - CHECK(relative_url.starts_with("/")) << "Relative URL should start with '/'"; + DCHECK(server.Started()) << "Server must be started to get WebSocket URL"; + DCHECK(relative_url.starts_with("/")) << "Relative URL should start with '/'"; GURL local_url = GetWebSocketURL(server, relative_url); GURL::Replacements replacements;
diff --git a/net/test/embedded_test_server/register_basic_auth_handler.cc b/net/test/embedded_test_server/register_basic_auth_handler.cc index d6074d9..00bd70b 100644 --- a/net/test/embedded_test_server/register_basic_auth_handler.cc +++ b/net/test/embedded_test_server/register_basic_auth_handler.cc
@@ -54,12 +54,12 @@ if (auth_header == request.headers.end() || auth_header->second != expected_auth_header) { - VLOG(1) << "Authorization failed or header missing. For Proxy: " - << std::boolalpha << is_proxy_auth; + DVLOG(1) << "Authorization failed or header missing. For Proxy: " + << std::boolalpha << is_proxy_auth; return CreateUnauthorizedResponse(is_proxy_auth); } - VLOG(3) << "Authorization successful. For Proxy: " << is_proxy_auth; + DVLOG(3) << "Authorization successful. For Proxy: " << is_proxy_auth; return nullptr; }
diff --git a/net/test/embedded_test_server/request_handler_util.cc b/net/test/embedded_test_server/request_handler_util.cc index 3d6ec86e..6a2fc54 100644 --- a/net/test/embedded_test_server/request_handler_util.cc +++ b/net/test/embedded_test_server/request_handler_util.cc
@@ -199,7 +199,7 @@ } // Trim the first byte ('/'). - CHECK(relative_path.starts_with("/")); + DCHECK(relative_path.starts_with("/")); std::string request_path = relative_path.substr(1); base::FilePath file_path(server_root.AppendASCII(request_path)); std::string file_contents;
diff --git a/net/test/embedded_test_server/websocket_check_origin_handler.cc b/net/test/embedded_test_server/websocket_check_origin_handler.cc index 2179ca8..ea0224b 100644 --- a/net/test/embedded_test_server/websocket_check_origin_handler.cc +++ b/net/test/embedded_test_server/websocket_check_origin_handler.cc
@@ -20,12 +20,12 @@ CHECK(it != request.headers.end()); origin_ = it->second; - VLOG(3) << "Stored WebSocket origin: " << origin_; + DVLOG(3) << "Stored WebSocket origin: " << origin_; } void WebSocketCheckOriginHandler::OnHandshakeComplete() { CHECK(connection()); - VLOG(3) << "Sending stored origin after handshake completion: " << origin_; + DVLOG(3) << "Sending stored origin after handshake completion: " << origin_; connection()->SendTextMessage(origin_); connection()->StartClosingHandshake(1000, "Goodbye"); }
diff --git a/net/test/embedded_test_server/websocket_close_observer_handler.cc b/net/test/embedded_test_server/websocket_close_observer_handler.cc index 4d2229b1..e6d3b1f 100644 --- a/net/test/embedded_test_server/websocket_close_observer_handler.cc +++ b/net/test/embedded_test_server/websocket_close_observer_handler.cc
@@ -47,7 +47,7 @@ std::string role; if (!GetValueForKeyInQuery(request.GetURL(), "role", &role)) { - VLOG(1) << "Missing required 'role' parameter."; + DVLOG(1) << "Missing required 'role' parameter."; SendBadRequest("Missing required 'role' parameter."); return; } @@ -59,7 +59,7 @@ } else if (role == "observed") { role_ = Role::kObserved; } else { - VLOG(1) << "Invalid 'role' parameter: " << role; + DVLOG(1) << "Invalid 'role' parameter: " << role; SendBadRequest("Invalid 'role' parameter."); return; } @@ -68,7 +68,7 @@ void WebSocketCloseObserverHandler::OnClosingHandshake( std::optional<uint16_t> code, std::string_view message) { - VLOG(3) << "OnClosingHandshake()"; + DVLOG(3) << "OnClosingHandshake()"; if (role_ == Role::kObserved) { g_code = code.value_or(1006); @@ -79,7 +79,7 @@ } void WebSocketCloseObserverHandler::BeObserver() { - VLOG(3) << "BeObserver()"; + DVLOG(3) << "BeObserver()"; if (g_code) { SendCloseCode(); } else {
diff --git a/net/test/embedded_test_server/websocket_connection.cc b/net/test/embedded_test_server/websocket_connection.cc index ab8d06a6..e1b67e4 100644 --- a/net/test/embedded_test_server/websocket_connection.cc +++ b/net/test/embedded_test_server/websocket_connection.cc
@@ -93,13 +93,13 @@ std::string_view message) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!stream_socket_) { - VLOG(2) << "Attempted to start closing handshake, but socket is null."; + DVLOG(2) << "Attempted to start closing handshake, but socket is null."; return; } - VLOG(3) << "Starting closing handshake. Code: " - << (code ? base::NumberToString(*code) : "none") - << ", Message: " << message; + DVLOG(3) << "Starting closing handshake. Code: " + << (code ? base::NumberToString(*code) : "none") + << ", Message: " << message; if (!code) { CHECK(base::IsStringUTF8AllowingNoncharacters(message)); @@ -120,8 +120,8 @@ std::string_view message) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (state_ == WebSocketState::kClosed) { - VLOG(2) << "Attempted to respond to close frame, but connection is " - "already closed."; + DVLOG(2) << "Attempted to respond to close frame, but connection is " + "already closed."; return; } @@ -155,7 +155,7 @@ void WebSocketConnection::DisconnectAfterAnyWritesDone() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!stream_socket_) { - VLOG(3) << "Socket is already disconnected."; + DVLOG(3) << "Socket is already disconnected."; return; } @@ -172,7 +172,7 @@ void WebSocketConnection::DisconnectImmediately() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!stream_socket_) { - VLOG(3) << "Socket is already disconnected."; + DVLOG(3) << "Socket is already disconnected."; handler_.reset(); return; } @@ -239,7 +239,7 @@ void WebSocketConnection::OnWriteComplete(int result) VALID_CONTEXT_REQUIRED(sequence_checker_) { if (result < 0) { - VLOG(1) << "Failed to write to WebSocket connection, error: " << result; + DVLOG(1) << "Failed to write to WebSocket connection, error: " << result; DisconnectImmediately(); return; } @@ -281,13 +281,13 @@ void WebSocketConnection::OnReadComplete(int result) VALID_CONTEXT_REQUIRED(sequence_checker_) { if (result <= 0) { - VLOG(1) << "Failed to read from WebSocket connection, error: " << result; + DVLOG(1) << "Failed to read from WebSocket connection, error: " << result; DisconnectImmediately(); return; } if (!handler_) { - VLOG(1) << "No handler set, ignoring read."; + DVLOG(1) << "No handler set, ignoring read."; return; } @@ -311,7 +311,7 @@ } if (assemble_result.error() == ERR_WS_PROTOCOL_ERROR) { - VLOG(1) << "Protocol error while handling frame."; + DVLOG(1) << "Protocol error while handling frame."; StartClosingHandshake(1002, "Protocol error"); DisconnectAfterAnyWritesDone(); return; @@ -352,8 +352,8 @@ case WebSocketFrameHeader::kOpCodeClose: { auto parse_close_frame_result = ParseCloseFrame(payload); if (parse_close_frame_result.error.has_value()) { - VLOG(1) << "Failed to parse close frame: " - << parse_close_frame_result.error.value(); + DVLOG(1) << "Failed to parse close frame: " + << parse_close_frame_result.error.value(); StartClosingHandshake(1002, "Protocol error"); DisconnectAfterAnyWritesDone(); } else { @@ -369,7 +369,7 @@ handler_->OnPong(base::as_bytes(payload)); break; default: - VLOG(2) << "Unknown frame opcode: " << opcode; + DVLOG(2) << "Unknown frame opcode: " << opcode; StartClosingHandshake(1002, "Protocol error"); DisconnectAfterAnyWritesDone(); break; @@ -380,7 +380,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!stream_socket_) { - VLOG(2) << "Stream socket is already null. Returning early."; + DVLOG(2) << "Stream socket is already null. Returning early."; return; } @@ -402,7 +402,8 @@ if (handler_) { handler_->OnHandshakeComplete(); } else { - VLOG(2) << "Handler is null after starting Read. Connection likely closed."; + DVLOG(2) + << "Handler is null after starting Read. Connection likely closed."; } } @@ -418,9 +419,9 @@ scoped_refptr<IOBufferWithSize> CreateCloseFrame(std::optional<uint16_t> code, std::string_view message) { - VLOG(3) << "Creating close frame with code: " - << (code ? base::NumberToString(*code) : "none") - << ", Message: " << message; + DVLOG(3) << "Creating close frame with code: " + << (code ? base::NumberToString(*code) : "none") + << ", Message: " << message; CHECK(message.empty() || code); CHECK(base::IsStringUTF8AllowingNoncharacters(message));
diff --git a/net/test/embedded_test_server/websocket_handler.cc b/net/test/embedded_test_server/websocket_handler.cc index d8b23e6a..9d6874f 100644 --- a/net/test/embedded_test_server/websocket_handler.cc +++ b/net/test/embedded_test_server/websocket_handler.cc
@@ -26,15 +26,15 @@ // Default implementation of OnPong that does nothing. void WebSocketHandler::OnPong(base::span<const uint8_t> payload) { // Default implementation does nothing. - VLOG(3) << "Received PONG message."; + DVLOG(3) << "Received PONG message."; } // Default implementation of OnClosingHandshake. void WebSocketHandler::OnClosingHandshake(std::optional<uint16_t> code, std::string_view message) { - VLOG(3) << "Closing handshake received with code: " - << (code.has_value() ? base::NumberToString(code.value()) : "none") - << ", message: " << message; + DVLOG(3) << "Closing handshake received with code: " + << (code.has_value() ? base::NumberToString(code.value()) : "none") + << ", message: " << message; connection()->RespondToCloseFrame(code, message); }
diff --git a/net/test/embedded_test_server/websocket_message_assembler.cc b/net/test/embedded_test_server/websocket_message_assembler.cc index e235eaa..6b03942 100644 --- a/net/test/embedded_test_server/websocket_message_assembler.cc +++ b/net/test/embedded_test_server/websocket_message_assembler.cc
@@ -26,7 +26,7 @@ switch (opcode) { case WebSocketFrameHeader::kOpCodeText: if (state_ != MessageState::kIdle) { - VLOG(1) << "Unexpected text frame while expecting continuation"; + DVLOG(1) << "Unexpected text frame while expecting continuation"; return base::unexpected(ERR_WS_PROTOCOL_ERROR); } is_text_message_ = true; @@ -34,7 +34,7 @@ case WebSocketFrameHeader::kOpCodeBinary: if (state_ != MessageState::kIdle) { - VLOG(1) << "Unexpected binary frame while expecting continuation"; + DVLOG(1) << "Unexpected binary frame while expecting continuation"; return base::unexpected(ERR_WS_PROTOCOL_ERROR); } // Explicitly set to indicate binary handling. @@ -43,13 +43,13 @@ case WebSocketFrameHeader::kOpCodeContinuation: if (state_ == MessageState::kIdle) { - VLOG(1) << "Unexpected continuation frame in idle state"; + DVLOG(1) << "Unexpected continuation frame in idle state"; return base::unexpected(ERR_WS_PROTOCOL_ERROR); } break; default: - VLOG(1) << "Invalid frame opcode: " << opcode; + DVLOG(1) << "Invalid frame opcode: " << opcode; return base::unexpected(ERR_WS_PROTOCOL_ERROR); }
diff --git a/remoting/host/it2me_desktop_environment.cc b/remoting/host/it2me_desktop_environment.cc index f085bf1..d5fa3ea 100644 --- a/remoting/host/it2me_desktop_environment.cc +++ b/remoting/host/it2me_desktop_environment.cc
@@ -135,12 +135,16 @@ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, base::WeakPtr<ClientSessionControl> client_session_control, const DesktopEnvironmentOptions& options, - std::unique_ptr<DesktopInteractionStrategy> interaction_strategy) { - return base::WrapUnique(new It2MeDesktopEnvironment( - std::move(caller_task_runner), std::move(ui_task_runner), - std::move(interaction_strategy), std::move(client_session_control), - options)); - }; + std::unique_ptr<DesktopInteractionStrategy> interaction_strategy) + -> std::unique_ptr<DesktopEnvironment> { + if (!interaction_strategy) { + return nullptr; + } + return base::WrapUnique(new It2MeDesktopEnvironment( + std::move(caller_task_runner), std::move(ui_task_runner), + std::move(interaction_strategy), std::move(client_session_control), + options)); + }; CreateInteractionStrategy( options, base::BindOnce(create_with_interaction_strategy,
diff --git a/remoting/host/linux/ei_sender_session.cc b/remoting/host/linux/ei_sender_session.cc index 3c7b68f..ad3b5c7 100644 --- a/remoting/host/linux/ei_sender_session.cc +++ b/remoting/host/linux/ei_sender_session.cc
@@ -424,8 +424,7 @@ void EiSenderSession::OnDeviceRemoved(EiDevicePtr device) { if (ei_device_has_capability(device.get(), EI_DEVICE_CAP_KEYBOARD)) { - std::erase_if(relative_pointers_, - [&device](auto& item) { return item == device; }); + std::erase_if(keyboards_, [&device](auto& item) { return item == device; }); } if (ei_device_has_capability(device.get(), EI_DEVICE_CAP_POINTER)) { std::erase_if(relative_pointers_,
diff --git a/remoting/host/me2me_desktop_environment.cc b/remoting/host/me2me_desktop_environment.cc index d1ec406..4b81e37d 100644 --- a/remoting/host/me2me_desktop_environment.cc +++ b/remoting/host/me2me_desktop_environment.cc
@@ -247,6 +247,9 @@ const DesktopEnvironmentOptions& options, std::unique_ptr<DesktopInteractionStrategy> interaction_strategy) -> std::unique_ptr<DesktopEnvironment> { + if (!interaction_strategy) { + return nullptr; + } auto desktop_environment = base::WrapUnique(new Me2MeDesktopEnvironment( std::move(caller_task_runner), std::move(ui_task_runner), std::move(interaction_strategy), client_session_control, options));
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc index 49d677a..15b114c 100644 --- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc
@@ -20,7 +20,6 @@ #include "base/test/test_file_util.h" #include "base/time/time.h" #include "build/build_config.h" -#include "crypto/secure_hash.h" #include "net/base/hash_value.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h"
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc index 6ff9172c..393bc33 100644 --- a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
@@ -21,7 +21,7 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/time/time.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" #include "net/base/hash_value.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" @@ -1107,12 +1107,11 @@ {data1, data2}); // Calculate the hash. - std::unique_ptr<crypto::SecureHash> secure_hash = - crypto::SecureHash::Create(crypto::SecureHash::SHA256); - secure_hash->Update(data1.c_str(), data1.size()); - secure_hash->Update(data2.c_str(), data2.size()); + crypto::hash::Hasher hasher(crypto::hash::kSha256); + hasher.Update(data1); + hasher.Update(data2); net::SHA256HashValue sha256; - secure_hash->Finish(sha256); + hasher.Finish(sha256); if (GetManagerType() == TestManagerType::kOnDisk) { FlushCacheTasks();
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_in_memory.cc b/services/network/shared_dictionary/shared_dictionary_writer_in_memory.cc index 9343d0e..40c4768 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_in_memory.cc +++ b/services/network/shared_dictionary/shared_dictionary_writer_in_memory.cc
@@ -18,8 +18,7 @@ SharedDictionaryWriterInMemory::SharedDictionaryWriterInMemory( FinishCallback finish_callback) - : finish_callback_(std::move(finish_callback)), - secure_hash_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {} + : finish_callback_(std::move(finish_callback)) {} SharedDictionaryWriterInMemory::~SharedDictionaryWriterInMemory() { if (finish_callback_) { @@ -45,7 +44,7 @@ } total_size_ = checked_total_size.ValueOrDie(); - secure_hash_->Update(data); + hash_.Update(data); data_.emplace_back(base::as_string_view(data)); } @@ -55,7 +54,7 @@ } net::SHA256HashValue sha256; - secure_hash_->Finish(sha256); + hash_.Finish(sha256); if (total_size_ == 0) { std::move(finish_callback_)
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_in_memory.h b/services/network/shared_dictionary/shared_dictionary_writer_in_memory.h index 5ce14008..3e6c72ba 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_in_memory.h +++ b/services/network/shared_dictionary/shared_dictionary_writer_in_memory.h
@@ -11,7 +11,7 @@ #include "base/component_export.h" #include "base/functional/callback.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" #include "net/base/hash_value.h" #include "services/network/shared_dictionary/shared_dictionary_writer.h" @@ -50,7 +50,7 @@ ~SharedDictionaryWriterInMemory() override; FinishCallback finish_callback_; - std::unique_ptr<crypto::SecureHash> secure_hash_; + crypto::hash::Hasher hash_{crypto::hash::kSha256}; std::vector<std::string> data_; size_t total_size_ = 0; };
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_in_memory_unittest.cc b/services/network/shared_dictionary/shared_dictionary_writer_in_memory_unittest.cc index e3a92d1..063cd61 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_in_memory_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_writer_in_memory_unittest.cc
@@ -6,7 +6,7 @@ #include "base/functional/callback_helpers.h" #include "base/test/bind.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" #include "net/base/hash_value.h" #include "net/base/io_buffer.h" #include "services/network/shared_dictionary/shared_dictionary_constants.h" @@ -20,15 +20,6 @@ const std::string kTestData1 = "Hello "; const std::string kTestData2 = "world"; -net::SHA256HashValue GetHash(const std::string& data) { - std::unique_ptr<crypto::SecureHash> secure_hash = - crypto::SecureHash::Create(crypto::SecureHash::SHA256); - secure_hash->Update(data.c_str(), data.size()); - net::SHA256HashValue sha256; - secure_hash->Finish(sha256); - return sha256; -} - } // namespace TEST(SharedDictionaryWriterInMemory, SimpleWrite) { @@ -45,7 +36,7 @@ kTestData, std::string(reinterpret_cast<const char*>(buffer->data()), size)); - EXPECT_EQ(GetHash(kTestData), hash); + EXPECT_EQ(crypto::hash::Sha256(kTestData), hash); finish_callback_called = true; })); writer->Append(base::as_byte_span(kTestData)); @@ -67,7 +58,7 @@ kTestData1 + kTestData2, std::string(reinterpret_cast<const char*>(buffer->data()), size)); - EXPECT_EQ(GetHash(kTestData1 + kTestData2), hash); + EXPECT_EQ(crypto::hash::Sha256(kTestData1 + kTestData2), hash); finish_callback_called = true; })); writer->Append(base::as_byte_span(kTestData1));
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_on_disk.cc b/services/network/shared_dictionary/shared_dictionary_writer_on_disk.cc index 59dd461..783def1 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_on_disk.cc +++ b/services/network/shared_dictionary/shared_dictionary_writer_on_disk.cc
@@ -16,11 +16,8 @@ SharedDictionaryWriterOnDisk::SharedDictionaryWriterOnDisk( const base::UnguessableToken& token, FinishCallback callback, - base::WeakPtr<SharedDictionaryDiskCache> disk_cahe) - : token_(token), - callback_(std::move(callback)), - disk_cahe_(disk_cahe), - secure_hash_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {} + base::WeakPtr<SharedDictionaryDiskCache> disk_cache) + : token_(token), callback_(std::move(callback)), disk_cache_(disk_cache) {} SharedDictionaryWriterOnDisk::~SharedDictionaryWriterOnDisk() { if (callback_) { @@ -31,11 +28,11 @@ void SharedDictionaryWriterOnDisk::Initialize() { DCHECK_EQ(State::kBeforeInitialize, state_); state_ = State::kInitializing; - DCHECK(disk_cahe_); + DCHECK(disk_cache_); // Binding `this` to keep `this` alive until callback will be called. auto split_callback = base::SplitOnceCallback( base::BindOnce(&SharedDictionaryWriterOnDisk::OnEntry, this)); - disk_cache::EntryResult result = disk_cahe_->OpenOrCreateEntry( + disk_cache::EntryResult result = disk_cache_->OpenOrCreateEntry( token_.ToString(), /*create=*/true, std::move(split_callback.first)); if (result.net_error() != net::ERR_IO_PENDING) { std::move(split_callback.second).Run(std::move(result)); @@ -56,7 +53,7 @@ } total_size_ = checked_total_size.ValueOrDie(); - secure_hash_->Update(data); + hash_.Update(data); switch (state_) { case State::kBeforeInitialize: NOTREACHED(); @@ -172,7 +169,7 @@ entry_.reset(); DCHECK_EQ(written_size_, total_size_); net::SHA256HashValue sha256; - secure_hash_->Finish(sha256); + hash_.Finish(sha256); std::move(callback_).Run(Result::kSuccess, total_size_, sha256); }
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_on_disk.h b/services/network/shared_dictionary/shared_dictionary_writer_on_disk.h index 1d2b51d..667e997 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_on_disk.h +++ b/services/network/shared_dictionary/shared_dictionary_writer_on_disk.h
@@ -14,7 +14,7 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "base/unguessable_token.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" #include "net/base/hash_value.h" #include "net/base/io_buffer.h" #include "net/disk_cache/disk_cache.h" @@ -66,8 +66,8 @@ const base::UnguessableToken token_; FinishCallback callback_; - base::WeakPtr<SharedDictionaryDiskCache> disk_cahe_; - std::unique_ptr<crypto::SecureHash> secure_hash_; + base::WeakPtr<SharedDictionaryDiskCache> disk_cache_; + crypto::hash::Hasher hash_{crypto::hash::kSha256}; size_t total_size_ = 0; size_t written_size_ = 0;
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc index 1788c00..8e58ab2f 100644 --- a/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/bind.h" #include "base/test/test_file_util.h" #include "build/build_config.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" #include "net/base/hash_value.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" @@ -36,15 +36,6 @@ kAsyncFailure, }; -net::SHA256HashValue GetHash(const std::string& data) { - std::unique_ptr<crypto::SecureHash> secure_hash = - crypto::SecureHash::Create(crypto::SecureHash::SHA256); - secure_hash->Update(data.c_str(), data.size()); - net::SHA256HashValue sha256; - secure_hash->Finish(sha256); - return sha256; -} - class FakeSharedDictionaryDiskCache : public SharedDictionaryDiskCache { public: explicit FakeSharedDictionaryDiskCache( @@ -189,7 +180,7 @@ EXPECT_EQ(SharedDictionaryWriterOnDisk::Result::kSuccess, result); EXPECT_EQ(kTestData.size(), size); - EXPECT_EQ(GetHash(kTestData), hash); + EXPECT_EQ(crypto::hash::Sha256(kTestData), hash); finish_callback_called = true; }), disk_cache->GetWeakPtr()); @@ -493,7 +484,7 @@ EXPECT_EQ(SharedDictionaryWriterOnDisk::Result::kSuccess, result); EXPECT_EQ(kTestData1.size() + kTestData2.size(), size); - EXPECT_EQ(GetHash(kTestData1 + kTestData2), hash); + EXPECT_EQ(crypto::hash::Sha256(kTestData1 + kTestData2), hash); finish_callback_called = true; }), disk_cache->GetWeakPtr()); @@ -567,7 +558,7 @@ EXPECT_EQ(SharedDictionaryWriterOnDisk::Result::kSuccess, result); EXPECT_EQ(kTestData1.size() + kTestData2.size(), size); - EXPECT_EQ(GetHash(kTestData1 + kTestData2), hash); + EXPECT_EQ(crypto::hash::Sha256(kTestData1 + kTestData2), hash); finish_callback_called = true; }), disk_cache->GetWeakPtr());
diff --git a/services/on_device_model/public/cpp/test_support/fake_service.cc b/services/on_device_model/public/cpp/test_support/fake_service.cc index 105ac37..f34702d 100644 --- a/services/on_device_model/public/cpp/test_support/fake_service.cc +++ b/services/on_device_model/public/cpp/test_support/fake_service.cc
@@ -454,7 +454,7 @@ void FakeOnDeviceModelService::GetDevicePerformanceInfo( GetDevicePerformanceInfoCallback callback) { auto result = mojom::DevicePerformanceInfo::New(); - result->performance_class = mojom::PerformanceClass::kVeryHigh; + result->performance_class = settings_->performance_class; base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( FROM_HERE, base::BindOnce(std::move(callback), std::move(result)), settings_->estimated_performance_delay);
diff --git a/services/on_device_model/public/cpp/test_support/fake_service.h b/services/on_device_model/public/cpp/test_support/fake_service.h index b8d43ff..307fc67 100644 --- a/services/on_device_model/public/cpp/test_support/fake_service.h +++ b/services/on_device_model/public/cpp/test_support/fake_service.h
@@ -45,6 +45,9 @@ // The delay before running the GetDevicePerformanceInfo() response callback. base::TimeDelta estimated_performance_delay; + mojom::PerformanceClass performance_class = + mojom::PerformanceClass::kVeryHigh; + // If non-empty, used as the output from Execute(). std::vector<std::string> model_execute_result;
diff --git a/services/webnn/ort/context_impl_ort.cc b/services/webnn/ort/context_impl_ort.cc index 7fffe98..ec2d9f4 100644 --- a/services/webnn/ort/context_impl_ort.cc +++ b/services/webnn/ort/context_impl_ort.cc
@@ -189,10 +189,14 @@ {DataTypeConstraint::kFloat16To32, kMaxRank}, /*leaky_relu_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank}, /*linear_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank}, - /*lstm_input=*/{}, - /*lstm_bias=*/{}, - /*lstm_cell_input=*/{}, - /*lstm_cell_bias=*/{}, + /*lstm_input=*/ + {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(3)}, + /*lstm_bias=*/ + {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(2)}, + /*lstm_cell_input=*/ + {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(2)}, + /*lstm_cell_bias=*/ + {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(1)}, /*matmul_input=*/{DataTypeConstraint::kFloat16To32Ints32To64, kMaxRank}, /*pad_input=*/ {DataTypeConstraint::kAllDataTypesAtLeast8bits, kMaxNonScalarRank},
diff --git a/services/webnn/ort/graph_builder_ort.cc b/services/webnn/ort/graph_builder_ort.cc index 42014fa..6acdbc9 100644 --- a/services/webnn/ort/graph_builder_ort.cc +++ b/services/webnn/ort/graph_builder_ort.cc
@@ -85,6 +85,7 @@ "InstanceNormalization"; constexpr base::cstring_view kOpTypeLayerNormalization = "LayerNormalization"; constexpr base::cstring_view kOpTypeLeakyRelu = "LeakyRelu"; +constexpr base::cstring_view kOpTypeLstm = "LSTM"; constexpr base::cstring_view kOpTypeMatMul = "MatMul"; constexpr base::cstring_view kOpTypePad = "Pad"; constexpr base::cstring_view kOpTypePRelu = "PRelu"; @@ -2172,6 +2173,267 @@ model_editor_.AddNode(kOpTypeAdd, add_node_name, add_inputs, add_outputs); } +// `LstmType` must be `mojom::Lstm` or `mojom::LstmCell`. +template <typename LstmType> + requires(std::is_same_v<LstmType, mojom::Lstm> || + std::is_same_v<LstmType, mojom::LstmCell>) +void GraphBuilderOrt::AddLstmOperation(const LstmType& lstm) { + const std::string node_name = GenerateNodeName(lstm.label); + std::string input = GetOperandNameById(lstm.input_operand_id); + std::string weight = GetOperandNameById(lstm.weight_operand_id); + std::string recurrent_weight = + GetOperandNameById(lstm.recurrent_weight_operand_id); + + const OperandDescriptor& input_descriptor = + GetOperand(lstm.input_operand_id).descriptor; + const OperandDescriptor& weight_descriptor = + GetOperand(lstm.weight_operand_id).descriptor; + const OperandDescriptor& recurrent_weight_descriptor = + GetOperand(lstm.recurrent_weight_operand_id).descriptor; + + uint32_t num_directions = 1; + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + CHECK(context_properties_.data_type_limits.lstm_input.Supports( + input_descriptor)); + CHECK(context_properties_.data_type_limits.lstm_input.Supports( + weight_descriptor)); + CHECK(context_properties_.data_type_limits.lstm_input.Supports( + recurrent_weight_descriptor)); + num_directions = + lstm.direction == mojom::RecurrentNetworkDirection::kBoth ? 2 : 1; + } else { + CHECK(context_properties_.data_type_limits.lstm_cell_input.Supports( + input_descriptor)); + CHECK(context_properties_.data_type_limits.lstm_cell_input.Supports( + weight_descriptor)); + CHECK(context_properties_.data_type_limits.lstm_cell_input.Supports( + recurrent_weight_descriptor)); + + // Reshape the input into a 3-D tensor, since the LSTM of ONNX requires + // the input shape to be [seq_length, batch_size, input_size]. For + // lstmCell, `seq_length` is equal to 1. + const std::vector<uint32_t>& input_shape = input_descriptor.shape(); + CHECK_EQ(input_shape.size(), 2u); + input = CreateReshapeNode(input, {1, input_shape[0], input_shape[1]}); + + // Reshape the weight into a 3-D tensor, since the LSTM of ONNX requires + // the weight shape to be [num_directions, 4*hidden_size, input_size]. + // For lstmCell, `num_directions` is equal to 1. + const std::vector<uint32_t>& weight_shape = weight_descriptor.shape(); + CHECK_EQ(weight_shape.size(), 2u); + weight = CreateReshapeNode(weight, {1, weight_shape[0], weight_shape[1]}); + + // Reshape the recurrent weight into a 3-D tensor, since the LSTM of ONNX + // requires the recurrent weight shape to be [num_directions, + // 4*hidden_size, hidden_size]. For lstmCell, `num_directions` is equal + // to 1. + const std::vector<uint32_t>& recurrent_weight_shape = + recurrent_weight_descriptor.shape(); + CHECK_EQ(recurrent_weight_shape.size(), 2u); + recurrent_weight = CreateReshapeNode( + recurrent_weight, + {1, recurrent_weight_shape[0], recurrent_weight_shape[1]}); + } + + constexpr std::array<uint32_t, 4> kIfgoToIofgPermutation = {0, 3, 1, 2}; + if (lstm.layout == mojom::LstmWeightLayout::kIfgo) { + weight = TransposeRnnWeightOrBiasLayout(weight, kIfgoToIofgPermutation); + recurrent_weight = TransposeRnnWeightOrBiasLayout(recurrent_weight, + kIfgoToIofgPermutation); + } + + std::vector<const char*> inputs = {input.c_str(), weight.c_str(), + recurrent_weight.c_str()}; + + const uint32_t hidden_size = lstm.hidden_size; + // Graph validation already checked that hidden_size * 4 would not overflow. + std::array<uint32_t, 2> bias_dims = {num_directions, hidden_size * 4}; + std::string bias, recurrent_bias, concatenated_bias; + if (!lstm.bias_operand_id.has_value() && + !lstm.recurrent_bias_operand_id.has_value()) { + // When both bias and recurrentBias are not present, set ONNX LSTM input "B" + // as not specified. + inputs.push_back(""); + } else { + if (lstm.bias_operand_id.has_value()) { + bias = GetOperandNameById(*lstm.bias_operand_id); + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + CHECK(context_properties_.data_type_limits.lstm_bias.Supports( + GetOperand(*lstm.bias_operand_id).descriptor)); + } else { + CHECK(context_properties_.data_type_limits.lstm_cell_bias.Supports( + GetOperand(*lstm.bias_operand_id).descriptor)); + // Reshape the bias into a 2-D tensor, since the LSTM of ONNX requires + // the bias shape to be [num_directions, 4*hidden_size]. For lstmCell, + // `num_directions` is equal to 1. + bias = CreateReshapeNode(bias, bias_dims); + } + if (lstm.layout == mojom::LstmWeightLayout::kIfgo) { + bias = TransposeRnnWeightOrBiasLayout(bias, kIfgoToIofgPermutation); + } + } else { + bias = CreateZeroInitializer(input_descriptor.data_type(), bias_dims); + } + + if (lstm.recurrent_bias_operand_id.has_value()) { + recurrent_bias = GetOperandNameById(*lstm.recurrent_bias_operand_id); + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + CHECK(context_properties_.data_type_limits.lstm_bias.Supports( + GetOperand(*lstm.recurrent_bias_operand_id).descriptor)); + } else { + CHECK(context_properties_.data_type_limits.lstm_cell_bias.Supports( + GetOperand(*lstm.recurrent_bias_operand_id).descriptor)); + // Reshape the recurrentBias into a 2-D tensor, since the LSTM of ONNX + // requires the recurrentBias shape to be [num_directions, + // 4*hidden_size]. For lstmCell, `num_directions` is equal to 1. + recurrent_bias = CreateReshapeNode(recurrent_bias, bias_dims); + } + if (lstm.layout == mojom::LstmWeightLayout::kIfgo) { + recurrent_bias = TransposeRnnWeightOrBiasLayout(recurrent_bias, + kIfgoToIofgPermutation); + } + } else { + recurrent_bias = + CreateZeroInitializer(input_descriptor.data_type(), bias_dims); + } + + // Concatenate bias and recurrent_bias to create the ONNX LSTM input "B". + concatenated_bias = GenerateOperandName(); + std::array<const char*, 2> bias_inputs = {bias.c_str(), + recurrent_bias.c_str()}; + std::array<const char*, 1> bias_outputs = {concatenated_bias.c_str()}; + std::array<ScopedOrtOpAttr, 1> bias_attributes = { + model_editor_.CreateAttribute(kAttrAxis, static_cast<int64_t>(1))}; + std::string concat_node_name = GenerateNodeName( + base::JoinString({kInserted, kOpTypeConcat}, kUnderscore)); + model_editor_.AddNode(kOpTypeConcat, concat_node_name, bias_inputs, + bias_outputs, bias_attributes); + inputs.push_back(concatenated_bias.c_str()); + } + + // "sequence_lens" is an optional tensor specifying lengths of the sequences + // in a batch. + inputs.push_back(""); + + std::string hidden_state, cell_state; + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + if (lstm.initial_hidden_state_operand_id.has_value()) { + hidden_state = GetOperandNameById(*lstm.initial_hidden_state_operand_id); + CHECK(context_properties_.data_type_limits.lstm_input.Supports( + GetOperand(*lstm.initial_hidden_state_operand_id).descriptor)); + } + if (lstm.initial_cell_state_operand_id.has_value()) { + cell_state = GetOperandNameById(*lstm.initial_cell_state_operand_id); + CHECK(context_properties_.data_type_limits.lstm_input.Supports( + GetOperand(*lstm.initial_cell_state_operand_id).descriptor)); + } + } else { + hidden_state = GetOperandNameById(lstm.hidden_state_operand_id); + const OperandDescriptor& hidden_state_descriptor = + GetOperand(lstm.hidden_state_operand_id).descriptor; + CHECK(context_properties_.data_type_limits.lstm_cell_input.Supports( + hidden_state_descriptor)); + cell_state = GetOperandNameById(lstm.cell_state_operand_id); + const OperandDescriptor& cell_state_descriptor = + GetOperand(lstm.cell_state_operand_id).descriptor; + CHECK(context_properties_.data_type_limits.lstm_cell_input.Supports( + cell_state_descriptor)); + + // Reshape the hidden/cell_state into a 3-D tensor, since the LSTM of ONNX + // requires the "initial_h"/"initial_c" shape to be [num_directions, + // batch_size, hidden_size]. For lstmCell, `num_directions` is equal to 1. + const std::vector<uint32_t>& hidden_state_shape = + hidden_state_descriptor.shape(); + const std::vector<uint32_t>& cell_state_shape = + cell_state_descriptor.shape(); + hidden_state = CreateReshapeNode( + hidden_state, {1, hidden_state_shape[0], hidden_state_shape[1]}); + cell_state = CreateReshapeNode( + cell_state, {1, cell_state_shape[0], cell_state_shape[1]}); + } + inputs.push_back(hidden_state.c_str()); + inputs.push_back(cell_state.c_str()); + + std::string peephole_weight; + if (lstm.peephole_weight_operand_id.has_value()) { + peephole_weight = GetOperandNameById(*lstm.peephole_weight_operand_id); + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + CHECK(context_properties_.data_type_limits.lstm_bias.Supports( + GetOperand(*lstm.peephole_weight_operand_id).descriptor)); + } else { + const OperandDescriptor& peephole_weight_descriptor = + GetOperand(*lstm.peephole_weight_operand_id).descriptor; + CHECK(context_properties_.data_type_limits.lstm_cell_bias.Supports( + peephole_weight_descriptor)); + // Reshape the peephole_weight into a 2-D tensor, since the LSTM of ONNX + // requires the peephole_weight shape to be [num_directions, + // 3*hidden_size]. For lstmCell, `num_directions` is equal to 1. + const std::vector<uint32_t>& peephole_weight_shape = + peephole_weight_descriptor.shape(); + peephole_weight = + CreateReshapeNode(peephole_weight, {1, peephole_weight_shape[0]}); + } + } + inputs.push_back(peephole_weight.c_str()); + + std::vector<ScopedOrtOpAttr> attributes; + attributes.reserve(3); + base::cstring_view direction = "forward"; + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + direction = GetRecurrentNetworkDirection(lstm.direction); + } + attributes.push_back( + model_editor_.CreateAttribute(kAttrDirection, direction)); + + const std::vector<base::cstring_view> activations = + GetRecurrentNetworkActivations(lstm.activations, + direction == "bidirectional"); + std::vector<const char*> activations_c_str; + for (const auto& activation : activations) { + activations_c_str.push_back(activation.c_str()); + } + attributes.push_back( + model_editor_.CreateAttribute(kAttrActivations, activations_c_str)); + + attributes.push_back(model_editor_.CreateAttribute( + kAttrHiddenSize, base::checked_cast<int64_t>(hidden_size))); + + std::string output, output_hidden, output_cell; + if constexpr (std::is_same_v<LstmType, mojom::Lstm>) { + output_hidden = GetOperandNameById(lstm.output_operand_ids[0]); + output_cell = GetOperandNameById(lstm.output_operand_ids[1]); + if (lstm.return_sequence) { + output = GetOperandNameById(lstm.output_operand_ids[2]); + } + } else { + output_hidden = GenerateOperandName(); + output_cell = GenerateOperandName(); + } + std::array<const char*, 3> outputs = {output.c_str(), output_hidden.c_str(), + output_cell.c_str()}; + model_editor_.AddNode(kOpTypeLstm, node_name, inputs, outputs, attributes); + + if constexpr (std::is_same_v<LstmType, mojom::LstmCell>) { + // Reshape the output_hidden and output_cell back to 2-D tensors, since the + // LSTM of WebNN requires the "output_h"/"output_c" shape to be + // [batch_size, hidden_size]. + const std::vector<uint32_t>& output_shape = + GetOperand(lstm.output_operand_ids[0]).descriptor.shape(); + CHECK_EQ(output_shape.size(), 2u); + InsertReshapeNode(output_hidden, + GetOperandNameById(lstm.output_operand_ids[0]), + output_shape); + InsertReshapeNode(output_cell, + GetOperandNameById(lstm.output_operand_ids[1]), + output_shape); + } +} + +template void GraphBuilderOrt::AddLstmOperation(const mojom::Lstm& lstm); + +template void GraphBuilderOrt::AddLstmOperation( + const mojom::LstmCell& lstm_cell); + void GraphBuilderOrt::AddMatMulOperation(const mojom::Matmul& matmul) { const std::string node_name = GenerateNodeName(matmul.label); const std::string input_a = GetOperandNameById(matmul.a_operand_id); @@ -2899,6 +3161,14 @@ AddLinearOperation(*operation->get_linear()); break; } + case mojom::Operation::Tag::kLstm: { + AddLstmOperation(*operation->get_lstm()); + break; + } + case mojom::Operation::Tag::kLstmCell: { + AddLstmOperation(*operation->get_lstm_cell()); + break; + } case mojom::Operation::Tag::kMatmul: { AddMatMulOperation(*operation->get_matmul()); break; @@ -3012,9 +3282,6 @@ AddWhereOperation(*operation->get_where()); break; } - case mojom::Operation::Tag::kLstm: - case mojom::Operation::Tag::kLstmCell: - NOTREACHED() << "[WebNN] Unsupported operation."; } }
diff --git a/services/webnn/ort/graph_builder_ort.h b/services/webnn/ort/graph_builder_ort.h index 77f72a480..95a0e16 100644 --- a/services/webnn/ort/graph_builder_ort.h +++ b/services/webnn/ort/graph_builder_ort.h
@@ -261,6 +261,10 @@ const mojom::LayerNormalization& layer_normalization); void AddLeakyReluOperation(const mojom::LeakyRelu& leaky_relu); void AddLinearOperation(const mojom::Linear& linear); + template <typename LstmType> + requires(std::is_same_v<LstmType, mojom::Lstm> || + std::is_same_v<LstmType, mojom::LstmCell>) + void AddLstmOperation(const LstmType& lstm); void AddMatMulOperation(const mojom::Matmul& matmul); void AddPadOperation(const mojom::Pad& pad); void AddPool2dOperation(const mojom::Pool2d& pool2d);
diff --git a/testing/perf/cbb_ref_info/chrome/stable/Android.json b/testing/perf/cbb_ref_info/chrome/stable/Android.json index 19d6e69..32ac496 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/Android.json +++ b/testing/perf/cbb_ref_info/chrome/stable/Android.json
@@ -2,5 +2,5 @@ "browser": "Chrome", "channel": "Stable", "platform": "Android", - "version": "138.0.7204.168" + "version": "138.0.7204.179" } \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/stable/Windows.json b/testing/perf/cbb_ref_info/chrome/stable/Windows.json index ec2105b9..a6688bb 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/Windows.json +++ b/testing/perf/cbb_ref_info/chrome/stable/Windows.json
@@ -2,5 +2,5 @@ "browser": "Chrome", "channel": "Stable", "platform": "Windows", - "version": "138.0.7204.169" + "version": "138.0.7204.184" } \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/stable/macOS.json b/testing/perf/cbb_ref_info/chrome/stable/macOS.json index 1d34ea2d..7ae704e 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/macOS.json +++ b/testing/perf/cbb_ref_info/chrome/stable/macOS.json
@@ -2,5 +2,5 @@ "browser": "Chrome", "channel": "Stable", "platform": "Mac", - "version": "138.0.7204.169" + "version": "138.0.7204.184" } \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/safari/stable/macOS.json b/testing/perf/cbb_ref_info/safari/stable/macOS.json index e7e3249..bdc8d744 100644 --- a/testing/perf/cbb_ref_info/safari/stable/macOS.json +++ b/testing/perf/cbb_ref_info/safari/stable/macOS.json
@@ -2,5 +2,5 @@ "browser": "Safari", "channel": "Stable", "platform": "macOS", - "version": "18.5 (20621.2.5.11.8)" + "version": "18.6 (20621.3.11.11.3)" }
diff --git a/testing/perf/cbb_ref_info/safari/technology-preview/macOS.json b/testing/perf/cbb_ref_info/safari/technology-preview/macOS.json index d642f9e3..f61a86f8 100644 --- a/testing/perf/cbb_ref_info/safari/technology-preview/macOS.json +++ b/testing/perf/cbb_ref_info/safari/technology-preview/macOS.json
@@ -2,5 +2,5 @@ "browser": "Safari", "channel": "Technology Preview", "platform": "macOS", - "version": "26.0 (Release 223, 20622.1.18.11.5)" + "version": "26.0 (Release 224, 20622.1.20.1)" }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 286213e..2596ac2 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -180,6 +180,21 @@ ] } ], + "AccessibilityManifestV3AccessibilityCommon": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AccessibilityManifestV3AccessibilityCommon" + ] + } + ] + } + ], "AccessibilityManifestV3BrailleIme": [ { "platforms": [ @@ -4167,33 +4182,6 @@ ] } ], - "CameraMicPreview": [ - { - "platforms": [ - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "CameraOther_20250408", - "params": { - "action_filter": "Accepted,AcceptedOnce,Dismissed", - "probability": "0.6", - "prompt_disposition_reason_filter": "DefaultFallback", - "request_type_filter": "VideoCapture", - "survey_display_time": "OnPromptResolved", - "trigger_id": "jGykX8MLD0ugnJ3q1cK0NzqCtGvZ" - }, - "enable_features": [ - "CameraMicPreview", - "GetUserMediaDeferredDeviceSettingsSelection", - "PermissionsPromptSurvey" - ] - } - ] - } - ], "Canvas2DAutoFlushParams": [ { "platforms": [ @@ -7420,6 +7408,28 @@ ] } ], + "DSEPrewarm": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled_20260624_Dogfood", + "params": { + "url": "https://www.google.com/", + "zero_suggest_trigger": "true" + }, + "enable_features": [ + "Prewarm" + ] + } + ] + } + ], "DTCAntivirusSignalEnabled": [ { "platforms": [ @@ -8378,6 +8388,9 @@ "experiments": [ { "name": "Enabled", + "params": { + "max_instance_limit": "20" + }, "enable_features": [ "DisableInstanceLimit", "InstanceSwitcherV2" @@ -10511,7 +10524,21 @@ "ForceOffTextAutosizing": [ { "platforms": [ - "android", + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ForceOffTextAutosizing" + ] + } + ] + } + ], + "ForceOffTextAutosizingWebView": [ + { + "platforms": [ "android_webview" ], "experiments": [ @@ -18349,6 +18376,28 @@ ] } ], + "Prerender2ReuseSearchResultHost": [ + { + "platforms": [ + "android", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "params": { + "reuse_search_host": "true" + }, + "enable_features": [ + "Prerender2ReuseHost" + ] + } + ] + } + ], "PreserveDiscardableImageMapQuality": [ { "platforms": [ @@ -20473,6 +20522,26 @@ ] } ], + "RequestMainFrameAfterFirstVideoFrame": [ + { + "platforms": [ + "android", + "android_webview", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "RequestMainFrameAfterFirstVideoFrame" + ] + } + ] + } + ], "ResamplingScrollEvents": [ { "platforms": [ @@ -22991,6 +23060,26 @@ ] } ], + "ShouldContributePriorityToProcessByFrameLifecycle": [ + { + "platforms": [ + "android_weblayer", + "android_webview", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ShouldContributePriorityToProcessByFrameLifecycle" + ] + } + ] + } + ], "ShowNewTabAnimationsAndroid": [ { "platforms": [ @@ -23779,6 +23868,41 @@ ] } ], + "SubframeImportance": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "SubframeImportance", + "SubframePriorityContribution" + ] + } + ] + } + ], + "SubframePriorityContribution": [ + { + "platforms": [ + "android_webview", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "SubframePriorityContribution" + ] + } + ] + } + ], "SunfishFeature": [ { "platforms": [ @@ -25284,25 +25408,6 @@ ] } ], - "UseSharedRebindServiceConnection": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "EnabledDeferredBindings10", - "params": { - "max-deferred-bindings": "10" - }, - "enable_features": [ - "GroupRebindingForGroupImportance", - "UseSharedRebindServiceConnection" - ] - } - ] - } - ], "UseSharedRebindServiceConnectionWebview": [ { "platforms": [
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index b3e26aa..f23cb64d 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -314,7 +314,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13850313/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13852510/artifacts/repository' } mavenCentral() }
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index 9e1afd4..47d77a49 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -13248,6 +13248,7 @@ V8OptimizerDisabled PrerenderFailedDuringPrefetch BrowsingDataRemoved + PrerenderHostReused # Fired when a preload enabled state is updated. event preloadEnabledStateUpdated
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index f80a04b4..27a9420 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1663,58 +1663,55 @@ void Element::DefaultEventHandler(Event& event) { if (RuntimeEnabledFeatures::HTMLInterestForAttributeEnabled( - GetDocument().GetExecutionContext())) { - if (InterestForElement() || GetInterestInvoker() || - GetInterestState() != InterestState::kNoInterest) [[unlikely]] { - // Handle new `interestfor` activation via mouse, keyboard, or long- - // press. - String type = event.type(); - if (auto* mouse_event = DynamicTo<MouseEvent>(event)) { - if (!mouse_event->FromTouch()) { - if (type == event_type_names::kMouseover) { - HandleInterestForHoverOrFocus(InterestSource::kHover); - } - if (type == event_type_names::kMouseout) { - HandleInterestForHoverOrFocus(InterestSource::kDeHover); - } - } - } - if (auto* focus_event = DynamicTo<FocusEvent>(event)) { - if (!focus_event->sourceCapabilities() || - !focus_event->sourceCapabilities()->firesTouchEvents()) { - if (type == event_type_names::kFocusin) { - HandleInterestForHoverOrFocus(InterestSource::kFocus); - } - if (type == event_type_names::kFocusout) { - HandleInterestForHoverOrFocus(InterestSource::kBlur); - } - } - } - if (IsA<GestureEvent>(event) && - type == event_type_names::kGesturelongpress) { - // Delays don't apply to long-press, since the "long press" has a - // built-in delay. Just show interest immediately in this case. This - // follows the same path used by context-menu activations on link - // elements. - // TODO(crbug.com/364669918): Touchscreen / long-press still needs a - // unit test. - ShowInterestNow(); + GetDocument().GetExecutionContext()) && + (InterestForElement() || GetInterestInvoker() || + GetInterestState() != InterestState::kNoInterest)) [[unlikely]] { + // Handle new `interestfor` activation via mouse, keyboard, or long- + // press. + String type = event.type(); + if (auto* mouse_event = DynamicTo<MouseEvent>(event); + mouse_event && !mouse_event->FromTouch()) { + if (type == event_type_names::kMouseover) { + HandleInterestForHoverOrFocus(InterestSource::kHover); + } else if (type == event_type_names::kMouseout) { + HandleInterestForHoverOrFocus(InterestSource::kDeHover); } } - if (GetInterestState() != InterestState::kNoInterest) [[unlikely]] { + if (auto* focus_event = DynamicTo<FocusEvent>(event); + focus_event && + (!focus_event->sourceCapabilities() || + !focus_event->sourceCapabilities()->firesTouchEvents())) { + if (type == event_type_names::kFocusin) { + HandleInterestForHoverOrFocus(InterestSource::kFocus); + } else if (type == event_type_names::kFocusout) { + HandleInterestForHoverOrFocus(InterestSource::kBlur); + } + } + + if (IsA<GestureEvent>(event) && + type == event_type_names::kGesturelongpress) { + // Delays don't apply to long-press, since the "long press" has a + // built-in delay. Just show interest immediately in this case. This + // follows the same path used by context-menu activations on link + // elements. + // TODO(crbug.com/364669918): Touchscreen / long-press still needs a + // unit test. + ShowInterestNow(); + } + + if (auto* keyboard_event = DynamicTo<KeyboardEvent>(event); + keyboard_event && event.type() == event_type_names::kKeydown && + GetInterestState() != InterestState::kNoInterest) { // Handle `interestfor` "activation" hotkey, and ESC key to lose // interest. - if (auto* keyboard_event = DynamicTo<KeyboardEvent>(event); - keyboard_event && event.type() == event_type_names::kKeydown) { - const int modifiers = keyboard_event->GetModifiers() & - blink::WebInputEvent::kKeyModifiers; - auto* target = GetInvokerData()->ActiveInterestTarget(); - DCHECK_EQ(InterestForElement(), target); - if (keyboard_event->key() == keywords::kEscape && !modifiers) { - if (GainOrLoseInterest(this, target, InterestState::kNoInterest)) { - event.SetDefaultHandled(); - return; - } + const int modifiers = + keyboard_event->GetModifiers() & blink::WebInputEvent::kKeyModifiers; + auto* target = GetInvokerData()->ActiveInterestTarget(); + DCHECK_EQ(InterestForElement(), target); + if (keyboard_event->key() == keywords::kEscape && !modifiers) { + if (GainOrLoseInterest(this, target, InterestState::kNoInterest)) { + event.SetDefaultHandled(); + return; } } }
diff --git a/third_party/blink/renderer/core/events/message_event.h b/third_party/blink/renderer/core/events/message_event.h index d55bc3d..bb472782 100644 --- a/third_party/blink/renderer/core/events/message_event.h +++ b/third_party/blink/renderer/core/events/message_event.h
@@ -57,17 +57,17 @@ public: static MessageEvent* Create() { return MakeGarbageCollected<MessageEvent>(); } static MessageEvent* Create(GCedMessagePortArray* ports, - const String& origin = String(), - const String& last_event_id = String(), - EventTarget* source = nullptr) { + const String& origin, + const String& last_event_id, + EventTarget* source) { return MakeGarbageCollected<MessageEvent>(origin, last_event_id, source, ports); } static MessageEvent* Create(GCedMessagePortArray* ports, scoped_refptr<SerializedScriptValue> data, - const String& origin = String(), - const String& last_event_id = String(), - EventTarget* source = nullptr) { + const String& origin, + const String& last_event_id, + EventTarget* source) { return MakeGarbageCollected<MessageEvent>( std::move(data), origin, last_event_id, source, ports, nullptr); } @@ -80,12 +80,11 @@ static MessageEvent* Create( Vector<MessagePortChannel> channels, scoped_refptr<SerializedScriptValue> data, - const String& origin = String(), - const String& last_event_id = String(), - EventTarget* source = nullptr, - UserActivation* user_activation = nullptr, - mojom::blink::DelegatedCapability delegated_capability = - mojom::blink::DelegatedCapability::kNone) { + const String& origin, + const String& last_event_id, + EventTarget* source, + UserActivation* user_activation, + mojom::blink::DelegatedCapability delegated_capability) { return MakeGarbageCollected<MessageEvent>( std::move(data), origin, last_event_id, source, std::move(channels), user_activation, delegated_capability);
diff --git a/third_party/blink/renderer/core/events/message_event_test.cc b/third_party/blink/renderer/core/events/message_event_test.cc index 103c2cd8..eb4087f 100644 --- a/third_party/blink/renderer/core/events/message_event_test.cc +++ b/third_party/blink/renderer/core/events/message_event_test.cc
@@ -86,7 +86,8 @@ GetTotalAmountOfExternalAllocatedMemoryForTesting(scope.GetIsolate()); GCedMessagePortArray* ports = MakeGarbageCollected<GCedMessagePortArray>(0); - MessageEvent::Create(ports, serialized_script_value); + MessageEvent::Create(ports, serialized_script_value, /* origin=*/{}, + /* last_event_id=*/{}, /* source=*/nullptr); int64_t size_with_event = V8ExternalMemoryAccounterBase:: GetTotalAmountOfExternalAllocatedMemoryForTesting(scope.GetIsolate());
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc index b3c0a2b..f20d0d8b 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
@@ -36,6 +36,8 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" +#include "third_party/blink/renderer/core/layout/layout_box.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -97,11 +99,31 @@ return builder.ToString(); }; - if (element->parentElement() != canvas_element) { - exception_state.ThrowTypeError( - build_error("Only immediate children of the <canvas> element can be " - "passed to %s.")); - return false; + if (!RuntimeEnabledFeatures::CanvasDrawElementInSubtreeEnabled()) { + if (element->parentElement() != canvas_element) { + exception_state.ThrowTypeError( + build_error("Only immediate children of the <canvas> element can be " + "passed to %s.")); + return false; + } + } else { + if (!element->IsDescendantOf(canvas_element)) { + exception_state.ThrowTypeError(build_error( + "Only descendants of the <canvas> element can be passed to %s.")); + return false; + } + // TODO(pdr): Update these checks to point to the updated spec. These are + // currently copied from element capture, which has similar paint reqs: + // https://screen-share.github.io/element-capture/#elements-eligible-for-restriction + auto* object = element->GetLayoutObject(); + if (!object || !object->IsStackingContext() || !object->CreatesGroup() || + !object->IsBox() || + To<LayoutBox>(object)->PhysicalFragmentCount() > 1) { + exception_state.ThrowTypeError( + build_error("Only elements with certain requirements (stacking " + "context, etc) can be passed to %s.")); + return false; + } } if (!canvas_element->layoutSubtree()) {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index 68f9c40..76f797b 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -78,6 +78,7 @@ #include "third_party/blink/renderer/core/html/media/audio_output_device_controller.h" #include "third_party/blink/renderer/core/html/media/autoplay_policy.h" #include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h" +#include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/html/media/media_controls.h" #include "third_party/blink/renderer/core/html/media/media_error.h" #include "third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h" @@ -103,6 +104,7 @@ #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/speech/speech_synthesis_base.h" +#include "third_party/blink/renderer/core/timing/soft_navigation_heuristics.h" #include "third_party/blink/renderer/platform/audio/audio_bus.h" #include "third_party/blink/renderer/platform/audio/audio_source_provider_client.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h" @@ -120,6 +122,7 @@ #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -779,6 +782,9 @@ StyleChangeReasonForTracing::FromAttribute(name)); // Trigger a reload, as long as the 'src' attribute is present. if (!params.new_value.IsNull()) { + if (auto* video_element = DynamicTo<HTMLVideoElement>(this)) { + SoftNavigationHeuristics::OnVideoSrcChanged(video_element); + } ignore_preload_none_ = false; InvokeLoadAlgorithm(); } @@ -957,6 +963,9 @@ << ": stream_descriptor=" << src_object_stream_descriptor_ << ", media_source_handle=" << src_object_media_source_handle_; + if (auto* video_element = DynamicTo<HTMLVideoElement>(this)) { + SoftNavigationHeuristics::OnVideoSrcChanged(video_element); + } InvokeLoadAlgorithm(); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc index b999462..de791fb 100644 --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -508,9 +508,17 @@ // During shutdown, the page and/or main frame might already be detached. // We must guard against accessing a null document. const Page* page = GetWebViewImpl()->GetPage(); - if (page->MainFrame() && To<LocalFrame>(page->MainFrame())->GetDocument()) { - page->GetFocusController().SetFocusEmulationEnabled(enabled); + if (!page) { + return response; } + + if (Frame* main_frame = page->MainFrame()) { + LocalFrame* local_main_frame = DynamicTo<LocalFrame>(main_frame); + if (local_main_frame && local_main_frame->GetDocument()) { + page->GetFocusController().SetFocusEmulationEnabled(enabled); + } + } + return response; }
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc index 5534f6d..71b3dc7 100644 --- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc +++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -34,6 +34,7 @@ #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/layout/logical_box_fragment.h" +#include "third_party/blink/renderer/core/layout/masonry/layout_masonry.h" #include "third_party/blink/renderer/core/layout/physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h" #include "third_party/blink/renderer/core/page/chrome_client.h" @@ -1310,18 +1311,170 @@ return flex_info; } -std::unique_ptr<protocol::DictionaryValue> BuildGridInfo( +// Builds track paths for grid/masonry layout. +std::unique_ptr<protocol::ListValue> BuildTrackPaths( + const LayoutObject* layout_object, + LocalFrameView* containing_view, + const Vector<LayoutUnit>& track_positions, + LayoutUnit span_start, + LayoutUnit span_size, + LayoutUnit gap, + GridTrackSizingDirection direction, + float scale, + bool is_rtl = false, + LayoutUnit rtl_offset = LayoutUnit()) { + HighlightPathBuilder track_builder; + const bool is_for_columns = direction == kForColumns; + + for (wtf_size_t i = 1; i < track_positions.size(); ++i) { + LayoutUnit track_start = + GetPositionForTrackAt(layout_object, i - 1, direction, track_positions); + LayoutUnit track_size = track_positions.at(i) - track_positions.at(i - 1); + + // Adjusts for final gap. + if (i != track_positions.size() - 1) { + track_size -= gap; + } + + // Handles RTL for columns. + if (is_rtl && is_for_columns) { + track_start += rtl_offset - track_size; + } + + PhysicalOffset position = is_for_columns + ? PhysicalOffset(track_start, span_start) + : PhysicalOffset(span_start, track_start); + PhysicalSize size = is_for_columns ? PhysicalSize(track_size, span_size) + : PhysicalSize(span_size, track_size); + PhysicalRect track_rect(position, size); + gfx::QuadF track_quad = layout_object->LocalRectToAbsoluteQuad(track_rect); + FrameQuadToViewport(containing_view, track_quad); + + const bool draw_end_line = + (is_rtl && is_for_columns) ? i == 1 : i == track_positions.size() - 1; + track_builder.AppendPath( + is_for_columns ? ColumnQuadToPath(track_quad, draw_end_line || gap > 0) + : RowQuadToPath(track_quad, draw_end_line || gap > 0), + scale); + } + + return track_builder.Release(); +} + +// Builds gap paths for grid/masonry layout. +std::unique_ptr<protocol::ListValue> BuildGapPaths( + const LayoutObject* layout_object, + LocalFrameView* containing_view, + const Vector<LayoutUnit>& track_positions, + LayoutUnit span_start, + LayoutUnit span_size, + LayoutUnit gap, + GridTrackSizingDirection direction, + float scale, + bool is_rtl = false, + LayoutUnit rtl_offset = LayoutUnit()) { + HighlightPathBuilder gap_builder; + const bool is_for_columns = direction == kForColumns; + + for (wtf_size_t i = 1; i < track_positions.size() - 1; ++i) { + LayoutUnit gap_start; + + if (!is_for_columns) { + gap_start = track_positions.at(i) - gap; + } else { + gap_start = + GetPositionForTrackAt(layout_object, i, direction, track_positions); + if (is_rtl) { + gap_start += rtl_offset; + } else { + gap_start -= gap; + } + } + + PhysicalOffset gap_position = is_for_columns + ? PhysicalOffset(gap_start, span_start) + : PhysicalOffset(span_start, gap_start); + PhysicalSize gap_size = is_for_columns ? PhysicalSize(gap, span_size) + : PhysicalSize(span_size, gap); + + PhysicalRect gap_rect(gap_position, gap_size); + gfx::QuadF gap_quad = layout_object->LocalRectToAbsoluteQuad(gap_rect); + FrameQuadToViewport(containing_view, gap_quad); + gap_builder.AppendPath(QuadToPath(gap_quad), scale); + } + + return gap_builder.Release(); +} + +std::unique_ptr<protocol::DictionaryValue> BuildGridInfoForMasonry( + Element* element, + const InspectorGridHighlightConfig& grid_highlight_config, + float scale) { + LocalFrameView* containing_view = element->GetDocument().View(); + auto* masonry = To<LayoutMasonry>(element->GetLayoutObject()); + std::unique_ptr<protocol::DictionaryValue> grid_info = + protocol::DictionaryValue::create(); + + grid_info->setInteger("rotationAngle", GetRotationAngle(masonry)); + grid_info->setString("writingMode", GetWritingMode(masonry->StyleRef())); + const bool is_for_columns = + masonry->StyleRef().MasonryTrackSizingDirection() == kForColumns; + + const Vector<LayoutUnit> masonry_tracks = + masonry->GridTrackPositions(is_for_columns ? kForColumns : kForRows); + LayoutUnit gap = + masonry->GridGap(is_for_columns ? kForColumns : kForRows) + + masonry->MasonryItemOffset(is_for_columns ? kForColumns : kForRows); + LayoutUnit span_start = + is_for_columns ? masonry->ContentTop() : masonry->ContentLeft(); + LayoutUnit span_size = + is_for_columns ? masonry->LogicalHeight() : masonry->LogicalWidth(); + + // Sets empty value for columns/columnGaps and rows/rowGaps - frontend + // expects both dimensions to be present in the `grid_info`. + grid_info->setValue( + "columns", + is_for_columns + ? BuildTrackPaths(masonry, containing_view, masonry_tracks, + span_start, span_size, gap, kForColumns, scale) + : protocol::ListValue::create()); + grid_info->setValue( + "columnGaps", + is_for_columns + ? BuildGapPaths(masonry, containing_view, masonry_tracks, span_start, + span_size, gap, kForColumns, scale) + : protocol::ListValue::create()); + grid_info->setValue( + "rows", + is_for_columns + ? protocol::ListValue::create() + : BuildTrackPaths(masonry, containing_view, masonry_tracks, + span_start, span_size, gap, kForRows, scale)); + grid_info->setValue( + "rowGaps", + is_for_columns + ? protocol::ListValue::create() + : BuildGapPaths(masonry, containing_view, masonry_tracks, span_start, + span_size, gap, kForRows, scale)); + + // Masonry layout only has one direction, so it doesn't have a grid border + // constructed by two directions data like grid layout. + grid_info->setValue("gridBorder", protocol::ListValue::create()); + grid_info->setValue("gridHighlightConfig", + BuildGridHighlightConfigInfo(grid_highlight_config)); + + return grid_info; +} + +std::unique_ptr<protocol::DictionaryValue> BuildGridInfoForGrid( Element* element, const InspectorGridHighlightConfig& grid_highlight_config, float scale, bool isPrimary) { LocalFrameView* containing_view = element->GetDocument().View(); - DCHECK(element->GetLayoutObject()); - auto* grid = To<LayoutGrid>(element->GetLayoutObject()); - std::unique_ptr<protocol::DictionaryValue> grid_info = protocol::DictionaryValue::create(); - + auto* grid = To<LayoutGrid>(element->GetLayoutObject()); const Vector<LayoutUnit> rows = grid->RowPositions(); const Vector<LayoutUnit> columns = grid->ColumnPositions(); @@ -1373,75 +1526,30 @@ bool is_ltr = grid->StyleRef().IsLeftToRightDirection(); - HighlightPathBuilder row_builder; - HighlightPathBuilder row_gap_builder; + // Rows LayoutUnit row_left = columns.front(); if (!is_ltr) { row_left += rtl_offset; } LayoutUnit row_width = columns.back() - columns.front(); - for (wtf_size_t i = 1; i < rows.size(); ++i) { - // Rows - PhysicalOffset position(row_left, rows.at(i - 1)); - PhysicalSize size(row_width, rows.at(i) - rows.at(i - 1)); - if (i != rows.size() - 1) - size.height -= row_gap; - PhysicalRect row(position, size); - gfx::QuadF row_quad = grid->LocalRectToAbsoluteQuad(row); - FrameQuadToViewport(containing_view, row_quad); - row_builder.AppendPath( - RowQuadToPath(row_quad, i == rows.size() - 1 || row_gap > 0), scale); - // Row Gaps - if (i != rows.size() - 1) { - PhysicalOffset gap_position(row_left, rows.at(i) - row_gap); - PhysicalSize gap_size(row_width, row_gap); - PhysicalRect gap(gap_position, gap_size); - gfx::QuadF gap_quad = grid->LocalRectToAbsoluteQuad(gap); - FrameQuadToViewport(containing_view, gap_quad); - row_gap_builder.AppendPath(QuadToPath(gap_quad), scale); - } - } - grid_info->setValue("rows", row_builder.Release()); - grid_info->setValue("rowGaps", row_gap_builder.Release()); + grid_info->setValue( + "rows", BuildTrackPaths(grid, containing_view, rows, row_left, row_width, + row_gap, kForRows, scale)); + grid_info->setValue( + "rowGaps", BuildGapPaths(grid, containing_view, rows, row_left, row_width, + row_gap, kForRows, scale)); - HighlightPathBuilder column_builder; - HighlightPathBuilder column_gap_builder; + // Columns LayoutUnit column_top = rows.front(); LayoutUnit column_height = rows.back() - rows.front(); - for (wtf_size_t i = 1; i < columns.size(); ++i) { - PhysicalSize size(columns.at(i) - columns.at(i - 1), column_height); - if (i != columns.size() - 1) - size.width -= column_gap; - LayoutUnit line_left = - GetPositionForTrackAt(grid, i - 1, kForColumns, columns); - if (!is_ltr) { - line_left += rtl_offset - size.width; - } - PhysicalOffset position(line_left, column_top); - PhysicalRect column(position, size); - gfx::QuadF column_quad = grid->LocalRectToAbsoluteQuad(column); - FrameQuadToViewport(containing_view, column_quad); - bool draw_end_line = is_ltr ? i == columns.size() - 1 : i == 1; - column_builder.AppendPath( - ColumnQuadToPath(column_quad, draw_end_line || column_gap > 0), scale); - // Column Gaps - if (i != columns.size() - 1) { - LayoutUnit gap_left = - GetPositionForTrackAt(grid, i, kForColumns, columns); - if (is_ltr) - gap_left -= column_gap; - else - gap_left += rtl_offset; - PhysicalOffset gap_position(gap_left, column_top); - PhysicalSize gap_size(column_gap, column_height); - PhysicalRect gap(gap_position, gap_size); - gfx::QuadF gap_quad = grid->LocalRectToAbsoluteQuad(gap); - FrameQuadToViewport(containing_view, gap_quad); - column_gap_builder.AppendPath(QuadToPath(gap_quad), scale); - } - } - grid_info->setValue("columns", column_builder.Release()); - grid_info->setValue("columnGaps", column_gap_builder.Release()); + grid_info->setValue( + "columns", + BuildTrackPaths(grid, containing_view, columns, column_top, column_height, + column_gap, kForColumns, scale, !is_ltr, rtl_offset)); + grid_info->setValue( + "columnGaps", + BuildGapPaths(grid, containing_view, columns, column_top, column_height, + column_gap, kForColumns, scale, !is_ltr, rtl_offset)); // Positive Row and column Line positions if (grid_highlight_config.show_positive_line_numbers) { @@ -1501,6 +1609,20 @@ std::unique_ptr<protocol::DictionaryValue> BuildGridInfo( Element* element, + const InspectorGridHighlightConfig& grid_highlight_config, + float scale, + bool isPrimary) { + DCHECK(element->GetLayoutObject()); + + if (element->GetLayoutObject()->IsLayoutMasonry()) { + return BuildGridInfoForMasonry(element, grid_highlight_config, scale); + } + + return BuildGridInfoForGrid(element, grid_highlight_config, scale, isPrimary); +} + +std::unique_ptr<protocol::DictionaryValue> BuildGridInfo( + Element* element, const InspectorHighlightConfig& highlight_config, float scale, bool isPrimary) { @@ -1990,7 +2112,7 @@ if (highlight_config.css_grid != Color::kTransparent || highlight_config.grid_highlight_config) { grid_info_ = protocol::ListValue::create(); - if (layout_object->IsLayoutGrid()) { + if (layout_object->IsLayoutGrid() || layout_object->IsLayoutMasonry()) { grid_info_->pushValue( BuildGridInfo(To<Element>(node), highlight_config, scale_, true)); } @@ -2214,7 +2336,8 @@ float scale = DeviceScaleFromFrameView(frame_view); LayoutObject* layout_object = node->GetLayoutObject(); - if (!layout_object || !layout_object->IsLayoutGrid()) { + if (!layout_object || + (!layout_object->IsLayoutGrid() && !layout_object->IsLayoutMasonry())) { return nullptr; }
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 5462914..a8393f8e 100644 --- a/third_party/blink/renderer/core/layout/grid/layout_grid.cc +++ b/third_party/blink/renderer/core/layout/grid/layout_grid.cc
@@ -143,12 +143,32 @@ } const GridLayoutData* LayoutGrid::LayoutData() const { + return GetGridLayoutDataFromFragments(this); +} + +// static +const GridLayoutData* LayoutGrid::GetGridLayoutDataFromFragments( + const LayoutBlock* layout_block) { + CHECK(layout_block); // Retrieve the layout data from the last fragment as it has the most // up-to-date grid geometry. - const wtf_size_t fragment_count = PhysicalFragmentCount(); + const wtf_size_t fragment_count = layout_block->PhysicalFragmentCount(); if (fragment_count == 0) return nullptr; - return GetLayoutResult(fragment_count - 1)->GetGridLayoutData(); + return layout_block->GetLayoutResult(fragment_count - 1)->GetGridLayoutData(); +} + +// static +LayoutUnit LayoutGrid::ComputeGridGap( + const GridLayoutData* grid_layout_data, + GridTrackSizingDirection track_direction) { + if (!grid_layout_data) { + return LayoutUnit(); + } + + return (track_direction == kForColumns) + ? grid_layout_data->Columns().GutterSize() + : grid_layout_data->Rows().GutterSize(); } wtf_size_t LayoutGrid::AutoRepeatCountForDirection( @@ -180,13 +200,7 @@ LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection track_direction) const { NOT_DESTROYED(); - const auto* grid_layout_data = LayoutData(); - if (!grid_layout_data) - return LayoutUnit(); - - return (track_direction == kForColumns) - ? grid_layout_data->Columns().GutterSize() - : grid_layout_data->Rows().GutterSize(); + return ComputeGridGap(LayoutData(), track_direction); } LayoutUnit LayoutGrid::GridItemOffset(
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 f0d4867..a0291821 100644 --- a/third_party/blink/renderer/core/layout/grid/layout_grid.h +++ b/third_party/blink/renderer/core/layout/grid/layout_grid.h
@@ -33,6 +33,12 @@ const GridLayoutData* grid_layout_data, GridTrackSizingDirection track_direction); + // Helper functions shared between LayoutGrid and LayoutMasonry. + static const GridLayoutData* GetGridLayoutDataFromFragments( + const LayoutBlock* layout_block); + static LayoutUnit ComputeGridGap(const GridLayoutData* grid_layout_data, + GridTrackSizingDirection track_direction); + bool HasCachedPlacementData() const; const GridPlacementData& CachedPlacementData() const; void SetCachedPlacementData(GridPlacementData&& placement_data);
diff --git a/third_party/blink/renderer/core/layout/masonry/layout_masonry.cc b/third_party/blink/renderer/core/layout/masonry/layout_masonry.cc index 6326087..652c5d5a 100644 --- a/third_party/blink/renderer/core/layout/masonry/layout_masonry.cc +++ b/third_party/blink/renderer/core/layout/masonry/layout_masonry.cc
@@ -4,8 +4,34 @@ #include "third_party/blink/renderer/core/layout/masonry/layout_masonry.h" +#include "third_party/blink/renderer/core/layout/grid/grid_data.h" +#include "third_party/blink/renderer/core/layout/grid/layout_grid.h" + namespace blink { LayoutMasonry::LayoutMasonry(Element* element) : LayoutBlock(element) {} +const GridLayoutData* LayoutMasonry::LayoutData() const { + return LayoutGrid::GetGridLayoutDataFromFragments(this); +} + +Vector<LayoutUnit> LayoutMasonry::GridTrackPositions( + GridTrackSizingDirection track_direction) const { + NOT_DESTROYED(); + return LayoutGrid::ComputeExpandedPositions(LayoutData(), track_direction); +} + +LayoutUnit LayoutMasonry::GridGap( + GridTrackSizingDirection track_direction) const { + NOT_DESTROYED(); + return LayoutGrid::ComputeGridGap(LayoutData(), track_direction); +} + +LayoutUnit LayoutMasonry::MasonryItemOffset( + GridTrackSizingDirection track_direction) const { + NOT_DESTROYED(); + // Distribution offset is baked into the `gutter_size` in Masonry. + return LayoutUnit(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/masonry/layout_masonry.h b/third_party/blink/renderer/core/layout/masonry/layout_masonry.h index 8bee250..7f3a3568 100644 --- a/third_party/blink/renderer/core/layout/masonry/layout_masonry.h +++ b/third_party/blink/renderer/core/layout/masonry/layout_masonry.h
@@ -7,9 +7,13 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/layout_block.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { +class GridLayoutData; + class CORE_EXPORT LayoutMasonry : public LayoutBlock { public: explicit LayoutMasonry(Element* element); @@ -21,6 +25,13 @@ return "LayoutMasonry"; } + Vector<LayoutUnit> GridTrackPositions( + GridTrackSizingDirection track_direction) const; + LayoutUnit GridGap(GridTrackSizingDirection track_direction) const; + LayoutUnit MasonryItemOffset(GridTrackSizingDirection track_direction) const; + + const GridLayoutData* LayoutData() const; + private: bool IsLayoutMasonry() const final { NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc b/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc index 3d369ad..571ed1e 100644 --- a/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc
@@ -167,6 +167,13 @@ PlaceOutOfFlowItems(oof_children); } + // Transfer track layout data to support masonry overlay in DevTools. + GridLayoutData layout_data; + layout_data.SetTrackCollection( + std::make_unique<GridLayoutTrackCollection>(track_collection)); + container_builder_.TransferGridLayoutData( + std::make_unique<GridLayoutData>(layout_data)); + // Account for border, scrollbar, and padding in the intrinsic block size. intrinsic_block_size_ += BorderScrollbarPadding().BlockSum();
diff --git a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc index 4a1c140..b65ba5bb 100644 --- a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc
@@ -669,13 +669,11 @@ } } -OutOfFlowLayoutPart::ContainingBlockInfo -OutOfFlowLayoutPart::ApplyPositionAreaOffsets( +LogicalRect OutOfFlowLayoutPart::ApplyPositionAreaOffsets( const PositionAreaOffsets& offsets, PhysicalOffset default_anchor_scroll_shift, const OutOfFlowLayoutPart::ContainingBlockInfo& container_info) const { - ContainingBlockInfo adjusted_container_info(container_info); - LogicalRect& rect = adjusted_container_info.rect; + LogicalRect rect = container_info.rect; // Reduce the container size and adjust the offset based on the position-area. const BoxStrut insets = @@ -747,7 +745,7 @@ rect.ShiftInlineEndEdgeTo(rect.InlineEndOffset() + delta); } - return adjusted_container_info; + return rect; } // Retrieve the stored ContainingBlockInfo needed for placing positioned nodes. @@ -2251,7 +2249,8 @@ DCHECK(base::ValuesEquivalent(node_info.node.Style().PositionAnchor(), candidate_style.PositionAnchor())); - ContainingBlockInfo container_info = node_info.base_container_info; + const ContainingBlockInfo& container_info = node_info.base_container_info; + LogicalRect container_rect = container_info.rect; if (const std::optional<PositionAreaOffsets> offsets = candidate_style.PositionAreaOffsets()) { Element* elm = To<Element>(node_info.node.GetDOMNode()); @@ -2265,7 +2264,7 @@ StyleEngine& style_engine = elm->GetDocument().GetStyleEngine(); style_engine.MarkForDefaultAnchorScrollShift(*elm); } - container_info = ApplyPositionAreaOffsets( + container_rect = ApplyPositionAreaOffsets( *offsets, default_anchor_scroll_shift, container_info); } @@ -2273,7 +2272,6 @@ candidate_style.GetWritingDirection(); const auto container_writing_direction = container_info.writing_direction; - const LogicalRect& container_rect = container_info.rect; const PhysicalSize container_physical_content_size = ToPhysicalSize(container_rect.size, node_info.default_writing_direction.GetWritingMode());
diff --git a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.h index c7869f4..70813a1 100644 --- a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.h
@@ -328,7 +328,7 @@ const BlockNode& candidate, const StitchedAnchorQueries* anchor_queries) const; - ContainingBlockInfo ApplyPositionAreaOffsets( + LogicalRect ApplyPositionAreaOffsets( const PositionAreaOffsets& offsets, PhysicalOffset default_anchor_scroll_shift, const ContainingBlockInfo& container_info) const;
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc index 193f00d9..3b87e22 100644 --- a/third_party/blink/renderer/core/page/context_menu_controller.cc +++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -504,8 +504,11 @@ data.alt_text = html_element->AltText().Utf8(); } - if (source_type == kMenuSourceLongPress || - source_type == kMenuSourceLongTap) { + const bool from_touch = source_type == kMenuSourceTouch || + source_type == kMenuSourceLongPress || + source_type == kMenuSourceLongTap; + + if (from_touch) { for (Node* node = result.InnerNode(); node; node = node->parentNode()) { if (HTMLElement* element = DynamicTo<HTMLElement>(node); element && element->InterestForElement()) { @@ -822,9 +825,6 @@ SetAutofillData(result.InnerNode(), data); - const bool from_touch = source_type == kMenuSourceTouch || - source_type == kMenuSourceLongPress || - source_type == kMenuSourceLongTap; if (from_touch && !ShouldShowContextMenuFromTouch(data)) return false;
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc index 26bc7c91..962e791 100644 --- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
@@ -275,6 +275,20 @@ } } +void ImagePaintTimingDetector::NotifyInteractionTriggeredVideoSrcChange( + const LayoutObject& object) { + // The `MediaTiming` parameter ignored when computing the hash for video + // elements, so pass nullptr here. It's ignored because of an issue where + // multiple LCP candidates are created for videos with a poster image, which + // is why we need to remove the record here so the subsequent first frame is + // attributed to the relevant interaction. See also crbug.com/330202431. + MediaRecordId record_id(&object, /*media=*/nullptr); + MediaRecordIdHash record_id_hash = record_id.GetHash(); + if (records_manager_.IsRecordedImage(record_id_hash)) { + records_manager_.RemoveRecord(record_id_hash); + } +} + bool ImagePaintTimingDetector::RecordImage( const LayoutObject& object, const gfx::Size& intrinsic_size,
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h index 219b616..8afcb52 100644 --- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
@@ -245,6 +245,10 @@ // candidate. void ReportLargestIgnoredImage(); + // Called when the "src" attribute changes on a <video> element and the change + // is attributable to an interaction. + void NotifyInteractionTriggeredVideoSrcChange(const LayoutObject&); + bool IsRecordingLargestImagePaint() const { return recording_largest_image_paint_; }
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc index b0d3acf..bd94f7b 100644 --- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
@@ -249,6 +249,18 @@ } } +// static +void PaintTimingDetector::NotifyInteractionTriggeredVideoSrcChange( + const LayoutObject& object) { + LocalFrameView* frame_view = object.GetFrameView(); + if (!frame_view) { + return; + } + frame_view->GetPaintTimingDetector() + .GetImagePaintTimingDetector() + .NotifyInteractionTriggeredVideoSrcChange(object); +} + void PaintTimingDetector::NotifyImageFinished(const LayoutObject& object, const MediaTiming* media_timing) { if (IgnorePaintTimingScope::ShouldIgnore()) {
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h index a16f882..7581a40 100644 --- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h
@@ -77,6 +77,10 @@ const gfx::Rect& image_border); inline static void NotifyTextPaint(const gfx::Rect& text_visual_rect); + // Called when the "src" attribute changes on a <video> element and the change + // is attributable to an interaction. + static void NotifyInteractionTriggeredVideoSrcChange(const LayoutObject&); + void NotifyImageFinished(const LayoutObject&, const MediaTiming*); void LayoutObjectWillBeDestroyed(const LayoutObject&); void NotifyImageRemoved(const LayoutObject&, const ImageResourceContent*);
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc index 448748f..28490fd 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -19,6 +19,7 @@ #include "third_party/blink/renderer/core/event_type_names.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h" @@ -342,14 +343,14 @@ } } -void SoftNavigationHeuristics::ModifiedDOM(Node* node) { +bool SoftNavigationHeuristics::ModifiedDOM(Node* node) { // This should only be called by `ModifiedNode()` and `InsertedNode()`, and // detached windows should already be filtered out. CHECK(window_->GetFrame()); SoftNavigationContext* context = GetSoftNavigationContextForCurrentTask(); if (!context) { - return; + return false; } if (IsPrePaintBasedAttributionEnabled()) { @@ -360,6 +361,7 @@ } MaybeCommitNavigationOrEmitSoftNavigationEntry(context); + return true; } // TODO(crbug.com/424448145): re-architect how we pick our FCP point, when we @@ -768,12 +770,22 @@ : container_node); } -void SoftNavigationHeuristics::ModifiedNode(Node* node) { +// static +bool SoftNavigationHeuristics::ModifiedNode(Node* node) { auto* heuristics = GetHeuristicsForNodeIfShouldTrack(*node); if (!heuristics) { - return; + return false; } - heuristics->ModifiedDOM(node); + return heuristics->ModifiedDOM(node); +} + +// static +void SoftNavigationHeuristics::OnVideoSrcChanged(HTMLVideoElement* element) { + if (ModifiedNode(element)) { + if (LayoutObject* object = element->GetLayoutObject()) { + PaintTimingDetector::NotifyInteractionTriggeredVideoSrcChange(*object); + } + } } // SoftNavigationHeuristics::EventScope implementation
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h index b487532f..7117f2c 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -24,6 +24,7 @@ class TaskAttributionInfo; } // namespace scheduler +class HTMLVideoElement; class SoftNavigationContext; class SoftNavigationPaintAttributionTracker; @@ -88,8 +89,14 @@ // Inform `SoftNavigationHeuristics` that `node` was modified in some way. // Sets up paint tracking if the modification is attributable to a - // `SoftNavigationContext` and connected to the DOM. - static void ModifiedNode(Node* node); + // `SoftNavigationContext` and connected to the DOM, in which case this + // returns true. + static bool ModifiedNode(Node* node); + + // Inform `SoftNavigationHeuristics` that the "src" attribute for the video + // element changed. Sets up paint tracking if the modification is attributable + // to a `SoftNavigationContext` and connected to the DOM. + static void OnVideoSrcChanged(HTMLVideoElement*); // GarbageCollected boilerplate. void Trace(Visitor*) const override; @@ -98,7 +105,7 @@ void SameDocumentNavigationCommitted(const String& url, SoftNavigationContext*); - void ModifiedDOM(Node* node); + bool ModifiedDOM(Node* node); uint32_t SoftNavigationCount() { return soft_navigation_count_; } // TaskAttributionTracker::Observer's implementation.
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc index 3f149a6..7650a76 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
@@ -282,7 +282,8 @@ debugger->ExternalAsyncTaskStarted(message.sender_stack_trace_id); if (message.message->CanDeserializeIn(GetExecutionContext())) { MessageEvent* event = - MessageEvent::Create(ports, std::move(message.message)); + MessageEvent::Create(ports, std::move(message.message), /* origin=*/{}, + /* last_event_id=*/{}, /* source=*/nullptr); event->SetTraceId(message.trace_id); TRACE_EVENT( "devtools.timeline", "HandlePostMessage", "data",
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h index e7c55f0..e04e13ce 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -32,7 +32,6 @@ #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "services/network/public/mojom/fetch_api.mojom-blink-forward.h" -#include "third_party/blink/public/common/loader/worker_main_script_load_parameters.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/mojom/loader/code_cache.mojom-blink-forward.h" #include "third_party/blink/public/mojom/script/script_type.mojom-blink-forward.h" @@ -74,6 +73,7 @@ class TrustedTypePolicyFactory; class V8UnionTrustedScriptURLOrUSVString; class WorkerLocation; +struct WorkerMainScriptLoadParameters; class WorkerNavigator; class WorkerThread;
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h index 3c613cc8..259cd86 100644 --- a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h +++ b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -10,6 +10,7 @@ #include "base/synchronization/waitable_event.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/blink/public/common/loader/worker_main_script_load_parameters.h" #include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
diff --git a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc index bf02154..3118c5f 100644 --- a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc +++ b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -175,7 +175,8 @@ context->IsSameAgentCluster(message.sender_agent_cluster_id)) && message.message->CanDeserializeIn(context)) { event = MessageEvent::Create(nullptr, std::move(message.message), - context->GetSecurityOrigin()->ToString()); + context->GetSecurityOrigin()->ToString(), + /* last_event_id=*/{}, /* source=*/nullptr); } else { event = MessageEvent::CreateError(context->GetSecurityOrigin()->ToString()); }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h index eeefda5..518cc17 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -180,6 +180,7 @@ } // CanvasRenderingContext implementation + bool IsComposited() const override; scoped_refptr<CanvasResource> PaintRenderingResultsToResource( SourceDrawingBuffer source_buffer, FlushReason reason) override; @@ -347,7 +348,6 @@ void DrawFocusRing(const Path&, Element*); void UpdateElementAccessibility(const Path&, Element*); - bool IsComposited() const override; bool HasAlpha() const override { return CreationAttributes().alpha; } bool IsDesynchronized() const override { return CreationAttributes().desynchronized;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 3904770..cc6f173a 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -1745,7 +1745,7 @@ // Draw to the canvas and verify that the canvas is composited. Context2D()->fillRect(0, 0, 1, 1); - EXPECT_TRUE(CanvasElement().IsCompositedForCanvas2D()); + EXPECT_TRUE(Context2D()->IsComposited()); EXPECT_EQ(CanvasElement().GetRasterModeForCanvas2D(), RasterMode::kCPU); } @@ -1767,7 +1767,7 @@ // Draw to the canvas and verify that the canvas is not composited. Context2D()->fillRect(0, 0, 1, 1); - EXPECT_FALSE(CanvasElement().IsCompositedForCanvas2D()); + EXPECT_FALSE(Context2D()->IsComposited()); EXPECT_EQ(CanvasElement().GetRasterModeForCanvas2D(), RasterMode::kCPU); }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc index 9309d0d..322064a 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -271,6 +271,10 @@ wgpu::DeviceDescriptor dawn_desc = {}; + wgpu::DawnConsumeAdapterDescriptor consume_adapter_desc; + consume_adapter_desc.consumeAdapter = true; + dawn_desc.nextInChain = &consume_adapter_desc; + GPUSupportedLimits::ComboLimits required_limits; if (descriptor->hasRequiredLimits()) { dawn_desc.requiredLimits = required_limits.GetLinked();
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc index e53515c5..efa7382f 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -824,7 +824,7 @@ for (String text : {text_default, emoji_default}) { EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*mono_font, text)), - String(kNotoEmojiFontName)); + StringView(kNotoEmojiFontName)); const char* system_mono_font_name = kSystemMonoEmojiFont; #if BUILDFLAG(IS_MAC) if (text == text_default) { @@ -833,7 +833,7 @@ #endif EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*color_font, text)), - String(system_mono_font_name)); + StringView(system_mono_font_name)); } } @@ -853,10 +853,10 @@ for (String text : {text_default, emoji_default}) { EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*mono_font, text)), - kSystemColorEmojiFont); + StringView(kSystemColorEmojiFont)); EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*color_font, text)), - kNotoColorEmojiFontName); + StringView(kNotoColorEmojiFontName)); } } @@ -904,10 +904,10 @@ EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*mono_font, text)), - String(expected_name_for_mono_requested_font)); + StringView(expected_name_for_mono_requested_font)); EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*color_font, text)), - String(expected_name_for_color_requested_font)); + StringView(expected_name_for_color_requested_font)); } } @@ -927,13 +927,13 @@ EXPECT_EQ(run_font_data.size(), 3u); EXPECT_EQ(MaybeStripFontationsSuffix( run_font_data[0].font_data_->PlatformData().FontFamilyName()), - kSystemColorEmojiFont); + StringView(kSystemColorEmojiFont)); EXPECT_EQ(MaybeStripFontationsSuffix( run_font_data[1].font_data_->PlatformData().FontFamilyName()), - kSystemMonoEmojiFont); + StringView(kSystemMonoEmojiFont)); EXPECT_EQ(MaybeStripFontationsSuffix( run_font_data[2].font_data_->PlatformData().FontFamilyName()), - kSystemColorEmojiFont); + StringView(kSystemColorEmojiFont)); } TEST_F(HarfBuzzShaperTest, FontVariantEmojiTextSystemFallback) { @@ -951,7 +951,7 @@ Font* color_font = CreateNotoColorEmoji(FontVariantEmoji::kTextVariantEmoji); EXPECT_EQ(MaybeStripFontationsSuffix( GetShapedFontFamilyNameForEmojiVS(*color_font, text)), - mono_font_name); + StringView(mono_font_name)); } #endif
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 5df85df..13ac0bf 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -799,6 +799,12 @@ status: "test", }, { + // Remove the restriction that drawElement can only draw immediate + // children of the canvas, and allow drawing canvas descendants. + name: "CanvasDrawElementInSubtree", + depends_on: ["CanvasDrawElement"], + }, + { name: "CanvasFloatingPoint", status: "stable", },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 12e9477..409c7dd 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2840,6 +2840,31 @@ crbug.com/433687466 external/wpt/webrtc/RTCDataChannel-worker-GC.html [ Failure ] +# [0729/035620.675:FATAL:ird_party\blink\renderer\bindings\modules\v8\v8_digital_credential_creation_options.h:43] DCHECK failed: hasRequests(). +crbug.com/434984251 external/wpt/digital-credentials/create.tentative.https.html [ Crash Timeout ] + +# UUID in URL dumped to `*-expected.txt` +crbug.com/435005743 external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-event-handler.html [ Failure ] + +# Possibly flaky byte count in `*-expected.txt` +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.html [ Failure ] + +crbug.com/434975373 external/wpt/svg/styling/image-sizing-min-content.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-calc-size.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-fit-content.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-max-content.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-min-content.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-stretch.tentative.svg [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB.tentative.html [ Failure ] +crbug.com/434975373 external/wpt/svg/styling/nested-svg-sizing-viewport-units.tentative.svg [ Failure ] + +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/cross-origin-iframe/max-payload.tentative.https.window.html [ Timeout ] +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.tentative.https.window.html [ Timeout ] +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/same-origin-iframe/accumulated-oversized-payload.tentative.https.window.html [ Timeout ] +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/same-origin-iframe/max-payload.tentative.https.window.html [ Timeout ] +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.tentative.https.window.html [ Timeout ] +crbug.com/434980772 external/wpt/fetch/fetch-later/quota/same-origin-iframe/oversized-payload.tentative.https.window.html [ Timeout ] + # ====== New tests from wpt-importer added here ====== crbug.com/433297073 external/wpt/css/filter-effects/fecolormatrix-display-p3.html [ Failure ] crbug.com/433324167 external/wpt/html/canvas/element/text/2d.text.writingmode.html [ Failure ] @@ -6872,9 +6897,6 @@ crbug.com/1345192 accessibility/aria-combo-box-with-delay-add.html [ Crash Failure Pass Timeout ] crbug.com/1345235 external/wpt/content-security-policy/style-src/stylehash-basic-blocked.sub.html [ Crash Failure Pass Timeout ] -# Temporarily disabled to land https://crrev.com/c/6796895 -crbug.com/433162438 http/tests/devtools/console/console-format-classes.js [ Failure Pass ] - # Sheriff 2022-07-26 crbug.com/1347459 [ Fuchsia ] fast/css3-text/css3-text-decoration/text-decoration-style-inherit-links.html [ Crash Failure Pass Timeout ] crbug.com/1347459 [ Fuchsia ] fast/css3-text/css3-text-decoration/text-decoration-style-inherit-not-propagated-by-out-of-flow.html [ Crash Failure Pass Timeout ] @@ -9479,7 +9501,6 @@ crbug.com/417921517 [ Win11-arm64 ] external/wpt/css/css-ruby/ruby-text-combine-upright-002a.html [ Failure Pass ] # Gardener 2025-05-19 -crbug.com/418345234 [ Win ] external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.html [ Failure ] crbug.com/418572857 external/wpt/background-fetch/fetch.https.window.html [ Failure Pass Timeout ] crbug.com/418362694 [ Linux ] external/wpt/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html [ Crash Timeout ] @@ -9623,3 +9644,6 @@ # Gardener 2025-07-23 crbug.com/40253082 [ Mac14 ] virtual/controls-refresh-hc/fast/forms/color-scheme/select/select-multiple-appearance-basic.html [ Failure ] + +# Gardener 2025-07-30 +crbug.com/434955776 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1252.html?include=loading [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 973c2851..836da94 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -192,6 +192,23 @@ ], "expires": "Sep 1, 2024" }, + { + "prefix": "canvas-draw-element-in-subtree", + "owners": [ + "pdr@chromium.org", + "paint-dev@chromium.org" + ], + "platforms": [ + "Linux", + "Mac", + "Win" + ], + "bases": [], + "args": [ + "--enable-blink-features=CanvasDrawElementInSubtree" + ], + "expires": "Jan 15, 2026" + }, "---------------------------- Close watchers -------------------------------", "TODO(https://crbug.com/1495208): These cannot be run in the normal web ", "platform tests environment because of",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index da50c0e..5ee432f 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1176,6 +1176,13 @@ ] ], "flexbox": { + "auto-height-flex-item-in-multicol-crash.html": [ + "82dec303cc1196c375355c5d4738fe34018e7119", + [ + null, + {} + ] + ], "button-in-multicol-crash.html": [ "30e373542a6975127232d07232cfe8fc2ccf4800", [ @@ -6043,6 +6050,13 @@ {} ] ], + "first-line-reparent-crash.html": [ + "7149d770f07de38e53102dfb9c9c51b700feee8b", + [ + null, + {} + ] + ], "get-computed-style-crash.html": [ "38cd5af7f83d60976f9712e446a55d11fe07160e", [ @@ -27410,6 +27424,23 @@ ] ] }, + "content-security-policy": { + "generic": { + "image-document-ignores-csp.html": [ + "a3f6f64854d98d40c8c405831d6f3f9656fdf34d", + [ + null, + [ + [ + "/content-security-policy/generic/image-document-ignores-csp-ref.html", + "==" + ] + ], + {} + ] + ] + } + }, "contenteditable": { "synthetic-height.html": [ "4d466bff412e6de924b9886ef808b49f7ff2b44d", @@ -63385,6 +63416,19 @@ {} ] ], + "border-spacing-095.html": [ + "8e5c8f55ccaeb749894a63970ac349cfbce98d53", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "border-spacing-applies-to-016.xht": [ "0536763244237b77645937fe30e4898f1efcbfb5", [ @@ -76318,6 +76362,19 @@ {} ] ], + "pseudo-element-implicit-anchor.html": [ + "a7192670cc1a7e604eb13da817ff3d1f9c5ed4db", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "sticky-anchor-position-invalid.html": [ "d1efeed5f29263fe3a16d60cbdaf9d2c26357ce5", [ @@ -76409,6 +76466,32 @@ {} ] ], + "transform-007.tentative.html": [ + "77216bfe2657ba9fb77639ef4924a9f76ebe8108", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "transform-008.tentative.html": [ + "ffbedaabbb8095eda6aef25f85a4698ea6a8ed73", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "vertical-aligned-table-cell.html": [ "9b16621b7132fdf92856f65eaf7a8450c1fc7b63", [ @@ -119691,6 +119774,47 @@ {} ] ], + "alignment": { + "flex-align-baseline-column-rtl-direction.html": [ + "3be57a2b34bf4c68f0041b874fbfdcecd797a20a", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], + "flex-align-baseline-column-vert-lr-rtl-wrap-reverse.html": [ + "767c129b057b75defe26f3fce7d52b2eb3f7aa68", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], + "flex-align-baseline-column-vert-rl-rtl-wrap-reverse.html": [ + "9608301aa1a2c6cd444edee072d95f236583ca3d", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ] + }, "anonymous-block.html": [ "915cca757d73cc711bc3cb47e7539bb4e3e49554", [ @@ -137249,6 +137373,32 @@ {} ] ], + "grid-abspos-staticpos-align-self-flex-end-large-border-padding.html": [ + "c9359c8e1c5b7b33807f83c02e7edbc1cd68f9f1", + [ + null, + [ + [ + "/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html", + "==" + ] + ], + {} + ] + ], + "grid-abspos-staticpos-align-self-flex-end.html": [ + "54c772e60873118e346c04cb2b6dfec908f6b73d", + [ + null, + [ + [ + "/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-ref.html", + "==" + ] + ], + {} + ] + ], "grid-abspos-staticpos-align-self-img-001.html": [ "cb5906603b35912cf2e649b1fa0a049d801ec236", [ @@ -137444,6 +137594,32 @@ {} ] ], + "grid-abspos-staticpos-align-self-self-end-large-border-padding.html": [ + "1478bbbe3adc0345fa55ef4acc00aec87d8788b4", + [ + null, + [ + [ + "/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html", + "==" + ] + ], + {} + ] + ], + "grid-abspos-staticpos-align-self-self-end.html": [ + "2cd256077ece2edc5339bccf2d83859fa2743de9", + [ + null, + [ + [ + "/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-ref.html", + "==" + ] + ], + {} + ] + ], "grid-abspos-staticpos-align-self-vertWM-001.html": [ "2feeb2c3a130ede88bb0c42bf8e70fc9b0223b75", [ @@ -218699,6 +218875,19 @@ {} ] ], + "pre-001.html": [ + "0e3e1e38c7293303d7cf07c0e64facfa76ba966d", + [ + null, + [ + [ + "/css/css-text/white-space/reference/pre-001-ref.html", + "==" + ] + ], + {} + ] + ], "pre-float-001.html": [ "8dd08d80992e6d6310a6697f84c2533d399c8e5e", [ @@ -257679,7 +257868,7 @@ ] ], "column-span-during-transition-doesnt-skip.html": [ - "67e6b5d5d0008ac08cb23214ed291c1375f9e236", + "81d4f93eccbd6d37d8f231f4e73b58993343218b", [ null, [ @@ -257688,7 +257877,23 @@ "==" ] ], - {} + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 1 + ], + [ + 0, + 100000 + ] + ] + ] + ] + } ] ], "content-smaller-than-box-size.html": [ @@ -259952,6 +260157,35 @@ } ] ], + "group-children-sizing-with-border-props.html": [ + "a3b35d83cf5686823387f3340b20fde9c98d865c", + [ + null, + [ + [ + "/css/css-view-transitions/nested/group-children-sizing-with-border-props-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 70 + ], + [ + 0, + 500 + ] + ] + ] + ] + } + ] + ], "group-children-sizing-with-border.html": [ "cb0cf819b428ed19b2e9c0071ce8ea2304aca0bf", [ @@ -319980,6 +320214,19 @@ {} ] ], + "image-sizing-min-content.tentative.svg": [ + "fc3f493750494af0552a0786664012d1f9223852", + [ + null, + [ + [ + "/svg/styling/image-sizing-min-content-expected.svg", + "==" + ] + ], + {} + ] + ], "invalidation": { "nth-child-of-class.svg": [ "a91f421337ceeaade2072cee54b29b6eeeda6a01", @@ -320008,6 +320255,188 @@ ] ] }, + "nested-svg-sizing-auto.tentative.svg": [ + "21ebe5bf6929b11e1d4e07a13a02b04bfebe5c96", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-calc-size.tentative.svg": [ + "1517f897b4904299a6db867ab71b41be17e49b52", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-calc.tentative.svg": [ + "ba409e5c7ee79ea8d5965a5e5f4f635194fd942b", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-expected.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-ems.tentative.svg": [ + "59574e6ec5ca046482a36b9c4c55b979ac295fc8", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-expected.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-fit-content.tentative.svg": [ + "02678cdb978142074be939104ea2bf507e56b469", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-inherit.tentative.svg": [ + "871ef77d9f6b134ece4ab692f47cadbd09565c12", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-initial.tentative.svg": [ + "65c65244bee1ef7a0fd87fc1714b3522e36e997e", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-max-content.tentative.svg": [ + "7650e4055046c5174533eea6b86976d39abfe38b", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-min-content.tentative.svg": [ + "871b66a816b4b20a45415208972dd18183a21cc4", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-percent.tentative.svg": [ + "150e409305a48e5db1a8e93be972a867c3e338e8", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-expected.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-rems.tentative.svg": [ + "44a5cb6001dda3439da22d64ce8682a5a4a736d2", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-expected.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-stretch.tentative.svg": [ + "f6fb436631bd7f556da108198da6d729f197f138", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-full-circle-ref.svg", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-viewport-units-with-ICB.tentative.html": [ + "a53911f39959d9e2ab6b3675b693b828d50bf31c", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-viewport-units-with-ICB-expected.html", + "==" + ] + ], + {} + ] + ], + "nested-svg-sizing-viewport-units.tentative.svg": [ + "387e97cb185f264b716c00b5d255dae2424370da", + [ + null, + [ + [ + "/svg/styling/nested-svg-sizing-expected.svg", + "==" + ] + ], + {} + ] + ], "nested-svg-sizing-with-use.svg": [ "5f3c4eed49024530cf05e0f832877974aa2b9d20", [ @@ -329278,6 +329707,10 @@ "5c580273dcfc94eff137a0ae65314bebc9b7b5c0", [] ], + "image-document-ignores-csp-ref.html": [ + "e0747fd6c2810ccd771c5e33795d8c46ba56ff6c", + [] + ], "negativeTests.js": [ "44b4d7f683d8fb674a3c2b5d22eb8ea9d7b31ada", [] @@ -330342,6 +330775,14 @@ "2fa1e0ac0663a65deae6602621521cc2844b93de", [] ], + "pass3.png": [ + "2fa1e0ac0663a65deae6602621521cc2844b93de", + [] + ], + "pass3.png.headers": [ + "6581fd425ed9da6b6273d1eefb84ea9ac9ac6e53", + [] + ], "ping.js": [ "750ae45f969491ea29eaa47c85f96f97d94b415f", [] @@ -330527,18 +330968,10 @@ "e3f78621264b6d32d7c8baeba34ba0e245d83458", [] ], - "META.yml": [ - "4bbc6311bdceece7580ba9c38344081e0b4aba57", - [] - ], "OWNERS": [ "7e45685dea195172d1b10a4c12f4cf196cd7e227", [] ], - "README.md": [ - "b8a1d0a6098492b615dfae8a1e5e44ade8a2f3db", - [] - ], "cookieListItem_attributes.https.any-expected.txt": [ "4113e2b1cf92a9d65c3349bf8bcf8bfa586a2193", [] @@ -330574,40 +331007,6 @@ "cookieStore_set_arguments.https.any.serviceworker-expected.txt": [ "ad6cdda02b6ce10df09a3774ab7e8e38af20e001", [] - ], - "resources": { - "always_changing_sw.sub.js": [ - "9fdf99848fa50316e275cd6636a5755270a9bb1e", - [] - ], - "cookie-test-helpers.js": [ - "82ca135f88e423440c3c3fd2bb02df4ed39aa436", - [] - ], - "cookie_helper.py": [ - "71dd8b82ee7eb50054455724bc4c018b22f20949", - [] - ], - "domain_parsing-child.sub.https.html": [ - "96a063990710b60105a1cb665f48a7c7449e1fe1", - [] - ], - "empty_sw.js": [ - "2b0ae226121503789d63d405670becb09e51b833", - [] - ], - "helper_iframe.sub.html": [ - "d5cae23d160ef8ac5a57820eee1d8239ad637532", - [] - ], - "helpers.js": [ - "8d5dddef6577fc534a68c9e8415854e4c64901fd", - [] - ] - }, - "serviceworker_cookieStore_cross_origin.js": [ - "fa1c4084fd45f1334a24d658d8c881e17291c915", - [] ] }, "cookies": { @@ -331000,6 +331399,50 @@ ] } }, + "cookiestore": { + "META.yml": [ + "a1d0ed48c87d9a2399674991726a5185aa9ebb41", + [] + ], + "README.md": [ + "d767a7b46811811f39c43598fb0848d828a69ec8", + [] + ], + "resources": { + "always_changing_sw.sub.js": [ + "9fdf99848fa50316e275cd6636a5755270a9bb1e", + [] + ], + "cookie-test-helpers.js": [ + "82ca135f88e423440c3c3fd2bb02df4ed39aa436", + [] + ], + "cookie_helper.py": [ + "71dd8b82ee7eb50054455724bc4c018b22f20949", + [] + ], + "domain_parsing-child.sub.https.html": [ + "96a063990710b60105a1cb665f48a7c7449e1fe1", + [] + ], + "empty_sw.js": [ + "2b0ae226121503789d63d405670becb09e51b833", + [] + ], + "helper_iframe.sub.html": [ + "d5cae23d160ef8ac5a57820eee1d8239ad637532", + [] + ], + "helpers.js": [ + "8d5dddef6577fc534a68c9e8415854e4c64901fd", + [] + ] + }, + "serviceworker_cookieStore_cross_origin.js": [ + "fa1c4084fd45f1334a24d658d8c881e17291c915", + [] + ] + }, "core-aam": { "DIR_METADATA": [ "c536c667a8d5dbeea8a1de059c919a3ed9ba4336", @@ -356099,6 +356542,14 @@ "868717bc53ba75e1d6244fbaccddcf178c8c14da", [] ], + "grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html": [ + "7f2a5ad8377f9948d7640673eb76cfac3edfa3cd", + [] + ], + "grid-abspos-staticpos-align-self-flex-end-ref.html": [ + "868717bc53ba75e1d6244fbaccddcf178c8c14da", + [] + ], "grid-abspos-staticpos-align-self-img-001-ref.html": [ "06d9d366127609b22f599fd87528693e37c8e6f4", [] @@ -356159,6 +356610,14 @@ "5e7fd9f9a9bb52235d9bca30dec9297011dfa06c", [] ], + "grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html": [ + "7f2a5ad8377f9948d7640673eb76cfac3edfa3cd", + [] + ], + "grid-abspos-staticpos-align-self-self-end-ref.html": [ + "868717bc53ba75e1d6244fbaccddcf178c8c14da", + [] + ], "grid-abspos-staticpos-align-self-vertWM-001-ref.html": [ "dd151d46fd0cd2a4d28dca8fa2e3b21700de7f59", [] @@ -373180,6 +373639,10 @@ "644dfc4b025e62babeddd3575af5ffee40c77e26", [] ], + "pre-001-ref.html": [ + "e950bbbc4960c650cd08b2532e6b0a3309ca5ffb", + [] + ], "pre-float-001-ref.html": [ "9753cb37b641f3f25d1045f3149875deffb1613c", [] @@ -374201,6 +374664,10 @@ "bc8409c24dd3ea29cd8ed34d071e9e1102860b30", [] ], + "text-decoration-valid-expected.txt": [ + "bbee844876a0b5172e9048f0ce46fb59027dcf9f", + [] + ], "text-emphasis-position-valid-expected.txt": [ "08d5ae4e8f6cb0fd5794ccdb719f90ee41c74a15", [] @@ -376761,7 +377228,7 @@ [] ], "historical-expected.txt": [ - "5be521fe5b91040b720c73bb5f53378cafaa4a5e", + "72454f2c80a85ed6b4c314f59f606efa5c782604", [] ], "idlharness-expected.txt": [ @@ -379975,6 +380442,10 @@ "4f994bd03f67c7e73b03bb58b8eec220cb7720c5", [] ], + "group-children-sizing-with-border-props-ref.html": [ + "c914fa25218ae99cb628293587b8be08c51b670f", + [] + ], "group-children-sizing-with-border-ref.html": [ "f1a484400e77b69372808af4d40c376c9a00aa14", [] @@ -386378,10 +386849,6 @@ [] ], "reactions": { - "Document-expected.txt": [ - "b68f94ced2d69f8f7e65754999337c3417c1e959", - [] - ], "WEB_FEATURES.yml": [ "fe4958dd49c703e6dd71cb9720aa70b36e49427c", [] @@ -386432,6 +386899,10 @@ "c5c25e44659658b4c8a1d0cc590dea2ecb21725d", [] ], + "Document-importNode-cross-document.window-expected.txt": [ + "359c67a9ea664f54c3f73cd84d33df572f64bf15", + [] + ], "Document-importNode-expected.txt": [ "1818c226c6a223040cf7cf19188b8b3efc79e0fd", [] @@ -386460,10 +386931,18 @@ "c8486615c1e03c1b70d9f22ddbfe2f95b617fd0a", [] ], + "adoption.window-expected.txt": [ + "834b0d87d9d5194b91d870022f96dd17e16217c0", + [] + ], "constructor-reentry-with-different-definition-expected.txt": [ "ae9069c20b4051efd1526ef1c11eb6ac65ef1c0e", [] ], + "global.window-expected.txt": [ + "c848fee3437a828116e0674791b3785fb0983e0e", + [] + ], "initial-about-blank.window-expected.txt": [ "a715c1e2339881b9cc061246cf1c0b71cdf4d371", [] @@ -386477,13 +386956,17 @@ [] ], "scoped-registry-define-upgrade-criteria-expected.txt": [ - "7d8ba836721be543c4e55e161afa9c8b51266d51", + "4b5efd5f89d859df165215ed0999b645cdf5d580", [] ], "scoped-registry-define-upgrade-order-expected.txt": [ "6eeb8c105f184e80a5d4649f6f83f32ca80a76f3", [] ], + "scoped-registry-initialize-expected.txt": [ + "1818c226c6a223040cf7cf19188b8b3efc79e0fd", + [] + ], "scoped-registry-registry-define-get-etc-expected.txt": [ "8064e9ae58da235b005fb5f1177c490e982b46f5", [] @@ -386511,10 +386994,6 @@ [] ] }, - "scoped-registry-initialize-expected.txt": [ - "1818c226c6a223040cf7cf19188b8b3efc79e0fd", - [] - ], "state": { "META.yml": [ "df335b339e1324d8c36939df30c8506efa6aae0a", @@ -390645,7 +391124,7 @@ [] ], "setmediakeys-to-multiple-video-elements.js": [ - "4c7faef69d0e8b8501b53be6050cf3b028909fdb", + "843d37e7a52d34d874f31dbe432df3e7fa6580f6", [] ], "setmediakeys.js": [ @@ -393786,7 +394265,7 @@ [] ], "fetch-later.html": [ - "955f815d940bf853a9c84a367bf2023d9738e1a0", + "b295be116c731c5ceec2d222ecd999fc5342d5c6", [] ], "get_beacon.py": [ @@ -396661,7 +397140,7 @@ [] ], "FileSystemBaseHandle-buckets.js": [ - "9654755148a871e8af19a16aab93208eaa24e6e8", + "c67cb1de64960dc144c49e15c9b0e8bb603dbbee", [] ], "FileSystemBaseHandle-getUniqueId.js": [ @@ -402431,7 +402910,7 @@ [] ], "path-objects.yaml": [ - "cf218829598c1ee4275ceefd025974590fbe1cd8", + "ccb3d79b93a44d36fec6abebc9a95621c2913b6c", [] ], "pixel-manipulation.yaml": [ @@ -414300,6 +414779,10 @@ "7decc7bc6035e60e6613e55cbb4dafef0b68dab9", [] ], + "script-src-event-handler-framed.sub.html": [ + "7b9e0edeb979e8d04c583d9b3080c388ddab1e17", + [] + ], "script-src-framed.sub.html": [ "baab01075022601ed258866a0b98a6d07129f5fb", [] @@ -414324,8 +414807,12 @@ "08609b1c12a0c79fc0fb8f260777b91fff85eec7", [] ], + "script-src-unsupported-language-framed.sub.html": [ + "62b2c4c017b49ac2dc7e01bc1382a2cc9b10aa39", + [] + ], "script-src-unsupported-type-framed.sub.html": [ - "1f38560ee152a61623667b2be9057296d05453c6", + "78e71941b358cc231b3190cdbf4aab4548611a88", [] ], "svg-image-href-framed.sub.html": [ @@ -414580,7 +415067,7 @@ [] ], "script-src-unsupported-type-nonspeculative.sub.html": [ - "94098b5c77539d7d49d4cb4c3ced4cea3a98ff68", + "dc8343c382406383b25ce8e41d2bad8ab7085a1f", [] ], "svg-image-href-nonspeculative.sub.html": [ @@ -414653,7 +415140,7 @@ }, "tools": { "generate.py": [ - "f0db885814b8997cd80ff34121132607d7e71c17", + "b3b577d9e1069b1dd2140f2a2499d51fa4947ff1", [] ] } @@ -417439,8 +417926,8 @@ "177c5b9f11d4e1dd48ebb407529a4e567d030f1a", [] ], - "cookie-store.idl": [ - "8a000cac0b262de89a1c265755d8a5aeb2985271", + "cookiestore.idl": [ + "ecb277756cc89869423f91e7f7d57b19789b1114", [] ], "crash-reporting.idl": [ @@ -427284,7 +427771,7 @@ [] ], "testharness.js": [ - "b5847ed406ae5af7f8493df3adbee90e318b8ebc", + "f495b62458ba75b8021c9f62ccadc4e0f4eaa3c9", [] ], "testharness.js.headers": [ @@ -427949,12 +428436,16 @@ "cc41cd292b6c7f76c9201b129edf70dd79fea592", [] ], + "authentication-invalid-payment-entity-logo.https-expected.txt": [ + "4a77d491724b68bd3b73837e72868a59fdced10b", + [] + ], "authentication-requires-user-activation.https-expected.txt": [ "19b11cfe3c365baf22b767ce7784ea17a4a0fbe8", [] ], "constructor-validate-payment-method-data.https-expected.txt": [ - "0d94a62de0bee382bc52a48aa1883558e21bce16", + "2b79dec23319043a1c262fdeac43e8581412cdca", [] ], "resources": { @@ -433697,7 +434188,11 @@ "ddfd51eed1f2403e2c6a964cee6a307c0d3838fb", [] ] - } + }, + "svg-get-bounding-client-rect-in-non-rendered-elements-expected.txt": [ + "b74a8cd873b81a7668293ae63b0026537d36c2b9", + [] + ] }, "historical-expected.txt": [ "9117938a1a631191a3c33ddf42bb6ac4b79a9cc2", @@ -434582,6 +435077,10 @@ "85aedd9c41369de3c93db94c13b755505d364138", [] ], + "image-sizing-min-content-expected.svg": [ + "9e9b69901f3772eac2049d292008e2c18197c582", + [] + ], "invalidation": { "nth-child-of-class-ref.svg": [ "780bb9f3f68551d37dac298dfff7cf1ac55597ab", @@ -434592,6 +435091,14 @@ "a8fa5211842b3a351660e047626517aeafe960b5", [] ], + "nested-svg-sizing-full-circle-ref.svg": [ + "f35ab0d4e2f8fa9fbc5d44ae5f6d83e71c684fc1", + [] + ], + "nested-svg-sizing-viewport-units-with-ICB-expected.html": [ + "4f3762c520665c3a0fdb2673091eb4db8a133942", + [] + ], "nested-svg-sizing-with-use-expected.svg": [ "daef973aa5d1b0ae0a5c29cc3d94e8f893273ace", [] @@ -436977,7 +437484,7 @@ [] ], "testharness.js": [ - "7c1ded21d0e266612d49cfe9eef89c24f704cf84", + "ff96f572077231d2e5949b08473ea9a3e3ea7a24", [] ], "testharnessreport.js": [ @@ -440304,6 +440811,12 @@ "b7458377ab0f792dbf46c839099650d52978339e", [] ], + "add_data_collector": { + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ] + }, "add_intercept": { "__init__.py": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", @@ -472896,7 +473409,7 @@ ] }, "getRandomValues.any.js": [ - "574134eb76dcd8ea059c531c88841477736fbed6", + "aecd38efd60bac63a28673241039d2743e5b911f", [ "WebCryptoAPI/getRandomValues.any.html", {} @@ -474531,7 +475044,7 @@ ] ], "detector.https.window.js": [ - "f52064696f33bdf1fdcc4d4cec56a24eaa35be6b", + "0ccbe8955d3721416acaca62043d451f0acd5719", [ "ai/language_detection/detector.https.window.html", { @@ -475252,7 +475765,7 @@ ] ], "translator.optional.https.window.js": [ - "1b2519cf2f0ed9c8b030fa1b2c6c79b000621478", + "ceb7846bf3695dc9c2ff5c0037f026cc0235d139", [ "ai/translator/translator.optional.https.window.html", { @@ -476231,7 +476744,7 @@ ] ], "fetch.https.window.js": [ - "1756a0e6e3fc3259bd26dd37d43e890ae0e9a7b0", + "6a2f6ee6711a0f1f8e1bbe9c74be18082e2b3f1d", [ "background-fetch/fetch.https.window.html", { @@ -496081,1191 +496594,6 @@ ] ] }, - "cookie-store": { - "change_eventhandler_for_already_expired.https.window.js": [ - "f3bbe0ea560974e9486941384e75a58d2d6a4637", - [ - "cookie-store/change_eventhandler_for_already_expired.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Test that setting an already-expired cookie does not trigger an event." - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_document_cookie.https.window.js": [ - "1937ebdae35942840dc3b641b5907f334048f3fb", - [ - "cookie-store/change_eventhandler_for_document_cookie.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Observing 'change' events in document when cookies set via document.cookie" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js": [ - "8517995acfe746bbff09243597d6d319e3af1bc2", - [ - "cookie-store/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Observing 'change' events in document when cookies set via Set-Cookie header" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_no_change.https.window.js": [ - "5f9c2927433fc408c70c005789dc0bcc34d46caa", - [ - "cookie-store/change_eventhandler_for_no_change.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Test that setting a duplicate cookie does not fire a second event." - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_no_name_and_no_value.https.window.js": [ - "4498caf59689cc3da875d1c56937f6d2a235cb5d", - [ - "cookie-store/change_eventhandler_for_no_name_and_no_value.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Observing 'change' events in document when modifications API is called with blank arguments" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_no_name_equals_in_value.https.window.js": [ - "13d721786c9a140b05ed5291c6096c894053f78b", - [ - "cookie-store/change_eventhandler_for_no_name_equals_in_value.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Observing 'change' events in document when setting a cookie value containing \"=\"" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "change_eventhandler_for_no_name_multiple_values.https.window.js": [ - "60c6c16518ae767d2dab68e62af8967b9890072b", - [ - "cookie-store/change_eventhandler_for_no_name_multiple_values.https.window.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Observing 'change' events in document when modifications API is called multiple times with a blank name" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "cookieListItem_attributes.https.any.js": [ - "b42a745d3e4e1a9f4c8a0c6e7d9c04c02f8d1340", - [ - "cookie-store/cookieListItem_attributes.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieListItem attributes" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieListItem_attributes.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieListItem attributes" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStoreManager_getSubscriptions_empty.https.any.js": [ - "8cfd732f304509582ff8c9be97e8e90e6c06e8ed", - [ - "cookie-store/cookieStoreManager_getSubscriptions_empty.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker without cookie change subscriptions" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ], - [ - "cookie-store/cookieStoreManager_getSubscriptions_empty.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker without cookie change subscriptions" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ] - ], - "cookieStoreManager_getSubscriptions_multiple.https.any.js": [ - "9e153d03aae798371d4c28649de7126f18aefe76", - [ - "cookie-store/cookieStoreManager_getSubscriptions_multiple.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker with multiple cookie change subscriptions" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ], - [ - "cookie-store/cookieStoreManager_getSubscriptions_multiple.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker with multiple cookie change subscriptions" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ] - ], - "cookieStoreManager_getSubscriptions_single.https.any.js": [ - "98ec19df3f1881666a48f2f920000c3a11b67f82", - [ - "cookie-store/cookieStoreManager_getSubscriptions_single.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker with one cookie change subscription" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ], - [ - "cookie-store/cookieStoreManager_getSubscriptions_single.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: ServiceWorker with one cookie change subscription" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ] - ], - "cookieStore_delete.sub.https.html": [ - "8cdfae6776dd88183479f7c1378be814f8c66105", - [ - null, - {} - ] - ], - "cookieStore_delete_arguments.https.any.js": [ - "27b54f5a8dcdbe25230b04a101ca0fb0b3c9851d", - [ - "cookie-store/cookieStore_delete_arguments.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() arguments" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_delete_arguments.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() arguments" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_delete_basic.https.any.js": [ - "08a1fac5afe1ed5c2713e60674fadc3d0be7e620", - [ - "cookie-store/cookieStore_delete_basic.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() return type" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_delete_basic.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() return type" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_event_arguments.https.window.js": [ - "bcb698eeb0d6ce760033ba628120ebf7772a1084", - [ - "cookie-store/cookieStore_event_arguments.https.window.html", - {} - ] - ], - "cookieStore_event_basic.https.window.js": [ - "c0075d6adcdd9a3438dfd3df622bf35883bf4110", - [ - "cookie-store/cookieStore_event_basic.https.window.html", - {} - ] - ], - "cookieStore_event_delete.https.window.js": [ - "d0fee1ab1d03cd3835f3b9e5828d4aef7eb45710", - [ - "cookie-store/cookieStore_event_delete.https.window.html", - {} - ] - ], - "cookieStore_event_overwrite.https.window.js": [ - "427e7dcbb7ce0ff1627a2f45a2a407d1c0189dc3", - [ - "cookie-store/cookieStore_event_overwrite.https.window.html", - {} - ] - ], - "cookieStore_getAll_arguments.https.any.js": [ - "868246f606f4ace75f807eef584d263114778f4b", - [ - "cookie-store/cookieStore_getAll_arguments.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.getAll() arguments" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_getAll_arguments.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.getAll() arguments" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_getAll_multiple.https.any.js": [ - "10dcacbd688d6c23364e3e8e1b946196cd0b4387", - [ - "cookie-store/cookieStore_getAll_multiple.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.getAll() with multiple cookies" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_getAll_multiple.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.getAll() with multiple cookies" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_getAll_set_basic.https.any.js": [ - "dee78e1867c7e0be04e779b4bfd949250540c289", - [ - "cookie-store/cookieStore_getAll_set_basic.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.getAll()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_getAll_set_basic.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.getAll()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_getAll_set_creation_url.https.any.js": [ - "d09c4aad4f87712afd70faf8111ee21f88d5f1a8", - [ - "cookie-store/cookieStore_getAll_set_creation_url.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set()/getAll() with Document URL changing" - ], - [ - "global", - "window" - ] - ] - } - ] - ], - "cookieStore_get_arguments.https.any.js": [ - "d6ea0edef6a3d4e0cc69d4455d6672ddd433deda", - [ - "cookie-store/cookieStore_get_arguments.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.get() arguments" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_get_arguments.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.get() arguments" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_get_delete_basic.https.any.js": [ - "9337669afd5b61d821e9945bd2f3299d8afb8bad", - [ - "cookie-store/cookieStore_get_delete_basic.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.delete()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_get_delete_basic.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.delete()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_get_set_across_frames.https.html": [ - "f7c737b422e559107bb210d0cea9267829e10ba7", - [ - null, - {} - ] - ], - "cookieStore_get_set_across_origins.sub.https.html": [ - "004e37630ac76016846b7a33633f583242b23a55", - [ - null, - {} - ] - ], - "cookieStore_get_set_basic.https.any.js": [ - "127f758f5f0b8154dccc74f2b6e81d3b0d2562a9", - [ - "cookie-store/cookieStore_get_set_basic.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.get()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_get_set_basic.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Interaction between cookieStore.set() and cookieStore.get()" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_get_set_creation_url.https.any.js": [ - "71f8108095f0e78518f73f5086eb0d2d4dee1253", - [ - "cookie-store/cookieStore_get_set_creation_url.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set()/get() with Document URL changing" - ], - [ - "global", - "window" - ] - ] - } - ] - ], - "cookieStore_get_set_creation_url.sub.https.html": [ - "216885298a58829d64653d7e1947fe3e6ec52012", - [ - null, - {} - ] - ], - "cookieStore_get_set_ordering.https.any.js": [ - "fe564e55fc4a6d9111a1be35888a750d5ccba9ac", - [ - "cookie-store/cookieStore_get_set_ordering.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Cookie ordering" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_get_set_ordering.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: Cookie ordering" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_in_detached_frame.https.html": [ - "cd2bd79e686cd9b31b9252412e9e9a069cd779be", - [ - null, - {} - ] - ], - "cookieStore_opaque_origin.https.html": [ - "94a13fe63f9acbb369c448c5e339286f1d6ebf4b", - [ - null, - {} - ] - ], - "cookieStore_set_arguments.https.any.js": [ - "37744cb7c88d05edf6b6126aed9f3f09daf112a7", - [ - "cookie-store/cookieStore_set_arguments.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set() arguments" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_set_arguments.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set() arguments" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_set_domain_parsing.sub.https.html": [ - "4326e2a2d0256a528beb382b02bb2c9eee50c55f", - [ - null, - { - "testdriver": true - } - ] - ], - "cookieStore_set_domain_parsing.tentative.sub.https.html": [ - "b7af61e3979c5ac7f8983bbd0adbf87da61a6950", - [ - null, - { - "testdriver": true - } - ] - ], - "cookieStore_set_limit.https.any.js": [ - "0bd9ceec08d55308fba01e46270d6b16e0b35043", - [ - "cookie-store/cookieStore_set_limit.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() return type" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_set_limit.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.delete() return type" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_special_names.https.any.js": [ - "36761b4493995e1bc41d56068b95b745b4cea3c5", - [ - "cookie-store/cookieStore_special_names.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set()/get()/delete() for cookies with special names" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ], - [ - "cookie-store/cookieStore_special_names.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.set()/get()/delete() for cookies with special names" - ], - [ - "global", - "window,serviceworker" - ] - ] - } - ] - ], - "cookieStore_subscribe_arguments.https.any.js": [ - "ca5f55d645be5188177eeb0b03a51a175a7f9e64", - [ - "cookie-store/cookieStore_subscribe_arguments.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.subscribe() arguments" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ], - [ - "cookie-store/cookieStore_subscribe_arguments.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookieStore.subscribe() arguments" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ] - ], - "cookieStore_subscriptions_empty.https.window.js": [ - "907a34b4de6632f5e91adbcd606839a92eead320", - [ - "cookie-store/cookieStore_subscriptions_empty.https.window.html", - { - "script_metadata": [ - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ] - } - ] - ], - "encoding.https.any.js": [ - "f5d2ca15e717a0837f1e08031ab682db5aa965ea", - [ - "cookie-store/encoding.https.any.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookie encoding" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ], - [ - "cookie-store/encoding.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookie encoding" - ], - [ - "global", - "window,serviceworker" - ], - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "httponly_cookies.https.window.js": [ - "836f47da3f6e0f8f2c89445d1b2fbdfdf9ddc9e6", - [ - "cookie-store/httponly_cookies.https.window.html", - { - "script_metadata": [ - [ - "script", - "resources/cookie-test-helpers.js" - ] - ] - } - ] - ], - "idlharness.https.any.js": [ - "6312f3c4ba3a1525df8955a5a7b7ddab4485a90a", - [ - "cookie-store/idlharness.https.any.html", - { - "script_metadata": [ - [ - "global", - "window,worker" - ], - [ - "timeout", - "long" - ], - [ - "script", - "/resources/WebIDLParser.js" - ], - [ - "script", - "/resources/idlharness.js" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ], - "timeout": "long" - } - ], - [ - "cookie-store/idlharness.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "global", - "window,worker" - ], - [ - "timeout", - "long" - ], - [ - "script", - "/resources/WebIDLParser.js" - ], - [ - "script", - "/resources/idlharness.js" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ], - "timeout": "long" - } - ], - [ - "cookie-store/idlharness.https.any.sharedworker.html", - { - "script_metadata": [ - [ - "global", - "window,worker" - ], - [ - "timeout", - "long" - ], - [ - "script", - "/resources/WebIDLParser.js" - ], - [ - "script", - "/resources/idlharness.js" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ], - "timeout": "long" - } - ], - [ - "cookie-store/idlharness.https.any.worker.html", - { - "script_metadata": [ - [ - "global", - "window,worker" - ], - [ - "timeout", - "long" - ], - [ - "script", - "/resources/WebIDLParser.js" - ], - [ - "script", - "/resources/idlharness.js" - ], - [ - "script", - "/service-workers/service-worker/resources/test-helpers.sub.js" - ] - ], - "timeout": "long" - } - ] - ], - "serviceworker_cookieStore_cross_origin.https.sub.html": [ - "6879c5da926384b2be6969b5585c8e2a75539f75", - [ - null, - {} - ] - ], - "serviceworker_cookieStore_subscriptions_reset.https.html": [ - "a1124e9220150ea48e016d805ead1f210a247a25", - [ - null, - {} - ] - ], - "serviceworker_cookiechange_eventhandler_already_expired.https.any.js": [ - "c40fdbeb6f108db1ea6e100c833a03c3fedbfc19", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_already_expired.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with already-expired cookie." - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js": [ - "30d8d70940dae248b3b5cba030056daac78b32a6", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with mismatched subscription" - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js": [ - "ef7cadf4c9e6553192c84610dd1d1692dd7248f6", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with multiple subscriptions" - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_cookiechange_eventhandler_no_change.https.any.js": [ - "fb2e2db7381fea7cbd3463576e126e1581a32d97", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_no_change.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with already-expired cookie." - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js": [ - "f8b1c1b7aa96f13ec40df6dfdfef2c605c447468", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with overlapping subscriptions" - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_cookiechange_eventhandler_single_subscription.https.any.js": [ - "3ccb4b303d90165eed0f7830ac1faed56ee29bba", - [ - "cookie-store/serviceworker_cookiechange_eventhandler_single_subscription.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: cookiechange event in ServiceWorker with single subscription" - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ], - "serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js": [ - "8def2440897b931c2af4402654a92ca89c34ea98", - [ - "cookie-store/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.serviceworker.html", - { - "script_metadata": [ - [ - "title", - "Cookie Store API: oncookiechange event in ServiceWorker with single subscription" - ], - [ - "global", - "serviceworker" - ] - ] - } - ] - ] - }, "cookies": { "attributes": { "attributes-ctl.sub.html": [ @@ -497474,7 +496802,7 @@ ] ], "scheme-bound-cookies.https.html": [ - "e7f1158fe1d3768a967be1b69bd55e5e368dd8a0", + "f738d61e9f51866bbc269e5a52585167a73a032e", [ null, {} @@ -497983,6 +497311,1191 @@ ] } }, + "cookiestore": { + "change_eventhandler_for_already_expired.https.window.js": [ + "f3bbe0ea560974e9486941384e75a58d2d6a4637", + [ + "cookiestore/change_eventhandler_for_already_expired.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Test that setting an already-expired cookie does not trigger an event." + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_document_cookie.https.window.js": [ + "1937ebdae35942840dc3b641b5907f334048f3fb", + [ + "cookiestore/change_eventhandler_for_document_cookie.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Observing 'change' events in document when cookies set via document.cookie" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js": [ + "8517995acfe746bbff09243597d6d319e3af1bc2", + [ + "cookiestore/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Observing 'change' events in document when cookies set via Set-Cookie header" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_no_change.https.window.js": [ + "5f9c2927433fc408c70c005789dc0bcc34d46caa", + [ + "cookiestore/change_eventhandler_for_no_change.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Test that setting a duplicate cookie does not fire a second event." + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_no_name_and_no_value.https.window.js": [ + "4498caf59689cc3da875d1c56937f6d2a235cb5d", + [ + "cookiestore/change_eventhandler_for_no_name_and_no_value.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Observing 'change' events in document when modifications API is called with blank arguments" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_no_name_equals_in_value.https.window.js": [ + "13d721786c9a140b05ed5291c6096c894053f78b", + [ + "cookiestore/change_eventhandler_for_no_name_equals_in_value.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Observing 'change' events in document when setting a cookie value containing \"=\"" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "change_eventhandler_for_no_name_multiple_values.https.window.js": [ + "60c6c16518ae767d2dab68e62af8967b9890072b", + [ + "cookiestore/change_eventhandler_for_no_name_multiple_values.https.window.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Observing 'change' events in document when modifications API is called multiple times with a blank name" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "cookieListItem_attributes.https.any.js": [ + "b42a745d3e4e1a9f4c8a0c6e7d9c04c02f8d1340", + [ + "cookiestore/cookieListItem_attributes.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieListItem attributes" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieListItem_attributes.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieListItem attributes" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStoreManager_getSubscriptions_empty.https.any.js": [ + "8cfd732f304509582ff8c9be97e8e90e6c06e8ed", + [ + "cookiestore/cookieStoreManager_getSubscriptions_empty.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker without cookie change subscriptions" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ], + [ + "cookiestore/cookieStoreManager_getSubscriptions_empty.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker without cookie change subscriptions" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ] + ], + "cookieStoreManager_getSubscriptions_multiple.https.any.js": [ + "e2538013c93220ec79c08bee4d79c07a0b342620", + [ + "cookiestore/cookieStoreManager_getSubscriptions_multiple.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker with multiple cookie change subscriptions" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ], + [ + "cookiestore/cookieStoreManager_getSubscriptions_multiple.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker with multiple cookie change subscriptions" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ] + ], + "cookieStoreManager_getSubscriptions_single.https.any.js": [ + "4f1053266043636e7ed2c004f2942ae3fac9164b", + [ + "cookiestore/cookieStoreManager_getSubscriptions_single.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker with one cookie change subscription" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ], + [ + "cookiestore/cookieStoreManager_getSubscriptions_single.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: ServiceWorker with one cookie change subscription" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ] + ], + "cookieStore_delete.sub.https.html": [ + "150b768a558cc780c615416d9f422996d2d4f57f", + [ + null, + {} + ] + ], + "cookieStore_delete_arguments.https.any.js": [ + "27b54f5a8dcdbe25230b04a101ca0fb0b3c9851d", + [ + "cookiestore/cookieStore_delete_arguments.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() arguments" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_delete_arguments.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() arguments" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_delete_basic.https.any.js": [ + "08a1fac5afe1ed5c2713e60674fadc3d0be7e620", + [ + "cookiestore/cookieStore_delete_basic.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() return type" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_delete_basic.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() return type" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_event_arguments.https.window.js": [ + "bcb698eeb0d6ce760033ba628120ebf7772a1084", + [ + "cookiestore/cookieStore_event_arguments.https.window.html", + {} + ] + ], + "cookieStore_event_basic.https.window.js": [ + "c0075d6adcdd9a3438dfd3df622bf35883bf4110", + [ + "cookiestore/cookieStore_event_basic.https.window.html", + {} + ] + ], + "cookieStore_event_delete.https.window.js": [ + "d0fee1ab1d03cd3835f3b9e5828d4aef7eb45710", + [ + "cookiestore/cookieStore_event_delete.https.window.html", + {} + ] + ], + "cookieStore_event_overwrite.https.window.js": [ + "427e7dcbb7ce0ff1627a2f45a2a407d1c0189dc3", + [ + "cookiestore/cookieStore_event_overwrite.https.window.html", + {} + ] + ], + "cookieStore_getAll_arguments.https.any.js": [ + "868246f606f4ace75f807eef584d263114778f4b", + [ + "cookiestore/cookieStore_getAll_arguments.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.getAll() arguments" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_getAll_arguments.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.getAll() arguments" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_getAll_multiple.https.any.js": [ + "10dcacbd688d6c23364e3e8e1b946196cd0b4387", + [ + "cookiestore/cookieStore_getAll_multiple.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.getAll() with multiple cookies" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_getAll_multiple.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.getAll() with multiple cookies" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_getAll_set_basic.https.any.js": [ + "dee78e1867c7e0be04e779b4bfd949250540c289", + [ + "cookiestore/cookieStore_getAll_set_basic.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.getAll()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_getAll_set_basic.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.getAll()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_getAll_set_creation_url.https.any.js": [ + "d09c4aad4f87712afd70faf8111ee21f88d5f1a8", + [ + "cookiestore/cookieStore_getAll_set_creation_url.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/getAll() with Document URL changing" + ], + [ + "global", + "window" + ] + ] + } + ] + ], + "cookieStore_get_arguments.https.any.js": [ + "d6ea0edef6a3d4e0cc69d4455d6672ddd433deda", + [ + "cookiestore/cookieStore_get_arguments.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.get() arguments" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_get_arguments.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.get() arguments" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_get_delete_basic.https.any.js": [ + "9337669afd5b61d821e9945bd2f3299d8afb8bad", + [ + "cookiestore/cookieStore_get_delete_basic.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.delete()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_get_delete_basic.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.delete()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_get_set_across_frames.https.html": [ + "5537f52c04bfe422a77248c5a8dc2154b95453da", + [ + null, + {} + ] + ], + "cookieStore_get_set_across_origins.sub.https.html": [ + "665e781ef9edab4218288bf34e4482c0c4399627", + [ + null, + {} + ] + ], + "cookieStore_get_set_basic.https.any.js": [ + "127f758f5f0b8154dccc74f2b6e81d3b0d2562a9", + [ + "cookiestore/cookieStore_get_set_basic.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.get()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_get_set_basic.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Interaction between cookieStore.set() and cookieStore.get()" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_get_set_creation_url.https.any.js": [ + "71f8108095f0e78518f73f5086eb0d2d4dee1253", + [ + "cookiestore/cookieStore_get_set_creation_url.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/get() with Document URL changing" + ], + [ + "global", + "window" + ] + ] + } + ] + ], + "cookieStore_get_set_creation_url.sub.https.html": [ + "d5ef7917ef990e0e01b1501ad0b9dae7be386a63", + [ + null, + {} + ] + ], + "cookieStore_get_set_ordering.https.any.js": [ + "fe564e55fc4a6d9111a1be35888a750d5ccba9ac", + [ + "cookiestore/cookieStore_get_set_ordering.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Cookie ordering" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_get_set_ordering.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: Cookie ordering" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_in_detached_frame.https.html": [ + "3acfc99820fe7ed0af4b37835905ef6986e81a77", + [ + null, + {} + ] + ], + "cookieStore_opaque_origin.https.html": [ + "649b486394164280b05333abb36789c3e4f5f418", + [ + null, + {} + ] + ], + "cookieStore_set_arguments.https.any.js": [ + "ce715b7f6c0fec061e4322fc18d32ebcdbddc490", + [ + "cookiestore/cookieStore_set_arguments.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set() arguments" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_set_arguments.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set() arguments" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_set_domain_parsing.sub.https.html": [ + "4326e2a2d0256a528beb382b02bb2c9eee50c55f", + [ + null, + { + "testdriver": true + } + ] + ], + "cookieStore_set_domain_parsing.tentative.sub.https.html": [ + "0f91e74256ff9df8fae48ea5e66f1005a31048bf", + [ + null, + { + "testdriver": true + } + ] + ], + "cookieStore_set_limit.https.any.js": [ + "0bd9ceec08d55308fba01e46270d6b16e0b35043", + [ + "cookiestore/cookieStore_set_limit.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() return type" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_set_limit.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.delete() return type" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_special_names.https.any.js": [ + "36761b4493995e1bc41d56068b95b745b4cea3c5", + [ + "cookiestore/cookieStore_special_names.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/get()/delete() for cookies with special names" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ], + [ + "cookiestore/cookieStore_special_names.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/get()/delete() for cookies with special names" + ], + [ + "global", + "window,serviceworker" + ] + ] + } + ] + ], + "cookieStore_subscribe_arguments.https.any.js": [ + "451ba36a373ebf7ace94353323b80046584578b9", + [ + "cookiestore/cookieStore_subscribe_arguments.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.subscribe() arguments" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ], + [ + "cookiestore/cookieStore_subscribe_arguments.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.subscribe() arguments" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ] + ], + "cookieStore_subscriptions_empty.https.window.js": [ + "907a34b4de6632f5e91adbcd606839a92eead320", + [ + "cookiestore/cookieStore_subscriptions_empty.https.window.html", + { + "script_metadata": [ + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ] + } + ] + ], + "encoding.https.any.js": [ + "f5d2ca15e717a0837f1e08031ab682db5aa965ea", + [ + "cookiestore/encoding.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookie encoding" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ], + [ + "cookiestore/encoding.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookie encoding" + ], + [ + "global", + "window,serviceworker" + ], + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "httponly_cookies.https.window.js": [ + "836f47da3f6e0f8f2c89445d1b2fbdfdf9ddc9e6", + [ + "cookiestore/httponly_cookies.https.window.html", + { + "script_metadata": [ + [ + "script", + "resources/cookie-test-helpers.js" + ] + ] + } + ] + ], + "idlharness.https.any.js": [ + "2ffa714420bfc11161f2c59dc54b568e43afd214", + [ + "cookiestore/idlharness.https.any.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "timeout", + "long" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ], + "timeout": "long" + } + ], + [ + "cookiestore/idlharness.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "timeout", + "long" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ], + "timeout": "long" + } + ], + [ + "cookiestore/idlharness.https.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "timeout", + "long" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ], + "timeout": "long" + } + ], + [ + "cookiestore/idlharness.https.any.worker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "timeout", + "long" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ] + ], + "timeout": "long" + } + ] + ], + "serviceworker_cookieStore_cross_origin.https.sub.html": [ + "beaa867aafa2b70733ff4adcc8a8093158b5caaa", + [ + null, + {} + ] + ], + "serviceworker_cookieStore_subscriptions_reset.https.html": [ + "695430c8fce15f6cc5e81bf45e0261ca1e36cf6b", + [ + null, + {} + ] + ], + "serviceworker_cookiechange_eventhandler_already_expired.https.any.js": [ + "4ccf245e1ca583cbd47361fcfed5994916a6dae2", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_already_expired.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with already-expired cookie." + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js": [ + "1dfd6a2177c1875e1dc6bfc39e0bd00823d44d34", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with mismatched subscription" + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js": [ + "bc7199e7d366640a5d2765642f27cf825c5d082c", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with multiple subscriptions" + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_cookiechange_eventhandler_no_change.https.any.js": [ + "fbbeeda4031c67b3d1a905cca27829e7486aef12", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_no_change.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with already-expired cookie." + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js": [ + "9ed65c73a816b7f0036dbf587f276c687d8498d4", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with overlapping subscriptions" + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_cookiechange_eventhandler_single_subscription.https.any.js": [ + "a9db40dd544904fe99e0a92083918c889746be98", + [ + "cookiestore/serviceworker_cookiechange_eventhandler_single_subscription.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookiechange event in ServiceWorker with single subscription" + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ], + "serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js": [ + "24b91706cb3c22766b5a269e2bff667f9f18320c", + [ + "cookiestore/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: oncookiechange event in ServiceWorker with single subscription" + ], + [ + "global", + "serviceworker" + ] + ] + } + ] + ] + }, "cors": { "304.htm": [ "2aee01417a7cdfb5cb9a69cce2bcc59d7b8eded2", @@ -500903,7 +501416,7 @@ ] ], "anchor-position-multicol-002.html": [ - "6ca4c22d8cd1e4f86a2d06e1a32460b16b7c756b", + "287b5521fce53ac52d67c4bbefa9644eb8496f48", [ null, {} @@ -501558,7 +502071,7 @@ ] ], "position-area-computed.html": [ - "0acc853eb9048cab3d5c2a5e10082ffa489abe59", + "8e1800644867ef06146a4d001a0bed5fe13a7324", [ null, {} @@ -501586,7 +502099,7 @@ ] ], "position-area-parsing.html": [ - "e6de6d7e2696266c02c41919a10c136ce621e90d", + "c8d7687cc88d4904b5626a17eddeb1bf06051c50", [ null, {} @@ -501922,7 +502435,7 @@ ] ], "try-tactic-position-area.html": [ - "e050dbccef2b5679229c8df8ba02535e989ed23e", + "ab5d95f2fe9c3ccf1533ab4c4e912540a5edde3c", [ null, {} @@ -508570,7 +509083,7 @@ ] ], "flex-abspos-staticpos-align-self-006.html": [ - "3c03636b35ea5e3bcec9a3fa0075205647e6bb91", + "c36a6d1574773ad37cae8efe14c91e8764042425", [ null, {} @@ -524462,6 +524975,13 @@ {} ] ], + "resnap-on-overflowing-snap-area.html": [ + "e0af5f315874f0558f0138bddfe57c2116d29ff4", + [ + null, + {} + ] + ], "resnap-on-reconstructing-frame.html": [ "d046608815aff119e443a17594a4947bea2ce587", [ @@ -538303,6 +538823,15 @@ ] ] }, + "nested": { + "group-children-animations.html": [ + "d4c3aa77818d676246a2796372687a3313c13c62", + [ + null, + {} + ] + ] + }, "no-crash-set-exception.html": [ "b57fce0d73f27878efe733877201f05df9239bf0", [ @@ -541216,6 +541745,13 @@ {} ] ], + "offsetParent-fixed.html": [ + "a2c4255a77729066fedc1ba21101cb123a396380", + [ + null, + {} + ] + ], "offsetParent_element_test.html": [ "dc2f8e91f1dcbd4ef6f21c1b920765cbc0bad1f5", [ @@ -542495,6 +543031,13 @@ {} ] ], + "at-custom-media-cssom.html": [ + "1b018592c3fe7f11129550aa20e9f8322e9d3ee9", + [ + null, + {} + ] + ], "display-mode.html": [ "4ade16799f9db32f502df643f33094e5a2552e70", [ @@ -546399,7 +546942,7 @@ ] ], "create.tentative.https.html": [ - "3e17d5b0853b38b36cb640ee665a12c398eb4ed3", + "67630d1426b6b370609ec6ae970c6db33cb18e34", [ null, { @@ -546449,7 +546992,7 @@ ] ], "get.tentative.https.html": [ - "7c1e6631da7cebe849958bb92201348c150c8c0d", + "1549bba673b2f4ea86d48ef670155212823bff42", [ null, { @@ -572999,11 +573542,12 @@ ] ], "fedcm-disconnect.sub.https.html": [ - "04fcd272dcf261a19cf71abb049e41c8b41abbbf", + "a80ed48534ae33d027595f7b2a392693c781cea2", [ null, { - "testdriver": true + "testdriver": true, + "timeout": "long" } ] ], @@ -584783,7 +585327,7 @@ }, "quota": { "accumulated-oversized-payload.tentative.https.window.js": [ - "6439b392e2a0230a3ff819e4e80b42341dc0c389", + "143546ff72340ebbae34e6b598a6348d044f8482", [ "fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.html", { @@ -584981,7 +585525,7 @@ ] ], "max-payload.tentative.https.window.js": [ - "8457060797ac2d140c85af6c657f79389288c356", + "aa797f135571ed417d21b5fbcd4a235bac6358aa", [ "fetch/fetch-later/quota/max-payload.tentative.https.window.html", { @@ -585033,7 +585577,7 @@ ] ], "oversized-payload.tentative.https.window.js": [ - "0036d040d8e201d8d621c6615e4e7c49daf45fff", + "740f17ea24ade1073c4e0507fb9134ae8715f57b", [ "fetch/fetch-later/quota/oversized-payload.tentative.https.window.html", { @@ -615576,6 +616120,31 @@ {} ] ], + "origin.tentative.any.js": [ + "fbdb067873200891b00807b9dbf6f279ad940fc9", + [ + "html/browsers/origin/origin.tentative.any.html", + { + "script_metadata": [ + [ + "title", + "Origin" + ] + ] + } + ], + [ + "html/browsers/origin/origin.tentative.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Origin" + ] + ] + } + ] + ], "relaxing-the-same-origin-restriction": { "document_domain.html": [ "d3af35c6d7ac50de4fd8942066875d52229634f2", @@ -621773,6 +622342,20 @@ {} ] ], + "2d.path.clip.winding.evenodd.1.html": [ + "a1922011e4ac937605a42e0b14a0de63b05ded73", + [ + null, + {} + ] + ], + "2d.path.clip.winding.evenodd.2.html": [ + "e5aeba44b008e76000af1db74a756becf27ecadc", + [ + null, + {} + ] + ], "2d.path.closePath.empty.html": [ "837f5a76dc9701748f4d485c102cc93f6d410ce9", [ @@ -621836,6 +622419,20 @@ {} ] ], + "2d.path.fill.winding.evenodd.1.html": [ + "d030b93239c310a76a1423fe13c1adcf9fe399ce", + [ + null, + {} + ] + ], + "2d.path.fill.winding.evenodd.2.html": [ + "4553f29d1e4b245fe231eeeb75973b5eba69c15d", + [ + null, + {} + ] + ], "2d.path.fill.winding.subtract.1.html": [ "fa1232e8d0ff59c5d283dc01641b1075372f0a77", [ @@ -633367,6 +633964,34 @@ {} ] ], + "2d.path.clip.winding.evenodd.1.html": [ + "4cf680f62f2b6328d838929f64ebe50729b5b270", + [ + null, + {} + ] + ], + "2d.path.clip.winding.evenodd.1.worker.js": [ + "da772ea73d00beb9ae3332e4bf9d19fda68fdd70", + [ + "html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.worker.html", + {} + ] + ], + "2d.path.clip.winding.evenodd.2.html": [ + "6d47707e5ec00a8a9302c3a2caea1e9e8f25350b", + [ + null, + {} + ] + ], + "2d.path.clip.winding.evenodd.2.worker.js": [ + "23f626e7d7293c7559baa66793264685876e7c0d", + [ + "html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.worker.html", + {} + ] + ], "2d.path.closePath.empty.html": [ "a14a036b253d90462d5f4d1881a0d947b869c5dd", [ @@ -633493,6 +634118,34 @@ {} ] ], + "2d.path.fill.winding.evenodd.1.html": [ + "fc839c9f58b19a4be7a0e43fe661799902ee257e", + [ + null, + {} + ] + ], + "2d.path.fill.winding.evenodd.1.worker.js": [ + "64e1aa1099370dc955bf79e0f05642a53609b2c9", + [ + "html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.worker.html", + {} + ] + ], + "2d.path.fill.winding.evenodd.2.html": [ + "acb70538fd946bd7a6bbb561eae0e93724161b8b", + [ + null, + {} + ] + ], + "2d.path.fill.winding.evenodd.2.worker.js": [ + "1a69f4639d0c8b9a67d3e6b16fd764ea7e5f6683", + [ + "html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.worker.html", + {} + ] + ], "2d.path.fill.winding.subtract.1.html": [ "814f3c3a9e76b711e1fc2f3dac373afc0ab07f0a", [ @@ -667283,6 +667936,13 @@ {} ] ], + "script-src-event-handler.sub.html": [ + "346660511ee77f105a54a1126266d0db4787008a", + [ + null, + {} + ] + ], "script-src-integrity.tentative.sub.html": [ "6f66636d7673387854f5c2053bad92bd0207aae8", [ @@ -667297,7 +667957,7 @@ {} ] ], - "script-src-nomodule.tentative.sub.html": [ + "script-src-nomodule.sub.html": [ "3f61dba8d41926994c8ad8e7937ba855dbe1eddd", [ null, @@ -667318,8 +667978,15 @@ {} ] ], - "script-src-unsupported-type.tentative.sub.html": [ - "1eaa56494dbe866a75b5f36b4d1046e3a4ac2447", + "script-src-unsupported-language.sub.html": [ + "e418c0e1edd8fea62752fe38c4db608153d2ad29", + [ + null, + {} + ] + ], + "script-src-unsupported-type.sub.html": [ + "665e7abb02d30c3b911e49228b7c214051c341fb", [ null, {} @@ -667705,6 +668372,13 @@ {} ] ], + "script-src-event-handler.html": [ + "6bb89bd463c7b3565352242f96d6b98c4b7bac47", + [ + null, + {} + ] + ], "script-src-integrity.tentative.html": [ "42719e994a4774d8e2c1ed28b70714ecef6df1b4", [ @@ -667719,7 +668393,7 @@ {} ] ], - "script-src-nomodule.tentative.html": [ + "script-src-nomodule.html": [ "20ca80222eb0c6b100c57b6dacfbba0bd62f8c97", [ null, @@ -667740,7 +668414,14 @@ {} ] ], - "script-src-unsupported-type.tentative.html": [ + "script-src-unsupported-language.html": [ + "60f50eb34d6e6beaf2496f0ed090d18f79ea1931", + [ + null, + {} + ] + ], + "script-src-unsupported-type.html": [ "c7c5b483a4eba8b08e0e8ee634cd04409ddf2c10", [ null, @@ -679181,7 +679862,7 @@ ] ], "mediasource-appendbuffer-quota-exceeded.html": [ - "c90d8448c508feed3ba676a3e7afdae5121264f8", + "470ee7211f8919d298d5e0c1a1dd9165a0b02a3b", [ null, { @@ -681312,7 +681993,7 @@ ] ], "MediaStreamTrack-getCapabilities.https.html": [ - "7d600c0e1b97c905cbeb172d0aae0a33ed961c9e", + "cc7d5cdff171ef50bf307d67945b963686a46fb8", [ null, { @@ -711673,6 +712354,16 @@ } ] ], + "getdisplaymedia-restrictOwnAudio.https.html": [ + "b4915dea9694505fe90b5f934ad39102be223944", + [ + null, + { + "testdriver": true, + "timeout": "long" + } + ] + ], "getdisplaymedia-settings.https.html": [ "afd8339d9919d8cabd4aaca03b4a43b792b7481d", [ @@ -711684,7 +712375,7 @@ ] ], "getdisplaymedia.https.html": [ - "4a7c655335161afdeaf398a4e6225598de325ce9", + "0051e4c5a0453a0f0b986235b9bb519668020673", [ null, { @@ -719503,7 +720194,7 @@ ] }, "offsetParent-across-shadow-boundaries.html": [ - "5491e2121336d1b59ef69198fd048a22acc80d46", + "44bbc0771d47e05a46fc2910acdd5ec6e525d2d5", [ null, {} @@ -722018,6 +722709,15 @@ } ] ], + "late-url-change.html": [ + "fbd0465bedfde6138144eede1365448f366d8bad", + [ + null, + { + "testdriver": true + } + ] + ], "lcp-unbuffered.html": [ "1df6bd11d0fb67ac9463ae3a0cdc3fb1cbf9e4f8", [ @@ -723361,7 +724061,7 @@ ] ], "cookies.https.html": [ - "2f02197fb5b191b782f45fc1f4d9f47ff6853286", + "3965284f8b9de8ec596edc9b997f07135f2319b8", [ null, { @@ -725266,7 +725966,7 @@ "storage": { "buckets": { "bucket-quota-indexeddb.tentative.https.any.js": [ - "ee9202777e7ec55faee0b89f4c656f7a76c05e83", + "9dc345579d3b26586bb1826fa20feaca367aaf0c", [ "storage/buckets/bucket-quota-indexeddb.tentative.https.any.html", { @@ -763881,7 +764581,7 @@ ] ], "biquad-basic.html": [ - "441e98a251187c3cc600299681306d29df11e618", + "4f86474935af68838e4826f1eb0d4e3a5d92c740", [ null, {} @@ -789446,7 +790146,7 @@ ] ], "tensor.https.any.js": [ - "ea2cedb3f6dad0f2424be21cf942539de24ae410", + "4b6a4ab8e7ff2c78b420b97047c31dc7695cfe4a", [ "webnn/conformance_tests/tensor.https.any.html?cpu", { @@ -791738,7 +792438,7 @@ ] ], "constant.https.any.js": [ - "f9e34ea94ec1a31cdf999c810e9f3f616f971654", + "420fd9d23d89f0cb19ae5ca6472f3d26adaa0221", [ "webnn/validation_tests/constant.https.any.html?cpu", { @@ -821778,7 +822478,7 @@ ] ], "storage_local_setitem_quotaexceedederr.window.js": [ - "fff7d6444a039e4fbc9795c5fbab823c80b170de", + "f2f3c4d6887542cc90dd0ca312080c8d23857e60", [ "webstorage/storage_local_setitem_quotaexceedederr.window.html", {} @@ -821799,7 +822499,7 @@ ] ], "storage_session_setitem_quotaexceedederr.window.js": [ - "42a895470efa628b47c83b4df963d635beb45646", + "693c98d29f99fd9e65f202244206fe0f224618e9", [ "webstorage/storage_session_setitem_quotaexceedederr.window.html", {} @@ -847330,6 +848030,15 @@ } }, "network": { + "add_data_collector": { + "invalid.py": [ + "aa6a19e3241668b093c8ce99866ebeb4a74012ba", + [ + null, + {} + ] + ] + }, "add_intercept": { "add_intercept.py": [ "c073e1cc3260f08d3b781102dfcdcd54804f60ce",
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any-expected.txt index a86fd15..b381aa4 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any-expected.txt
@@ -1,21 +1,21 @@ This is a testharness.js-based test. [FAIL] Large length: Int8Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Int16Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Int32Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: BigInt64Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint8Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint8ClampedArray - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint16Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint32Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: BigUint64Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.js index 574134e..aecd38e 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.js
@@ -60,9 +60,9 @@ test(function() { const maxlength = 65536 / ctor.BYTES_PER_ELEMENT; - assert_throws_dom("QuotaExceededError", function() { - self.crypto.getRandomValues(new ctor(maxlength + 1)) - }, "crypto.getRandomValues length over 65536") + assert_throws_quotaexceedederror(() => { + self.crypto.getRandomValues(new ctor(maxlength + 1)); + }, null, null, "crypto.getRandomValues length over 65536"); }, "Large length: " + array); test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.worker-expected.txt index a86fd15..b381aa4 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getRandomValues.any.worker-expected.txt
@@ -1,21 +1,21 @@ This is a testharness.js-based test. [FAIL] Large length: Int8Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Int16Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Int32Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: BigInt64Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint8Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint8ClampedArray - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65537) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint16Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65538) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: Uint32Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65540) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] Large length: BigUint64Array - assert_throws_dom: crypto.getRandomValues length over 65536 function "function() {\n self.crypto.getRandomValues(new ctor(maxlength + 1))\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: crypto.getRandomValues length over 65536 function "() => {\n self.crypto.getRandomValues(new ctor(maxlength + 1));\n }" threw object "QuotaExceededError: Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (65544) exceeds the number of bytes of entropy available via this API (65536)." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/ai/language_detection/detector.https.window.js b/third_party/blink/web_tests/external/wpt/ai/language_detection/detector.https.window.js index f520646..0ccbe89 100644 --- a/third_party/blink/web_tests/external/wpt/ai/language_detection/detector.https.window.js +++ b/third_party/blink/web_tests/external/wpt/ai/language_detection/detector.https.window.js
@@ -133,7 +133,7 @@ const detectPromise = detector.detect(text); if (inputUsage >= detector.inputQuota) { - await promise_rejects_dom(t, 'QuotaExceededError', detectPromise); + await promise_rejects_quotaexceedederror(t, detectPromise, requested => requested !== null, detector.inputQuota); } else { await detectPromise; }
diff --git a/third_party/blink/web_tests/external/wpt/ai/translator/translator.optional.https.window.js b/third_party/blink/web_tests/external/wpt/ai/translator/translator.optional.https.window.js index 1b2519cf2..ceb7846 100644 --- a/third_party/blink/web_tests/external/wpt/ai/translator/translator.optional.https.window.js +++ b/third_party/blink/web_tests/external/wpt/ai/translator/translator.optional.https.window.js
@@ -189,8 +189,7 @@ if (inputUsage < translator.inputQuota) { assert_equals(await translator.translate(text), 'こんにちは'); } else { - await promise_rejects_dom( - t, 'QuotaExceededError', translator.translate(text)); + await promise_rejects_quotaexceedederror(t, translator.translate(text), requested => requested !== null, translator.inputQuota); } }, 'Translator.measureInputUsage() and inputQuota basic usage.');
diff --git a/third_party/blink/web_tests/external/wpt/background-fetch/fetch.https.window.js b/third_party/blink/web_tests/external/wpt/background-fetch/fetch.https.window.js index 1756a0e6e..6a2f6ee 100644 --- a/third_party/blink/web_tests/external/wpt/background-fetch/fetch.https.window.js +++ b/third_party/blink/web_tests/external/wpt/background-fetch/fetch.https.window.js
@@ -170,10 +170,10 @@ // Very large download total that will definitely exceed the quota. const options = {downloadTotal: Number.MAX_SAFE_INTEGER}; - await promise_rejects_dom( - test, 'QUOTA_EXCEEDED_ERR', - backgroundFetch.fetch(registrationId, 'resources/feature-name.txt', options), - 'This fetch should have thrown a quota exceeded error'); + await promise_rejects_quotaexceedederror( + test, backgroundFetch.fetch(registrationId, 'resources/feature-name.txt', options), + null, null + ); }, 'Background Fetch that exceeds the quota throws a QuotaExceededError');
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp-ref.html b/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp-ref.html new file mode 100644 index 0000000..e0747fd6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp-ref.html
@@ -0,0 +1,3 @@ +<!doctype html> +<meta charset="utf-8"> +<iframe src="../support/pass.png">
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp.html new file mode 100644 index 0000000..a3f6f64 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/generic/image-document-ignores-csp.html
@@ -0,0 +1,7 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSP header ignored for image document</title> +<link rel="help" href="https://github.com/servo/servo/issues/38180"> +<link rel='match' href='image-document-ignores-csp-ref.html'> +<link rel="author" title="Josh Matthews" href="mailto:josh@joshmatthews.net"> +<iframe src="../support/pass3.png">
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png b/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png new file mode 100644 index 0000000..2fa1e0a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png.headers new file mode 100644 index 0000000..6581fd42 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/support/pass3.png.headers
@@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none'
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/META.yml b/third_party/blink/web_tests/external/wpt/cookie-store/META.yml deleted file mode 100644 index 4bbc631..0000000 --- a/third_party/blink/web_tests/external/wpt/cookie-store/META.yml +++ /dev/null
@@ -1,3 +0,0 @@ -spec: https://wicg.github.io/cookie-store/ -suggested_reviewers: - - dcthetall
diff --git a/third_party/blink/web_tests/external/wpt/cookiestore/META.yml b/third_party/blink/web_tests/external/wpt/cookiestore/META.yml new file mode 100644 index 0000000..a1d0ed4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookiestore/META.yml
@@ -0,0 +1,3 @@ +spec: https://cookiestore.spec.whatwg.org/ +suggested_reviewers: + - dcthetall
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/README.md b/third_party/blink/web_tests/external/wpt/cookiestore/README.md similarity index 95% rename from third_party/blink/web_tests/external/wpt/cookie-store/README.md rename to third_party/blink/web_tests/external/wpt/cookiestore/README.md index b8a1d0a..d767a7b 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/README.md +++ b/third_party/blink/web_tests/external/wpt/cookiestore/README.md
@@ -1,5 +1,5 @@ This directory contains tests for the -[Cookie Store API](https://github.com/WICG/cookie-store). +[Cookie Store API](https://cookiestore.spec.whatwg.org/). ## Note on cookie naming conventions
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_already_expired.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_already_expired.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_already_expired.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_already_expired.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_document_cookie.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_document_cookie.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_document_cookie.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_document_cookie.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_http_cookie_and_set_cookie_headers.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_change.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_change.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_change.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_change.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_and_no_value.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_and_no_value.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_and_no_value.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_and_no_value.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_equals_in_value.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_equals_in_value.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_equals_in_value.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_equals_in_value.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_multiple_values.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_multiple_values.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/change_eventhandler_for_no_name_multiple_values.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/change_eventhandler_for_no_name_multiple_values.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any-expected.txt similarity index 71% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any-expected.txt index 4113e2b1..eade0ea 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] CookieListItem - cookieStore.set does not add / to path if it does not end with / - assert_equals: expected "/cookie-store" but got "/cookie-store/" + assert_equals: expected "/cookiestore" but got "/cookiestore/" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any.serviceworker-expected.txt similarity index 71% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.serviceworker-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any.serviceworker-expected.txt index 4113e2b1..eade0ea 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieListItem_attributes.https.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] CookieListItem - cookieStore.set does not add / to path if it does not end with / - assert_equals: expected "/cookie-store" but got "/cookie-store/" + assert_equals: expected "/cookiestore" but got "/cookiestore/" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_empty.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_empty.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_empty.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_empty.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_multiple.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_multiple.https.any.js similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_multiple.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_multiple.https.any.js index 9e153d0..e253801 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_multiple.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_multiple.https.any.js
@@ -17,7 +17,7 @@ let scope; if (self.GLOBAL.isWindow()) { - scope = '/cookie-store/resources/does/not/exist'; + scope = '/cookiestore/resources/does/not/exist'; const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', scope); @@ -29,7 +29,7 @@ self.registration = registration; } else { - scope = '/cookie-store/does/not/exist'; + scope = '/cookiestore/does/not/exist'; // Must wait for the service worker to enter the 'activated' state before // subscribing to cookiechange events.
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_single.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_single.https.any.js similarity index 94% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_single.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_single.https.any.js index 98ec19d..4f10532 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStoreManager_getSubscriptions_single.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStoreManager_getSubscriptions_single.https.any.js
@@ -8,7 +8,7 @@ let scope; if (self.GLOBAL.isWindow()) { - scope = '/cookie-store/resources/does/not/exist'; + scope = '/cookiestore/resources/does/not/exist'; const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', scope); @@ -20,7 +20,7 @@ self.registration = registration; } else { - scope = '/cookie-store/does/not/exist'; + scope = '/cookiestore/does/not/exist'; // Must wait for the service worker to enter the 'activated' state before // subscribing to cookiechange events.
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete.sub.https.html similarity index 92% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete.sub.https.html index 8cdfae67..150b768 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete.sub.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset='utf-8'> <title>Async Cookies: cookieStore basic API across origins</title> -<link rel='help' href='https://github.com/WICG/cookie-store'> +<link rel='help' href='https://cookiestore.spec.whatwg.org/'> <link rel='author' href='jarrydg@chromium.org' title='Jarryd Goodman'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> @@ -11,7 +11,7 @@ <script> 'use strict'; -const kPath = '/cookie-store/resources/helper_iframe.sub.html'; +const kPath = '/cookiestore/resources/helper_iframe.sub.html'; const kCorsBase = `https://{{domains[www1]}}:{{ports[https][0]}}`; const kCorsUrl = `${kCorsBase}${kPath}`;
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any.serviceworker-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.serviceworker-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_arguments.https.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_basic.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_basic.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_basic.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_delete_basic.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_arguments.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_arguments.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_arguments.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_arguments.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_basic.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_basic.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_basic.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_basic.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_delete.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_delete.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_delete.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_delete.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_overwrite.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_overwrite.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_event_overwrite.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_event_overwrite.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_arguments.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_arguments.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_arguments.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_arguments.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_arguments.https.any.serviceworker-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_arguments.https.any.serviceworker-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_arguments.https.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_multiple.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_multiple.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_multiple.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_multiple.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_basic.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_set_basic.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_basic.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_set_basic.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_creation_url.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_set_creation_url.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_creation_url.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_getAll_set_creation_url.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_arguments.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_arguments.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_arguments.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_arguments.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_arguments.https.any.serviceworker-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_arguments.https.any.serviceworker-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_arguments.https.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_delete_basic.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_delete_basic.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_delete_basic.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_delete_basic.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_frames.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_frames.https.html similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_frames.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_frames.https.html index f7c737b42..5537f52 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_frames.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_frames.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset='utf-8'> <title>Async Cookies: cookieStore basic API across frames</title> -<link rel='help' href='https://github.com/WICG/cookie-store'> +<link rel='help' href='https://cookiestore.spec.whatwg.org/'> <link rel='author' href='jarrydg@chromium.org' title='Jarryd Goodman'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_origins.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_origins.sub.https.html similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_origins.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_origins.sub.https.html index 004e376..665e781e 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_across_origins.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_across_origins.sub.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset='utf-8'> <title>Async Cookies: cookieStore basic API across origins</title> -<link rel='help' href='https://github.com/WICG/cookie-store'> +<link rel='help' href='https://cookiestore.spec.whatwg.org/'> <link rel='author' href='jarrydg@chromium.org' title='Jarryd Goodman'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> @@ -11,7 +11,7 @@ <script> 'use strict'; -const kPath = '/cookie-store/resources/helper_iframe.sub.html'; +const kPath = '/cookiestore/resources/helper_iframe.sub.html'; const kCorsBase = `https://{{domains[www1]}}:{{ports[https][0]}}`; const kCorsUrl = `${kCorsBase}${kPath}`;
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_basic.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_basic.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_basic.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_basic.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_creation_url.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_creation_url.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_creation_url.sub.https.html similarity index 94% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_creation_url.sub.https.html index 2168852..d5ef791 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_creation_url.sub.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset='utf-8'> <title>Async Cookies: cookieStore basic API on creation URL with fragments</title> -<link rel='help' href='https://github.com/WICG/cookie-store'> +<link rel='help' href='https://cookiestore.spec.whatwg.org/'> <link rel='author' href='baku@mozilla.com' title='Andrea Marchesini'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> @@ -11,7 +11,7 @@ <script> 'use strict'; -const kUrl = '/cookie-store/resources/helper_iframe.sub.html'; +const kUrl = '/cookiestore/resources/helper_iframe.sub.html'; promise_test(async t => { const url = new URL(kUrl, location);
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_ordering.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_ordering.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_ordering.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_get_set_ordering.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_in_detached_frame.https-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_in_detached_frame.https-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_in_detached_frame.https-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_in_detached_frame.https-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_in_detached_frame.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_in_detached_frame.https.html similarity index 90% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_in_detached_frame.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_in_detached_frame.https.html index cd2bd79..3acfc99 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_in_detached_frame.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_in_detached_frame.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset="utf-8"> <title>cookieStore on DOMWindow of detached iframe</title> -<link rel="help" href="https://github.com/WICG/cookie-store"> +<link rel="help" href="https://cookiestore.spec.whatwg.org/"> <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_opaque_origin.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_opaque_origin.https.html similarity index 97% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_opaque_origin.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_opaque_origin.https.html index 94a13fe..649b486 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_opaque_origin.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_opaque_origin.https.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <meta charset=utf-8> <title>Cookie Store API: Opaque origins for cookieStore</title> -<link rel=help href="https://wicg.github.io/cookie-store/"> +<link rel=help href="https://cookiestore.spec.whatwg.org/"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script>
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any.js similarity index 98% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any.js index 37744cb..ce715b7 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any.js
@@ -337,7 +337,7 @@ }, 'cookieStore.set with get result'); promise_test(async testCase => { - // The maximum attribute value size is specified as 1024 bytes at https://wicg.github.io/cookie-store/#cookie-maximum-attribute-value-size. + // The maximum attribute value size is specified as 1024 bytes at https://cookiestore.spec.whatwg.org/#cookie-maximum-attribute-value-size. await cookieStore.delete('cookie-name'); await promise_rejects_js(testCase, TypeError, cookieStore.set( @@ -349,7 +349,7 @@ }, 'cookieStore.set checks if the path is too long'); promise_test(async testCase => { - // The maximum attribute value size is specified as 1024 bytes at https://wicg.github.io/cookie-store/#cookie-maximum-attribute-value-size. + // The maximum attribute value size is specified as 1024 bytes at https://cookiestore.spec.whatwg.org/#cookie-maximum-attribute-value-size. await cookieStore.delete('cookie-name'); await promise_rejects_js(testCase, TypeError, cookieStore.set(
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any.serviceworker-expected.txt similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.serviceworker-expected.txt rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_arguments.https.any.serviceworker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_domain_parsing.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_domain_parsing.sub.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_domain_parsing.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_domain_parsing.sub.https.html
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_domain_parsing.tentative.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_domain_parsing.tentative.sub.https.html similarity index 87% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_domain_parsing.tentative.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_domain_parsing.tentative.sub.https.html index b7af61e3..0f91e74 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_domain_parsing.tentative.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_domain_parsing.tentative.sub.https.html
@@ -14,7 +14,7 @@ // into this tentative file, but it probably should be removed from WPT // entirely and instead included in Chromium's internal test suite. promise_test(async () => { - const childUrl = new URL("https://127.0.0.1:8444/cookie-store/resources/domain_parsing-child.sub.https.html?test=IP"); + const childUrl = new URL("https://127.0.0.1:8444/cookiestore/resources/domain_parsing-child.sub.https.html?test=IP"); const childWindow = window.open(childUrl.href); await fetch_tests_from_window(childWindow); }, "cookieStore.set with domain on IP host");
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_limit.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_limit.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_limit.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_set_limit.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_special_names.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_special_names.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_special_names.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_special_names.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_subscribe_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_subscribe_arguments.https.any.js similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_subscribe_arguments.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_subscribe_arguments.https.any.js index ca5f55d..451ba36 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_subscribe_arguments.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_subscribe_arguments.https.any.js
@@ -8,7 +8,7 @@ if (self.GLOBAL.isWindow()) { const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', - '/cookie-store/resources/does/not/exist'); + '/cookiestore/resources/does/not/exist'); testCase.add_cleanup(() => registration.unregister()); // Must wait for the service worker to enter the 'activated' state before @@ -41,7 +41,7 @@ if (self.GLOBAL.isWindow()) { const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', - '/cookie-store/resources/does/not/exist'); + '/cookiestore/resources/does/not/exist'); testCase.add_cleanup(() => registration.unregister()); // Must wait for the service worker to enter the 'activated' state before @@ -66,7 +66,7 @@ if (self.GLOBAL.isWindow()) { const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', - '/cookie-store/resources/does/not/exist'); + '/cookiestore/resources/does/not/exist'); testCase.add_cleanup(() => registration.unregister()); // Must wait for the service worker to enter the 'activated' state before @@ -103,7 +103,7 @@ if (self.GLOBAL.isWindow()) { const registration = await service_worker_unregister_and_register( testCase, 'resources/empty_sw.js', - '/cookie-store/resources/does/not/exist'); + '/cookiestore/resources/does/not/exist'); testCase.add_cleanup(() => registration.unregister()); // Must wait for the service worker to enter the 'activated' state before
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_subscriptions_empty.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_subscriptions_empty.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_subscriptions_empty.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/cookieStore_subscriptions_empty.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/encoding.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/encoding.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/encoding.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/encoding.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/httponly_cookies.https.window.js b/third_party/blink/web_tests/external/wpt/cookiestore/httponly_cookies.https.window.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/httponly_cookies.https.window.js rename to third_party/blink/web_tests/external/wpt/cookiestore/httponly_cookies.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/idlharness.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/idlharness.https.any.js similarity index 95% rename from third_party/blink/web_tests/external/wpt/cookie-store/idlharness.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/idlharness.https.any.js index 6312f3c..2ffa7144 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/idlharness.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/idlharness.https.any.js
@@ -5,10 +5,10 @@ // META: script=/service-workers/service-worker/resources/test-helpers.sub.js 'use strict'; -// https://wicg.github.io/cookie-store/ +// https://cookiestore.spec.whatwg.org/ idl_test( - ['cookie-store'], + ['cookiestore'], ['service-workers', 'html', 'dom'], async (idl_array, t) => { const isServiceWorker = 'ServiceWorkerGlobalScope' in self
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/always_changing_sw.sub.js b/third_party/blink/web_tests/external/wpt/cookiestore/resources/always_changing_sw.sub.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/always_changing_sw.sub.js rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/always_changing_sw.sub.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/cookie-test-helpers.js b/third_party/blink/web_tests/external/wpt/cookiestore/resources/cookie-test-helpers.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/cookie-test-helpers.js rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/cookie-test-helpers.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/cookie_helper.py b/third_party/blink/web_tests/external/wpt/cookiestore/resources/cookie_helper.py similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/cookie_helper.py rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/cookie_helper.py
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/domain_parsing-child.sub.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/resources/domain_parsing-child.sub.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/domain_parsing-child.sub.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/domain_parsing-child.sub.https.html
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/empty_sw.js b/third_party/blink/web_tests/external/wpt/cookiestore/resources/empty_sw.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/empty_sw.js rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/empty_sw.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/helper_iframe.sub.html b/third_party/blink/web_tests/external/wpt/cookiestore/resources/helper_iframe.sub.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/helper_iframe.sub.html rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/helper_iframe.sub.html
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/resources/helpers.js b/third_party/blink/web_tests/external/wpt/cookiestore/resources/helpers.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/resources/helpers.js rename to third_party/blink/web_tests/external/wpt/cookiestore/resources/helpers.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.https.sub.html b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_cross_origin.https.sub.html similarity index 91% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.https.sub.html rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_cross_origin.https.sub.html index 6879c5da..beaa867a 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_cross_origin.https.sub.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset='utf-8'> <title>Async Cookies: cookieStore API in ServiceWorker across origins</title> -<link rel='help' href='https://github.com/WICG/cookie-store'> +<link rel='help' href='https://cookiestore.spec.whatwg.org/'> <link rel='author' href='jarrydg@chromium.org' title='Jarryd Goodman'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> @@ -10,7 +10,7 @@ <script> 'use strict'; -const kPath = '/cookie-store/resources/helper_iframe.sub.html'; +const kPath = '/cookiestore/resources/helper_iframe.sub.html'; const kCorsBase = `https://{{domains[www1]}}:{{ports[https][0]}}`; const kCorsUrl = `${kCorsBase}${kPath}`;
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_cross_origin.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_cross_origin.js
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_reset.https.html b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_subscriptions_reset.https.html similarity index 97% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_reset.https.html rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_subscriptions_reset.https.html index a1124e92..695430c 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_reset.https.html +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookieStore_subscriptions_reset.https.html
@@ -1,7 +1,7 @@ <!doctype html> <meta charset="utf-8"> <title>Cookie Store API: reset cookie change subscription list</title> -<link rel="help" href="https://github.com/WICG/cookie-store"> +<link rel="help" href="https://cookiestore.spec.whatwg.org/"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/service-workers/service-worker/resources/test-helpers.sub.js">
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_already_expired.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_already_expired.https.any.js similarity index 97% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_already_expired.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_already_expired.https.any.js index c40fdbeb..4ccf245 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_already_expired.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_already_expired.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; function WorkerActivationPromise() { return new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js index 30d8d70..1dfd6a2 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_mismatched_subscription.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. const kServiceWorkerActivatedPromise = new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js similarity index 97% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js index ef7cadf..bc7199e 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_multiple_subscriptions.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. const kServiceWorkerActivatedPromise = new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_no_change.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_no_change.https.any.js similarity index 98% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_no_change.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_no_change.https.any.js index fb2e2db7..fbbeeda 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_no_change.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_no_change.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. function WorkerActivationPromise() {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js similarity index 98% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js index f8b1c1b7..9ed65c7 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_overlapping_subscriptions.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. const kServiceWorkerActivatedPromise = new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js index 3ccb4b3..a9db40d 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_cookiechange_eventhandler_single_subscription.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. const kServiceWorkerActivatedPromise = new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js similarity index 96% rename from third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js rename to third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js index 8def244..24b9170 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookiestore/serviceworker_oncookiechange_eventhandler_single_subscription.https.any.js
@@ -3,7 +3,7 @@ 'use strict'; -const kScope = '/cookie-store/does/not/exist'; +const kScope = '/cookiestore/does/not/exist'; // Resolves when the service worker receives the 'activate' event. const kServiceWorkerActivatedPromise = new Promise((resolve) => {
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/tables/border-spacing-095.html b/third_party/blink/web_tests/external/wpt/css/CSS2/tables/border-spacing-095.html new file mode 100644 index 0000000..8e5c8f5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/CSS2/tables/border-spacing-095.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>CSS Test: Border-spacing: cell spanning multiple columns</title> +<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com"> +<link rel="help" href="https://www.w3.org/TR/CSS2/tables.html#propdef-border-spacing"> +<link rel="help" href="https://github.com/servo/servo/issues/38277"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="The cell spans 3 columns and 2 gutters, each 20px wide. + The contents of the cell should be able to use the entire 100px, not just the 60px + of the columns."> + +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<table cellpadding="0" style="border-spacing: 20px; margin: -20px"> + <tr> + <td colspan="3" style="width: 100px; background: red"> + <div style="height: 100px; background: green"></div> + </td> + </tr> +</table>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed-expected.txt new file mode 100644 index 0000000..53cb731a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed-expected.txt
@@ -0,0 +1,228 @@ +This is a testharness.js-based test. +Found 112 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Property position-area value 'block-start inline-start' + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] Property position-area value 'inline-start block-start' + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] Property position-area value 'block-start inline-end' + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] Property position-area value 'inline-end block-start' + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] Property position-area value 'block-start span-inline-start' + assert_equals: expected "start span-start" but got "block-start span-inline-start" +[FAIL] Property position-area value 'span-inline-start block-start' + assert_equals: expected "start span-start" but got "block-start span-inline-start" +[FAIL] Property position-area value 'block-start span-inline-end' + assert_equals: expected "start span-end" but got "block-start span-inline-end" +[FAIL] Property position-area value 'span-inline-end block-start' + assert_equals: expected "start span-end" but got "block-start span-inline-end" +[FAIL] Property position-area value 'block-end inline-start' + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] Property position-area value 'inline-start block-end' + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] Property position-area value 'block-end inline-end' + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] Property position-area value 'inline-end block-end' + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] Property position-area value 'block-end span-inline-start' + assert_equals: expected "end span-start" but got "block-end span-inline-start" +[FAIL] Property position-area value 'span-inline-start block-end' + assert_equals: expected "end span-start" but got "block-end span-inline-start" +[FAIL] Property position-area value 'block-end span-inline-end' + assert_equals: expected "end span-end" but got "block-end span-inline-end" +[FAIL] Property position-area value 'span-inline-end block-end' + assert_equals: expected "end span-end" but got "block-end span-inline-end" +[FAIL] Property position-area value 'span-block-start inline-start' + assert_equals: expected "span-start start" but got "span-block-start inline-start" +[FAIL] Property position-area value 'inline-start span-block-start' + assert_equals: expected "span-start start" but got "span-block-start inline-start" +[FAIL] Property position-area value 'span-block-start inline-end' + assert_equals: expected "span-start end" but got "span-block-start inline-end" +[FAIL] Property position-area value 'inline-end span-block-start' + assert_equals: expected "span-start end" but got "span-block-start inline-end" +[FAIL] Property position-area value 'span-block-start span-inline-start' + assert_equals: expected "span-start" but got "span-block-start span-inline-start" +[FAIL] Property position-area value 'span-inline-start span-block-start' + assert_equals: expected "span-start" but got "span-block-start span-inline-start" +[FAIL] Property position-area value 'span-block-start span-inline-end' + assert_equals: expected "span-start span-end" but got "span-block-start span-inline-end" +[FAIL] Property position-area value 'span-inline-end span-block-start' + assert_equals: expected "span-start span-end" but got "span-block-start span-inline-end" +[FAIL] Property position-area value 'span-block-end inline-start' + assert_equals: expected "span-end start" but got "span-block-end inline-start" +[FAIL] Property position-area value 'inline-start span-block-end' + assert_equals: expected "span-end start" but got "span-block-end inline-start" +[FAIL] Property position-area value 'span-block-end inline-end' + assert_equals: expected "span-end end" but got "span-block-end inline-end" +[FAIL] Property position-area value 'inline-end span-block-end' + assert_equals: expected "span-end end" but got "span-block-end inline-end" +[FAIL] Property position-area value 'span-block-end span-inline-start' + assert_equals: expected "span-end span-start" but got "span-block-end span-inline-start" +[FAIL] Property position-area value 'span-inline-start span-block-end' + assert_equals: expected "span-end span-start" but got "span-block-end span-inline-start" +[FAIL] Property position-area value 'span-block-end span-inline-end' + assert_equals: expected "span-end" but got "span-block-end span-inline-end" +[FAIL] Property position-area value 'span-inline-end span-block-end' + assert_equals: expected "span-end" but got "span-block-end span-inline-end" +[FAIL] Property position-area value 'block-start center' + assert_equals: expected "start center" but got "block-start center" +[FAIL] Property position-area value 'center block-start' + assert_equals: expected "start center" but got "block-start center" +[FAIL] Property position-area value 'block-end center' + assert_equals: expected "end center" but got "block-end center" +[FAIL] Property position-area value 'center block-end' + assert_equals: expected "end center" but got "block-end center" +[FAIL] Property position-area value 'span-block-start center' + assert_equals: expected "span-start center" but got "span-block-start center" +[FAIL] Property position-area value 'center span-block-start' + assert_equals: expected "span-start center" but got "span-block-start center" +[FAIL] Property position-area value 'span-block-end center' + assert_equals: expected "span-end center" but got "span-block-end center" +[FAIL] Property position-area value 'center span-block-end' + assert_equals: expected "span-end center" but got "span-block-end center" +[FAIL] Property position-area value 'inline-start center' + assert_equals: expected "center start" but got "center inline-start" +[FAIL] Property position-area value 'center inline-start' + assert_equals: expected "center start" but got "center inline-start" +[FAIL] Property position-area value 'inline-end center' + assert_equals: expected "center end" but got "center inline-end" +[FAIL] Property position-area value 'center inline-end' + assert_equals: expected "center end" but got "center inline-end" +[FAIL] Property position-area value 'span-inline-start center' + assert_equals: expected "center span-start" but got "center span-inline-start" +[FAIL] Property position-area value 'center span-inline-start' + assert_equals: expected "center span-start" but got "center span-inline-start" +[FAIL] Property position-area value 'span-inline-end center' + assert_equals: expected "center span-end" but got "center span-inline-end" +[FAIL] Property position-area value 'center span-inline-end' + assert_equals: expected "center span-end" but got "center span-inline-end" +[FAIL] Property position-area value 'self-block-start self-inline-start' + assert_equals: expected "self-start" but got "self-block-start self-inline-start" +[FAIL] Property position-area value 'self-inline-start self-block-start' + assert_equals: expected "self-start" but got "self-block-start self-inline-start" +[FAIL] Property position-area value 'self-block-start self-inline-end' + assert_equals: expected "self-start self-end" but got "self-block-start self-inline-end" +[FAIL] Property position-area value 'self-inline-end self-block-start' + assert_equals: expected "self-start self-end" but got "self-block-start self-inline-end" +[FAIL] Property position-area value 'self-block-start span-self-inline-start' + assert_equals: expected "self-start span-self-start" but got "self-block-start span-self-inline-start" +[FAIL] Property position-area value 'span-self-inline-start self-block-start' + assert_equals: expected "self-start span-self-start" but got "self-block-start span-self-inline-start" +[FAIL] Property position-area value 'self-block-start span-self-inline-end' + assert_equals: expected "self-start span-self-end" but got "self-block-start span-self-inline-end" +[FAIL] Property position-area value 'span-self-inline-end self-block-start' + assert_equals: expected "self-start span-self-end" but got "self-block-start span-self-inline-end" +[FAIL] Property position-area value 'self-block-end self-inline-start' + assert_equals: expected "self-end self-start" but got "self-block-end self-inline-start" +[FAIL] Property position-area value 'self-inline-start self-block-end' + assert_equals: expected "self-end self-start" but got "self-block-end self-inline-start" +[FAIL] Property position-area value 'self-block-end self-inline-end' + assert_equals: expected "self-end" but got "self-block-end self-inline-end" +[FAIL] Property position-area value 'self-inline-end self-block-end' + assert_equals: expected "self-end" but got "self-block-end self-inline-end" +[FAIL] Property position-area value 'self-block-end span-self-inline-start' + assert_equals: expected "self-end span-self-start" but got "self-block-end span-self-inline-start" +[FAIL] Property position-area value 'span-self-inline-start self-block-end' + assert_equals: expected "self-end span-self-start" but got "self-block-end span-self-inline-start" +[FAIL] Property position-area value 'self-block-end span-self-inline-end' + assert_equals: expected "self-end span-self-end" but got "self-block-end span-self-inline-end" +[FAIL] Property position-area value 'span-self-inline-end self-block-end' + assert_equals: expected "self-end span-self-end" but got "self-block-end span-self-inline-end" +[FAIL] Property position-area value 'span-self-block-start self-inline-start' + assert_equals: expected "span-self-start self-start" but got "span-self-block-start self-inline-start" +[FAIL] Property position-area value 'self-inline-start span-self-block-start' + assert_equals: expected "span-self-start self-start" but got "span-self-block-start self-inline-start" +[FAIL] Property position-area value 'span-self-block-start self-inline-end' + assert_equals: expected "span-self-start self-end" but got "span-self-block-start self-inline-end" +[FAIL] Property position-area value 'self-inline-end span-self-block-start' + assert_equals: expected "span-self-start self-end" but got "span-self-block-start self-inline-end" +[FAIL] Property position-area value 'span-self-block-start span-self-inline-start' + assert_equals: expected "span-self-start" but got "span-self-block-start span-self-inline-start" +[FAIL] Property position-area value 'span-self-inline-start span-self-block-start' + assert_equals: expected "span-self-start" but got "span-self-block-start span-self-inline-start" +[FAIL] Property position-area value 'span-self-block-start span-self-inline-end' + assert_equals: expected "span-self-start span-self-end" but got "span-self-block-start span-self-inline-end" +[FAIL] Property position-area value 'span-self-inline-end span-self-block-start' + assert_equals: expected "span-self-start span-self-end" but got "span-self-block-start span-self-inline-end" +[FAIL] Property position-area value 'span-self-block-end self-inline-start' + assert_equals: expected "span-self-end self-start" but got "span-self-block-end self-inline-start" +[FAIL] Property position-area value 'self-inline-start span-self-block-end' + assert_equals: expected "span-self-end self-start" but got "span-self-block-end self-inline-start" +[FAIL] Property position-area value 'span-self-block-end self-inline-end' + assert_equals: expected "span-self-end self-end" but got "span-self-block-end self-inline-end" +[FAIL] Property position-area value 'self-inline-end span-self-block-end' + assert_equals: expected "span-self-end self-end" but got "span-self-block-end self-inline-end" +[FAIL] Property position-area value 'span-self-block-end span-self-inline-start' + assert_equals: expected "span-self-end span-self-start" but got "span-self-block-end span-self-inline-start" +[FAIL] Property position-area value 'span-self-inline-start span-self-block-end' + assert_equals: expected "span-self-end span-self-start" but got "span-self-block-end span-self-inline-start" +[FAIL] Property position-area value 'span-self-block-end span-self-inline-end' + assert_equals: expected "span-self-end" but got "span-self-block-end span-self-inline-end" +[FAIL] Property position-area value 'span-self-inline-end span-self-block-end' + assert_equals: expected "span-self-end" but got "span-self-block-end span-self-inline-end" +[FAIL] Property position-area value 'self-block-start center' + assert_equals: expected "self-start center" but got "self-block-start center" +[FAIL] Property position-area value 'center self-block-start' + assert_equals: expected "self-start center" but got "self-block-start center" +[FAIL] Property position-area value 'self-block-end center' + assert_equals: expected "self-end center" but got "self-block-end center" +[FAIL] Property position-area value 'center self-block-end' + assert_equals: expected "self-end center" but got "self-block-end center" +[FAIL] Property position-area value 'span-self-block-start center' + assert_equals: expected "span-self-start center" but got "span-self-block-start center" +[FAIL] Property position-area value 'center span-self-block-start' + assert_equals: expected "span-self-start center" but got "span-self-block-start center" +[FAIL] Property position-area value 'span-self-block-end center' + assert_equals: expected "span-self-end center" but got "span-self-block-end center" +[FAIL] Property position-area value 'center span-self-block-end' + assert_equals: expected "span-self-end center" but got "span-self-block-end center" +[FAIL] Property position-area value 'self-inline-start center' + assert_equals: expected "center self-start" but got "center self-inline-start" +[FAIL] Property position-area value 'center self-inline-start' + assert_equals: expected "center self-start" but got "center self-inline-start" +[FAIL] Property position-area value 'self-inline-end center' + assert_equals: expected "center self-end" but got "center self-inline-end" +[FAIL] Property position-area value 'center self-inline-end' + assert_equals: expected "center self-end" but got "center self-inline-end" +[FAIL] Property position-area value 'span-self-inline-start center' + assert_equals: expected "center span-self-start" but got "center span-self-inline-start" +[FAIL] Property position-area value 'center span-self-inline-start' + assert_equals: expected "center span-self-start" but got "center span-self-inline-start" +[FAIL] Property position-area value 'span-self-inline-end center' + assert_equals: expected "center span-self-end" but got "center span-self-inline-end" +[FAIL] Property position-area value 'center span-self-inline-end' + assert_equals: expected "center span-self-end" but got "center span-self-inline-end" +[FAIL] Property position-area value 'start span-all' + assert_equals: expected "block-start" but got "start span-all" +[FAIL] Property position-area value 'span-all start' + assert_equals: expected "inline-start" but got "span-all start" +[FAIL] Property position-area value 'end span-all' + assert_equals: expected "block-end" but got "end span-all" +[FAIL] Property position-area value 'span-all end' + assert_equals: expected "inline-end" but got "span-all end" +[FAIL] Property position-area value 'span-start span-all' + assert_equals: expected "span-block-start" but got "span-start span-all" +[FAIL] Property position-area value 'span-all span-start' + assert_equals: expected "span-inline-start" but got "span-all span-start" +[FAIL] Property position-area value 'span-end span-all' + assert_equals: expected "span-block-end" but got "span-end span-all" +[FAIL] Property position-area value 'span-all span-end' + assert_equals: expected "span-inline-end" but got "span-all span-end" +[FAIL] Property position-area value 'self-start span-all' + assert_equals: expected "self-block-start" but got "self-start span-all" +[FAIL] Property position-area value 'span-all self-start' + assert_equals: expected "self-inline-start" but got "span-all self-start" +[FAIL] Property position-area value 'self-end span-all' + assert_equals: expected "self-block-end" but got "self-end span-all" +[FAIL] Property position-area value 'span-all self-end' + assert_equals: expected "self-inline-end" but got "span-all self-end" +[FAIL] Property position-area value 'span-self-start span-all' + assert_equals: expected "span-self-block-start" but got "span-self-start span-all" +[FAIL] Property position-area value 'span-all span-self-start' + assert_equals: expected "span-self-inline-start" but got "span-all span-self-start" +[FAIL] Property position-area value 'span-self-end span-all' + assert_equals: expected "span-self-block-end" but got "span-self-end span-all" +[FAIL] Property position-area value 'span-all span-self-end' + assert_equals: expected "span-self-inline-end" but got "span-all span-self-end" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed.html index 0acc853eb..8e18006 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-computed.html
@@ -9,14 +9,189 @@ <div id="target"></div> </div> <script> + // Keywords that refer to the physical horizontal/vertical axes. + + const horizontal = [ + "left", + "right", + "span-left", + "span-right", + "x-start", + "x-end", + "span-x-start", + "span-x-end", + "x-self-start", + "x-self-end", + "span-x-self-start", + "span-x-self-end" + ]; + + const vertical = [ + "top", + "bottom", + "span-top", + "span-bottom", + "y-start", + "y-end", + "span-y-start", + "span-y-end", + "y-self-start", + "y-self-end", + "span-y-self-start", + "span-y-self-end" + ]; + + // Keywords that refer to the logical block/inline axis. + // Key is the full form of the keyword, value is the equivalent reduced keyword. + + const inline = { + "inline-start": "start", + "inline-end": "end", + "span-inline-start": "span-start", + "span-inline-end": "span-end", + } + + const block = { + "block-start": "start", + "block-end": "end", + "span-block-start": "span-start", + "span-block-end": "span-end", + } + + const self_inline = { + "self-inline-start": "self-start", + "self-inline-end": "self-end", + "span-self-inline-start": "span-self-start", + "span-self-inline-end": "span-self-end", + } + + const self_block = { + "self-block-start": "self-start", + "self-block-end": "self-end", + "span-self-block-start": "span-self-start", + "span-self-block-end": "span-self-end", + } + + // Keywords that refer to an ambiguous axis. + // Key is the keyword, value is the equivalent keyword if the original keyword refers + // to a block or inline axis. + + const start_end = { + "start": { "block": "block-start", "inline": "inline-start" }, + "end": { "block": "block-end", "inline": "inline-end" }, + "span-start": { "block": "span-block-start", "inline": "span-inline-start" }, + "span-end": { "block": "span-block-end", "inline": "span-inline-end" }, + }; + + const self_start_end = { + "self-start": { "block": "self-block-start", "inline": "self-inline-start" }, + "self-end": { "block": "self-block-end", "inline": "self-inline-end" }, + "span-self-start": { "block": "span-self-block-start", "inline": "span-self-inline-start" }, + "span-self-end": { "block": "span-self-block-end", "inline": "span-self-inline-end" }, + }; + + function test_single_keyword(keywords) { + for (const keyword of keywords) + test_computed_value("position-area", keyword); + } + + function test_physical_keywords(horizontal_keywords, vertical_keywords) { + for (const horizontal of horizontal_keywords) { + for (const vertical of vertical_keywords) { + test_computed_value("position-area", `${horizontal} ${vertical}`); + test_computed_value("position-area", `${vertical} ${horizontal}`, `${horizontal} ${vertical}`); + } + } + + for (const keyword of horizontal_keywords) { + test_computed_value("position-area", `${keyword} span-all`, keyword); + test_computed_value("position-area", `span-all ${keyword}`, keyword); + + test_computed_value("position-area", `${keyword} center`); + test_computed_value("position-area", `center ${keyword}`, `${keyword} center`); + } + + for (const keyword of vertical_keywords) { + test_computed_value("position-area", `span-all ${keyword}`, keyword); + test_computed_value("position-area", `${keyword} span-all`, keyword); + + test_computed_value("position-area", `center ${keyword}`); + test_computed_value("position-area", `${keyword} center`, `center ${keyword}`); + } + } + + function test_unambiguous_logical_keywords(block_keywords, inline_keywords) { + for (const [block_long_keyword, block_short_keyword] of Object.entries(block_keywords)) { + for (const [inline_long_keyword, inline_short_keyword] of Object.entries(inline_keywords)) { + let expected_computed = `${block_short_keyword} ${inline_short_keyword}`; + if (block_short_keyword == inline_short_keyword) + expected_computed = block_short_keyword; + + test_computed_value("position-area", `${block_long_keyword} ${inline_long_keyword}`, expected_computed); + test_computed_value("position-area", `${inline_long_keyword} ${block_long_keyword}`, expected_computed); + } + } + + for (const [long_keyword, short_keyword] of Object.entries(block_keywords)) { + test_computed_value("position-area", `${long_keyword} span-all`, long_keyword); + test_computed_value("position-area", `span-all ${long_keyword}`, long_keyword); + + test_computed_value("position-area", `${long_keyword} center`, `${short_keyword} center`); + test_computed_value("position-area", `center ${long_keyword}`, `${short_keyword} center`); + } + + for (const [long_keyword, short_keyword] of Object.entries(inline_keywords)) { + test_computed_value("position-area", `${long_keyword} span-all`, long_keyword); + test_computed_value("position-area", `span-all ${long_keyword}`, long_keyword); + + test_computed_value("position-area", `${long_keyword} center`, `center ${short_keyword}`); + test_computed_value("position-area", `center ${long_keyword}`, `center ${short_keyword}`); + } + } + + function test_ambiguous_logical_keywords(keywords) { + for (const keyword1 of Object.keys(keywords)) { + for (const keyword2 of Object.keys(keywords)) { + if (keyword1 == keyword2) + test_computed_value("position-area", `${keyword1} ${keyword2}`, `${keyword1}`); + else + test_computed_value("position-area", `${keyword1} ${keyword2}`); + } + } + + for (const [keyword, { block: block_keyword, inline: inline_keyword }] of Object.entries(keywords)) { + test_computed_value("position-area", `${keyword} span-all`, block_keyword); + test_computed_value("position-area", `span-all ${keyword}`, inline_keyword); + + test_computed_value("position-area", `${keyword} center`); + test_computed_value("position-area", `center ${keyword}`); + }; + } + + // Test computed value when position-area is a single keyword. test_computed_value("position-area", "none"); test_computed_value("position-area", "span-all"); - test_computed_value("position-area", "x-start"); test_computed_value("position-area", "center"); + test_single_keyword(horizontal); + test_single_keyword(vertical); + test_single_keyword(Object.keys(inline)); + test_single_keyword(Object.keys(block)); + test_single_keyword(Object.keys(self_inline)); + test_single_keyword(Object.keys(self_block)); + test_single_keyword(Object.keys(start_end)); + test_single_keyword(Object.keys(self_start_end)); + + // Test computed value when position-area are two keywords. + test_physical_keywords(horizontal, vertical); + test_unambiguous_logical_keywords(block, inline); + test_unambiguous_logical_keywords(self_block, self_inline); + test_ambiguous_logical_keywords(start_end); + test_ambiguous_logical_keywords(self_start_end); + test_computed_value("position-area", "span-all span-all", "span-all"); + test_computed_value("position-area", "span-all center"); + test_computed_value("position-area", "center span-all"); test_computed_value("position-area", "center center", "center"); - test_computed_value("position-area", "top center", "center top"); - test_computed_value("position-area", "span-bottom span-all", "span-bottom"); assert_not_inherited("position-area", "none", "span-all"); -</script> +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-parsing.html index e6de6d7e..c8d7687 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-parsing.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-parsing.html
@@ -102,6 +102,8 @@ test_valid_single_position_area_values(vertical); test_valid_single_position_area_values(inline); test_valid_single_position_area_values(block); + test_valid_single_position_area_values(self_inline); + test_valid_single_position_area_values(self_block); test_valid_single_position_area_values(start_end); test_valid_single_position_area_values(self_start_end);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area-expected.txt new file mode 100644 index 0000000..8e4524a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area-expected.txt
@@ -0,0 +1,76 @@ +This is a testharness.js-based test. +Found 36 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] flip-inline, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-inline, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-inline, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-inline, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-block, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-block, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-block flip-inline, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-block flip-inline, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-block flip-inline, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block flip-inline, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-start, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-start, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-start, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-start, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-block flip-start, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-block flip-start, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block flip-start, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-block flip-start, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-inline flip-start, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-inline flip-start, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-inline flip-start, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-inline flip-start, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block flip-inline flip-start, position-area:block-start inline-start, ltr horizontal-tb + assert_equals: expected "end" but got "block-end inline-end" +[FAIL] flip-block flip-inline flip-start, position-area:block-end inline-start, ltr horizontal-tb + assert_equals: expected "end start" but got "block-end inline-start" +[FAIL] flip-block flip-inline flip-start, position-area:block-end inline-end, ltr horizontal-tb + assert_equals: expected "start" but got "block-start inline-start" +[FAIL] flip-block flip-inline flip-start, position-area:block-start inline-end, ltr horizontal-tb + assert_equals: expected "start end" but got "block-start inline-end" +[FAIL] flip-block flip-inline, position-area:span-block-start span-inline-start, ltr horizontal-tb + assert_equals: expected "span-end" but got "span-block-end span-inline-end" +[FAIL] flip-block flip-inline, position-area:self-block-start self-inline-start, ltr horizontal-tb + assert_equals: expected "self-end" but got "self-block-end self-inline-end" +[FAIL] flip-block flip-inline, position-area:span-self-block-start span-self-inline-start, ltr horizontal-tb + assert_equals: expected "span-self-end" but got "span-self-block-end span-self-inline-end" +[FAIL] flip-block, position-area:start span-all, ltr horizontal-tb + assert_equals: expected "block-end" but got "end span-all" +[FAIL] flip-block, position-area:span-all start, ltr horizontal-tb + assert_equals: expected "inline-start" but got "span-all start" +[FAIL] flip-inline, position-area:span-all start, ltr horizontal-tb + assert_equals: expected "inline-end" but got "span-all end" +[FAIL] flip-start, position-area:span-all start, ltr horizontal-tb + assert_equals: expected "block-start" but got "start span-all" +[FAIL] flip-start, position-area:span-block-start inline-end, ltr horizontal-tb + assert_equals: expected "end span-start" but got "block-end span-inline-start" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area.html index e050dbc..ab5d95f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/try-tactic-position-area.html
@@ -145,45 +145,45 @@ // Logical: -test_computed_value('flip-inline', 'position-area', 'block-start inline-start', 'block-start inline-end'); -test_computed_value('flip-inline', 'position-area', 'block-end inline-start', 'block-end inline-end'); -test_computed_value('flip-inline', 'position-area', 'block-end inline-end', 'block-end inline-start'); -test_computed_value('flip-inline', 'position-area', 'block-start inline-end', 'block-start inline-start'); +test_computed_value('flip-inline', 'position-area', 'block-start inline-start', 'start end'); +test_computed_value('flip-inline', 'position-area', 'block-end inline-start', 'end'); +test_computed_value('flip-inline', 'position-area', 'block-end inline-end', 'end start'); +test_computed_value('flip-inline', 'position-area', 'block-start inline-end', 'start'); -test_computed_value('flip-block', 'position-area', 'block-start inline-start', 'block-end inline-start'); -test_computed_value('flip-block', 'position-area', 'block-end inline-start', 'block-start inline-start'); -test_computed_value('flip-block', 'position-area', 'block-end inline-end', 'block-start inline-end'); -test_computed_value('flip-block', 'position-area', 'block-start inline-end', 'block-end inline-end'); +test_computed_value('flip-block', 'position-area', 'block-start inline-start', 'end start'); +test_computed_value('flip-block', 'position-area', 'block-end inline-start', 'start'); +test_computed_value('flip-block', 'position-area', 'block-end inline-end', 'start end'); +test_computed_value('flip-block', 'position-area', 'block-start inline-end', 'end'); -test_computed_value('flip-block flip-inline', 'position-area', 'block-start inline-start', 'block-end inline-end'); -test_computed_value('flip-block flip-inline', 'position-area', 'block-end inline-start', 'block-start inline-end'); -test_computed_value('flip-block flip-inline', 'position-area', 'block-end inline-end', 'block-start inline-start'); -test_computed_value('flip-block flip-inline', 'position-area', 'block-start inline-end', 'block-end inline-start'); +test_computed_value('flip-block flip-inline', 'position-area', 'block-start inline-start', 'end'); +test_computed_value('flip-block flip-inline', 'position-area', 'block-end inline-start', 'start end'); +test_computed_value('flip-block flip-inline', 'position-area', 'block-end inline-end', 'start'); +test_computed_value('flip-block flip-inline', 'position-area', 'block-start inline-end', 'end start'); -test_computed_value('flip-start', 'position-area', 'block-start inline-start', 'block-start inline-start'); -test_computed_value('flip-start', 'position-area', 'block-end inline-start', 'block-start inline-end'); -test_computed_value('flip-start', 'position-area', 'block-end inline-end', 'block-end inline-end'); -test_computed_value('flip-start', 'position-area', 'block-start inline-end', 'block-end inline-start'); +test_computed_value('flip-start', 'position-area', 'block-start inline-start', 'start'); +test_computed_value('flip-start', 'position-area', 'block-end inline-start', 'start end'); +test_computed_value('flip-start', 'position-area', 'block-end inline-end', 'end'); +test_computed_value('flip-start', 'position-area', 'block-start inline-end', 'end start'); -test_computed_value('flip-block flip-start', 'position-area', 'block-start inline-start', 'block-start inline-end'); -test_computed_value('flip-block flip-start', 'position-area', 'block-end inline-start', 'block-start inline-start'); -test_computed_value('flip-block flip-start', 'position-area', 'block-end inline-end', 'block-end inline-start'); -test_computed_value('flip-block flip-start', 'position-area', 'block-start inline-end', 'block-end inline-end'); +test_computed_value('flip-block flip-start', 'position-area', 'block-start inline-start', 'start end'); +test_computed_value('flip-block flip-start', 'position-area', 'block-end inline-start', 'start'); +test_computed_value('flip-block flip-start', 'position-area', 'block-end inline-end', 'end start'); +test_computed_value('flip-block flip-start', 'position-area', 'block-start inline-end', 'end'); -test_computed_value('flip-inline flip-start', 'position-area', 'block-start inline-start', 'block-end inline-start'); -test_computed_value('flip-inline flip-start', 'position-area', 'block-end inline-start', 'block-end inline-end'); -test_computed_value('flip-inline flip-start', 'position-area', 'block-end inline-end', 'block-start inline-end'); -test_computed_value('flip-inline flip-start', 'position-area', 'block-start inline-end', 'block-start inline-start'); +test_computed_value('flip-inline flip-start', 'position-area', 'block-start inline-start', 'end start'); +test_computed_value('flip-inline flip-start', 'position-area', 'block-end inline-start', 'end'); +test_computed_value('flip-inline flip-start', 'position-area', 'block-end inline-end', 'start end'); +test_computed_value('flip-inline flip-start', 'position-area', 'block-start inline-end', 'start'); -test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-start inline-start', 'block-end inline-end'); -test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-end inline-start', 'block-end inline-start'); -test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-end inline-end', 'block-start inline-start'); -test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-start inline-end', 'block-start inline-end'); +test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-start inline-start', 'end'); +test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-end inline-start', 'end start'); +test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-end inline-end', 'start'); +test_computed_value('flip-block flip-inline flip-start', 'position-area', 'block-start inline-end', 'start end'); // Variations: -test_computed_value('flip-block flip-inline', 'position-area', 'span-block-start span-inline-start', 'span-block-end span-inline-end'); -test_computed_value('flip-block flip-inline', 'position-area', 'self-block-start self-inline-start', 'self-block-end self-inline-end'); -test_computed_value('flip-block flip-inline', 'position-area', 'span-self-block-start span-self-inline-start', 'span-self-block-end span-self-inline-end'); +test_computed_value('flip-block flip-inline', 'position-area', 'span-block-start span-inline-start', 'span-end'); +test_computed_value('flip-block flip-inline', 'position-area', 'self-block-start self-inline-start', 'self-end'); +test_computed_value('flip-block flip-inline', 'position-area', 'span-self-block-start span-self-inline-start', 'span-self-end'); // start/end @@ -224,15 +224,15 @@ test_computed_value('flip-block', 'position-area', 'left span-all', 'left'); test_computed_value('flip-block', 'position-area', 'span-all top', 'bottom'); test_computed_value('flip-block', 'position-area', 'span-all', 'span-all'); -test_computed_value('flip-block', 'position-area', 'start span-all', 'end span-all'); -test_computed_value('flip-block', 'position-area', 'span-all start', 'span-all start'); -test_computed_value('flip-inline', 'position-area', 'span-all start', 'span-all end'); -test_computed_value('flip-start', 'position-area', 'span-all start', 'start span-all'); +test_computed_value('flip-block', 'position-area', 'start span-all', 'block-end'); +test_computed_value('flip-block', 'position-area', 'span-all start', 'inline-start'); +test_computed_value('flip-inline', 'position-area', 'span-all start', 'inline-end'); +test_computed_value('flip-start', 'position-area', 'span-all start', 'block-start'); // Span mix: test_computed_value('flip-block', 'position-area', 'left span-top', 'left span-bottom'); test_computed_value('flip-inline', 'position-area', 'left span-top', 'right span-top'); -test_computed_value('flip-start', 'position-area', 'span-block-start inline-end', 'block-end span-inline-start'); +test_computed_value('flip-start', 'position-area', 'span-block-start inline-end', 'end span-start'); // Writing modes: test_computed_value('flip-block', 'position-area', 'left top', 'right top', 'ltr', 'vertical-rl');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/flex-abspos-staticpos-align-self-006.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/flex-abspos-staticpos-align-self-006.html index 3c03636b..c36a6d1 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/flex-abspos-staticpos-align-self-006.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/flex-abspos-staticpos-align-self-006.html
@@ -51,7 +51,7 @@ https://www.w3.org/TR/css-align-3/#propdef-align-self --> <!-- auto | normal | stretch --> <div class="container"><div style="align-self: auto" data-offset-x="6" data-offset-y="1"></div></div> - <div class="container"><div style="align-self: normal" data-offset-x="10" data-offset-y=""></div></div> + <div class="container"><div style="align-self: normal" data-offset-x="10" data-offset-y="1"></div></div> <div class="container"><div style="align-self: stretch" data-offset-x="10" data-offset-y="1"></div></div> <br> <!-- <baseline-position> -->
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-rtl-direction.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-rtl-direction.html new file mode 100644 index 0000000..3be57a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-rtl-direction.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html"> +<meta name="assert" content="Baseline aligned item should be aligned towards the start of the inline axis (right side)." +<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#flex-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline"> +<style> +.flexbox { + display: flex; + width: 100px; + height: 100px; + align-items: baseline; + flex-direction: column; + direction: rtl; + position: relative; +} +.item { + width: 50px; + height: 100px; + background-color: green; +} +.abspos { + position: absolute; + right: 50px; +} +</style> +</head> +<body> +<p>Test passes if there is a filled green square.</p> +<div class="flexbox"> + <div class="abspos item"></div> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-lr-rtl-wrap-reverse.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-lr-rtl-wrap-reverse.html new file mode 100644 index 0000000..767c129b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-lr-rtl-wrap-reverse.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html"> +<meta name="assert" content="Baseline aligned item should be aligned towards the start of the inline axis (bottom side)." +<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#flex-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline"> +<style> +.flexbox { + display: flex; + width: 100px; + height: 100px; + align-items: baseline; + flex-direction: column; + writing-mode: vertical-lr; + direction: rtl; + flex-wrap: wrap-reverse; + position: relative; +} +.item { + width: 100px; + height: 50px; + background-color: green; +} +.abspos { + position: absolute; + bottom: 50px; +} +</style> +</head> +<body> +<p>Test passes if there is a filled green square.</p> +<div class="flexbox"> + <div class="abspos item"></div> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-rl-rtl-wrap-reverse.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-rl-rtl-wrap-reverse.html new file mode 100644 index 0000000..9608301 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-column-vert-rl-rtl-wrap-reverse.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html"> +<meta name="assert" content="Baseline aligned item should be aligned towards the start of the inline axis (bottom side)." +<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#flex-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline"> +<style> +.flexbox { + display: flex; + width: 100px; + height: 100px; + align-items: baseline; + flex-direction: column; + writing-mode: vertical-rl; + direction: rtl; + flex-wrap: wrap-reverse; + position: relative; +} +.item { + width: 100px; + height: 50px; + background-color: green; +} +.abspos { + position: absolute; + bottom: 50px; +} +</style> +</head> +<body> +<p>Test passes if there is a filled green square.</p> +<div class="flexbox"> + <div class="abspos item"></div> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html new file mode 100644 index 0000000..7f2a5ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<style> +.grid { + display: grid; + padding: 13px; + padding-bottom: 42px; + border: 23px solid black; + border-bottom-width: 45px; + width: 100px; + height: 100px; +} +.item { + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +<body> +<div class="grid"> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding.html new file mode 100644 index 0000000..c9359c8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-large-border-padding.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-abspos"> +<link rel="help" href="https://www.w3.org/TR/css-position-3/#staticpos-rect"> +<link rel="match" href="grid-abspos-staticpos-align-self-flex-end-large-border-padding-ref.html"> +<meta name="assert" content="Abspos child of grid is aligned to end of grid content box when statically positioned and end self alignment."> +<style> +.grid { + display: grid; + padding: 13px; + padding-bottom: 42px; + border: 23px solid black; + border-bottom-width: 45px; + width: 100px; + height: 100px; +} +.abspos { + position: absolute; + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +</head> +<body> +<div class="grid"> + <div class="abspos"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-ref.html new file mode 100644 index 0000000..868717bc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end-ref.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<style> +.grid { + display: grid; + border: 1px solid black; + width: 100px; + height: 100px; +} +.item { + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +<body> +<div class="grid"> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end.html new file mode 100644 index 0000000..54c772e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-flex-end.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-abspos"> +<link rel="help" href="https://www.w3.org/TR/css-position-3/#staticpos-rect"> +<link rel="match" href="grid-abspos-staticpos-align-self-flex-end-ref.html"> +<meta name="assert" content="Abspos child of grid is aligned to end of grid content box when statically positioned and end self alignment."> +<style> +.grid { + display: grid; + border: 1px solid black; + width: 100px; + height: 100px; +} +.abspos { + position: absolute; + width: 50px; + height: 50px; + background-color: green; + align-self: flex-end; +} +</style> +</head> +<body> +<div class="grid"> + <div class="abspos"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html new file mode 100644 index 0000000..7f2a5ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<style> +.grid { + display: grid; + padding: 13px; + padding-bottom: 42px; + border: 23px solid black; + border-bottom-width: 45px; + width: 100px; + height: 100px; +} +.item { + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +<body> +<div class="grid"> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding.html new file mode 100644 index 0000000..1478bbb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-large-border-padding.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-abspos"> +<link rel="help" href="https://www.w3.org/TR/css-position-3/#staticpos-rect"> +<link rel="match" href="grid-abspos-staticpos-align-self-self-end-large-border-padding-ref.html"> +<meta name="assert" content="Abspos child of grid is aligned to end of grid content box when statically positioned and end self alignment."> +<style> +.grid { + display: grid; + padding: 13px; + padding-bottom: 42px; + border: 23px solid black; + border-bottom-width: 45px; + width: 100px; + height: 100px; +} +.abspos { + position: absolute; + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +</head> +<body> +<div class="grid"> + <div class="abspos"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-ref.html new file mode 100644 index 0000000..868717bc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end-ref.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<style> +.grid { + display: grid; + border: 1px solid black; + width: 100px; + height: 100px; +} +.item { + width: 50px; + height: 50px; + background-color: green; + align-self: end; +} +</style> +<body> +<div class="grid"> + <div class="item"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end.html new file mode 100644 index 0000000..2cd2560 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-self-end.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-abspos"> +<link rel="help" href="https://www.w3.org/TR/css-position-3/#staticpos-rect"> +<link rel="match" href="grid-abspos-staticpos-align-self-self-end-ref.html"> +<meta name="assert" content="Abspos child of grid is aligned to end of grid content box when statically positioned and end self alignment."> +<style> +.grid { + display: grid; + border: 1px solid black; + width: 100px; + height: 100px; +} +.abspos { + position: absolute; + width: 50px; + height: 50px; + background-color: green; + align-self: self-end; +} +</style> +</head> +<body> +<div class="grid"> + <div class="abspos"></div> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/resnap-on-overflowing-snap-area.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/resnap-on-overflowing-snap-area.html new file mode 100644 index 0000000..e0af5f3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/resnap-on-overflowing-snap-area.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/#re-snap" /> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1978946"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +#scroller { + overflow-y: auto; + scroll-snap-type: y mandatory; + width: 100vw; + height: calc(100svh - 80px); +} +.child { + scroll-snap-align: start; + scroll-snap-stop: always; + width: 100%; + height: calc(100svh - 80px); + font-size: 30px; +} +.child:last-child { + background-image: linear-gradient(to right, black 1px, transparent 1px), + linear-gradient(to bottom, black 1px, transparent 1px); + background-size: 64px 64px; + height: 200%; +} +</style> +<div id="scroller"> + <div class="child">1</div> + <div class="child">2</div> +</div> +<script> +promise_test(async () => { + assert_equals(scroller.scrollTop, 0); + + const scrollendPromise = new Promise(resolve => { + scroller.addEventListener("scrollend", resolve); + }); + + const expectedPosition = + scroller.children[0].getBoundingClientRect().height + 100; + // Try to scroll downward, it will snap to a position inside + // the second child. + scroller.scrollTo(0, expectedPosition); + await scrollendPromise; + + assert_equals(scroller.scrollTop, expectedPosition, + "The scroll position is the expected one"); + + // Change the second child width, it will re-evaluate the snap position. + scroller.querySelector(":last-child").style.width = "99%"; + + // Give a chance to scroll if it happens. + await new Promise(resolve => { + requestAnimationFrame(() => requestAnimationFrame(resolve)); + }); + + assert_equals(scroller.scrollTop, expectedPosition, + "Should stay at the last snap point"); +}, "Keep the same snap position on overflowing-snap-area when re-snapping"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-001.html new file mode 100644 index 0000000..0e3e1e38 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-001.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>CSS-white-space test: restore collapsed whitespace</title> +<link rel="author" title="JoeDow" href="ibluegalaxy_taoj@163.com"> +<link rel="match" href="reference/pre-001-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +html { + font: 20px/1 Ahem; +} +.span { + background-color: blueviolet; +} +#target { + background-color: blue; +} +</style> +<body> + <div> + <span class="span">aa bb </span><span id="target"> target </span><span class="span">bb aa</span> + </div> + + <script> + window.onload = function() { + const target = document.getElementById("target"); + // force layout + target.offsetLeft; + target.style.whiteSpace = "pre"; + } + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-001-ref.html new file mode 100644 index 0000000..e950bbb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-001-ref.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +html { + font: 20px/1 Ahem; +} +.span { + background-color: blueviolet; +} +#target { + background-color: blue; + white-space: pre; +} +</style> +<body> + <div> + <span class="span">aa bb </span><span id="target"> target </span><span class="span">bb aa</span> + </div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/column-span-during-transition-doesnt-skip.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/column-span-during-transition-doesnt-skip.html index 67e6b5d..81d4f93e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/column-span-during-transition-doesnt-skip.html +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/column-span-during-transition-doesnt-skip.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <html class=reftest-wait> <title>View transitions: column-span elements in a fragmented container aren't skipped</title> +<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-100000"> <link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> <link rel="author" href="mailto:mattwoodrow@apple.com"> <link rel="match" href="column-span-during-transition-doesnt-skip-ref.html"> @@ -37,10 +38,11 @@ failIfNot(document.startViewTransition, "Missing document.startViewTransition"); function runTransition() { - let t = document.startViewTransition(); + let t = document.startViewTransition(() => { + container.classList.add("fragment") + }); t.ready.then(() => { requestAnimationFrame(() => { - container.classList.add("fragment") requestAnimationFrame(takeScreenshot); }); });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/first-line-reparent-crash.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/first-line-reparent-crash.html new file mode 100644 index 0000000..7149d770 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/first-line-reparent-crash.html
@@ -0,0 +1,13 @@ +<!doctype html> +<html class="test-wait"> +<script> +window.addEventListener("load", () => { + const a = document.createElement("style") + document.documentElement.appendChild(a) + a.textContent = ":first-line{}" + document.adoptNode(document.body) + document.startViewTransition().ready.then(() => { + document.documentElement.className = ""; + }); +}) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html index 3e17d5b..67630d1 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html
@@ -217,4 +217,11 @@ await promise_rejects_js(t, TypeError, navigator.credentials.create(options)); } }, "Mediation is required to create a DigitalCredential."); + + promise_test(async (t) => { + await promise_rejects_js( + t, + TypeError, + navigator.credentials.create({digital: {}})); + }, "`requests` field is required in the options object."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt index 70beb572..a190f75 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt
@@ -1,10 +1,4 @@ This is a testharness.js-based test. -[FAIL] navigator.credentials.get() API rejects if there are no credential request. - assert_unreached: Should have rejected: undefined Reached unreachable code -[FAIL] navigator.credentials.get() API rejects if there are no credential request for same-origin iframe. - assert_unreached: Should have rejected: undefined Reached unreachable code -[FAIL] navigator.credentials.get() API rejects if there are no credential request in cross-origin iframe. - assert_equals: expected "TypeError" but got "DOMException" [FAIL] Mediation is required to get a DigitalCredential. assert_unreached: Should have rejected: undefined Reached unreachable code [FAIL] Throws TypeError when request data is not JSON stringifiable.
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https.html index 7c1e663..1549bba 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https.html
@@ -107,8 +107,12 @@ }, "Calling navigator.credentials.get() without a digital member same origin."); promise_test(async (t) => { - for (const request of [undefined, []]) { - const options = makeGetOptions(request); + for (const r of [undefined, []]) { + const options = { + digital: { + requests: r + }, + }; await test_driver.bless("user activation"); await promise_rejects_js( t, @@ -121,8 +125,12 @@ promise_test(async (t) => { iframeSameOrigin.focus(); const { contentWindow: iframeWindow } = iframeSameOrigin; - for (const request of [undefined, []]) { - const options = makeGetOptions(request); + for (const r of [undefined, []]) { + const options = { + digital: { + requests: r + }, + }; await test_driver.bless("user activation"); await promise_rejects_js( t, @@ -134,8 +142,12 @@ promise_test(async (t) => { iframeCrossOrigin.focus(); - for (const request of [undefined, []]) { - const options = makeGetOptions(request); + for (const r of [undefined, []]) { + const options = { + digital: { + requests: r + }, + }; const result = await sendMessage(iframeCrossOrigin, { action: "get", options, @@ -251,4 +263,11 @@ ); } }, "Throws TypeError when request data is not JSON stringifiable."); + +promise_test(async (t) => { + await promise_rejects_js( + t, + TypeError, + navigator.credentials.get({digital: {}})); + }, "`requests` field is required in the options object."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js b/third_party/blink/web_tests/external/wpt/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js index 4c7faef..843d37e 100644 --- a/third_party/blink/web_tests/external/wpt/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js +++ b/third_party/blink/web_tests/external/wpt/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js
@@ -35,7 +35,9 @@ assert_equals(_video2.mediaKeys, _mediaKeys); return Promise.resolve(); }, function(error) { - assert_equals(error.name, 'QuotaExceededError'); + assert_equals(error.constructor, globalThis.QuotaExceededError, 'QuotaExceededError constructor match'); + assert_equals(error.quota, null, 'quota'); + assert_equals(error.requested, null, 'requested'); assert_not_equals(error.message, ''); // Return something so the promise resolves properly. return Promise.resolve(); @@ -51,4 +53,4 @@ test.done(); }).catch(onFailure); }, testname); -} \ No newline at end of file +}
diff --git a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-helper.sub.js b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-helper.sub.js index d370ea6..7330c3e 100644 --- a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-helper.sub.js +++ b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-helper.sub.js
@@ -198,7 +198,11 @@ resolve(type); } catch (ex) { if (String(ex).includes("no such alert")) { - t.step_timeout(helper, 100); + if (t) { + t.step_timeout(helper, 100); + } else{ + window.setTimeout(helper, 100); + } } else { reject(ex); }
diff --git a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-iframe.html b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-iframe.html index 085d612..e814b4c 100644 --- a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-iframe.html +++ b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm-iframe.html
@@ -2,7 +2,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script type="module"> -import {request_options_with_mediation_required} from './fedcm-helper.sub.js'; +import {request_options_with_mediation_required, + fedcm_get_and_select_first_account} from './fedcm-helper.sub.js'; // Loading fedcm-iframe.html in the test will make a FedCM call on load, and // trigger a postMessage upon completion. @@ -18,19 +19,7 @@ // Use this variable to stop trying to select an account once the get() promise is resolved. let cancelHelper = false; try { - const credentialPromise = navigator.credentials.get(request_options_with_mediation_required()); - async function helper() { - try { - if (cancelHelper) - return; - - await window.test_driver.select_fedcm_account(0); - } catch (ex) { - setTimeout(helper, 100); - } - } - helper(); - const cred = await credentialPromise; + const cred = await fedcm_get_and_select_first_account(null, request_options_with_mediation_required()); window.top.postMessage({result: "Pass", token: cred.token}, '*'); } catch (error) { window.top.postMessage({result: "Fail", errorType: error.name}, '*');
diff --git a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm/disconnect-iframe.html b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm/disconnect-iframe.html index ae97011a..acead807 100644 --- a/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm/disconnect-iframe.html +++ b/third_party/blink/web_tests/external/wpt/fedcm/support/fedcm/disconnect-iframe.html
@@ -4,7 +4,9 @@ <script type="module"> import {disconnect_options, request_options_with_mediation_required, - set_fedcm_cookie, manifest_origin} from './../fedcm-helper.sub.js'; + set_fedcm_cookie, + manifest_origin, + fedcm_get_and_select_first_account} from './../fedcm-helper.sub.js'; // Loading this iframe in the test will make a FedCM call on load, and // trigger a postMessage upon completion. @@ -35,19 +37,7 @@ // promise is resolved. let cancelHelper = false; try { - const credentialPromise = navigator.credentials.get(request_options_with_mediation_required()); - async function helper() { - try { - if (cancelHelper) - return; - - await window.test_driver.select_fedcm_account(0); - } catch (ex) { - setTimeout(helper, 100); - } - } - helper(); - const cred = await credentialPromise; + await fedcm_get_and_select_first_account(null, request_options_with_mediation_required()); await set_fedcm_cookie(manifest_origin); // Now that we have a get(), attempt to disconnect permission. attemptDisconnect();
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window-expected.txt index df0a946..8ec6107 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] The 2nd fetchLater(same-origin) call in the top-level document is not allowed to exceed per-origin quota for its POST body of String. - assert_throws_dom: function "() => {\n fetchLater(requestUrl, {\n method: 'POST',\n signal: controller.signal,\n body: makeBeaconData(generatePayload(quota), dataType),\n // Required, as the size of referrer also take up quota.\n referrer: '',\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65536 bytes, expected less than 32734 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater(requestUrl, {\n method: 'POST',\n signal: controller.signal,\n body: makeBeaconData(generatePayload(quota), dataType),\n // Required, as the size of referrer also take up quota.\n referrer: '',\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65536 bytes, expected less than 32734 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js index 6439b39..143546f 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js
@@ -37,7 +37,7 @@ // Makes the 2nd call (POST) to the same reporting origin that sends // max bytes, which should be rejected. - assert_throws_dom('QuotaExceededError', () => { + assert_throws_quotaexceedederror(() => { fetchLater(requestUrl, { method: 'POST', signal: controller.signal, @@ -45,7 +45,7 @@ // Required, as the size of referrer also take up quota. referrer: '', }); - }); + }, null, null); // Makes the 3rd call (GET) to the same reporting origin, where its // request size is len(requestUrl) + headers, which should be accepted.
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js index 84570607..aa797f13 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js
@@ -36,13 +36,14 @@ test(_ => { const uuid = token(); const requestUrl = generateSetBeaconURL(uuid, {host: HTTPS_ORIGIN}); - assert_throws_dom( - 'QuotaExceededError', - () => fetchLater(requestUrl, { - activateAfter: 0, - method: 'POST', - body: generatePayload( - getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1, - dataType), - })); + + assert_throws_quotaexceedederror(() => { + fetchLater(requestUrl, { + activateAfter: 0, + method: 'POST', + body: generatePayload( + getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1, + dataType), + }); + }, null, null); }, `fetchLater() rejects max+1 payload in a POST request body of ${dataType}.`);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window-expected.txt index f37e984e..4f68d94 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window-expected.txt
@@ -1,15 +1,15 @@ This is a testharness.js-based test. [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of String. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65616 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65616 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of ArrayBuffer. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65580 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65580 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of FormData. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65798 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65798 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of URLSearchParams. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65649 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65649 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of Blob. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65580 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65580 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 [FAIL] fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of File. - assert_throws_dom: function "() => fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65602 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n fetchLater('/', {\n activateAfter: 0,\n method: 'POST',\n body: makeBeaconData(\n generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),\n });\n }" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65602 bytes, expected less than 65536 bytes." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js index 0036d04..740f17e 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js
@@ -9,16 +9,16 @@ for (const dataType in BeaconDataType) { // Test making a POST request with oversized payload, which should be rejected // by fetchLater API. - test( - () => assert_throws_dom( - 'QuotaExceededError', - () => fetchLater('/', { - activateAfter: 0, - method: 'POST', - body: makeBeaconData( - generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType), - })), - `fetchLater() does not accept payload[size=${ + test(() => { + assert_throws_quotaexceedederror(() => { + fetchLater('/', { + activateAfter: 0, + method: 'POST', + body: makeBeaconData( + generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType), + }); + }, null, null); + }, `fetchLater() does not accept payload[size=${ OVERSIZED_REQUEST_BODY_SIZE}] exceeding per-origin quota in a POST request body of ${ dataType}.`); }
diff --git a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/resources/fetch-later.html b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/resources/fetch-later.html index 955f815d..b295be11 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/fetch-later/resources/fetch-later.html +++ b/third_party/blink/web_tests/external/wpt/fetch/fetch-later/resources/fetch-later.html
@@ -30,12 +30,6 @@ fetchLater(TARGET_URL, REQUEST_INIT); postMessageBack({type: FetchLaterIframeMessageType.DONE}); } catch (e) { - if (e.name == "QuotaExceededError" && - e instanceof DOMException) { - // PostMessage is unable to serialize the QuotExceededError object. - // Therefore do basic checks here and pass error name if successful. - e = {name: e.name}; - } postMessageBack({type: FetchLaterIframeMessageType.ERROR, error: e}); } </script>
diff --git a/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any-expected.txt index 6c8aec5..18df667 100644 --- a/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] Bucket quota restricts the size of a file that can be created - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError: The operation failed because it would cause the application to exceed its storage quota." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + promise_rejects_quotaexceedederror: function "function() { throw e; }" threw object "QuotaExceededError: The operation failed because it would cause the application to exceed its storage quota." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any.worker-expected.txt index 6c8aec5..18df667 100644 --- a/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/fs/FileSystemBaseHandle-buckets.https.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] Bucket quota restricts the size of a file that can be created - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError: The operation failed because it would cause the application to exceed its storage quota." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + promise_rejects_quotaexceedederror: function "function() { throw e; }" threw object "QuotaExceededError: The operation failed because it would cause the application to exceed its storage quota." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-buckets.js b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-buckets.js index 9654755..c67cb1de 100644 --- a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-buckets.js +++ b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-buckets.js
@@ -34,10 +34,12 @@ await createFileWithContents('mtime.txt', 'short file', inboxRootDir); // Longer file fails. - return promise_rejects_dom( - t, 'QuotaExceededError', - createFileWithContents( + return promise_rejects_quotaexceedederror( + t, + createFileWithContents( 'mtime2.txt', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', - inboxRootDir)); + inboxRootDir + ), + null, null); }, 'Bucket quota restricts the size of a file that can be created');
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.1.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.1.html new file mode 100644 index 0000000..a192201 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.1.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>Canvas test: 2d.path.clip.winding.evenodd.1</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.path.clip.winding.evenodd.1</h1> +<p class="desc">evenodd winding number rule works in clip</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("evenodd winding number rule works in clip"); +_addTest(function(canvas, ctx) { + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.clip("evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.2.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.2.html new file mode 100644 index 0000000..e5aeba4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.clip.winding.evenodd.2.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>Canvas test: 2d.path.clip.winding.evenodd.2</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.path.clip.winding.evenodd.2</h1> +<p class="desc">evenodd winding number rule works in clip</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("evenodd winding number rule works in clip"); +_addTest(function(canvas, ctx) { + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.clip(path, "evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.1.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.1.html new file mode 100644 index 0000000..d030b932 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.1.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>Canvas test: 2d.path.fill.winding.evenodd.1</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.path.fill.winding.evenodd.1</h1> +<p class="desc">evenodd winding number rule works in fill</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("evenodd winding number rule works in fill"); +_addTest(function(canvas, ctx) { + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.fill("evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.2.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.2.html new file mode 100644 index 0000000..4553f29d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/path-objects/2d.path.fill.winding.evenodd.2.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>Canvas test: 2d.path.fill.winding.evenodd.2</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.path.fill.winding.evenodd.2</h1> +<p class="desc">evenodd winding number rule works in fill</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("evenodd winding number rule works in fill"); +_addTest(function(canvas, ctx) { + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.fill(path, "evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.html new file mode 100644 index 0000000..4cf680f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>OffscreenCanvas test: 2d.path.clip.winding.evenodd.1</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<h1>2d.path.clip.winding.evenodd.1</h1> +<p class="desc">evenodd winding number rule works in clip</p> + + +<script> +var t = async_test("evenodd winding number rule works in clip"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.clip("evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); + +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.worker.js new file mode 100644 index 0000000..da772ea --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.1.worker.js
@@ -0,0 +1,33 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.path.clip.winding.evenodd.1 +// Description:evenodd winding number rule works in clip +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("evenodd winding number rule works in clip"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.clip("evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); +}); +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.html new file mode 100644 index 0000000..6d47707 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>OffscreenCanvas test: 2d.path.clip.winding.evenodd.2</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<h1>2d.path.clip.winding.evenodd.2</h1> +<p class="desc">evenodd winding number rule works in clip</p> + + +<script> +var t = async_test("evenodd winding number rule works in clip"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.clip(path, "evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); + +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.worker.js new file mode 100644 index 0000000..23f626e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.clip.winding.evenodd.2.worker.js
@@ -0,0 +1,34 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.path.clip.winding.evenodd.2 +// Description:evenodd winding number rule works in clip +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("evenodd winding number rule works in clip"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.clip(path, "evenodd"); + ctx.fillRect(0, 0, 100, 50); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); +}); +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.html new file mode 100644 index 0000000..fc839c9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>OffscreenCanvas test: 2d.path.fill.winding.evenodd.1</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<h1>2d.path.fill.winding.evenodd.1</h1> +<p class="desc">evenodd winding number rule works in fill</p> + + +<script> +var t = async_test("evenodd winding number rule works in fill"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.fill("evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); + +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.worker.js new file mode 100644 index 0000000..64e1aa1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.1.worker.js
@@ -0,0 +1,32 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.path.fill.winding.evenodd.1 +// Description:evenodd winding number rule works in fill +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("evenodd winding number rule works in fill"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.fill("evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); +}); +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.html new file mode 100644 index 0000000..acb7053 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<meta charset="UTF-8"> +<title>OffscreenCanvas test: 2d.path.fill.winding.evenodd.2</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<h1>2d.path.fill.winding.evenodd.2</h1> +<p class="desc">evenodd winding number rule works in fill</p> + + +<script> +var t = async_test("evenodd winding number rule works in fill"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.fill(path, "evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); + +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.worker.js new file mode 100644 index 0000000..1a69f46 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/path-objects/2d.path.fill.winding.evenodd.2.worker.js
@@ -0,0 +1,33 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.path.fill.winding.evenodd.2 +// Description:evenodd winding number rule works in fill +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("evenodd winding number rule works in fill"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + + var canvas = new OffscreenCanvas(100, 50); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.fill(path, "evenodd"); + + _assertPixel(canvas, 50,25, 0,255,0,255); + t.done(); +}); +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/path-objects.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/path-objects.yaml index cf218829..ccb3d79b 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/path-objects.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/path-objects.yaml
@@ -2479,6 +2479,37 @@ cr.rectangle(0, 0, 100, 50) cr.fill() +- name: 2d.path.fill.winding.evenodd.1 + desc: evenodd winding number rule works in fill + code: | + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.fill("evenodd"); + + @assert pixel 50,25 == 0,255,0,255; + +- name: 2d.path.fill.winding.evenodd.2 + desc: evenodd winding number rule works in fill + code: | + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.fill(path, "evenodd"); + + @assert pixel 50,25 == 0,255,0,255; + - name: 2d.path.fill.winding.add code: | ctx.fillStyle = '#f00'; @@ -3046,6 +3077,39 @@ @assert pixel 50,25 == 0,255,0,255; expected: green +- name: 2d.path.clip.winding.evenodd.1 + desc: evenodd winding number rule works in clip + code: | + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + ctx.beginPath(); + ctx.rect(0, 0, 100, 50); + ctx.rect(0, 0, 100, 50); + + ctx.fillStyle = "#f00"; + ctx.clip("evenodd"); + ctx.fillRect(0, 0, 100, 50); + + @assert pixel 50,25 == 0,255,0,255; + +- name: 2d.path.clip.winding.evenodd.2 + desc: evenodd winding number rule works in clip + code: | + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + + let path = new Path2D(); + path.rect(0, 0, 100, 50); + path.rect(0, 0, 100, 50); + path.closePath(); + + ctx.fillStyle = "#f00"; + ctx.clip(path, "evenodd"); + ctx.fillRect(0, 0, 100, 50); + + @assert pixel 50,25 == 0,255,0,255; + - name: 2d.path.clip.winding.1 code: | ctx.fillStyle = '#0f0';
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt index be47723..07cd37b 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window-expected.txt
@@ -1,11 +1,11 @@ This is a testharness.js-based test. [FAIL] web API-created DOMException (structuredClone()) - assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2684:25)\\n at test (http://web-platform.test:8001/resources/testharness.js:633:30)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:41:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2869:25)\\n at test (http://web-platform.test:8001/resources/testharness.js:633:30)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:40:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (worker) - assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:53:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2684:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:52:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:53:19)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2869:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:52:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (cross-site iframe) - assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:99:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2684:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:96:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:99:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2869:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:96:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined [FAIL] web API-created DOMException (same-origin iframe) - assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:104:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2684:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:102:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined + assert_equals: expected (string) "InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:33:14\\n at iframeTest (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:72:19)\\n at Test.<anonymous> (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:104:5)\\n at Test.step (http://web-platform.test:8001/resources/testharness.js:2869:25)\\n at async_test (http://web-platform.test:8001/resources/testharness.js:681:34)\\n at stackTests (http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:102:3)\\n at http://web-platform.test:8001/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js:31:1" but got (undefined) undefined Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub-expected.txt b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub-expected.txt new file mode 100644 index 0000000..68de27d4c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Speculative parsing, document.write(): script-src-event-handler + Unhandled rejection: assert_equals: speculative case incorrectly fetched expected "" but got "param-encodingcheck: %C4%9E\\r\\nAccept: */*\\r\\nReferer: http://web-platform.test:8001/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub.html" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub.html similarity index 75% copy from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html copy to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub.html index 1eaa564..3466605 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-event-handler.sub.html
@@ -3,7 +3,7 @@ /html/syntax/speculative-parsing/tools/generate.py --> <meta charset=utf-8> -<title>Speculative parsing, document.write(): script-src-unsupported-type</title> +<title>Speculative parsing, document.write(): script-src-event-handler</title> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> <script src=/common/utils.js></script> @@ -12,7 +12,7 @@ setup({single_test: true}); const uuid = token(); expect_fetched_onload(uuid, false) - .then(compare_with_nonspeculative(uuid, 'script-src-unsupported-type', true)) + .then(compare_with_nonspeculative(uuid, 'script-src-event-handler', false)) .then(done); document.write(` <script src="/common/slow.py?delay=1500"><\/script> @@ -20,6 +20,6 @@ document.write('<plaintext>'); <\/script> <\!-- speculative case in document.write --> - <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" type=text/plain><\/script> + <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" event="" for=""><\/script> `); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-nomodule.tentative.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-nomodule.sub.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-nomodule.tentative.sub.html rename to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-nomodule.sub.html
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-language.sub.html similarity index 86% copy from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html copy to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-language.sub.html index 1eaa564..e418c0e 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-language.sub.html
@@ -3,7 +3,7 @@ /html/syntax/speculative-parsing/tools/generate.py --> <meta charset=utf-8> -<title>Speculative parsing, document.write(): script-src-unsupported-type</title> +<title>Speculative parsing, document.write(): script-src-unsupported-language</title> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> <script src=/common/utils.js></script> @@ -12,7 +12,7 @@ setup({single_test: true}); const uuid = token(); expect_fetched_onload(uuid, false) - .then(compare_with_nonspeculative(uuid, 'script-src-unsupported-type', true)) + .then(compare_with_nonspeculative(uuid, 'script-src-unsupported-language', false)) .then(done); document.write(` <script src="/common/slow.py?delay=1500"><\/script> @@ -20,6 +20,6 @@ document.write('<plaintext>'); <\/script> <\!-- speculative case in document.write --> - <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" type=text/plain><\/script> + <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" language="vbscript"><\/script> `); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.sub.html similarity index 97% rename from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html rename to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.sub.html index 1eaa564..665e7ab 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/document-write/script-src-unsupported-type.sub.html
@@ -20,6 +20,6 @@ document.write('<plaintext>'); <\/script> <\!-- speculative case in document.write --> - <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" type=text/plain><\/script> + <script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid=${uuid}&encodingcheck=Ğ" type="text/plain"><\/script> `); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-event-handler-framed.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-event-handler-framed.sub.html new file mode 100644 index 0000000..7b9e0ed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-event-handler-framed.sub.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT. This file has been generated. Source: + /html/syntax/speculative-parsing/tools/generate.py +--> +<meta charset=utf-8> +<title>Speculative parsing, page load (helper file): script-src-event-handler</title> +<script src="/common/slow.py?delay=1500"></script> +<script> + document.write('<plaintext>'); +</script> +<!-- speculative case --> +<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" event="" for=""></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-language-framed.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-language-framed.sub.html new file mode 100644 index 0000000..62b2c4c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-language-framed.sub.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT. This file has been generated. Source: + /html/syntax/speculative-parsing/tools/generate.py +--> +<meta charset=utf-8> +<title>Speculative parsing, page load (helper file): script-src-unsupported-language</title> +<script src="/common/slow.py?delay=1500"></script> +<script> + document.write('<plaintext>'); +</script> +<!-- speculative case --> +<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" language="vbscript"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-type-framed.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-type-framed.sub.html index 1f38560..78e7194 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-type-framed.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/resources/script-src-unsupported-type-framed.sub.html
@@ -9,4 +9,4 @@ document.write('<plaintext>'); </script> <!-- speculative case --> -<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" type=text/plain></script> +<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" type="text/plain"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-event-handler.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-event-handler.html new file mode 100644 index 0000000..6bb89bd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-event-handler.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT. This file has been generated. Source: + /html/syntax/speculative-parsing/tools/generate.py +--> +<meta charset=utf-8> +<title>Speculative parsing, page load: script-src-event-handler</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<script src=/html/syntax/speculative-parsing/resources/speculative-parsing-util.js></script> +<body> +<script> + setup({single_test: true}); + const uuid = token(); + const iframe = document.createElement('iframe'); + iframe.src = `resources/script-src-event-handler-framed.sub.html?uuid=${uuid}`; + document.body.appendChild(iframe); + expect_fetched_onload(uuid, false) + .then(compare_with_nonspeculative(uuid, 'script-src-event-handler', false)) + .then(done); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-nomodule.tentative.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-nomodule.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-nomodule.tentative.html rename to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-nomodule.html
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-language.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-language.html new file mode 100644 index 0000000..60f50eb34 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-language.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT. This file has been generated. Source: + /html/syntax/speculative-parsing/tools/generate.py +--> +<meta charset=utf-8> +<title>Speculative parsing, page load: script-src-unsupported-language</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<script src=/html/syntax/speculative-parsing/resources/speculative-parsing-util.js></script> +<body> +<script> + setup({single_test: true}); + const uuid = token(); + const iframe = document.createElement('iframe'); + iframe.src = `resources/script-src-unsupported-language-framed.sub.html?uuid=${uuid}`; + document.body.appendChild(iframe); + expect_fetched_onload(uuid, false) + .then(compare_with_nonspeculative(uuid, 'script-src-unsupported-language', false)) + .then(done); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-type.tentative.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-type.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-type.tentative.html rename to third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/page-load/script-src-unsupported-type.html
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/resources/script-src-unsupported-type-nonspeculative.sub.html b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/resources/script-src-unsupported-type-nonspeculative.sub.html index 94098b5..dc8343c 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/resources/script-src-unsupported-type-nonspeculative.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/generated/resources/script-src-unsupported-type-nonspeculative.sub.html
@@ -5,6 +5,6 @@ <meta charset=utf-8> <title>Speculative parsing, non-speculative (helper file): script-src-unsupported-type</title> <!-- non-speculative case --> -<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" type=text/plain></script> +<script src="/html/syntax/speculative-parsing/resources/stash.py?action=put&uuid={{GET[uuid]}}&encodingcheck=Ğ" type="text/plain"></script> <!-- block the load event for a bit: --> <script src="/common/slow.py?delay=1500"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/tools/generate.py b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/tools/generate.py index f0db885..b3b577d9 100755 --- a/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/tools/generate.py +++ b/third_party/blink/web_tests/external/wpt/html/syntax/speculative-parsing/tools/generate.py
@@ -89,14 +89,6 @@ u'true' ), ( - u'script-src-unsupported-type', - u'utf-8', - u'<script src="{}" type=text/plain></script>', - None, - u'false', - u'true' - ), - ( u'script-src-type-application-ecmascript', u'utf-8', u'<script src="{}" type=application/ecmascript></script>', @@ -105,14 +97,6 @@ u'true' ), ( - u'script-src-nomodule', - u'utf-8', - u'<script src="{}" nomodule></script>', - None, - u'false', - u'true' - ), - ( u'script-src-module', u'utf-8', u'<script src="{}" type=module></script>', @@ -526,6 +510,38 @@ # template_testcase_markup, # expect_load, # test_nonspeculative + ( + u'script-src-unsupported-type', + u'utf-8', + u'<script src="{}" type="text/plain"></script>', + None, + u'false', + u'true' + ), + ( + u'script-src-unsupported-language', + u'utf-8', + u'<script src="{}" language="vbscript"></script>', + None, + u'false', + u'false' + ), + ( + u'script-src-nomodule', + u'utf-8', + u'<script src="{}" nomodule></script>', + None, + u'false', + u'true' + ), + ( + u'script-src-event-handler', + u'utf-8', + u'<script src="{}" event="" for=""></script>', + None, + u'false', + u'false' + ), ] # Templates
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/cookie-store.idl b/third_party/blink/web_tests/external/wpt/interfaces/cookiestore.idl similarity index 97% rename from third_party/blink/web_tests/external/wpt/interfaces/cookie-store.idl rename to third_party/blink/web_tests/external/wpt/interfaces/cookiestore.idl index 8a000ca..ecb2777 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/cookie-store.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/cookiestore.idl
@@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: Cookie Store API (https://wicg.github.io/cookie-store/) +// Source: Cookie Store API (https://cookiestore.spec.whatwg.org/) [Exposed=(ServiceWorker,Window), SecureContext]
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index 75a2004..5571f01 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -171,6 +171,7 @@ SET TIMEOUT: encrypted-media/polyfill/chrome-polyfill.js SET TIMEOUT: encrypted-media/polyfill/clearkey-polyfill.js SET TIMEOUT: encrypted-media/scripts/playback-temporary-events.js +SET TIMEOUT: fedcm/support/fedcm-helper.sub.js SET TIMEOUT: fedcm/support/fedcm-iframe.html SET TIMEOUT: fedcm/support/fedcm/disconnect-iframe.html SET TIMEOUT: fedcm/support/login_delay.html
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-appendbuffer-quota-exceeded.html b/third_party/blink/web_tests/external/wpt/media-source/mediasource-appendbuffer-quota-exceeded.html index c90d844..470ee7211 100644 --- a/third_party/blink/web_tests/external/wpt/media-source/mediasource-appendbuffer-quota-exceeded.html +++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-appendbuffer-quota-exceeded.html
@@ -46,7 +46,10 @@ sourceBuffer.appendBuffer(dataAudio); }, function (ex, previousBufferedStart, previousBufferedEnd) { // onCaughtExceptionCallback - assert_equals(ex.name, 'QuotaExceededError'); + assert_equals(ex.constructor, globalThis.QuotaExceededError, 'QuotaExceededError constructor match'); + assert_equals(ex.quota, null, 'quota'); + assert_equals(ex.requested, null, 'requested'); + // Verify that the state looks like appendBuffer stops executing its steps if the prepare append // algorithm aborts after throwing `QuotaExceededError`.
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js index b5847ed..f495b624 100644 --- a/third_party/blink/web_tests/external/wpt/resources/testharness.js +++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -867,6 +867,54 @@ }); } +/** + * Assert that a `Promise` is rejected with a `QuotaExceededError` with the + * expected values. + * + * For the remaining arguments, there are two ways of calling + * `promise_rejects_quotaexceedederror`: + * + * 1) If the `QuotaExceededError` is expected to come from the + * current global, the second argument should be the promise + * expected to reject, the third and a fourth the expected + * `requested` and `quota` property values, and the fifth, + * optional, argument is the assertion description. + * + * 2) If the `QuotaExceededError` is expected to come from some + * other global, the second argument should be the + * `QuotaExceededError` constructor from that global, the third + * argument should be the promise expected to reject, the fourth + * and fifth the expected `requested` and `quota` property + * values, and the sixth, optional, argument is the assertion + * description. + * + */ + function promise_rejects_quotaexceedederror(test, promiseOrConstructor, requestedOrPromise, quotaOrRequested, descriptionOrQuota, maybeDescription) + { + let constructor, promise, requested, quota, description; + if (typeof promiseOrConstructor === "function" && + promiseOrConstructor.name === "QuotaExceededError") { + constructor = promiseOrConstructor; + promise = requestedOrPromise; + requested = quotaOrRequested; + quota = descriptionOrQuota; + description = maybeDescription; + } else { + constructor = self.QuotaExceededError; + promise = promiseOrConstructor; + requested = requestedOrPromise; + quota = quotaOrRequested; + description = descriptionOrQuota; + assert(maybeDescription === undefined, + "Too many args passed to no-constructor version of promise_rejects_quotaexceedederror"); + } + return bring_promise_to_current_realm(promise) + .then(test.unreached_func("Should have rejected: " + description)) + .catch(function(e) { + assert_throws_quotaexceedederror_impl(function() { throw e; }, requested, quota, description, "promise_rejects_quotaexceedederror", constructor); + }); + } + /** * Assert that a Promise is rejected with the provided value. * @@ -1240,6 +1288,7 @@ expose(promise_test, 'promise_test'); expose(promise_rejects_js, 'promise_rejects_js'); expose(promise_rejects_dom, 'promise_rejects_dom'); + expose(promise_rejects_quotaexceedederror, 'promise_rejects_quotaexceedederror'); expose(promise_rejects_exactly, 'promise_rejects_exactly'); expose(generate_tests, 'generate_tests'); expose(setup, 'setup'); @@ -2296,7 +2345,6 @@ NETWORK_ERR: 'NetworkError', ABORT_ERR: 'AbortError', URL_MISMATCH_ERR: 'URLMismatchError', - QUOTA_EXCEEDED_ERR: 'QuotaExceededError', TIMEOUT_ERR: 'TimeoutError', INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError', DATA_CLONE_ERR: 'DataCloneError' @@ -2321,7 +2369,6 @@ NetworkError: 19, AbortError: 20, URLMismatchError: 21, - QuotaExceededError: 22, TimeoutError: 23, InvalidNodeTypeError: 24, DataCloneError: 25, @@ -2352,12 +2399,19 @@ if (typeof type === "number") { if (type === 0) { throw new AssertionError('Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()'); - } else if (!(type in code_name_map)) { + } + if (type === 22) { + throw new AssertionError('Test bug: QuotaExceededError needs to be tested for using assert_throws_quotaexceedederror()'); + } + if (!(type in code_name_map)) { throw new AssertionError('Test bug: unrecognized DOMException code "' + type + '" passed to assert_throws_dom()'); } name = code_name_map[type]; required_props.code = type; } else if (typeof type === "string") { + if (name === "QuotaExceededError") { + throw new AssertionError('Test bug: QuotaExceededError needs to be tested for using assert_throws_quotaexceedederror()'); + } name = type in codename_name_map ? codename_name_map[type] : type; if (!(name in name_code_map)) { throw new AssertionError('Test bug: unrecognized DOMException code name or name "' + type + '" passed to assert_throws_dom()'); @@ -2393,6 +2447,137 @@ } /** + * Assert a `QuotaExceededError` with the expected values is thrown. + * + * There are two ways of calling `assert_throws_quotaexceedederror`: + * + * 1) If the `QuotaExceededError` is expected to come from the + * current global, the first argument should be the function + * expected to throw, the second and a third the expected + * `requested` and `quota` property values, and the fourth, + * optional, argument is the assertion description. + * + * 2) If the `QuotaExceededError` is expected to come from some + * other global, the first argument should be the + * `QuotaExceededError` constructor from that global, the second + * argument should be the function expected to throw, the third + * and fourth the expected `requested` and `quota` property + * values, and the fifth, optional, argument is the assertion + * description. + * + * For the `requested` and `quota` values, instead of `null` or a + * number, the caller can provide a function which determines + * whether the value is acceptable by returning a boolean. + * + */ + function assert_throws_quotaexceedederror(funcOrConstructor, requestedOrFunc, quotaOrRequested, descriptionOrQuota, maybeDescription) + { + let constructor, func, requested, quota, description; + if (funcOrConstructor.name === "QuotaExceededError") { + constructor = funcOrConstructor; + func = requestedOrFunc; + requested = quotaOrRequested; + quota = descriptionOrQuota; + description = maybeDescription; + } else { + constructor = self.QuotaExceededError; + func = funcOrConstructor; + requested = requestedOrFunc; + quota = quotaOrRequested; + description = descriptionOrQuota; + assert(maybeDescription === undefined, + "Too many args passed to no-constructor version of assert_throws_quotaexceedederror"); + } + assert_throws_quotaexceedederror_impl(func, requested, quota, description, "assert_throws_quotaexceedederror", constructor); + } + expose_assert(assert_throws_quotaexceedederror, "assert_throws_quotaexceedederror"); + + /** + * Similar to `assert_throws_quotaexceedederror` but allows + * specifying the assertion type + * (`"assert_throws_quotaexceedederror"` or + * `"promise_rejects_quotaexceedederror"`, in practice). The + * `constructor` argument must be the `QuotaExceededError` + * constructor from the global we expect the exception to come from. + */ + function assert_throws_quotaexceedederror_impl(func, requested, quota, description, assertion_type, constructor) + { + try { + func.call(this); + assert(false, assertion_type, description, "${func} did not throw", + {func}); + } catch (e) { + if (e instanceof AssertionError) { + throw e; + } + + // Basic sanity-checks on the thrown exception. + assert(typeof e === "object", + assertion_type, description, + "${func} threw ${e} with type ${type}, not an object", + {func, e, type:typeof e}); + + assert(e !== null, + assertion_type, description, + "${func} threw null, not an object", + {func}); + + // Sanity-check our requested and quota. + assert(requested === null || + typeof requested === "number" || + typeof requested === "function", + assertion_type, description, + "${requested} is not null, a number, or a function", + {requested}); + assert(quota === null || + typeof quota === "number" || + typeof quota === "function", + assertion_type, description, + "${quota} is not null or a number", + {quota}); + + const required_props = { + code: 22, + name: "QuotaExceededError" + }; + if (typeof requested !== "function") { + required_props.requested = requested; + } + if (typeof quota !== "function") { + required_props.quota = quota; + } + + for (const [prop, expected] of Object.entries(required_props)) { + assert(prop in e && e[prop] == expected, + assertion_type, description, + "${func} threw ${e} that is not a correct QuotaExceededError: property ${prop} is equal to ${actual}, expected ${expected}", + {func, e, prop, actual:e[prop], expected}); + } + + if (typeof requested === "function") { + assert(requested(e.requested), + assertion_type, description, + "${func} threw ${e} that is not a correct QuotaExceededError: requested value ${requested} did not pass the requested predicate", + {func, e, requested}); + } + if (typeof quota === "function") { + assert(quota(e.quota), + assertion_type, description, + "${func} threw ${e} that is not a correct QuotaExceededError: quota value ${quota} did not pass the quota predicate", + {func, e, quota}); + } + + // Check that the exception is from the right global. This check is last + // so more specific, and more informative, checks on the properties can + // happen in case a totally incorrect exception is thrown. + assert(e.constructor === constructor, + assertion_type, description, + "${func} threw an exception from the wrong global", + {func}); + } + } + + /** * Assert the provided value is thrown. * * @param {value} exception The expected exception.
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/video-srcObject-change.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/video-srcObject-change.html new file mode 100644 index 0000000..2d25164 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/video-srcObject-change.html
@@ -0,0 +1,77 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<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> +<script src="/media-source/dedicated-worker/mediasource-message-util.js"></script> +<script src="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script> + +<button id="navigateButton">Click here!</button> +<video id="testVideo" style="height:500px;width:500px"></img> + +<script> + // Based on /media-source/dedicated-worker/mediasource-worker-play.html. + promise_test(async t => { + // Fail fast if MSE-in-Workers is not supported. + assert_implements( + MediaSource.hasOwnProperty('canConstructInDedicatedWorker'), + 'MediaSource hasOwnProperty \'canConstructInDedicatedWorker\''); + assert_implements( + MediaSource.canConstructInDedicatedWorker, + 'MediaSource.canConstructInDedicatedWorker'); + + t.add_cleanup(() => { testVideo.srcObject = null; }); + + const url = '/video-srcobject-change-1'; + let worker; + + // Returns a promise that will be resolved with the MediaSource handle for + // the video. + function initVideoWorker() { + return new Promise(resolve => { + worker = new Worker('/media-source/dedicated-worker/mediasource-worker-play.js'); + worker.onerror = t.unreached_func('worker error'); + worker.onmessage = t.step_func(e => { + let subject = e.data.subject; + assert_true(subject != undefined, 'message must have a subject field'); + switch (subject) { + case messageSubject.ERROR: + assert_unreached('Worker error: ' + e.data.info); + break; + case messageSubject.HANDLE: + resolve(e.data.info); + break; + default: + assert_unreached('Unexpected message subject: ' + subject); + } + }); + }); + } + + navigateButton.addEventListener("click", async () => { + history.pushState({}, '', url); + let handle = await initVideoWorker(); + testVideo.srcObject = handle; + testVideo.play(); + }, {once: true}); + + const softNavPromise = SoftNavigationTestHelper.getPerformanceEntries( + /*type=*/ "soft-navigation", + /*include_soft_navigation_observations=*/ false, + /*min_num_entries=*/ 1, + ); + + if (test_driver) { + test_driver.click(navigateButton); + } + + const helper = new SoftNavigationTestHelper(t); + const entries = await helper.withTimeoutMessage( + softNavPromise, "Soft navigation entry never arrived.", 5000); + assert_equals(entries.length, 1, 'Expected exactly one soft navigation.'); + assert_true( + entries[0].name.endsWith(url), + 'Unexpected Soft Navigation URL.'); + }, 'Soft Navigation Detection supports HTMLVideoElment.srcObject'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/video-src-change.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/video-src-change.html new file mode 100644 index 0000000..9a37bdc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/video-src-change.html
@@ -0,0 +1,58 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<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> +<script src="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script> + +<button id="navigateButton">Click here!</button> +<video id="testVideo" src="/media/test.webm"></img> + +<script> + function waitForVideoRender() { + return new Promise(resolve => { + new PerformanceObserver((list, observer) => { + if (list.getEntries().filter((e) => e.id === 'testVideo').length) { + resolve(); + observer.disconnect(); + } + }).observe({type: 'largest-contentful-paint', buffered: true}); + }); + } + + async function runTest(t, url, newVideoSrc) { + navigateButton.addEventListener("click", () => { + history.pushState({}, '', url); + testVideo.src = newVideoSrc; + }, {once: true}); + + const softNavPromise = SoftNavigationTestHelper.getPerformanceEntries( + /*type=*/ "soft-navigation", + /*include_soft_navigation_observations=*/ false, + /*min_num_entries=*/ 1, + ); + + if (test_driver) { + test_driver.click(navigateButton); + } + + const helper = new SoftNavigationTestHelper(t); + const entries = await helper.withTimeoutMessage( + softNavPromise, "Soft navigation entry never arrived.", 5000); + assert_equals(entries.length, 1, 'Expected exactly one soft navigation.'); + assert_true( + entries[0].name.endsWith(url), + 'Unexpected Soft Navigation URL.'); + } + + // Wait for the video to initially load and make its way through the image + // timing pipeline before changing its source. + promise_setup(waitForVideoRender); + + promise_test(async t => { + const url = '/video-src-change-1'; + const src = '/media/A4.webm'; + return runTest(t, url, src); + }, 'Soft Navigation Detection supports HTMLVideoElment.src'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html index 2f02197f..3965284 100644 --- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html +++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/utils.js"></script> <script src="/common/dispatcher/dispatcher.js"></script> -<script src="/cookie-store/resources/cookie-test-helpers.js"></script> +<script src="/cookiestore/resources/cookie-test-helpers.js"></script> <script src="../resources/utils.js"></script> <script src="resources/utils.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any-expected.txt index 135a0f85..5daf616 100644 --- a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] IDB respects bucket quota - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError" that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + promise_rejects_quotaexceedederror: function "function() { throw e; }" threw object "QuotaExceededError" that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js index ee920277..9dc3455 100644 --- a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
@@ -17,6 +17,9 @@ await indexedDbOpenRequest(t, bucket.indexedDB, dbname, (db_to_upgrade) => { db_to_upgrade.createObjectStore(objectStoreName); }); + t.add_cleanup(() => { + db.close(); + }); const txn = db.transaction(objectStoreName, 'readwrite'); const buffer = new ArrayBuffer(arraySize); @@ -34,8 +37,5 @@ type: 'binary/random' }), 2); - await promise_rejects_dom( - t, 'QuotaExceededError', transactionPromise(txn)); - - db.close(); + await promise_rejects_quotaexceedederror(t, transactionPromise(txn), null, null); }, 'IDB respects bucket quota');
diff --git a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.worker-expected.txt index 135a0f85..5daf616 100644 --- a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] IDB respects bucket quota - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError" that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + promise_rejects_quotaexceedederror: function "function() { throw e; }" threw object "QuotaExceededError" that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content-expected.svg b/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content-expected.svg new file mode 100644 index 0000000..9e9b699 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content-expected.svg
@@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <image width="128" height="128" style="width:auto;height:auto" href="/images/green-256x256.png"/> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content.tentative.svg new file mode 100644 index 0000000..fc3f49375 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/image-sizing-min-content.tentative.svg
@@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in auto) as presentation attributes on image</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="image-sizing-min-content-expected.svg" /> + <image width="128" height="128" style="width:min-content;height:min-content" href="/images/green-256x256.png"/> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-auto.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-auto.tentative.svg new file mode 100644 index 0000000..21ebe5b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-auto.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in auto) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:auto;height:auto;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc-size.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc-size.tentative.svg new file mode 100644 index 0000000..1517f897 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc-size.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in calc-size) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:calc-size(fit-content, size);height:calc-size(fit-content, size);"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc.tentative.svg new file mode 100644 index 0000000..ba409e5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-calc.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in calc) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-expected.svg" /> + <svg style="width:calc(100% - 50px);height:calc(100% - 50px);"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-ems.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-ems.tentative.svg new file mode 100644 index 0000000..59574e6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-ems.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in Ems) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-expected.svg" /> + <svg font-size="2px" style="width:25em;height:25em;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-fit-content.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-fit-content.tentative.svg new file mode 100644 index 0000000..02678cdb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-fit-content.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in fit-content) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:fit-content;height:fit-content;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-full-circle-ref.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-full-circle-ref.svg new file mode 100644 index 0000000..f35ab0d4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-full-circle-ref.svg
@@ -0,0 +1,5 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> + <svg width="100" height="100"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-inherit.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-inherit.tentative.svg new file mode 100644 index 0000000..871ef77 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-inherit.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in inherit) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:inherit;height:inherit;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-initial.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-initial.tentative.svg new file mode 100644 index 0000000..65c6524 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-initial.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in initial) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:initial;height:initial;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-max-content.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-max-content.tentative.svg new file mode 100644 index 0000000..7650e40 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-max-content.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in max-content) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:max-content;height:max-content;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-min-content.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-min-content.tentative.svg new file mode 100644 index 0000000..871b66a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-min-content.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in min-content) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:min-content;height:min-content;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-percent.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-percent.tentative.svg new file mode 100644 index 0000000..150e4093 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-percent.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in min-content) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-expected.svg" /> + <svg style="width:50%;height:50%;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-rems.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-rems.tentative.svg new file mode 100644 index 0000000..44a5cb6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-rems.tentative.svg
@@ -0,0 +1,8 @@ +<svg font-size="2px" width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in Rems) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-expected.svg" /> + <svg style="width:25rem;height:25rem;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-stretch.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-stretch.tentative.svg new file mode 100644 index 0000000..f6fb4366 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-stretch.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in stretch) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-full-circle-ref.svg" /> + <svg width="50" height="50" style="width:stretch;height:stretch;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB-expected.html b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB-expected.html new file mode 100644 index 0000000..4f3762c5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB-expected.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<svg width="50vw" height="50vh" xmlns="http://www.w3.org/2000/svg"> + <svg width="50%" height="50%"> + <rect width="100%" height="100%" fill="green" /> + </svg> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB.tentative.html b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB.tentative.html new file mode 100644 index 0000000..a53911f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units-with-ICB.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Width and Height (in viewport units) as presentation attributes on nested svg</title> +<link rel="author" title="Divyansh Mangal" href="mailto:dmangal@microsoft.com"> +<link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"> +<link rel="match" href="nested-svg-sizing-viewport-units-with-ICB-expected.html"> + +<svg width="50vw" height="50vh" xmlns="http://www.w3.org/2000/svg"> + <svg style="width:50vw;height:50vh;"> + <rect width="100%" height="100%" fill="green" /> + </svg> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units.tentative.svg new file mode 100644 index 0000000..387e97c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/styling/nested-svg-sizing-viewport-units.tentative.svg
@@ -0,0 +1,8 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <title>Width and Height (in viewport units) as presentation attributes on nested svg</title> + <html:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute"/> + <html:link rel="match" href="nested-svg-sizing-expected.svg" /> + <svg style="width:50vw;height:50vh;"> + <circle cx="50" cy="50" r="40" fill="green" /> + </svg> +</svg> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/wasm/core/js/harness/testharness.js b/third_party/blink/web_tests/external/wpt/wasm/core/js/harness/testharness.js index 7c1ded2..ff96f572 100644 --- a/third_party/blink/web_tests/external/wpt/wasm/core/js/harness/testharness.js +++ b/third_party/blink/web_tests/external/wpt/wasm/core/js/harness/testharness.js
@@ -1210,7 +1210,6 @@ NETWORK_ERR: 'NetworkError', ABORT_ERR: 'AbortError', URL_MISMATCH_ERR: 'URLMismatchError', - QUOTA_EXCEEDED_ERR: 'QuotaExceededError', TIMEOUT_ERR: 'TimeoutError', INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError', DATA_CLONE_ERR: 'DataCloneError' @@ -1237,7 +1236,6 @@ NetworkError: 19, AbortError: 20, URLMismatchError: 21, - QuotaExceededError: 22, TimeoutError: 23, InvalidNodeTypeError: 24, DataCloneError: 25,
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/__init__.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid-expected.txt b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid-expected.txt new file mode 100644 index 0000000..22e10307 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid-expected.txt
@@ -0,0 +1,7 @@ +This is a wdspec test. +[FAIL] test_params_max_encoded_data_size_invalid_value[0] + Failed: DID NOT RAISE <class 'webdriver.bidi.error.InvalidArgumentException'> +[FAIL] test_params_max_encoded_data_size_exceeds_max_total_size + Failed: DID NOT RAISE <class 'webdriver.bidi.error.InvalidArgumentException'> +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid.py new file mode 100644 index 0000000..aa6a19e3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/add_data_collector/invalid.py
@@ -0,0 +1,152 @@ +import pytest +import webdriver.bidi.error as error + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.parametrize("value", [None, "foo", False, 42, {}]) +async def test_params_data_types_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=value, max_encoded_data_size=1000 + ) + + +async def test_params_data_types_empty_array(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=[], max_encoded_data_size=1000 + ) + + +@pytest.mark.parametrize("value", [None, False, 42, {}, []]) +async def test_params_data_types_entry_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=[value], max_encoded_data_size=1000 + ) + + +@pytest.mark.parametrize("value", ["foo", "request", "invalid"]) +async def test_params_data_types_entry_invalid_value(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=[value], max_encoded_data_size=1000 + ) + + +@pytest.mark.parametrize("value", [None, "foo", False, {}, []]) +async def test_params_max_encoded_data_size_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=value + ) + + +@pytest.mark.parametrize("value", [0, -1, -100]) +async def test_params_max_encoded_data_size_invalid_value(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=value + ) + + +async def test_params_max_encoded_data_size_exceeds_max_total_size(bidi_session): + # Use a very large value that should exceed the maximum total size + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=999999999999 + ) + + +# collectorType parameter tests +@pytest.mark.parametrize("value", [False, 42, {}, []]) +async def test_params_collector_type_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, collector_type=value + ) + + +@pytest.mark.parametrize("value", ["foo", "invalid", "stream"]) +async def test_params_collector_type_invalid_value(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, collector_type=value + ) + + +@pytest.mark.parametrize("value", [False, 42, {}, ""]) +async def test_params_contexts_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, contexts=value + ) + + +async def test_params_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, contexts=[] + ) + + +@pytest.mark.parametrize("value", [None, False, 42, {}, []]) +async def test_params_contexts_entry_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, contexts=[value] + ) + + +async def test_params_contexts_invalid_value(bidi_session): + with pytest.raises(error.NoSuchFrameException): + await bidi_session.network.add_data_collector( + data_types=["response"], + max_encoded_data_size=1000, + contexts=["does not exist"], + ) + + +@pytest.mark.parametrize("value", [False, 42, {}, ""]) +async def test_params_user_contexts_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, user_contexts=value + ) + + +async def test_params_user_contexts_empty_list(bidi_session): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, user_contexts=[] + ) + + +@pytest.mark.parametrize("value", [None, False, 42, {}, []]) +async def test_params_user_contexts_entry_invalid_type(bidi_session, value): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], max_encoded_data_size=1000, user_contexts=[value] + ) + + +async def test_params_user_contexts_invalid_value(bidi_session): + with pytest.raises(error.NoSuchUserContextException): + await bidi_session.network.add_data_collector( + data_types=["response"], + max_encoded_data_size=1000, + user_contexts=["does not exist"], + ) + + +async def test_params_contexts_and_user_contexts_mutually_exclusive( + bidi_session, new_tab +): + with pytest.raises(error.InvalidArgumentException): + await bidi_session.network.add_data_collector( + data_types=["response"], + max_encoded_data_size=1000, + contexts=[new_tab["context"]], + user_contexts=["default"], + )
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window-expected.txt b/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window-expected.txt index 46a5fb0..f2cce0c 100644 --- a/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] Throws QuotaExceededError when the quota has been exceeded - assert_throws_dom: function "function() {\n while (true) {\n index++;\n localStorage.setItem("" + key + index, "" + val + index);\n }\n }" threw object "QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'name5063' exceeded the quota." that is not a DOMException QUOTA_EXCEEDED_ERR: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n while (true) {\n index++;\n localStorage.setItem("" + key + index, "" + val + index);\n }\n }" threw object "QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'name5063' exceeded the quota." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window.js b/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window.js index fff7d6444..f2f3c4d 100644 --- a/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window.js +++ b/third_party/blink/web_tests/external/wpt/webstorage/storage_local_setitem_quotaexceedederr.window.js
@@ -1,16 +1,18 @@ -test(function() { +test(t => { localStorage.clear(); var index = 0; var key = "name"; var val = "x".repeat(1024); - assert_throws_dom("QUOTA_EXCEEDED_ERR", function() { + t.add_cleanup(() => { + localStorage.clear(); + }); + + assert_throws_quotaexceedederror(() => { while (true) { index++; localStorage.setItem("" + key + index, "" + val + index); } - }); - - localStorage.clear(); + }, null, null); }, "Throws QuotaExceededError when the quota has been exceeded");
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window-expected.txt b/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window-expected.txt index c5fe5ba6..c8301b46 100644 --- a/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] Throws QuotaExceededError when the quota has been exceeded - assert_throws_dom: function "function() {\n while (true) {\n index++;\n sessionStorage.setItem("" + key + index, "" + val + index);\n }\n }" threw object "QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'name5063' exceeded the quota." that is not a DOMException QUOTA_EXCEEDED_ERR: property "code" is equal to 0, expected 22 + assert_throws_quotaexceedederror: function "() => {\n while (true) {\n index++;\n sessionStorage.setItem("" + key + index, "" + val + index);\n }\n }" threw object "QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'name5063' exceeded the quota." that is not a correct QuotaExceededError: property "code" is equal to 0, expected 22 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window.js b/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window.js index 42a8954..693c98d 100644 --- a/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window.js +++ b/third_party/blink/web_tests/external/wpt/webstorage/storage_session_setitem_quotaexceedederr.window.js
@@ -1,16 +1,18 @@ -test(function() { +test(t => { sessionStorage.clear(); var index = 0; var key = "name"; var val = "x".repeat(1024); - assert_throws_dom("QUOTA_EXCEEDED_ERR", function() { + t.add_cleanup(() => { + sessionStorage.clear(); + }); + + assert_throws_quotaexceedederror(() => { while (true) { index++; sessionStorage.setItem("" + key + index, "" + val + index); } - }); - - sessionStorage.clear(); + }, null, null); }, "Throws QuotaExceededError when the quota has been exceeded");
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt index ec2ebcc9..dc752e2 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt
@@ -15,14 +15,15 @@ formatted-stack-frame devtools-link text-button link-style hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 (6) [1, empty × 2, 2, (...), empty] console-row-wrapper console-message @@ -48,14 +49,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 {a: 1} console-row-wrapper console-message @@ -77,14 +79,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 {str: '', nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} console-row-wrapper console-message @@ -114,14 +117,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 {null: null, undef: undefined, re: /^[regexp]$/g, constructedRe: /foo\/bar/, bool: false} console-row-wrapper console-message @@ -151,14 +155,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 Proxy(Object) {a: 1} console-row-wrapper console-message @@ -181,14 +186,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:32 HTMLAllCollection(4) [html, head, base, body] console-row-wrapper console-message @@ -217,14 +223,15 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text console-format-classes.js:36 (7) [Error: custom error with link www.chromium.org at test://evaluations/0/console-format-classes.j…, Array(6), {…}, {…}, {…}, Proxy(Object), HTMLAllCollection(4)] console-row-wrapper @@ -253,12 +260,13 @@ object-state-note info-note children hidden-stack-trace - monospace stack-preview-container width-constrained - stack-preview-container width-constrained - show-all-link - link - css-inserted-text - show-less-link - link - css-inserted-text + vbox flex-auto monospace stack-preview-container width-constrained + widget + stack-preview-container width-constrained + show-all-link + link + css-inserted-text + show-less-link + link + css-inserted-text
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry-expected.txt new file mode 100644 index 0000000..85a3c51 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry-expected.txt
@@ -0,0 +1,595 @@ +This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS masonry div. + +masonry-columns-container{ + "paths": [ + { + "path": [ + "M", + 8, + 8, + "L", + 508, + 8, + "L", + 508, + 148, + "L", + 8, + 148, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 508, + 8, + "L", + 508, + 148, + "L", + 8, + 148, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 508, + 8, + "L", + 508, + 148, + "L", + 8, + 148, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 508, + 8, + "L", + 508, + 148, + "L", + 8, + 148, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "showAccessibilityInfo": true, + "colorFormat": "hex", + "elementInfo": { + "tagName": "div", + "idValue": "masonry-columns-container", + "className": ".masonry-columns", + "nodeWidth": "500", + "nodeHeight": "140", + "isKeyboardFocusable": false, + "accessibleName": "", + "accessibleRole": "generic", + "layoutObjectName": "LayoutMasonry", + "showAccessibilityInfo": true + }, + "gridInfo": [ + { + "rotationAngle": 0, + "writingMode": "horizontal-tb", + "columns": [ + "M", + 8, + 8, + "L", + 8, + 148, + "M", + 58, + 148, + "L", + 58, + 8, + "M", + 68, + 8, + "L", + 68, + 148, + "M", + 168, + 148, + "L", + 168, + 8, + "M", + 178, + 8, + "L", + 178, + 148, + "M", + 328, + 148, + "L", + 328, + 8 + ], + "columnGaps": [ + "M", + 58, + 8, + "L", + 68, + 8, + "L", + 68, + 148, + "L", + 58, + 148, + "Z", + "M", + 168, + 8, + "L", + 178, + 8, + "L", + 178, + 148, + "L", + 168, + 148, + "Z" + ], + "rows": [], + "rowGaps": [], + "gridBorder": [], + "gridHighlightConfig": { + "gridBorderDash": false, + "rowLineDash": true, + "columnLineDash": true, + "showGridExtensionLines": true, + "showPositiveLineNumbers": true, + "showNegativeLineNumbers": true, + "showAreaNames": true, + "showLineNames": true, + "gridBorderColor": "rgba(255, 0, 0, 0)", + "rowLineColor": "rgba(128, 0, 0, 0)", + "columnLineColor": "rgba(128, 0, 0, 0)", + "rowGapColor": "rgba(0, 255, 0, 0)", + "columnGapColor": "rgba(0, 0, 255, 0)", + "rowHatchColor": "rgba(255, 255, 255, 0)", + "columnHatchColor": "rgba(128, 128, 128, 0)", + "areaBorderColor": "rgba(255, 0, 0, 0)", + "gridBackgroundColor": "rgba(255, 0, 0, 0)" + } + } + ] +} +masonry-rows-container{ + "paths": [ + { + "path": [ + "M", + 8, + 148, + "L", + 308, + 148, + "L", + 308, + 648, + "L", + 8, + 648, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 8, + 148, + "L", + 308, + 148, + "L", + 308, + 648, + "L", + 8, + 648, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 8, + 148, + "L", + 308, + 148, + "L", + 308, + 648, + "L", + 8, + 648, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 148, + "L", + 308, + 148, + "L", + 308, + 648, + "L", + 8, + 648, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "showAccessibilityInfo": true, + "colorFormat": "hex", + "elementInfo": { + "tagName": "div", + "idValue": "masonry-rows-container", + "className": ".masonry-rows", + "nodeWidth": "300", + "nodeHeight": "500", + "isKeyboardFocusable": false, + "accessibleName": "", + "accessibleRole": "generic", + "layoutObjectName": "LayoutMasonry", + "showAccessibilityInfo": true + }, + "gridInfo": [ + { + "rotationAngle": 0, + "writingMode": "horizontal-tb", + "columns": [], + "columnGaps": [], + "rows": [ + "M", + 8, + 148, + "L", + 308, + 148, + "M", + 308, + 248, + "L", + 8, + 248, + "M", + 8, + 268, + "L", + 308, + 268, + "M", + 308, + 298, + "L", + 8, + 298, + "M", + 8, + 318, + "L", + 308, + 318, + "M", + 308, + 368, + "L", + 8, + 368, + "M", + 8, + 388, + "L", + 308, + 388, + "M", + 308, + 418, + "L", + 8, + 418, + "M", + 8, + 438, + "L", + 308, + 438, + "M", + 308, + 488, + "L", + 8, + 488 + ], + "rowGaps": [ + "M", + 8, + 248, + "L", + 308, + 248, + "L", + 308, + 268, + "L", + 8, + 268, + "Z", + "M", + 8, + 298, + "L", + 308, + 298, + "L", + 308, + 318, + "L", + 8, + 318, + "Z", + "M", + 8, + 368, + "L", + 308, + 368, + "L", + 308, + 388, + "L", + 8, + 388, + "Z", + "M", + 8, + 418, + "L", + 308, + 418, + "L", + 308, + 438, + "L", + 8, + 438, + "Z" + ], + "gridBorder": [], + "gridHighlightConfig": { + "gridBorderDash": false, + "rowLineDash": true, + "columnLineDash": true, + "showGridExtensionLines": true, + "showPositiveLineNumbers": true, + "showNegativeLineNumbers": true, + "showAreaNames": true, + "showLineNames": true, + "gridBorderColor": "rgba(255, 0, 0, 0)", + "rowLineColor": "rgba(128, 0, 0, 0)", + "columnLineColor": "rgba(128, 0, 0, 0)", + "rowGapColor": "rgba(0, 255, 0, 0)", + "columnGapColor": "rgba(0, 0, 255, 0)", + "rowHatchColor": "rgba(255, 255, 255, 0)", + "columnHatchColor": "rgba(128, 128, 128, 0)", + "areaBorderColor": "rgba(255, 0, 0, 0)", + "gridBackgroundColor": "rgba(255, 0, 0, 0)" + } + } + ] +} +empty-masonry-container{ + "paths": [ + { + "path": [ + "M", + 8, + 648, + "L", + 208, + 648, + "L", + 208, + 848, + "L", + 8, + 848, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 8, + 648, + "L", + 208, + 648, + "L", + 208, + 848, + "L", + 8, + 848, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 8, + 648, + "L", + 208, + 648, + "L", + 208, + 848, + "L", + 8, + 848, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 648, + "L", + 208, + 648, + "L", + 208, + 848, + "L", + 8, + 848, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "showAccessibilityInfo": true, + "colorFormat": "hex", + "elementInfo": { + "tagName": "div", + "idValue": "empty-masonry-container", + "className": ".empty-masonry", + "nodeWidth": "200", + "nodeHeight": "200", + "isKeyboardFocusable": false, + "accessibleName": "", + "accessibleRole": "generic", + "layoutObjectName": "LayoutMasonry", + "showAccessibilityInfo": true + }, + "gridInfo": [ + { + "rotationAngle": 0, + "writingMode": "horizontal-tb", + "columns": [ + "M", + 8, + 648, + "L", + 8, + 848, + "M", + 28, + 648, + "L", + 28, + 848, + "M", + 68, + 848, + "L", + 68, + 648 + ], + "columnGaps": [ + "M", + 28, + 648, + "L", + 28, + 648, + "L", + 28, + 848, + "L", + 28, + 848, + "Z" + ], + "rows": [], + "rowGaps": [], + "gridBorder": [], + "gridHighlightConfig": { + "gridBorderDash": false, + "rowLineDash": true, + "columnLineDash": true, + "showGridExtensionLines": true, + "showPositiveLineNumbers": true, + "showNegativeLineNumbers": true, + "showAreaNames": true, + "showLineNames": true, + "gridBorderColor": "rgba(255, 0, 0, 0)", + "rowLineColor": "rgba(128, 0, 0, 0)", + "columnLineColor": "rgba(128, 0, 0, 0)", + "rowGapColor": "rgba(0, 255, 0, 0)", + "columnGapColor": "rgba(0, 0, 255, 0)", + "rowHatchColor": "rgba(255, 255, 255, 0)", + "columnHatchColor": "rgba(128, 128, 128, 0)", + "areaBorderColor": "rgba(255, 0, 0, 0)", + "gridBackgroundColor": "rgba(255, 0, 0, 0)" + } + } + ] +} +
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry.js b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry.js new file mode 100644 index 0000000..86a2a96 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-masonry.js
@@ -0,0 +1,68 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {TestRunner} from 'test_runner'; +import {ElementsTestRunner} from 'elements_test_runner'; + +(async function() { + TestRunner.addResult(`This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS masonry div.\n`); + await TestRunner.showPanel('elements'); + await TestRunner.loadHTML(` + <style> + body { + width: 2000px; + height: 2000px; + background-color: grey; + } + .masonry-columns { + display: masonry; + grid-template-columns: 50px 20% 30%; + width: 500px; + gap: 10px; + } + .masonry-rows { + display: masonry; + grid-template-rows: 100px repeat(2, 30px 10%); + masonry-direction: row; + height: 500px; + width: 300px; + gap: 20px; + } + .empty-masonry { + display: masonry; + width: 200px; + height: 200px; + grid-template-columns: 10% 20%; + } + </style> + <div id="masonry-columns-container" class="masonry-columns"> + <div style="width: 100%; height: 50px;"></div> + <div style="width: 100%; height: 30px;"></div> + <div style="width: 100%; height: 25px;"></div> + <div style="width: 100%; height: 100px;"></div> + <div style="width: 100%; height: 80px;"></div> + <div style="width: 100%; height: 60px;"></div> + </div> + <div id="masonry-rows-container" class="masonry-rows"> + <div style="width:50px; height: 100%;"></div> + <div style="width:100px; height: 100%;"></div> + <div style="width:150px; height: 100%;"></div> + <div style="width:200px; height: 100%;"></div> + <div style="width:250px; height: 100%;"></div> + <div style="width:30px; height: 100%;"></div> + </div> + <div id="empty-masonry-container" class="empty-masonry"></div> + <p id="description">This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS masonry div.</p> + `); + + function dumpMasonryHighlight(id) { + return new Promise(resolve => ElementsTestRunner.dumpInspectorHighlightJSON(id, resolve)); + } + + await dumpMasonryHighlight('masonry-columns-container'); + await dumpMasonryHighlight('masonry-rows-container'); + await dumpMasonryHighlight('empty-masonry-container'); + + TestRunner.completeTest(); +})();
diff --git a/third_party/blink/web_tests/http/tests/html/resources/oopif-composited-text-with-offset.html b/third_party/blink/web_tests/http/tests/html/resources/oopif-composited-text-with-offset.html new file mode 100644 index 0000000..a4b3b69 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/html/resources/oopif-composited-text-with-offset.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> + <head> + <style> + * { + margin: 0; + } + </style> + </head> + <body> + <div style="height:2px"></div> + <div style="font-size: 10.6667px; font-family: Arial;will-change:transform"> + Saturday, December 01, 2018 + </div> + </body> +</html>
diff --git a/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset-expected.html b/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset-expected.html new file mode 100644 index 0000000..620f6b72 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset-expected.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> + <head> + <style> + * { + margin: 0; + } + </style> + </head> + <body> + <h1>Mainframe with scaled OOPIF containing composited text with offset</h1> + This test verifies that the text within the OOP iframe is not blurry. + <div style="transform: scale(2.3); transform-origin: 0 0; width: 100px; height: 50px; background-color:pink"> + <div style="height:2px"></div> + <div style="font-size: 10.6667px; font-family: Arial;will-change:transform"> + Saturday, December 01, 2018 + </div> + </div> + </body> +</html>
diff --git a/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset.html b/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset.html new file mode 100644 index 0000000..ac1172d --- /dev/null +++ b/third_party/blink/web_tests/http/tests/html/scaled-oopif-composited-text-with-offset.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <head> + <link rel=match href="scaled-oopif-composited-text-with-offset-expected.html"> + <style> + * { + margin: 0; + } + </style> + </head> + <body> + <h1>Mainframe with scaled OOPIF containing composited text with offset</h1> + This test verifies that the text within the OOP iframe is not blurry. + <div style="transform: scale(2.3); transform-origin: 0 0; width: 100px; height: 50px; background-color:pink"> + <iframe style="border: none; height: 100px; width: 100px;" + src="http://localhost:8080/html/resources/oopif-composited-text-with-offset.html" + onload="document.documentElement.className = ''"></iframe> + </div> + </body> +</html>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt deleted file mode 100644 index 56fc77f..0000000 --- a/third_party/blink/web_tests/platform/linux/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] fetchLater() rejects max+1 payload in a POST request body of String. - assert_throws_dom: function "() => fetchLater(requestUrl, {\n activateAfter: 0,\n method: 'POST',\n body: generatePayload(\n getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,\n dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65549 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt deleted file mode 100644 index 56fc77f..0000000 --- a/third_party/blink/web_tests/platform/mac/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] fetchLater() rejects max+1 payload in a POST request body of String. - assert_throws_dom: function "() => fetchLater(requestUrl, {\n activateAfter: 0,\n method: 'POST',\n body: generatePayload(\n getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,\n dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65549 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win10/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/platform/win10/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt deleted file mode 100644 index 56fc77f..0000000 --- a/third_party/blink/web_tests/platform/win10/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] fetchLater() rejects max+1 payload in a POST request body of String. - assert_throws_dom: function "() => fetchLater(requestUrl, {\n activateAfter: 0,\n method: 'POST',\n body: generatePayload(\n getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,\n dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65549 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt deleted file mode 100644 index 56fc77f..0000000 --- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] fetchLater() rejects max+1 payload in a POST request body of String. - assert_throws_dom: function "() => fetchLater(requestUrl, {\n activateAfter: 0,\n method: 'POST',\n body: generatePayload(\n getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,\n dataType),\n })" threw object "QuotaExceededError: Failed to execute 'fetchLater' on 'Window': fetchLater exceeds its quota for the origin: got 65549 bytes, expected less than 65536 bytes." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/README.md b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/README.md new file mode 100644 index 0000000..f22219a --- /dev/null +++ b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/README.md
@@ -0,0 +1,2 @@ +This virtual suite runs a subset of tests with +CanvasDrawElementInSubtree enabled. \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild-expected.html b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild-expected.html new file mode 100644 index 0000000..5d83728 --- /dev/null +++ b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild-expected.html
@@ -0,0 +1,2 @@ +<!DOCTYPE html> +<canvas width="100" height="100" style="background: green;"></canvas>
diff --git a/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild.html b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild.html new file mode 100644 index 0000000..1ff8d617 --- /dev/null +++ b/third_party/blink/web_tests/virtual/canvas-draw-element-in-subtree/draw-element-grandchild.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<title>Canvas.drawElement: elements from the subtree are supported</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<style> + #child { + width: 100px; + height: 100px; + background: orange; + } + #grandchild { + width: 100px; + height: 100px; + background: green; + /* forces a stacking context and grouping */ + isolation: isolate; + } + #canvas { + background: red; + } +</style> + +<canvas id=canvas width="100" height="100" layoutsubtree> + <div id=child> + <div id=grandchild></div> + </div> +</canvas> + +<script> + function runTest() { + var context = canvas.getContext('2d'); + context.drawElement(grandchild, 0, 0); + } + onload = () => runTest(); +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window-expected.txt b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window-expected.txt index 287e754..2b3558c 100644 --- a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window-expected.txt +++ b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] Language Model Prompt Quota Exceeded - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError: The input is too large." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + Test bug: unrecognized DOMException code name or name "QuotaExceededError" passed to assert_throws_dom() Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window-expected.txt b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window-expected.txt index ca8a90c3..ff2ba5a 100644 --- a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window-expected.txt +++ b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] QuotaExceededError is thrown when initial prompts are too large. - promise_rejects_dom: function "function() { throw e; }" threw object "QuotaExceededError: The input is too large." that is not a DOMException QuotaExceededError: property "code" is equal to 0, expected 22 + Test bug: unrecognized DOMException code name or name "QuotaExceededError" passed to assert_throws_dom() Harness: the test ran to completion.
diff --git a/third_party/boringssl/src b/third_party/boringssl/src index 47dc1fc..4b328500 160000 --- a/third_party/boringssl/src +++ b/third_party/boringssl/src
@@ -1 +1 @@ -Subproject commit 47dc1fc3b0b79140049a8c907b57f2243f04447b +Subproject commit 4b3285002397da82681bebaacea9b4f231c9dbfc
diff --git a/third_party/dawn b/third_party/dawn index 09c514a..794b6fa 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 09c514a8b1fb356128bd6259b3ffac69810d625f +Subproject commit 794b6fadc4171f7b853a77ffdf0948fbec431f41
diff --git a/third_party/depot_tools b/third_party/depot_tools index 6d01946..e473b90 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 6d019469b47bf20f564f6c1b2d7a1283a7d51efa +Subproject commit e473b90df1020c5d938bb363c6ab91ef4fca896b
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index c40b214..eacc272 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit c40b214c6ba326ed891b8916a9310ebc866cb613 +Subproject commit eacc2727f14ea429e661baea76c855caad202f06
diff --git a/third_party/jetstream/main b/third_party/jetstream/main index e1acad0..5a96520 160000 --- a/third_party/jetstream/main +++ b/third_party/jetstream/main
@@ -1 +1 @@ -Subproject commit e1acad05c913d1d6de92f75abb74b4534ade48c8 +Subproject commit 5a96520552213eab2947ff3aa177306ec928200b
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index 14ca6ad..33645b3 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit 14ca6ad7d68c47a6b7c18d53a6c69d4fa3a27571 +Subproject commit 33645b3d12b221b370d9282bc910afb8bf3c29cc
diff --git a/third_party/skia b/third_party/skia index 2b27343..052d2f8 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 2b273431466193e5b257417e241ae597531846af +Subproject commit 052d2f8d927581522b2490625a5c1b2dacfd3777
diff --git a/tools/android/checkstyle/suppressions.xml b/tools/android/checkstyle/suppressions.xml index 0de2637b..9914a89 100644 --- a/tools/android/checkstyle/suppressions.xml +++ b/tools/android/checkstyle/suppressions.xml
@@ -4,7 +4,7 @@ <suppressions> <!-- Code in chrome/ should use SharedPreferencesManager. Ref: crbug.com/1022108 --> <suppress id="UseSharedPreferencesManagerFromChromeCheck" - files="src/(android_webview|base|chromecast|components|content|device|media|net|remoting|services|testing|third_party|tools|ui|weblayer)/"/> + files="src/(android_webview|base|chromecast|components|content|device|media|net|remoting|services|testing|third_party|tools|ui)/"/> <!-- FooTest.java, FooTestUtil.java, and FooTestUtils.java do not need to use SharedPreferencesManager. --> <suppress id="UseSharedPreferencesManagerFromChromeCheck" files="Test(Utils?)?\.java"/>
diff --git a/tools/android/io_benchmark/DEPS b/tools/android/io_benchmark/DEPS index 21ffec5f..9efee167 100644 --- a/tools/android/io_benchmark/DEPS +++ b/tools/android/io_benchmark/DEPS
@@ -1,5 +1,5 @@ include_rules = [ - "+crypto/secure_hash.h", + "+crypto/hash.h", "+third_party/brotli", "+third_party/snappy", "+third_party/zlib",
diff --git a/tools/android/io_benchmark/sha_benchmark.cc b/tools/android/io_benchmark/sha_benchmark.cc index e5b48c1..92e993b 100644 --- a/tools/android/io_benchmark/sha_benchmark.cc +++ b/tools/android/io_benchmark/sha_benchmark.cc
@@ -15,12 +15,11 @@ #include "base/logging.h" #include "base/time/time.h" -#include "crypto/secure_hash.h" +#include "crypto/hash.h" namespace { -constexpr size_t kSha256HashBytes = 32; -using SHA256HashValue = std::array<uint8_t, kSha256HashBytes>; +using SHA256HashValue = std::array<uint8_t, crypto::hash::kSha256Size>; std::vector<uint8_t> GenerateData(size_t size) { std::random_device device; @@ -52,14 +51,11 @@ size_t chunk_size, std::vector<SHA256HashValue>* hashes) { size_t chunk_count = data.size() / chunk_size; + base::span<const uint8_t> data_span = data; - SHA256HashValue hash_value; for (size_t i = 0; i < chunk_count; ++i) { - auto hasher = crypto::SecureHash::Create(crypto::SecureHash::SHA256); - - hasher->Update(&data[i * chunk_size], chunk_size); - hasher->Finish(&hash_value[0], kSha256HashBytes); - hashes->push_back(hash_value); + auto chunk = data_span.subspan(i * chunk_size, chunk_size); + hashes->push_back(crypto::hash::Sha256(chunk)); } }
diff --git a/tools/binary_size/supersize.json b/tools/binary_size/supersize.json index edeb03d..4b4062f 100644 --- a/tools/binary_size/supersize.json +++ b/tools/binary_size/supersize.json
@@ -55,9 +55,6 @@ }, "vr": { "default_component": "Internals>XR>VR" - }, - "weblayer": { - "default_component": "Internals>WebLayer" } }, "component_overrides": {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 2ee1c92..2fd4d25 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -7151,7 +7151,7 @@ <action name="CloseTab_EndTabInSplit"> <owner>agale@chromium.org</owner> - <owner>chrome-desktop-ui-sea@google.com</owner> + <owner>top-chrome-desktop-ui@google.com</owner> <description> User clicked the close tab button; the tab was the last tab in a split. </description> @@ -7194,7 +7194,7 @@ <action name="CloseTab_StartTabInSplit"> <owner>agale@chromium.org</owner> - <owner>chrome-desktop-ui-sea@google.com</owner> + <owner>top-chrome-desktop-ui@google.com</owner> <description> User clicked the close tab button; the tab was the first tab in a split. </description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 0cf8c92..70e1078a 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -9116,6 +9116,7 @@ <int value="-1837329460" label="NewEncodeCpuLoadEstimator:enabled"/> <int value="-1837137559" label="MediaAppImageMantisErase:enabled"/> <int value="-1836854634" label="CloseTabSuggestions:enabled"/> + <int value="-1836834774" label="DiskCacheBackendExperiment:enabled"/> <int value="-1836511093" label="QueryTilesRemoveTrendingAfterInactivity:enabled"/> <int value="-1836412886" label="UseChimeAndroidSdk:disabled"/> @@ -12616,6 +12617,7 @@ <int value="-547301855" label="SyncPseudoUSSSupervisedUsers:enabled"/> <int value="-547179727" label="AutofillEnableFIDOProgressDialog:enabled"/> <int value="-546825817" label="EnableShortcutCustomizationLogging:disabled"/> + <int value="-546737535" label="DiskCacheBackendExperiment:disabled"/> <int value="-546217920" label="HttpsFirstModeIncognito:enabled"/> <int value="-546188357" label="InitialNavigationEntry:enabled"/> <int value="-545624357" @@ -13388,6 +13390,7 @@ <int value="-265697837" label="PhoneHub:disabled"/> <int value="-265475987" label="NtpWallpaperSearchButton:disabled"/> <int value="-265277473" label="FastPairHandshakeLongTermRefactor:enabled"/> + <int value="-265074126" label="Prewarm:disabled"/> <int value="-265041545" label="WifiConcurrency:enabled"/> <int value="-263645996" label="InteractiveWindowCycleList:enabled"/> <int value="-263150202" label="BundledConnectionHelp:disabled"/> @@ -16237,6 +16240,7 @@ <int value="777569794" label="FeedWebUi:enabled"/> <int value="777667507" label="DesktopPWAsLinkCapturing:enabled"/> <int value="778000757" label="EnableInputEventLogging:disabled"/> + <int value="778338284" label="Prewarm:enabled"/> <int value="779086132" label="enable-data-reduction-proxy-alt"/> <int value="779703052" label="ChromeOSAmbientMode:enabled"/> <int value="779849093" label="OfflinePagesCTSuppressNotifications:disabled"/> @@ -17346,6 +17350,7 @@ <int value="1201008500" label="EnableAmbientAuthenticationInIncognito:enabled"/> <int value="1201619786" label="ShoppingIconColorVariant:disabled"/> + <int value="1202058349" label="BookmarkTabGroupConversion:disabled"/> <int value="1203002682" label="CmdDecoderAlwaysGetSizeFromSourceTexture:disabled"/> <int value="1203084856" @@ -17697,6 +17702,7 @@ <int value="1314067176" label="FederatedService:disabled"/> <int value="1314407143" label="SafeBrowsingSyncCheckerCheckAllowlist:enabled"/> + <int value="1314617754" label="BookmarkTabGroupConversion:enabled"/> <int value="1314681756" label="NoStatePrefetch:disabled"/> <int value="1314797690" label="CCTRealTimeEngagementSignalsAlternativeImpl:disabled"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 0e37482..cb3d9f0 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4966,7 +4966,7 @@ </histogram> <histogram name="Ash.LoginAnimation.Jank.{TabletOrClamshellMode}" units="%" - expires_after="2025-08-24"> + expires_after="2026-07-28"> <owner>oshima@chromium.org</owner> <owner>chromeos-wm@google.com</owner> <summary> @@ -4977,7 +4977,7 @@ </histogram> <histogram name="Ash.LoginAnimation.Smoothness.{TabletOrClamshellMode}" - units="%" expires_after="2025-08-24"> + units="%" expires_after="2026-07-28"> <owner>oshima@chromium.org</owner> <owner>chromeos-wm@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/enums.xml b/tools/metrics/histograms/metadata/custom_tabs/enums.xml index c22c00f..8944cc0 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/enums.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/enums.xml
@@ -151,6 +151,8 @@ EXTRA_OPEN_IN_BROWSER_STATE"/> <int value="64" label="Launch Handler API usage EXTRA_LAUNCH_HANDLER"/> <int value="65" label="File Handlers API usage EXTRA_FILE_HANDLERS"/> + <int value="66" + label="Custom context menu items EXTRA_CUSTOM_CONTENT_ACTIONS"/> </enum> <!--LINT.ThenChange(//chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java:CustomTabsFeature) -->
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index f8333da2..91e2572 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -309,6 +309,18 @@ </summary> </histogram> +<histogram name="CustomTabs.ContextMenu.DisplayedContextualCustomActionType" + enum="ContextualCustomActionType" expires_after="2025-10-30"> + <owner>adelm@google.com</owner> + <owner>chrome-connective-tissue@google.com</owner> + <summary> + Records when a custom content action is displayed in the context menu in a + Custom Tab, broken down by the type of content the action was for (e.g. Link + or Image). This allows for tracking overall engagement with custom actions + of different types with respect to the amount of times it was displayed. + </summary> +</histogram> + <histogram name="CustomTabs.ContextMenu.SelectedContextualCustomActionType" enum="ContextualCustomActionType" expires_after="2025-10-30"> <owner>adelm@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml index bb7ac49..f50680b 100644 --- a/tools/metrics/histograms/metadata/glic/histograms.xml +++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -405,6 +405,18 @@ </summary> </histogram> +<histogram name="Glic.Media.TimestampRangeCount" units="count" + expires_after="2026-01-15"> + <owner>liberato@chromium.org</owner> + <owner>chrome-media-ux@google.com</owner> + <summary> + Recorded when a speech recognition result is received. Records the number of + media timestamp ranges in the result. This can be greater than one, for + example, around seeks. Zero means that there was no timing information, or + the list of ranges was empty. + </summary> +</histogram> + <histogram name="Glic.Metrics.Error" enum="GlicMetricsError" expires_after="2026-01-15"> <owner>dewittj@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml index b28ff4b..4ec43ccb 100644 --- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -470,6 +470,30 @@ </token> </histogram> +<histogram + name="NewTabPage.Composebox.Session.File.DeletedCount.{ComposeboxFileTypes}.{FileState}" + units="count" expires_after="2026-01-20"> + <owner>mfacey@google.com</owner> + <owner>chrome-desktop-ntp@google.com</owner> + <summary> + Count the file deletions from the composebox. This is recorded when a file + is uploaded and then deleted from the composebox. Every deletion emits true + if it was successful and false if it was not. + </summary> + <token key="ComposeboxFileTypes" variants="ComposeboxFileTypes"> + <variant name=""/> + </token> + <token key="FileState"> + <variant name="NotUploaded" summary="File not uploaded"/> + <variant name="Processing" summary="File upload processing"/> + <variant name="Unknown" summary="Unknown"/> + <variant name="UploadFailed" summary="File upload failed"/> + <variant name="UploadStarted" summary="File upload started"/> + <variant name="UploadSuccessful" summary="File upload successful"/> + <variant name="ValidationFailed" summary="File validation failed"/> + </token> +</histogram> + <histogram name="NewTabPage.Composebox.Session.QueryCount" units="count" expires_after="2026-01-20"> <owner>jennserrano@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index 2fcd498a..7d33786 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -2877,7 +2877,7 @@ <histogram name="Tabs.SplitViewMenu.{SplitViewMenuSource}" enum="SplitViewMenuEntry" expires_after="2025-12-24"> <owner>agale@chromium.org</owner> - <owner>chrome-desktop-ui-sea@google.com</owner> + <owner>top-chrome-desktop-ui@google.com</owner> <summary> Records the menu item selected from the split view menu anchored to {SplitViewMenuSource}.
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index b0a9768f..c80318c3 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/361808c959b026d558c9948602ea38bf25d8981e/linux-arm64/trace_processor_shell" }, "win": { - "hash": "892cb8d8f5929f5c9d3e0faadb4327c5bff5781a", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/df8fbc76268b531f7bc47fc5ba4c4ba567472c3b/trace_processor_shell.exe" + "hash": "fe856ed62bd01b8f62956d74b3aa49f49d469b6a", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/21e93a3b04c8475ef3e527e39095b471f42b4f6e/trace_processor_shell.exe" }, "linux_arm": { "hash": "ab1a0d9236a63649044414663b6ace711253648f",
diff --git a/tools/resources/find_unused_assets.py b/tools/resources/find_unused_assets.py index 91f1f7f3..e5de8338 100755 --- a/tools/resources/find_unused_assets.py +++ b/tools/resources/find_unused_assets.py
@@ -176,8 +176,6 @@ 'remoting/android', 'tools/android', 'ui/android', - 'weblayer/browser', - 'weblayer/shell', ] xml_pattern = f'@{res_type}/{basename}'
diff --git a/tools/test_selection/decisiongraph_invoker.py b/tools/test_selection/decisiongraph_invoker.py index 7e7feeb..add06d3 100755 --- a/tools/test_selection/decisiongraph_invoker.py +++ b/tools/test_selection/decisiongraph_invoker.py
@@ -159,8 +159,8 @@ if tests_to_skip: f.write( '# A list of tests to be skipped, generated by test selection.\n') - for test_name in tests_to_skip: - f.write(f'-{test_name}\n') + for test_name in sorted(set(tests_to_skip)): + f.write(f'-{test_name}.*\n') print( f'Successfully wrote {len(tests_to_skip)} tests to skip to {file_path}') return True
diff --git a/tools/test_selection/decisiongraph_invoker_test.py b/tools/test_selection/decisiongraph_invoker_test.py index b0b03f4..c8ee6d6 100755 --- a/tools/test_selection/decisiongraph_invoker_test.py +++ b/tools/test_selection/decisiongraph_invoker_test.py
@@ -123,6 +123,24 @@ self.assertIn('-Test1.testA', content) self.assertIn('-Test2.testB', content) + def test_overwrite_filter_file_appends_wildcard(self): + """Tests that a wildcard '*' is appended to each test name.""" + test_suite = 'browser_tests' + tests_to_skip = ['TestClassOne', 'TestClassTwo'] + result = dgi.overwrite_filter_file(self.test_dir, test_suite, tests_to_skip) + + self.assertTrue(result) + filter_file_path = os.path.join(self.test_dir, f'{test_suite}.filter') + + with open(filter_file_path, 'r', encoding='utf-8') as f: + content = f.read() + + expected_content = ('# A list of tests to be skipped, generated by test' + ' selection.\n' + '-TestClassOne.*\n' + '-TestClassTwo.*\n') + self.assertEqual(content, expected_content) + @patch('builtins.print') def test_overwrite_filter_file_dir_not_found(self, mock_print): result = dgi.overwrite_filter_file('non_existent_dir', 'suite', [])
diff --git a/ui/android/java/res/layout/list_menu_checkbox.xml b/ui/android/java/res/layout/list_menu_checkbox.xml index 0625904..9404d94 100644 --- a/ui/android/java/res/layout/list_menu_checkbox.xml +++ b/ui/android/java/res/layout/list_menu_checkbox.xml
@@ -6,6 +6,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" @@ -15,14 +16,17 @@ <CheckBox android:id="@+id/checkbox" + android:clickable="false" style="@style/ListMenuItemIconStyle.Start" /> <TextView android:id="@+id/checkbox_title" + android:labelFor="@+id/checkbox" android:layout_height="wrap_content" android:layout_width="match_parent" android:maxLines="1" android:ellipsize="end" - style="@style/TextAppearance.ListMenuItem" /> + style="@style/TextAppearance.ListMenuItem" + tools:ignore="LabelFor" /> <!-- Text will be set by ViewBinder --> </LinearLayout>
diff --git a/ui/android/java/res/layout/list_menu_layout.xml b/ui/android/java/res/layout/list_menu_layout.xml index bfabd66..9d057d43 100644 --- a/ui/android/java/res/layout/list_menu_layout.xml +++ b/ui/android/java/res/layout/list_menu_layout.xml
@@ -21,6 +21,8 @@ android:id="@+id/menu_header_bottom_hairline" android:layout_height="@dimen/divider_height" android:visibility="invisible" + android:focusable="false" + android:screenReaderFocusable="false" style="@style/HorizontalDivider"/> <ListView android:id="@+id/menu_list"
diff --git a/ui/android/java/res/layout/list_menu_radio_button.xml b/ui/android/java/res/layout/list_menu_radio_button.xml index b8733c6..21b4652 100644 --- a/ui/android/java/res/layout/list_menu_radio_button.xml +++ b/ui/android/java/res/layout/list_menu_radio_button.xml
@@ -6,6 +6,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" @@ -15,14 +16,17 @@ <RadioButton android:id="@+id/radio_button" + android:clickable="false" style="@style/ListMenuItemIconStyle.Start" /> <TextView android:id="@+id/radio_button_title" + android:labelFor="@+id/radio_button" android:layout_height="wrap_content" android:layout_width="match_parent" android:maxLines="1" android:ellipsize="end" - style="@style/TextAppearance.ListMenuItem" /> + style="@style/TextAppearance.ListMenuItem" + tools:ignore="LabelFor" /> <!-- Text will be set by ViewBinder --> </LinearLayout>
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java b/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java index 830b7b9..b91933a 100644 --- a/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java +++ b/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java
@@ -110,6 +110,8 @@ } private final ListView mListView; + private final ModelList mHeaderModelList = new ModelList(); + private final ModelList mContentModelList; private final ModelListAdapter mAdapter; private final View mContentView; private final List<Runnable> mClickRunnables = new LinkedList<>(); @@ -136,23 +138,22 @@ View contentView = LayoutInflater.from(context).inflate(R.layout.list_menu_layout, null); View hairline = contentView.findViewById(R.id.menu_header_bottom_hairline); ListView listView = contentView.findViewById(R.id.menu_list); - mAdapter = - createAdapter( - data, - Set.of(), - (model) -> { - if (delegate != null) delegate.onItemSelected(model); - // We will run the runnables that are registered by the time this lambda - // is called. - for (Runnable r : mClickRunnables) { - r.run(); - } - }); + mAdapter = createAdapter(data, Set.of(), (model) -> callDelegate(delegate, model)); mContentView = contentView; + mContentModelList = data; mListView = listView; mListView.setAdapter(mAdapter); mListView.setDivider(null); + ListView headerListView = mContentView.findViewById(R.id.menu_header); + headerListView.setAdapter( + createAdapter( + mHeaderModelList, Set.of(), (model) -> callDelegate(delegate, model))); + + // Allow keyboard focus + keyboard clicks on list items. + headerListView.setItemsCanFocus(true); + listView.setItemsCanFocus(true); + if (backgroundDrawable != Resources.ID_NULL) { contentView.setBackgroundResource(backgroundDrawable); } @@ -205,6 +206,25 @@ return mAdapter; } + /** + * Runs {@param dismissDialog} at the end of each callback, recursively (through submenu items). + * If an item doesn't already have a click callback in its model, no click callback is added. + * + * @param dismissDialog The {@link Runnable} to run. + */ + public void setupCallbacksRecursively(Runnable dismissDialog) { + ListMenuUtils.setupCallbacksRecursively(mHeaderModelList, mContentModelList, dismissDialog); + } + + private void callDelegate(@Nullable Delegate delegate, PropertyModel model) { + if (delegate != null) delegate.onItemSelected(model); + // We will run the runnables that are registered by the time this lambda + // is called. + for (Runnable r : mClickRunnables) { + r.run(); + } + } + /** Listens to scrolls on list view contents and changes visibility of header hairline. */ private static class ContentListOnScrollChangeListener implements View.OnScrollChangeListener {
diff --git a/ui/file_manager/integration_tests/file_manager/skyvault.ts b/ui/file_manager/integration_tests/file_manager/skyvault.ts index 6c56722..aa8e057 100644 --- a/ui/file_manager/integration_tests/file_manager/skyvault.ts +++ b/ui/file_manager/integration_tests/file_manager/skyvault.ts
@@ -291,3 +291,18 @@ const myFilesLabel = 'My files'; await directoryTree.waitForItemLostByLabel(myFilesLabel); } + +/** +Tests that the Files app opens successfully when the migration +destination is set to "delete", addressing a crash (crbug.com/433496883) that +occurred when the policy was configured and no files were present for deletion. + */ +export async function skyVaultMigrationDeleteLocalFiles() { + await remoteCall.setLocalFilesMigrationDestination('delete'); + // Mount the local folder after setting the policies. + await sendTestMessage({name: 'skyvault:mountMyFiles'}); + + // Open Files app. It shouldn't crash. + const appId = await remoteCall.openNewWindow(null, null); + chrome.test.assertTrue(!!appId, 'failed to open new window'); +}
diff --git a/ui/gfx/gpu_memory_buffer_handle.h b/ui/gfx/gpu_memory_buffer_handle.h index 8f8c63c..30bf5771 100644 --- a/ui/gfx/gpu_memory_buffer_handle.h +++ b/ui/gfx/gpu_memory_buffer_handle.h
@@ -136,8 +136,6 @@ // is always consistent, particularly that the only one handle is set at the // same time and it corresponds to |type|. struct COMPONENT_EXPORT(GFX) GpuMemoryBufferHandle { - static constexpr GpuMemoryBufferId kInvalidId = GpuMemoryBufferId(-1); - GpuMemoryBufferHandle(); explicit GpuMemoryBufferHandle(base::UnsafeSharedMemoryRegion region); #if BUILDFLAG(IS_WIN)
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc index 0af1098..10206be1 100644 --- a/ui/gtk/gtk_ui.cc +++ b/ui/gtk/gtk_ui.cc
@@ -10,12 +10,15 @@ #include "ui/gtk/gtk_ui.h" #include <cairo.h> +#include <glib.h> #include <pango/pango.h> +#include <array> #include <cmath> #include <memory> #include <optional> #include <set> +#include <string_view> #include <unordered_set> #include <utility> @@ -198,6 +201,100 @@ return std::round(font_scale * 64) / 64; } +// Some misconfigured systems have missing or corrupted schemas, see +// https://crbug.com/434763642. Avoid initializing GTK in this case to prevent +// a crash. +bool IsValidSchema(ui::LinuxUiBackend backend) { + struct GFreeDeleter { + void operator()(gchar* ptr) const { g_free(ptr); } + }; + struct GVariantDeleter { + void operator()(GVariant* ptr) const { g_variant_unref(ptr); } + }; + struct GSettingsSchemaKeyDeleter { + void operator()(GSettingsSchemaKey* ptr) const { + g_settings_schema_key_unref(ptr); + } + }; + struct GSettingsSchemaDeleter { + void operator()(GSettingsSchema* ptr) const { + g_settings_schema_unref(ptr); + } + }; + + struct { + const char* interface; + std::array<const char*, 3> keys; + } static constexpr kInterfaces[] = { + {"org.gnome.desktop.interface", + {"font-antialiasing", "font-hinting", "font-rgba-order"}}, + {"org.gnome.settings-daemon.plugins.xsettings", + {"antialiasing", "hinting", "rgba-order"}}, + }; + + if (backend != ui::LinuxUiBackend::kWayland) { + // The GTK codepath using these schemas is only used on Wayland. + return true; + } + + auto* source = g_settings_schema_source_get_default(); + if (!source) { + return true; + } + + for (const auto& interface : kInterfaces) { + std::unique_ptr<GSettingsSchema, GSettingsSchemaDeleter> schema( + g_settings_schema_source_lookup(source, interface.interface, + /*recursive=*/true)); + if (!schema) { + // Not an error, try the next schema. + continue; + } + + for (const char* key_string : interface.keys) { + // Checking for the key first is required, otherwise + // g_settings_schema_get_key() could crash. + if (!g_settings_schema_has_key(schema.get(), key_string)) { + LOG(ERROR) << "Schema " << interface.interface << " does not have key " + << key_string; + return false; + } + + std::unique_ptr<GSettingsSchemaKey, GSettingsSchemaKeyDeleter> key( + g_settings_schema_get_key(schema.get(), key_string)); + if (!key) { + LOG(ERROR) << "Schema " << interface.interface << " has key " + << key_string << ", but g_settings_schema_get_key() failed"; + return false; + } + + std::unique_ptr<GVariant, GVariantDeleter> range( + g_settings_schema_key_get_range(key.get())); + if (!range) { + LOG(ERROR) << "Schema " << interface.interface << " key " << key_string + << " has no range, but it is required"; + return false; + } + + char* type_string = nullptr; + g_variant_get(range.get(), "(sv)", &type_string, nullptr); + std::unique_ptr<gchar, GFreeDeleter> type_string_deleter(type_string); + if (!type_string || type_string != std::string_view("enum")) { + LOG(ERROR) << "Schema " << interface.interface << " key " << key_string + << " must be an enum"; + return false; + } + } + + // Valid schema. Return now since GTK uses the first present schema. + return true; + } + + // No schema found. This is acceptable, because GTK will fallback to using + // default values. + return true; +} + } // namespace GtkUi::GtkUi() : window_frame_actions_() { @@ -221,12 +318,17 @@ DCHECK(delegate); const auto backend = delegate->GetBackend(); + if (!IsValidSchema(backend)) { + return false; + } + if (!LoadGtk(backend) || !GtkCheckVersion(3, 20)) { return false; } // Gtk initialization through pango may call FcInit() before we get to that. - // Retrieve global FontConfig config here to call FcInit() with configuration we control. + // Retrieve global FontConfig config here to call FcInit() with configuration + // we control. gfx::GetGlobalFontConfig(); platform_ = CreateGtkUiPlatform(backend);
diff --git a/v8 b/v8 index 01f63de..e4e7a46 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 01f63de24840c686c6382de9f632bd049ba950a8 +Subproject commit e4e7a46a03f808587e94234aceef6e8441d0ee32