M126 stage 8

This commit is contained in:
Alexander Frick 2024-07-29 15:01:38 -05:00
parent bc032a22b6
commit 47eac6e9fb
28 changed files with 1774 additions and 930 deletions

View file

@ -132,6 +132,8 @@ all_platforms+=" -DCONFIG_AV1_HIGHBITDEPTH=0"
# Use real-time only build.
all_platforms+=" -DCONFIG_REALTIME_ONLY=1"
all_platforms+=" -DCONFIG_AV1_TEMPORAL_DENOISING=1"
# Disable Quantization Matrix.
all_platforms+=" -DCONFIG_QUANT_MATRIX=0"
# avx2 optimizations account for ~0.3mb of the decoder.
#all_platforms+=" -DENABLE_AVX2=0"
toolchain="-DCMAKE_TOOLCHAIN_FILE=${SRC}/build/cmake/toolchains"

View file

@ -104,6 +104,42 @@ config("libvpx_public_config") {
]
}
executable("decode_encode_profile_test") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
include_dirs = libvpx_include_dirs + [
"source/libvpx/third_party/libwebm/",
"source/libvpx/third_party/googletest/src/include/",
"source/libvpx/third_party/googletest/src/",
]
testonly = true
sources = [
"source/libvpx/test/decode_test_driver.cc",
"source/libvpx/test/encode_test_driver.cc",
"source/libvpx/test/init_vpx_test.cc",
"source/libvpx/test/test_libvpx.cc",
"source/libvpx/test/test_vectors.cc",
"source/libvpx/test/test_vectors.h",
"source/libvpx/third_party/googletest/src/src/gtest-all.cc",
"source/libvpx/third_party/libwebm/mkvparser/mkvparser.cc",
"source/libvpx/third_party/libwebm/mkvparser/mkvreader.cc",
"source/libvpx/tools_common.h",
"source/libvpx/webmdec.cc",
"source/libvpx/y4minput.c",
"tests/pgo/decode_encode_profile_test.cc",
]
deps = [ ":libvpx" ]
# gtest-death-test dependency on fdio for fuchsia builds
if (is_fuchsia) {
deps += [
"//third_party/fuchsia-sdk/sdk/pkg/fdio",
"//third_party/fuchsia-sdk/sdk/pkg/zx",
]
}
}
if (current_cpu == "x86" || (current_cpu == "x64" && !is_msan)) {
nasm_assemble("libvpx_asm") {
if (current_cpu == "x86") {

View file

@ -30,17 +30,13 @@ config("xnnpack_config") {
]
defines = [
"CHROMIUM",
# Don't enable this without first talking to Chrome Security!
# XNNPACK runs in the browser process. The hardening and fuzzing needed
# to ensure JIT can be used safely is not in place yet.
"XNN_ENABLE_JIT=0",
# TODO: b/327013106 - Before enabling this and removing
# --define=xnn_enable_avx512amx=false from the generation script, ensure
# the detection has been updated to remove use of syscall() or that the
# function has been allowed in the sandbox.
"XNN_ENABLE_AVX512AMX=0",
"XNN_ENABLE_ASSEMBLY=1",
"XNN_ENABLE_GEMM_M_SPECIALIZATION=1",
"XNN_ENABLE_MEMOPT=1",
@ -68,13 +64,13 @@ if (current_cpu == "x64" || current_cpu == "x86") {
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vbmi",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni-amx-tile-amx-int8",
":amalgam_f16c-fma-no-avx2",
":amalgam_f16c-no-avx2-no-fma",
":amalgam_sse2-no-sse3",
":amalgam_sse4.1-no-sse4.2",
":amalgam_ssse3-no-sse4.1",
":amalgam_x64",
":amalgam_xop-no-avx2",
":configs_x64",
":enums_x64",
":operators_x64",
@ -88,6 +84,7 @@ if (current_cpu == "x64" || current_cpu == "x86") {
":amalgam_avx512f_standalone",
":amalgam_f16c-fma-avx2_standalone",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vbmi_standalone",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni-amx-tile-amx-int8_standalone",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni_standalone",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni_standalone",
":amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl_standalone",
@ -97,7 +94,6 @@ if (current_cpu == "x64" || current_cpu == "x86") {
":amalgam_sse4.1-no-sse4.2_standalone",
":amalgam_ssse3-no-sse4.1_standalone",
":amalgam_x64_standalone",
":amalgam_xop-no-avx2_standalone",
":configs_x64_standalone",
":enums_x64_standalone",
":operators_x64_standalone",
@ -704,6 +700,75 @@ if (current_cpu == "x64" || current_cpu == "x86") {
}
}
source_set(
"amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni-amx-tile-amx-int8") {
cflags = [
"-mamx-int8",
"-mamx-tile",
"-mavx512bw",
"-mavx512cd",
"-mavx512dq",
"-mavx512f",
"-mavx512vl",
"-mavx512vnni",
"-mf16c",
"-mfma",
"-mgfni",
]
sources = [ "src/src/amalgam/gen/avx512amx.c" ]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
deps = [
"//third_party/cpuinfo",
"//third_party/fp16",
"//third_party/fxdiv",
"//third_party/pthreadpool",
]
public_configs = [ ":xnnpack_config" ]
}
# This is a target that cannot depend on //base.
source_set(
"amalgam_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni-gfni-amx-tile-amx-int8_standalone") {
cflags = [
"-mamx-int8",
"-mamx-tile",
"-mavx512bw",
"-mavx512cd",
"-mavx512dq",
"-mavx512f",
"-mavx512vl",
"-mavx512vnni",
"-mf16c",
"-mfma",
"-mgfni",
]
sources = [ "src/src/amalgam/gen/avx512amx.c" ]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
deps = [
"//third_party/cpuinfo",
"//third_party/fp16",
"//third_party/fxdiv",
"//third_party/pthreadpool:pthreadpool_standalone",
]
public_configs = [ ":xnnpack_config" ]
if (!(is_android && use_order_profiling)) {
assert_no_deps = [ "//base" ]
}
}
source_set("amalgam_f16c-fma-no-avx2") {
cflags = [
"-mf16c",
@ -1002,55 +1067,6 @@ if (current_cpu == "x64" || current_cpu == "x86") {
}
}
source_set("amalgam_xop-no-avx2") {
cflags = [
"-mno-avx2",
"-mxop",
]
sources = [ "src/src/amalgam/gen/xop.c" ]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
deps = [
"//third_party/cpuinfo",
"//third_party/fp16",
"//third_party/fxdiv",
"//third_party/pthreadpool",
]
public_configs = [ ":xnnpack_config" ]
}
# This is a target that cannot depend on //base.
source_set("amalgam_xop-no-avx2_standalone") {
cflags = [
"-mno-avx2",
"-mxop",
]
sources = [ "src/src/amalgam/gen/xop.c" ]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
deps = [
"//third_party/cpuinfo",
"//third_party/fp16",
"//third_party/fxdiv",
"//third_party/pthreadpool:pthreadpool_standalone",
]
public_configs = [ ":xnnpack_config" ]
if (!(is_android && use_order_profiling)) {
assert_no_deps = [ "//base" ]
}
}
source_set("configs_x64") {
cflags = []
@ -1160,6 +1176,7 @@ if (current_cpu == "x64" || current_cpu == "x86") {
cflags = []
sources = [
"src/src/enums/allocation-type.c",
"src/src/enums/datatype-strings.c",
"src/src/enums/microkernel-type.c",
"src/src/enums/node-type.c",
@ -1185,6 +1202,7 @@ if (current_cpu == "x64" || current_cpu == "x86") {
cflags = []
sources = [
"src/src/enums/allocation-type.c",
"src/src/enums/datatype-strings.c",
"src/src/enums/microkernel-type.c",
"src/src/enums/node-type.c",
@ -1343,6 +1361,7 @@ if (current_cpu == "x64" || current_cpu == "x86") {
"src/src/subgraph/multiply2.c",
"src/src/subgraph/negate.c",
"src/src/subgraph/prelu.c",
"src/src/subgraph/reciprocal-square-root.c",
"src/src/subgraph/reshape-2d.c",
"src/src/subgraph/reshape-helpers.c",
"src/src/subgraph/rope.c",
@ -1415,6 +1434,7 @@ if (current_cpu == "x64" || current_cpu == "x86") {
"src/src/subgraph/multiply2.c",
"src/src/subgraph/negate.c",
"src/src/subgraph/prelu.c",
"src/src/subgraph/reciprocal-square-root.c",
"src/src/subgraph/reshape-2d.c",
"src/src/subgraph/reshape-helpers.c",
"src/src/subgraph/rope.c",
@ -1872,6 +1892,7 @@ if (current_cpu == "arm64") {
cflags = []
sources = [
"src/src/enums/allocation-type.c",
"src/src/enums/datatype-strings.c",
"src/src/enums/microkernel-type.c",
"src/src/enums/node-type.c",
@ -1897,6 +1918,7 @@ if (current_cpu == "arm64") {
cflags = []
sources = [
"src/src/enums/allocation-type.c",
"src/src/enums/datatype-strings.c",
"src/src/enums/microkernel-type.c",
"src/src/enums/node-type.c",
@ -3155,12 +3177,6 @@ if (current_cpu == "arm64") {
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-cortex-a75.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64-prfm.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-fp32-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-fp32-asm-aarch64-neondot-ld128.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
]
configs -= [ "//build/config/compiler:chromium_code" ]
@ -3188,12 +3204,6 @@ if (current_cpu == "arm64") {
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-cortex-a75.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64-prfm.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-fp32-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-fp32-asm-aarch64-neondot-ld128.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-gemm/gen/qu8-gemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
]
configs -= [ "//build/config/compiler:chromium_code" ]
@ -3224,12 +3234,6 @@ if (current_cpu == "arm64") {
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-cortex-a75.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64-prfm.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-fp32-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-fp32-asm-aarch64-neondot-ld128.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
]
configs -= [ "//build/config/compiler:chromium_code" ]
@ -3257,12 +3261,6 @@ if (current_cpu == "arm64") {
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-cortex-a75.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64-prfm.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-asm-aarch64-neon-mlal-lane-ld64.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-fp32-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-fp32-asm-aarch64-neondot-ld128.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x16c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-cortex-a55.S",
"src/src/qu8-igemm/gen/qu8-igemm-4x8c4-minmax-rndnu-asm-aarch64-neondot-ld128.S",
]
configs -= [ "//build/config/compiler:chromium_code" ]
@ -3318,6 +3316,7 @@ if (current_cpu == "arm64") {
"src/src/subgraph/multiply2.c",
"src/src/subgraph/negate.c",
"src/src/subgraph/prelu.c",
"src/src/subgraph/reciprocal-square-root.c",
"src/src/subgraph/reshape-2d.c",
"src/src/subgraph/reshape-helpers.c",
"src/src/subgraph/rope.c",
@ -3390,6 +3389,7 @@ if (current_cpu == "arm64") {
"src/src/subgraph/multiply2.c",
"src/src/subgraph/negate.c",
"src/src/subgraph/prelu.c",
"src/src/subgraph/reciprocal-square-root.c",
"src/src/subgraph/reshape-2d.c",
"src/src/subgraph/reshape-helpers.c",
"src/src/subgraph/rope.c",

View file

@ -36,6 +36,7 @@
import atexit
import collections
import io
import json
import logging
import os
@ -43,6 +44,8 @@ import platform
import shutil
import subprocess
import sys
import urllib.request
import zipfile
from dataclasses import dataclass, field
@ -79,17 +82,13 @@ config("xnnpack_config") {
]
defines = [
"CHROMIUM",
# Don't enable this without first talking to Chrome Security!
# XNNPACK runs in the browser process. The hardening and fuzzing needed
# to ensure JIT can be used safely is not in place yet.
"XNN_ENABLE_JIT=0",
# TODO: b/327013106 - Before enabling this and removing
# --define=xnn_enable_avx512amx=false from the generation script, ensure
# the detection has been updated to remove use of syscall() or that the
# function has been allowed in the sandbox.
"XNN_ENABLE_AVX512AMX=0",
"XNN_ENABLE_ASSEMBLY=1",
"XNN_ENABLE_GEMM_M_SPECIALIZATION=1",
"XNN_ENABLE_MEMOPT=1",
@ -530,7 +529,6 @@ def GenerateObjectBuilds(cpu):
'mnemonic("CppCompile", filter("//:", deps(:xnnpack_for_tflite)))',
'--define',
'xnn_enable_jit=false',
'--define=xnn_enable_avx512amx=false',
"--output=jsonproto",
])
logging.info('parsing actions from bazel aquery...')
@ -633,6 +631,17 @@ def MakeXNNPACKDepsList(target_sss):
return deps_list
def EnsureAndroidNDK():
"""
Ensures that the Android NDK is available and bazel can find it later.
"""
if 'ANDROID_NDK_HOME' in os.environ:
return
logging.info('Downloading a copy of the Android NDK for bazel')
resp = urllib.request.urlopen('https://dl.google.com/android/repository/android-ndk-r19c-linux-x86_64.zip')
logging.info('Unpacking the Android NDK')
zipfile.ZipFile(io.BytesIO(resp.read())).extractall(path='/tmp/')
os.environ['ANDROID_NDK_HOME'] = '/tmp/android-ndk-r19c'
def MakeXNNPACKSourceSet(ss):
"""
@ -657,6 +666,8 @@ def main():
logging.error('On x86-64 Debian, install gcc-aarch64-linux-gnu and gcc.')
sys.exit(1)
EnsureAndroidNDK()
CreateToolchainFiles()
# Create SourceSet's for each target architecture.

View file

@ -313,6 +313,10 @@ const AcceleratorData kAcceleratorData[] = {
// Projector shortcuts.
{true, ui::VKEY_OEM_3, ui::EF_COMMAND_DOWN,
AcceleratorAction::kToggleProjectorMarker},
// Accessibility key.
{true, ui::VKEY_ACCESSIBILITY, ui::EF_NONE,
AcceleratorAction::kAccessibilityAction},
};
const size_t kAcceleratorDataLength = std::size(kAcceleratorData);
@ -397,11 +401,21 @@ const size_t kToggleGameDashboardAcceleratorDataLength =
std::size(kToggleGameDashboardAcceleratorData);
const AcceleratorData kTogglePickerAcceleratorData[] = {
{true, ui::VKEY_S, ui::EF_COMMAND_DOWN, AcceleratorAction::kTogglePicker}};
{true, ui::VKEY_RIGHT_ALT, ui::EF_NONE, AcceleratorAction::kTogglePicker},
{true, ui::VKEY_F, ui::EF_COMMAND_DOWN, AcceleratorAction::kTogglePicker},
};
const size_t kTogglePickerAcceleratorDataLength =
std::size(kTogglePickerAcceleratorData);
const AcceleratorData kTogglePickerFlipAcceleratorData[] = {
{false, ui::VKEY_RIGHT_ALT, ui::EF_NONE, AcceleratorAction::kTogglePicker},
{true, ui::VKEY_F, ui::EF_COMMAND_DOWN, AcceleratorAction::kTogglePicker},
};
const size_t kTogglePickerFlipAcceleratorDataLength =
std::size(kTogglePickerAcceleratorData);
// static
AcceleratorController* AcceleratorController::Get() {
return g_instance;

View file

@ -11,8 +11,8 @@ import("//ui/webui/webui_features.gni")
aggregate_vector_icons("chrome_vector_icons") {
icon_directory = "."
# Keep sorted alphabetically.
sources = [
# go/keep-sorted start
"account_add_chrome_refresh.icon",
"account_box.icon",
"account_child.icon",
@ -57,13 +57,13 @@ aggregate_vector_icons("chrome_vector_icons") {
"click_to_call_illustration.icon",
"click_to_call_illustration_dark.icon",
"close_chrome_refresh.icon",
"close_group.icon",
"close_group_refresh.icon",
"close_tab_chrome_refresh.icon",
"computer_with_circle_background.icon",
"copy.icon",
"copy_menu.icon",
"crashed_tab.icon",
"create_new_tab_group.icon",
"credit_card.icon",
"credit_card_chrome_refresh.icon",
"cut_menu.icon",
@ -108,6 +108,7 @@ aggregate_vector_icons("chrome_vector_icons") {
"incognito_menu_art.icon",
"incognito_profile.icon",
"incognito_refresh_menu.icon",
"info.icon",
"ink_highlighter.icon",
"input.icon",
"install_desktop_chrome_refresh.icon",
@ -135,7 +136,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"menu_book_chrome_refresh.icon",
"mixed_content.icon",
"more_tools_menu.icon",
"move_group_to_new_window.icon",
"move_group_to_new_window_refresh.icon",
"my_location.icon",
"name_window.icon",
@ -145,7 +145,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"navigate_stop.icon",
"navigate_stop_chrome_refresh.icon",
"navigate_stop_touch.icon",
"new_tab_in_group.icon",
"new_tab_in_group_refresh.icon",
"new_tab_refresh.icon",
"new_window.icon",
@ -164,6 +163,7 @@ aggregate_vector_icons("chrome_vector_icons") {
"payments/save_card_and_vcn_success_confirmation.icon",
"payments/save_card_and_vcn_success_confirmation_dark.icon",
"performance.icon",
"person.icon",
"person_filled_padded_large.icon",
"person_filled_padded_small.icon",
"photo_camera.icon",
@ -184,7 +184,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"read_anything_line_spacing_very_loose.icon",
"read_anything_links_disabled.icon",
"read_anything_links_enabled.icon",
"read_later.icon",
"read_later_add.icon",
"reading_list.icon",
"release_alert.icon",
@ -198,7 +197,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"right_panel_close.icon",
"sad_tab.icon",
"safety_check.icon",
"save_group.icon",
"save_group_refresh.icon",
"save_page.icon",
"saved_tab_group_bar_everything.icon",
@ -257,7 +255,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"trash_can_refresh.icon",
"tv.icon",
"unbranded_translate.icon",
"ungroup.icon",
"ungroup_refresh.icon",
"usb_cable.icon",
"user_account_avatar.icon",
@ -274,8 +271,6 @@ aggregate_vector_icons("chrome_vector_icons") {
"webauthn/passkey_error_dark.icon",
"webauthn/passkey_fingerprint.icon",
"webauthn/passkey_fingerprint_dark.icon",
"webauthn/passkey_header.icon",
"webauthn/passkey_header_dark.icon",
"webauthn/passkey_phone.icon",
"webauthn/passkey_phone_dark.icon",
"webauthn/passkey_usb.icon",
@ -283,6 +278,8 @@ aggregate_vector_icons("chrome_vector_icons") {
"webauthn/usb_security_key.icon",
"webauthn/webauthn_error.icon",
"webauthn/webauthn_error_dark.icon",
"webauthn/windows_hello.icon",
"webid_globe.icon",
"zoom_in.icon",
"zoom_minus.icon",
"zoom_minus_chrome_refresh.icon",
@ -290,6 +287,8 @@ aggregate_vector_icons("chrome_vector_icons") {
"zoom_plus.icon",
"zoom_plus_chrome_refresh.icon",
"zoom_plus_menu_refresh.icon",
# go/keep-sorted end
]
if (is_thorium_build) {

View file

@ -0,0 +1,53 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
CANVAS_DIMENSIONS, 960,
FILL_RULE_NONZERO,
PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
MOVE_TO, 440, 680,
R_H_LINE_TO, 80,
R_V_LINE_TO, -240,
R_H_LINE_TO, -80,
R_V_LINE_TO, 240,
CLOSE,
R_MOVE_TO, 40, -320,
R_QUADRATIC_TO, 17, 0, 28.5f, -11.5f,
QUADRATIC_TO_SHORTHAND, 520, 320,
R_QUADRATIC_TO, 0, -17, -11.5f, -28.5f,
QUADRATIC_TO_SHORTHAND, 480, 280,
R_QUADRATIC_TO, -17, 0, -28.5f, 11.5f,
QUADRATIC_TO_SHORTHAND, 440, 320,
R_QUADRATIC_TO, 0, 17, 11.5f, 28.5f,
QUADRATIC_TO_SHORTHAND, 480, 360,
CLOSE,
R_MOVE_TO, 0, 520,
R_QUADRATIC_TO, -83, 0, -156, -31.5f,
QUADRATIC_TO_SHORTHAND, 197, 763,
R_QUADRATIC_TO, -54, -54, -85.5f, -127,
QUADRATIC_TO_SHORTHAND, 80, 480,
R_QUADRATIC_TO, 0, -83, 31.5f, -156,
QUADRATIC_TO_SHORTHAND, 197, 197,
R_QUADRATIC_TO, 54, -54, 127, -85.5f,
QUADRATIC_TO_SHORTHAND, 480, 80,
R_QUADRATIC_TO, 83, 0, 156, 31.5f,
QUADRATIC_TO_SHORTHAND, 763, 197,
R_QUADRATIC_TO, 54, 54, 85.5f, 127,
QUADRATIC_TO_SHORTHAND, 880, 480,
R_QUADRATIC_TO, 0, 83, -31.5f, 156,
QUADRATIC_TO_SHORTHAND, 763, 763,
R_QUADRATIC_TO, -54, 54, -127, 85.5f,
QUADRATIC_TO_SHORTHAND, 480, 880,
CLOSE,
R_MOVE_TO, 0, -80,
R_QUADRATIC_TO, 134, 0, 227, -93,
R_QUADRATIC_TO, 93, -93, 93, -227,
R_QUADRATIC_TO, 0, -134, -93, -227,
R_QUADRATIC_TO, -93, -93, -227, -93,
R_QUADRATIC_TO, -134, 0, -227, 93,
R_QUADRATIC_TO, -93, 93, -93, 227,
R_QUADRATIC_TO, 0, 134, 93, 227,
R_QUADRATIC_TO, 93, 93, 227, 93,
CLOSE,
R_MOVE_TO, 0, -320,
CLOSE

View file

@ -4,8 +4,8 @@
#include "chrome/browser/download/bubble/download_bubble_prefs.h"
#include "base/feature_list.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"

View file

@ -57,7 +57,6 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pdf_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/download/public/common/download_danger_type.h"
@ -67,6 +66,7 @@
#include "components/download/public/common/download_stats.h"
#include "components/offline_pages/buildflags/buildflags.h"
#include "components/pdf/common/constants.h"
#include "components/pdf/common/pdf_util.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_member.h"
@ -75,6 +75,7 @@
#include "components/safe_browsing/content/browser/download/download_stats.h"
#include "components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h"
#include "components/safe_browsing/content/common/file_type_policies.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_search_api/safe_search_util.h"
#include "components/services/quarantine/public/mojom/quarantine.mojom.h"
#include "components/services/quarantine/quarantine_impl.h"
@ -110,6 +111,7 @@
#include "chrome/browser/download/android/insecure_download_dialog_bridge.h"
#include "chrome/browser/download/android/insecure_download_infobar_delegate.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/ui/android/pdf/pdf_jni_headers/PdfUtils_jni.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "components/infobars/content/content_infobar_manager.h"
@ -168,6 +170,8 @@ namespace {
// there is no user interaction).
constexpr base::TimeDelta kEphemeralWarningLifetimeBeforeCancel =
base::Hours(1);
#else
const char kPdfDirName[] = "pdfs";
#endif
// Used with GetPlatformDownloadPath() to indicate which platform path to
@ -433,8 +437,6 @@ download::DownloadDangerType SavePackageDangerType(
return download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
case safe_browsing::DownloadCheckResult::DEEP_SCANNED_SAFE:
return download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE;
case safe_browsing::DownloadCheckResult::BLOCKED_UNSUPPORTED_FILE_TYPE:
return download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE;
case safe_browsing::DownloadCheckResult::BLOCKED_PASSWORD_PROTECTED:
return download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED;
case safe_browsing::DownloadCheckResult::BLOCKED_TOO_LARGE:
@ -549,6 +551,14 @@ void ChromeDownloadManagerDelegate::Shutdown() {
}
}
void ChromeDownloadManagerDelegate::OnDownloadCanceledAtShutdown(
download::DownloadItem* item) {
// Be careful, limited objects are still alive at this point. This function is
// called at profile shutdown. Only keyed service, downloadItem and objects
// directly owned by the browser process are available.
MaybeSendDangerousDownloadCanceledReport(item, /*is_shutdown=*/true);
}
content::DownloadIdCallback
ChromeDownloadManagerDelegate::GetDownloadIdReceiverCallback() {
return base::BindOnce(&ChromeDownloadManagerDelegate::SetNextId,
@ -616,20 +626,24 @@ bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
DownloadPathReservationTracker::FilenameConflictAction action =
kDefaultPlatformConflictAction;
#if BUILDFLAG(IS_ANDROID)
if (download->IsTransient() && download_path.empty() &&
download->GetMimeType() == pdf::kPDFMimeType &&
!download->IsMustDownload()) {
base::FilePath generated_filename = net::GenerateFileName(
download->GetURL(), download->GetContentDisposition(),
profile_->GetPrefs()->GetString(prefs::kDefaultCharset),
download->GetSuggestedFilename(), download->GetMimeType(),
l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
base::FilePath cache_dir;
base::android::GetCacheDirectory(&cache_dir);
download_path = cache_dir.Append(generated_filename);
}
if (!download_path.empty())
if (download->IsTransient()) {
if (download_path.empty() && download->GetMimeType() == pdf::kPDFMimeType &&
!download->IsMustDownload()) {
base::FilePath generated_filename = net::GenerateFileName(
download->GetURL(), download->GetContentDisposition(),
profile_->GetPrefs()->GetString(prefs::kDefaultCharset),
download->GetSuggestedFilename(), download->GetMimeType(),
l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
base::FilePath cache_dir;
base::android::GetCacheDirectory(&cache_dir);
download_path = cache_dir.Append(kPdfDirName).Append(generated_filename);
action = DownloadPathReservationTracker::UNIQUIFY;
} else {
action = DownloadPathReservationTracker::OVERWRITE;
}
} else if (!download_path.empty()) {
action = DownloadPathReservationTracker::UNIQUIFY;
}
#endif
DownloadTargetDeterminer::Start(download, download_path, action,
download_prefs_.get(), this,
@ -644,7 +658,7 @@ bool ChromeDownloadManagerDelegate::ShouldAutomaticallyOpenFile(
if (path.Extension().empty())
return false;
#if BUILDFLAG(ENABLE_EXTENSIONS)
// TODO(crbug.com/1077929): This determination is done based on |path|, while
// TODO(crbug.com/40129365): This determination is done based on |path|, while
// ShouldOpenDownload() detects extension downloads based on the
// characteristics of the download. Reconcile this.
if (path.MatchesExtension(extensions::kExtensionFileExtension))
@ -672,7 +686,7 @@ bool ChromeDownloadManagerDelegate::ShouldAutomaticallyOpenFileByPolicy(
if (path.Extension().empty())
return false;
#if BUILDFLAG(ENABLE_EXTENSIONS)
// TODO(crbug.com/1077929): This determination is done based on |path|, while
// TODO(crbug.com/40129365): This determination is done based on |path|, while
// ShouldOpenDownload() detects extension downloads based on the
// characteristics of the download. Reconcile this.
if (path.MatchesExtension(extensions::kExtensionFileExtension))
@ -714,11 +728,14 @@ bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if BUILDFLAG(FULL_SAFE_BROWSING)
// If this is a chrome triggered download, return true;
if (!item->RequireSafetyChecks())
if (!item->RequireSafetyChecks()) {
return true;
}
if (!download_prefs_->safebrowsing_for_trusted_sources_enabled() &&
download_prefs_->IsFromTrustedSource(*item)) {
download_prefs_->IsFromTrustedSource(*item) &&
!safe_browsing::DeepScanningRequest::ShouldUploadBinary(item)
.has_value()) {
return true;
}
@ -888,8 +905,7 @@ bool ChromeDownloadManagerDelegate::InterceptDownloadIfApplicable(
}
}
if (base::FeatureList::IsEnabled(features::kAndroidOpenPdfInline) &&
mime_type == pdf::kPDFMimeType) {
if (ShouldOpenPdfInline() && mime_type == pdf::kPDFMimeType) {
// If this is already a file, there is no need to download.
if (url.SchemeIsFile() || url.SchemeIs("content")) {
return true;
@ -995,10 +1011,11 @@ void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, false);
if (download->GetMimeType() == "application/x-x509-user-cert")
if (download->GetMimeType() == "application/x-x509-user-cert") {
chrome::ShowSettingsSubPage(browser, "certificates");
else
browser->OpenURL(params);
} else {
browser->OpenURL(params, /*navigation_handle_callback=*/{});
}
RecordDownloadOpen(DOWNLOAD_OPEN_METHOD_DEFAULT_BROWSER,
download->GetMimeType());
@ -1456,10 +1473,6 @@ void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
danger_type = download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING;
is_pending_scanning = true;
break;
case safe_browsing::DownloadCheckResult::BLOCKED_UNSUPPORTED_FILE_TYPE:
danger_type =
download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE;
break;
case safe_browsing::DownloadCheckResult::DANGEROUS_ACCOUNT_COMPROMISE:
danger_type =
download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE;
@ -1477,14 +1490,16 @@ void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
danger_type = download::DOWNLOAD_DANGER_TYPE_BLOCKED_SCAN_FAILED;
break;
case safe_browsing::DownloadCheckResult::IMMEDIATE_DEEP_SCAN:
is_pending_scanning = true;
danger_type = download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING;
safe_browsing::DownloadProtectionService::UploadForConsumerDeepScanning(
item,
DownloadItemWarningData::DeepScanTrigger::
TRIGGER_IMMEDIATE_DEEP_SCAN,
/*password=*/std::nullopt);
break;
// We return early because starting deep scanning immediately triggers
// this function with a `DownloadCheckResult` of `ASYNC_SCANNING`. Doing
// two updates would lead to two announced accessible alerts. See
// https://crbug.com/40926583.
return;
}
DCHECK_NE(danger_type,
download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT);
@ -1600,7 +1615,6 @@ void ChromeDownloadManagerDelegate::CheckSavePackageScanningDone(
/*allowed*/ true);
break;
case safe_browsing::DownloadCheckResult::BLOCKED_UNSUPPORTED_FILE_TYPE:
case safe_browsing::DownloadCheckResult::BLOCKED_PASSWORD_PROTECTED:
case safe_browsing::DownloadCheckResult::BLOCKED_TOO_LARGE:
case safe_browsing::DownloadCheckResult::SENSITIVE_CONTENT_BLOCK:
@ -1732,10 +1746,6 @@ bool ChromeDownloadManagerDelegate::IsOpenInBrowserPreferredForFile(
bool ChromeDownloadManagerDelegate::ShouldBlockFile(
download::DownloadItem* item,
download::DownloadDangerType danger_type) const {
// Don't block downloads if flag is set
if (base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads")) {
return false;
}
// Chrome-initiated background downloads should not be blocked.
if (item && !item->RequireSafetyChecks()) {
return false;
@ -1747,12 +1757,6 @@ bool ChromeDownloadManagerDelegate::ShouldBlockFile(
if (IsDangerTypeBlocked(danger_type))
return true;
// TODO(crbug/1061111): Move this into IsDangerTypeBlocked once the UX is
// ready.
if (danger_type ==
download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE)
return true;
bool file_type_dangerous =
(item && DownloadItemModel(item).GetDangerLevel() !=
DownloadFileType::NOT_DANGEROUS);
@ -1813,6 +1817,39 @@ void ChromeDownloadManagerDelegate::MaybeSendDangerousDownloadOpenedReport(
}
}
void ChromeDownloadManagerDelegate::MaybeSendDangerousDownloadCanceledReport(
DownloadItem* download,
bool is_shutdown) {
#if BUILDFLAG(FULL_SAFE_BROWSING)
if (!DownloadProtectionService::ShouldSendDangerousDownloadReport(download) ||
!base::FeatureList::IsEnabled(
safe_browsing::kDownloadReportWithoutUserDecision)) {
return;
}
safe_browsing::SafeBrowsingService* sb_service =
g_browser_process->safe_browsing_service();
if (!sb_service) {
return;
}
// Note: We cannot go through download_protection_service here, because this
// function may be called at shutdown. The download_protection_service
// object may already be deleted at this point.
if (is_shutdown) {
sb_service->PersistDownloadReportAndSendOnNextStartup(
download,
safe_browsing::ClientSafeBrowsingReportRequest::
DANGEROUS_DOWNLOAD_PROFILE_CLOSED,
/*did_proceed=*/false, std::nullopt);
} else {
sb_service->SendDownloadReport(
download,
safe_browsing::ClientSafeBrowsingReportRequest::
DANGEROUS_DOWNLOAD_AUTO_DELETED,
/*did_proceed=*/false, std::nullopt);
}
#endif
}
void ChromeDownloadManagerDelegate::CheckDownloadAllowed(
const content::WebContents::Getter& web_contents_getter,
const GURL& url,
@ -1946,6 +1983,11 @@ bool ChromeDownloadManagerDelegate::IsFromExternalApp(
return false;
}
bool ChromeDownloadManagerDelegate::ShouldOpenPdfInline() {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_PdfUtils_shouldOpenPdfInline(env);
}
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(FULL_SAFE_BROWSING)
@ -2013,6 +2055,7 @@ void ChromeDownloadManagerDelegate::CancelForEphemeralWarning(
LogCancelEphemeralWarningEvent(
CancelEphemeralWarningEvent::kCancellationSucceeded);
download->Cancel(/*user_cancel=*/false);
MaybeSendDangerousDownloadCanceledReport(download, /*is_shutdown=*/false);
} else {
LogCancelEphemeralWarningEvent(
CancelEphemeralWarningEvent::kCancellationFailedDownloadNotEphemeral);

View file

@ -247,7 +247,6 @@ DownloadTargetDeterminer::Result
return QUIT_DOLOOP;
}
conflict_action_ = DownloadPathReservationTracker::OVERWRITE;
DCHECK(virtual_path_.IsAbsolute());
return CONTINUE;
}
@ -483,7 +482,7 @@ void DownloadTargetDeterminer::ReserveVirtualPathDone(
<< "Transient download should not ask the user for confirmation.";
DCHECK(result != download::PathValidationResult::CONFLICT)
<< "Transient download"
"should always overwrite the file.";
"should always overwrite or uniquify the file.";
switch (result) {
case download::PathValidationResult::PATH_NOT_WRITABLE:
case download::PathValidationResult::NAME_TOO_LONG:
@ -496,8 +495,8 @@ void DownloadTargetDeterminer::ReserveVirtualPathDone(
case download::PathValidationResult::SUCCESS:
case download::PathValidationResult::SUCCESS_RESOLVED_CONFLICT:
case download::PathValidationResult::SAME_AS_SOURCE:
DCHECK_EQ(virtual_path_, path) << "Transient download path should not"
"be changed.";
DCHECK(virtual_path_ == path ||
conflict_action_ == DownloadPathReservationTracker::UNIQUIFY);
break;
case download::PathValidationResult::COUNT:
NOTREACHED();
@ -510,7 +509,7 @@ void DownloadTargetDeterminer::ReserveVirtualPathDone(
case download::PathValidationResult::SAME_AS_SOURCE:
break;
// TODO(crbug.com/1361503): This should trigger a duplicate download
// TODO(crbug.com/40863725): This should trigger a duplicate download
// prompt.
case download::PathValidationResult::SUCCESS_RESOLVED_CONFLICT:
break;
@ -960,11 +959,6 @@ DownloadTargetDeterminer::Result
DCHECK_CURRENTLY_ON(BrowserThread::UI);
next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH;
// Allow all downloads with this Thorium flag
if (base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads")) {
return CONTINUE;
}
// Checking if there are prior visits to the referrer is only necessary if the
// danger level of the download depends on the file type.
if (danger_type_ != download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS &&
@ -1271,6 +1265,13 @@ DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel(
PriorVisitsToReferrer visits) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Allow all downloads with this Thorium flag
static const bool allow_insecure_downloads_ =
base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads");
if (allow_insecure_downloads_) {
return DownloadFileType::NOT_DANGEROUS;
}
// If the user has has been prompted or will be, assume that the user has
// approved the download. A programmatic download is considered safe unless it
// contains malware.

View file

@ -36,6 +36,9 @@ using InsecureDownloadStatus = download::DownloadItem::InsecureDownloadStatus;
namespace {
static const bool allow_insecure_downloads_ =
base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads");
// Configuration for which extensions to warn/block. These parameters are set
// differently for testing, so the listed defaults are only used when the flag
// is manually enabled (and in unit tests).
@ -278,9 +281,9 @@ struct InsecureDownloadData {
// - anything extension related,
// - etc.
//
// TODO(1029062): INTERNAL_API is also used for background fetch. That
// probably isn't the correct behavior, since INTERNAL_API is otherwise used
// for Chrome stuff. Background fetch should probably be HTTPS-only.
// TODO(crbug.com/40661154): INTERNAL_API is also used for background fetch.
// That probably isn't the correct behavior, since INTERNAL_API is otherwise
// used for Chrome stuff. Background fetch should probably be HTTPS-only.
auto download_source = item->GetDownloadSource();
auto transition_type = item->GetTransitionType();
if (download_source == DownloadSource::RETRY ||
@ -334,10 +337,10 @@ struct InsecureDownloadData {
download_source == DownloadSource::INTERNAL_API ||
download_source == DownloadSource::EXTENSION_API ||
download_source == DownloadSource::EXTENSION_INSTALLER ||
base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads")) {
allow_insecure_downloads_) {
is_insecure_download_ = false;
} else { // Not ignorable download.
// TODO(crbug.com/1352598): Add blocking metrics.
// TODO(crbug.com/40857867): Add blocking metrics.
// insecure downloads are either delivered insecurely, or we can't trust
// who told us to download them (i.e. have an insecure initiator).
is_insecure_download_ =
@ -413,7 +416,7 @@ void PrintConsoleMessage(const InsecureDownloadData& data) {
bool IsDownloadPermittedByContentSettings(
Profile* profile,
const std::optional<url::Origin>& initiator) {
// TODO(crbug.com/1048957): Checking content settings crashes unit tests on
// TODO(crbug.com/40117459): Checking content settings crashes unit tests on
// Android. It shouldn't.
#if !BUILDFLAG(IS_ANDROID)
HostContentSettingsMap* host_content_settings_map =
@ -454,7 +457,12 @@ InsecureDownloadStatus GetInsecureDownloadStatusForDownload(
InsecureDownloadData data(path, item);
// If the download is fully secure, early abort.
if (!data.is_insecure_download_ || base::CommandLine::ForCurrentProcess()->HasSwitch("allow-insecure-downloads")) {
if (!data.is_insecure_download_) {
return InsecureDownloadStatus::SAFE;
}
// Don't nag
if (allow_insecure_downloads_) {
return InsecureDownloadStatus::SAFE;
}

View file

@ -36,16 +36,17 @@ found in the LICENSE file.
<org.chromium.ui.listmenu.ListMenuButton
android:id="@+id/header_menu"
android:layout_width="@dimen/feed_v2_header_menu_width"
android:layout_height="@dimen/snippets_article_header_menu_size"
android:layout_width="@dimen/min_touch_target_size"
android:layout_height="@dimen/min_touch_target_size"
android:scaleType="centerInside"
android:layout_marginStart="15dp"
android:layout_centerVertical="true"
android:paddingEnd="8dp"
android:layout_alignParentEnd="true"
android:background="@null"
android:src="@drawable/ic_settings_gear_24dp"
android:background="@drawable/toolbar_menu_button_ripple"
android:src="@drawable/ic_more_vert_24dp"
android:contentDescription="@string/accessibility_ntp_feed_menu_button"
app:menuMaxWidth="@dimen/feed_header_menu_max_width"
app:tint="@null" />
app:tint="@color/header_title_text_color_list" />
</RelativeLayout>
</org.chromium.chrome.browser.feed.sections.SectionHeaderView>

View file

@ -63,14 +63,15 @@ found in the LICENSE file.
<org.chromium.ui.listmenu.ListMenuButton
android:id="@+id/header_menu"
android:layout_width="@dimen/feed_header_icon_size"
android:layout_height="@dimen/snippets_article_header_menu_size"
android:layout_width="@dimen/min_touch_target_size"
android:layout_height="@dimen/min_touch_target_size"
android:scaleType="centerInside"
android:layout_marginStart="@dimen/feed_header_icon_margin"
android:background="@null"
android:src="@drawable/ic_settings_gear_24dp"
android:paddingEnd="8dp"
android:background="@drawable/toolbar_menu_button_ripple"
android:src="@drawable/ic_more_vert_24dp"
android:contentDescription="@string/accessibility_ntp_feed_menu_button"
app:menuMaxWidth="@dimen/feed_header_menu_max_width"
app:tint="@null" />
app:tint="@color/header_title_text_color_list" />
</LinearLayout>
</org.chromium.chrome.browser.feed.sections.SectionHeaderView>

View file

@ -5,6 +5,7 @@
#include "chrome/browser/net/profile_network_context_service.h"
#include <string>
#include <string_view>
#include "base/base64.h"
#include "base/check_op.h"
@ -38,6 +39,8 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/sct_reporting_service.h"
#include "chrome/browser/ssl/sct_reporting_service_factory.h"
#include "chrome/browser/webid/federated_identity_permission_context.h"
#include "chrome/browser/webid/federated_identity_permission_context_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_content_client.h"
@ -132,6 +135,13 @@
#include "chromeos/startup/browser_params_proxy.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#include "chrome/browser/enterprise/client_certificates/certificate_provisioning_service_factory.h"
#include "components/enterprise/client_certificates/core/certificate_provisioning_service.h"
#include "components/enterprise/client_certificates/core/client_certificates_service.h"
#include "components/enterprise/client_certificates/core/features.h"
#endif
namespace {
bool* g_discard_domain_reliability_uploads_for_testing = nullptr;
@ -154,33 +164,6 @@ std::string ComputeAcceptLanguageFromPref(const std::string& language_pref) {
return net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str);
}
#if BUILDFLAG(IS_CHROMEOS)
cert_verifier::mojom::AdditionalCertificatesPtr GetAdditionalCertificates(
const policy::PolicyCertService* policy_cert_service,
const base::FilePath& storage_partition_path) {
auto additional_certificates =
cert_verifier::mojom::AdditionalCertificates::New();
net::CertificateList all_certificates;
net::CertificateList trust_anchors;
policy_cert_service->GetPolicyCertificatesForStoragePartition(
storage_partition_path, &all_certificates, &trust_anchors);
for (const auto& cert : all_certificates) {
base::span<const uint8_t> cert_bytes =
net::x509_util::CryptoBufferAsSpan(cert->cert_buffer());
additional_certificates->all_certificates.push_back(
std::vector<uint8_t>(cert_bytes.begin(), cert_bytes.end()));
}
for (const auto& cert : trust_anchors) {
base::span<const uint8_t> cert_bytes =
net::x509_util::CryptoBufferAsSpan(cert->cert_buffer());
additional_certificates->trust_anchors.push_back(
std::vector<uint8_t>(cert_bytes.begin(), cert_bytes.end()));
}
return additional_certificates;
}
#endif // defined (OS_CHROMEOS)
// Tests allowing ambient authentication with default credentials based on the
// profile type.
bool IsAmbientAuthAllowedForProfile(Profile* profile) {
@ -246,9 +229,25 @@ void UpdateCookieSettings(Profile* profile, ContentSettingsType type) {
if (!IsContentSettingsTypeEnabled(type)) {
return;
}
ContentSettingsForOneType settings =
HostContentSettingsMapFactory::GetForProfile(profile)
->GetSettingsForOneType(type);
ContentSettingsForOneType settings;
if (type == ContentSettingsType::FEDERATED_IDENTITY_SHARING) {
// Note: FederatedIdentityPermissionContext also syncs the permissions
// directly, in order to avoid a race condition. (Namely,
// FederatedIdentityPermissionContext must guarantee that the permissions
// have propagated before it calls its callback. However, the syncing that
// occurs in this class is unsynchronized, so it would be racy to rely on
// this update finishing before calling the context's callback.) This
// unfortunately triggers a double-update here.
if (FederatedIdentityPermissionContext* fedcm_context =
FederatedIdentityPermissionContextFactory::GetForProfile(profile);
fedcm_context) {
settings = fedcm_context->GetSharingPermissionGrantsAsContentSettings();
}
} else {
settings = HostContentSettingsMapFactory::GetForProfile(profile)
->GetSettingsForOneType(type);
}
profile->ForEachLoadedStoragePartition(
[&](content::StoragePartition* storage_partition) {
storage_partition->GetCookieManagerForBrowserProcess()
@ -256,6 +255,27 @@ void UpdateCookieSettings(Profile* profile, ContentSettingsType type) {
});
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
std::unique_ptr<net::ClientCertStore> GetWrappedCertStore(
Profile* profile,
std::unique_ptr<net::ClientCertStore> platform_store) {
if (!profile || !client_certificates::features::
IsManagedClientCertificateForUserEnabled()) {
return platform_store;
}
auto* provisioning_service =
client_certificates::CertificateProvisioningServiceFactory::GetForProfile(
profile);
if (!provisioning_service) {
return platform_store;
}
return client_certificates::ClientCertificatesService::Create(
provisioning_service, std::move(platform_store));
}
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
} // namespace
ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile)
@ -276,8 +296,6 @@ ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile)
base::Unretained(this)));
cookie_settings_ = CookieSettingsFactory::GetForProfile(profile);
cookie_settings_observation_.Observe(cookie_settings_.get());
privacy_sandbox_settings_observer_.Observe(
PrivacySandboxSettingsFactory::GetForProfile(profile));
DisableQuicIfNotAllowed();
@ -314,9 +332,11 @@ ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile)
schedule_update_cert_policy);
pref_change_registrar_.Add(prefs::kCAHintCertificates,
schedule_update_cert_policy);
#if !BUILDFLAG(IS_CHROMEOS)
pref_change_registrar_.Add(prefs::kCAPlatformIntegrationEnabled,
schedule_update_cert_policy);
#endif
#endif // BUILDFLAG(CHROME_CERTIFICATE_POLICIES_SUPPORTED)
pref_change_registrar_.Add(
prefs::kGloballyScopeHTTPAuthCacheEnabled,
@ -363,22 +383,6 @@ void ProfileNetworkContextService::ConfigureNetworkContextParams(
}
}
#if BUILDFLAG(IS_CHROMEOS)
void ProfileNetworkContextService::UpdateAdditionalCertificates() {
const policy::PolicyCertService* policy_cert_service =
policy::PolicyCertServiceFactory::GetForProfile(profile_);
if (!policy_cert_service)
return;
profile_->ForEachLoadedStoragePartition(
[&](content::StoragePartition* storage_partition) {
auto additional_certificates = GetAdditionalCertificates(
policy_cert_service, storage_partition->GetPath());
storage_partition->GetCertVerifierServiceUpdater()
->UpdateAdditionalCertificates(std::move(additional_certificates));
});
}
#endif
void ProfileNetworkContextService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(embedder_support::kAlternateErrorPagesEnabled,
@ -392,9 +396,11 @@ void ProfileNetworkContextService::RegisterProfilePrefs(
registry->RegisterListPref(prefs::kCACertificatesWithConstraints);
registry->RegisterListPref(prefs::kCADistrustedCertificates);
registry->RegisterListPref(prefs::kCAHintCertificates);
#if !BUILDFLAG(IS_CHROMEOS)
// Include user added platform certs by default.
registry->RegisterBooleanPref(prefs::kCAPlatformIntegrationEnabled, true);
#endif
#endif // BUILDFLAG(CHROME_CERTIFICATE_POLICIES_SUPPORTED)
}
// static
@ -470,14 +476,6 @@ void ProfileNetworkContextService::OnTruncatedCookieBlockingChanged() {
});
}
void ProfileNetworkContextService::OnFirstPartySetsEnabledChanged(
bool enabled) {
// Update all FPS Access Delegates on the FPS service to be `enabled`.
first_party_sets::FirstPartySetsPolicyServiceFactory::GetForBrowserContext(
profile_)
->OnFirstPartySetsEnabledChanged(enabled);
}
std::string ProfileNetworkContextService::ComputeAcceptLanguage() const {
// If reduce accept language is enabled, only return the first language
// without expanding the language list.
@ -546,11 +544,36 @@ void ProfileNetworkContextService::ScheduleUpdateCTPolicy() {
#if BUILDFLAG(CHROME_CERTIFICATE_POLICIES_SUPPORTED)
cert_verifier::mojom::AdditionalCertificatesPtr
ProfileNetworkContextService::GetCertificatePolicy() {
ProfileNetworkContextService::GetCertificatePolicy(
const base::FilePath& storage_partition_path) {
auto* prefs = profile_->GetPrefs();
auto additional_certificates =
cert_verifier::mojom::AdditionalCertificates::New();
#if BUILDFLAG(IS_CHROMEOS)
const policy::PolicyCertService* policy_cert_service =
policy::PolicyCertServiceFactory::GetForProfile(profile_);
if (policy_cert_service) {
net::CertificateList all_certificates;
net::CertificateList trust_anchors;
policy_cert_service->GetPolicyCertificatesForStoragePartition(
storage_partition_path, &all_certificates, &trust_anchors);
for (const auto& cert : all_certificates) {
base::span<const uint8_t> cert_bytes =
net::x509_util::CryptoBufferAsSpan(cert->cert_buffer());
additional_certificates->all_certificates.push_back(
std::vector<uint8_t>(cert_bytes.begin(), cert_bytes.end()));
}
for (const auto& cert : trust_anchors) {
base::span<const uint8_t> cert_bytes =
net::x509_util::CryptoBufferAsSpan(cert->cert_buffer());
additional_certificates->trust_anchors.push_back(
std::vector<uint8_t>(cert_bytes.begin(), cert_bytes.end()));
}
}
#endif // BUILDFLAG(IS_CHROMEOS)
for (const base::Value& cert_b64 :
prefs->GetList(prefs::kCAHintCertificates)) {
std::optional<std::vector<uint8_t>> decoded_opt =
@ -680,7 +703,7 @@ ProfileNetworkContextService::GetCertificatePolicy() {
if (!base::Base64Decode(cert_b64.GetString(), &decoded)) {
continue;
}
base::StringPiece spki_piece;
std::string_view spki_piece;
bool success = net::asn1::ExtractSPKIFromDERCert(decoded, &spki_piece);
if (success) {
additional_certificates->distrusted_spkis.emplace_back(spki_piece.begin(),
@ -688,30 +711,29 @@ ProfileNetworkContextService::GetCertificatePolicy() {
}
}
#if !BUILDFLAG(IS_CHROMEOS)
additional_certificates->include_system_trust_store =
prefs->GetBoolean(prefs::kCAPlatformIntegrationEnabled);
#endif
return additional_certificates;
}
void ProfileNetworkContextService::UpdateCertificatePolicy() {
std::vector<cert_verifier::mojom::CertVerifierServiceUpdater*> updaters;
void ProfileNetworkContextService::UpdateAdditionalCertificates() {
profile_->ForEachLoadedStoragePartition(
[&](content::StoragePartition* storage_partition) {
updaters.push_back(storage_partition->GetCertVerifierServiceUpdater());
storage_partition->GetCertVerifierServiceUpdater()
->UpdateAdditionalCertificates(
GetCertificatePolicy(storage_partition->GetPath()));
});
for (auto* updater : updaters) {
updater->UpdateAdditionalCertificates(GetCertificatePolicy());
}
}
void ProfileNetworkContextService::ScheduleUpdateCertificatePolicy() {
cert_policy_update_timer_.Start(
FROM_HERE, base::Seconds(0), this,
&ProfileNetworkContextService::UpdateCertificatePolicy);
&ProfileNetworkContextService::UpdateAdditionalCertificates);
}
#endif
#endif // BUILDFLAG(CHROME_CERTIFICATE_POLICIES_SUPPORTED)
bool ProfileNetworkContextService::ShouldSplitAuthCacheByNetworkIsolationKey()
const {
@ -778,8 +800,19 @@ ProfileNetworkContextService::CreateCookieManagerParams(
if (!IsContentSettingsTypeEnabled(type)) {
continue;
}
out->content_settings[type] =
host_content_settings_map->GetSettingsForOneType(type);
if (type == ContentSettingsType::FEDERATED_IDENTITY_SHARING) {
if (FederatedIdentityPermissionContext* fedcm_context =
FederatedIdentityPermissionContextFactory::GetForProfile(profile);
fedcm_context) {
out->content_settings[type] =
fedcm_context->GetSharingPermissionGrantsAsContentSettings();
} else {
out->content_settings[type] = ContentSettingsForOneType();
}
} else {
out->content_settings[type] =
host_content_settings_map->GetSettingsForOneType(type);
}
}
out->cookie_access_delegate_type =
@ -792,7 +825,8 @@ ProfileNetworkContextService::CreateCookieManagerParams(
cookie_settings.MitigationsEnabledFor3pcd();
out->tracking_protection_enabled_for_3pcd =
cookie_settings.TrackingProtectionEnabledFor3pcd();
TrackingProtectionSettingsFactory::GetForProfile(profile)
->IsTrackingProtection3pcdEnabled();
return out;
}
@ -807,6 +841,15 @@ void ProfileNetworkContextService::FlushCachedClientCertIfNeeded(
});
}
void ProfileNetworkContextService::FlushMatchingCachedClientCert(
const scoped_refptr<net::X509Certificate>& certificate) {
profile_->ForEachLoadedStoragePartition(
[&](content::StoragePartition* storage_partition) {
storage_partition->GetNetworkContext()->FlushMatchingCachedClientCert(
certificate);
});
}
void ProfileNetworkContextService::FlushProxyConfigMonitorForTesting() {
proxy_config_monitor_.FlushForTesting();
}
@ -871,7 +914,7 @@ ProfileNetworkContextService::CreateClientCertStore() {
if (!Profile::FromBrowserContext(
chrome::GetBrowserContextRedirectedInIncognito(profile_))
->IsMainProfile()) {
// TODO(crbug.com/1148298): At the moment client certs are only enabled for
// TODO(crbug.com/40156976): At the moment client certs are only enabled for
// the main profile and its incognito profile (similarly to how it worked in
// Ash-Chrome). Return some cert store for secondary profiles in
// Lacros-Chrome when certs are supported there.
@ -886,18 +929,16 @@ ProfileNetworkContextService::CreateClientCertStore() {
return store;
#elif BUILDFLAG(IS_WIN)
return std::make_unique<net::ClientCertStoreWin>();
return GetWrappedCertStore(profile_,
std::make_unique<net::ClientCertStoreWin>());
#elif BUILDFLAG(IS_MAC)
return std::make_unique<net::ClientCertStoreMac>();
return GetWrappedCertStore(profile_,
std::make_unique<net::ClientCertStoreMac>());
#elif BUILDFLAG(IS_ANDROID)
// Android does not use the ClientCertStore infrastructure. On Android client
// cert matching is done by the OS as part of the call to show the cert
// selection dialog.
return nullptr;
#elif BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/1380609): Implement ClientCertStore support.
NOTIMPLEMENTED_LOG_ONCE();
return nullptr;
#else
#error Unknown platform.
#endif
@ -950,21 +991,6 @@ bool GetHttpCacheBackendResetParam(PrefService* local_state) {
current_field_trial_status != previous_field_trial_status;
}
#if BUILDFLAG(IS_CHROMEOS)
void ProfileNetworkContextService::PopulateInitialAdditionalCerts(
const base::FilePath& relative_partition_path,
cert_verifier::mojom::CertVerifierCreationParams* creation_params) {
if (policy::PolicyCertServiceFactory::CreateAndStartObservingForProfile(
profile_)) {
const policy::PolicyCertService* policy_cert_service =
policy::PolicyCertServiceFactory::GetForProfile(profile_);
creation_params->initial_additional_certificates =
GetAdditionalCertificates(policy_cert_service,
GetPartitionPath(relative_partition_path));
}
}
#endif // BUILDFLAG(IS_CHROMEOS)
void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
bool in_memory,
const base::FilePath& relative_partition_path,
@ -1052,6 +1078,7 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
// network service.
network_context_params->enable_locking_cookie_database =
base::FeatureList::IsEnabled(features::kLockProfileCookieDatabase);
#endif // BUILDFLAG(IS_WIN)
if (base::FeatureList::IsEnabled(
features::kUseOsCryptAsyncForCookieEncryption)) {
@ -1060,7 +1087,6 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
network_context_params);
}
#endif // BUILDFLAG(IS_WIN)
network_context_params->file_paths->trust_token_database_name =
base::FilePath(chrome::kTrustTokenFilename);
@ -1136,8 +1162,7 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
}
}
PopulateInitialAdditionalCerts(relative_partition_path,
cert_verifier_creation_params);
policy::PolicyCertServiceFactory::CreateAndStartObservingForProfile(profile_);
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
@ -1161,20 +1186,17 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
}
}
if (profile_supports_policy_certs) {
PopulateInitialAdditionalCerts(relative_partition_path,
cert_verifier_creation_params);
policy::PolicyCertServiceFactory::CreateAndStartObservingForProfile(
profile_);
}
#endif
#if BUILDFLAG(CHROME_CERTIFICATE_POLICIES_SUPPORTED)
// TODO(crbug.com/1477317): check to see if IsManaged() ensures the pref isn't
// set in user profiles, or if that does something else. If that's true, add
// an isManaged() check here.
// TODO(crbug.com/1477317): when adding ChromeOS support for these policies
// figure out how to integrate in the ChromeOS enterprise policy support with
// these policies.
// TODO(crbug.com/40928765): check to see if IsManaged() ensures the pref
// isn't set in user profiles, or if that does something else. If that's true,
// add an isManaged() check here.
cert_verifier_creation_params->initial_additional_certificates =
GetCertificatePolicy();
GetCertificatePolicy(GetPartitionPath(relative_partition_path));
#endif
#if BUILDFLAG(IS_CHROMEOS)
@ -1236,6 +1258,9 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
network_context_params->enable_ip_protection =
ipp_config_provider->IsIpProtectionEnabled();
}
network_context_params->device_bound_sessions_enabled =
base::FeatureList::IsEnabled(net::features::kDeviceBoundSessions);
}
base::FilePath ProfileNetworkContextService::GetPartitionPath(

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
// Copyright 2024 The Chromium Authors and Alex313031
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@ -198,7 +198,7 @@ BrowserRootView::DropInfo::~DropInfo() {
BrowserRootView::BrowserRootView(BrowserView* browser_view,
views::Widget* widget)
: views::internal::RootView(widget), browser_view_(browser_view) {
scroll_event_changes_tab_ = ShouldScrollChangesTab();
scroll_event_changes_tab_ = ShouldScrollChangesTab();
}
BrowserRootView::~BrowserRootView() {
@ -240,7 +240,7 @@ bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
// necessary because we don't want to return true if the custom MIME type is
// there but the mouse is not over the tab strip region, and we don't know the
// current mouse location.
// TODO(crbug.com/1307594): This is a smoking gun code smell;
// TODO(crbug.com/40828528): This is a smoking gun code smell;
// TabStripRegionView and Toolbar have different affordances, so they should
// separately override the drag&drop methods.
if (data.HasCustomFormat(
@ -416,7 +416,8 @@ void BrowserRootView::OnMouseExited(const ui::MouseEvent& event) {
RootView::OnMouseExited(event);
}
gfx::Size BrowserRootView::CalculatePreferredSize() const {
gfx::Size BrowserRootView::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
return browser_view_->GetRestoredBounds().size();
}
@ -474,28 +475,23 @@ void BrowserRootView::PaintChildren(const views::PaintInfo& paint_info) {
cc::PaintFlags flags;
flags.setColor(toolbar_top_separator_color);
flags.setAntiAlias(true);
if (features::IsChromeRefresh2023()) {
const float stroke_width = scale;
// Outset the rectangle and corner radius by half the stroke width
// to draw an outer stroke.
const float stroke_outset = stroke_width / 2;
const float corner_radius =
GetLayoutConstant(TOOLBAR_CORNER_RADIUS) * scale + stroke_outset;
const float stroke_width = scale;
// Outset the rectangle and corner radius by half the stroke width
// to draw an outer stroke.
const float stroke_outset = stroke_width / 2;
const float corner_radius =
GetLayoutConstant(TOOLBAR_CORNER_RADIUS) * scale + stroke_outset;
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setStrokeWidth(stroke_width);
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setStrokeWidth(stroke_width);
// Only draw the top half of the rounded rect.
canvas->ClipRect(gfx::RectF(x, 0, width, bottom + corner_radius),
SkClipOp::kIntersect);
// Only draw the top half of the rounded rect.
canvas->ClipRect(gfx::RectF(x, 0, width, bottom + corner_radius),
SkClipOp::kIntersect);
gfx::RectF rect(x, bottom, width, 2 * corner_radius);
rect.Outset(stroke_outset);
canvas->DrawRoundRect(rect, corner_radius, flags);
} else {
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawRect(gfx::RectF(x, bottom - scale, width, scale), flags);
}
gfx::RectF rect(x, bottom, width, 2 * corner_radius);
rect.Outset(stroke_outset);
canvas->DrawRoundRect(rect, corner_radius, flags);
}
}

View file

@ -89,7 +89,8 @@ class BrowserRootView : public views::internal::RootView {
DropCallback GetDropCallback(const ui::DropTargetEvent& event) override;
bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
gfx::Size CalculatePreferredSize() const override;
gfx::Size CalculatePreferredSize(
const views::SizeBounds& available_size) const override;
protected:
// views::View:

View file

@ -113,6 +113,10 @@ constexpr int kTabAlertIndicatorCloseButtonPaddingAdjustmentTouchUI = 8;
constexpr int kTabAlertIndicatorCloseButtonPaddingAdjustment = 6;
constexpr int kTabAlertIndicatorCloseButtonPaddingAdjustmentRefresh = 4;
// When the DiscardRingImprovements feature is enabled, increase the radius of
// the discard ring by this amount if there is enough space.
constexpr int kIncreasedDiscardIndicatorRadiusDp = 2;
bool g_show_hover_card_on_mouse_hover = true;
// Helper functions ------------------------------------------------------------
@ -228,17 +232,11 @@ Tab::Tab(TabSlotController* controller)
// |title_| paints on top of an opaque region (the tab background) of a
// non-opaque layer (the tabstrip's layer), which cannot currently be detected
// by the subpixel-rendering opacity check.
// TODO(https://crbug.com/1139395): Improve the check so that this case doen't
// TODO(crbug.com/40725997): Improve the check so that this case doen't
// need a manual suppression by detecting cases where the text is painted onto
// onto opaque parts of a not-entirely-opaque layer.
title_->SetSkipSubpixelRenderingOpacityCheck(true);
if (features::IsChromeRefresh2023() &&
base::FeatureList::IsEnabled(features::kChromeRefresh2023TopChromeFont)) {
title_->SetTextContext(views::style::CONTEXT_LABEL);
title_->SetTextStyle(views::style::STYLE_BODY_4_EMPHASIS);
}
AddChildView(title_.get());
SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
@ -337,6 +335,16 @@ void Tab::Layout(PassKey) {
} else {
MaybeAdjustLeftForPinnedTab(&favicon_bounds, gfx::kFaviconSize);
}
if (base::FeatureList::IsEnabled(
performance_manager::features::kDiscardRingImprovements)) {
icon_->EnlargeDiscardIndicatorRadius(
width() - 2 * tab_style()->GetBottomCornerRadius() >=
gfx::kFaviconSize + 2 * kIncreasedDiscardIndicatorRadiusDp
? kIncreasedDiscardIndicatorRadiusDp
: 0);
}
// Add space for insets outside the favicon bounds.
favicon_bounds.Inset(-icon_->GetInsets());
favicon_bounds.set_size(icon_->GetPreferredSize());
@ -650,7 +658,7 @@ void Tab::MaybeUpdateHoverStatus(const ui::MouseEvent& event) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Move the hit test area for hovering up so that it is not overlapped by tab
// hover cards when they are shown.
// TODO(crbug.com/978134): Once Linux/CrOS widget transparency is solved,
// TODO(crbug.com/41467565): Once Linux/CrOS widget transparency is solved,
// remove that case.
constexpr int kHoverCardOverlap = 6;
if (event.location().y() >= height() - kHoverCardOverlap) {
@ -747,7 +755,8 @@ void Tab::GetAccessibleNodeData(ui::AXNodeData* node_data) {
}
}
gfx::Size Tab::CalculatePreferredSize() const {
gfx::Size Tab::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
return gfx::Size(tab_style()->GetStandardWidth(),
GetLayoutConstant(TAB_HEIGHT));
}
@ -985,13 +994,14 @@ void Tab::SetTabNeedsAttention(bool attention) {
SchedulePaint();
}
void Tab::SetFreezingVoteToken(
std::unique_ptr<performance_manager::freezing::FreezingVoteToken> token) {
freezing_token_ = std::move(token);
void Tab::CreateFreezingVote(content::WebContents* contents) {
if (!freezing_vote_.has_value()) {
freezing_vote_.emplace(contents);
}
}
void Tab::ReleaseFreezingVoteToken() {
freezing_token_.reset();
void Tab::ReleaseFreezingVote() {
freezing_vote_.reset();
}
// static
@ -1027,8 +1037,8 @@ void Tab::MaybeAdjustLeftForPinnedTab(gfx::Rect* bounds,
const int pinned_width = tab_style()->GetPinnedWidth();
const int ideal_delta = width() - pinned_width;
const int ideal_x = (pinned_width - visual_width) / 2;
// TODO(crbug.com/533570): This code is broken when the current width is less
// than the pinned width.
// TODO(crbug.com/40436434): This code is broken when the current width is
// less than the pinned width.
bounds->set_x(
bounds->x() +
base::ClampRound(

View file

@ -14,11 +14,12 @@
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
@ -29,6 +30,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/not_fatal_until.h"
#include "base/numerics/safe_conversions.h"
#include "base/observer_list.h"
#include "base/ranges/algorithm.h"
@ -169,7 +171,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
// from us before our destructor is even called.
~TabDragContextImpl() override = default;
gfx::Size CalculatePreferredSize() const override {
gfx::Size CalculatePreferredSize(
const views::SizeBounds& available_size) const override {
int max_child_x = 0;
for (views::View* child : children()) {
if (!views::IsViewClass<TabSlotView>(child)) {
@ -298,17 +301,21 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
}
}
DCHECK(!dragging_views.empty());
DCHECK(base::Contains(dragging_views, source));
CHECK(!dragging_views.empty(), base::NotFatalUntil::M128)
<< "Dragging views cannot be empty during drag initialization.";
CHECK(base::Contains(dragging_views, source), base::NotFatalUntil::M128)
<< "Source must be part of dragging views.";
// Delete the existing DragController before creating a new one. We do this
// as creating the DragController remembers the WebContents delegates and we
// need to make sure the existing DragController isn't still a delegate.
drag_controller_.reset();
DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
CHECK((event.type() == ui::ET_MOUSE_PRESSED ||
event.type() == ui::ET_GESTURE_TAP_DOWN ||
event.type() == ui::ET_GESTURE_SCROLL_BEGIN);
event.type() == ui::ET_GESTURE_SCROLL_BEGIN),
base::NotFatalUntil::M128)
<< "Event type must be suitable for starting a drag.";
drag_controller_ = std::make_unique<TabDragController>();
@ -400,8 +407,12 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
void OwnDragController(
std::unique_ptr<TabDragController> controller) override {
DCHECK(controller);
DCHECK(!drag_controller_);
CHECK(controller, base::NotFatalUntil::M128)
<< "The provided TabDragController is null, which is not expected.";
CHECK(!drag_controller_, base::NotFatalUntil::M128)
<< "Attempting to own a new drag controller while one already exists.";
drag_controller_ = std::move(controller);
if (drag_controller_set_callback_) {
std::move(drag_controller_set_callback_).Run(drag_controller_.get());
@ -505,9 +516,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
const int first_dragged_tab_model_index =
tab_strip_->GetModelIndexOf(dragged_views[group.has_value() ? 1 : 0])
.value();
const int index =
CalculateInsertionIndex(dragged_bounds, first_dragged_tab_model_index,
num_dragged_tabs, std::move(group));
const int index = CalculateInsertionIndex(
dragged_bounds, first_dragged_tab_model_index, num_dragged_tabs, group);
const Tab* last_visible_tab = tab_strip_->GetLastVisibleTab();
int last_insertion_point =
@ -523,7 +533,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
std::vector<gfx::Rect> CalculateBoundsForDraggedViews(
const std::vector<raw_ptr<TabSlotView, VectorExperimental>>& views)
override {
DCHECK(!views.empty());
CHECK(!views.empty(), base::NotFatalUntil::M128)
<< "The views vector must not be empty.";
std::vector<gfx::Rect> bounds;
const int overlap = TabStyle::Get()->GetTabOverlap();
@ -540,8 +551,11 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
void SetBoundsForDrag(
const std::vector<raw_ptr<TabSlotView, VectorExperimental>>& views,
const std::vector<gfx::Rect>& bounds) override {
CHECK(!views.empty() || !bounds.empty(), base::NotFatalUntil::M128)
<< "Views and bounds cannot both be empty.";
tab_strip_->tab_container_->CancelAnimation();
DCHECK_EQ(views.size(), bounds.size());
CHECK_EQ(views.size(), bounds.size(), base::NotFatalUntil::M128)
<< "The sizes of views and bounds must match.";
for (size_t i = 0; i < views.size(); ++i) {
views[i]->SetBoundsRect(bounds[i]);
}
@ -554,9 +568,9 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
// Reset the layout size as we've effectively laid out a different size.
// This ensures a layout happens after the drag is done.
tab_strip_->tab_container_->InvalidateIdealBounds();
if (views.at(0)->group().has_value()) {
if (views[0]->group().has_value()) {
tab_strip_->tab_container_->UpdateTabGroupVisuals(
views.at(0)->group().value());
views[0]->group().value());
}
}
@ -569,7 +583,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
// No tabs should be dragging at this point.
for (int i = 0; i < GetTabCount(); ++i) {
DCHECK(!GetTabAt(i)->dragging());
CHECK(!GetTabAt(i)->dragging(), base::NotFatalUntil::M128)
<< "A tab is still marked as dragging when starting a new drag.";
}
tab_strip_->tab_container_->CompleteAnimationAndLayout();
@ -641,7 +656,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
const gfx::Point& location,
bool initial_drag) override {
std::vector<gfx::Rect> bounds = CalculateBoundsForDraggedViews(views);
DCHECK_EQ(views.size(), bounds.size());
CHECK_EQ(views.size(), bounds.size(), base::NotFatalUntil::M128)
<< "The sizes of views and bounds must match in LayoutDraggedViewsAt.";
// The index of `source_view` in the TabStrip's viewmodel.
std::optional<int> source_view_model_index = GetIndexOf(source_view);
@ -825,7 +841,9 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
}
}
CHECK_NE(min_distance_index, -1);
CHECK_NE(min_distance_index, -1)
<< "No valid insertion index found for the dragged tab, which "
"indicates a potential logic error in tab placement calculations.";
// When moving a tab within a tabstrip, the target index is expressed as if
// the tabs are not in the tabstrip, i.e. it acts like the tabs are first
@ -997,7 +1015,8 @@ TabStrip::~TabStrip() {
RemoveChildViewT(base::to_address(tab_container_));
RemoveChildViewT(base::to_address(drag_context_));
CHECK(!IsInObserverList());
CHECK(!IsInObserverList())
<< "TabStrip should not be in any observer lists at destruction.";
}
void TabStrip::SetAvailableWidthCallback(
@ -1067,7 +1086,8 @@ void TabStrip::UpdateLoadingAnimations(const base::TimeDelta& elapsed_time) {
}
void TabStrip::AddTabAt(int model_index, TabRendererData data) {
DCHECK(IsValidModelIndex(model_index));
CHECK(IsValidModelIndex(model_index), base::NotFatalUntil::M128)
<< "Attempted to add a tab with an invalid model index.";
const bool pinned = data.pinned;
Tab* tab = tab_container_->AddTab(
@ -1087,10 +1107,10 @@ void TabStrip::AddTabAt(int model_index, TabRendererData data) {
observer.OnTabAdded(model_index);
}
// At the start of AddTabAt() the model and tabs are out sync. Any queries to
// find a tab given a model index can go off the end of |tabs_|. As such, it
// is important that we complete the drag *after* adding the tab so that the
// model and tabstrip are in sync.
// At the start of AddTabAt() the model and tabs are out of sync. Any queries
// to find a tab given a model index can go off the end of |tabs_|. As such,
// it is important that we complete the drag *after* adding the tab so that
// the model and tabstrip are in sync.
drag_context_->TabWasAdded();
Profile* profile = controller_->GetProfile();
@ -1115,7 +1135,9 @@ void TabStrip::AddTabAt(int model_index, TabRendererData data) {
void TabStrip::MoveTab(int from_model_index,
int to_model_index,
TabRendererData data) {
DCHECK_GT(GetTabCount(), 0);
CHECK_GT(GetTabCount(), 0, base::NotFatalUntil::M128)
<< "The tab strip must contain at least one tab to perform a move "
"operation.";
Tab* moving_tab = tab_at(from_model_index);
moving_tab->SetData(std::move(data));
@ -1135,7 +1157,10 @@ void TabStrip::RemoveTabAt(content::WebContents* contents,
// OnTabWillBeRemoved should have ended any ongoing drags containing
// `contents` already - unless the call is coming from inside the house! (i.e.
// the TabDragController is doing the removing as part of reverting a drag)
DCHECK(drag_context_->CanRemoveTabIfDragging(contents));
CHECK(drag_context_->CanRemoveTabIfDragging(contents),
base::NotFatalUntil::M128)
<< "Attempted to remove a tab that could not be removed during drag.";
tab_container_->RemoveTab(model_index, was_active);
UpdateHoverCard(nullptr, HoverCardUpdateType::kTabRemoved);
@ -1275,8 +1300,11 @@ bool TabStrip::ShouldDrawStrokes() const {
}
void TabStrip::SetSelection(const ui::ListSelectionModel& new_selection) {
DCHECK(new_selection.active().has_value())
// This CHECK ensures there is always an active tab to maintain UI
// consistency.
CHECK(new_selection.active().has_value(), base::NotFatalUntil::M128)
<< "We should never transition to a state where no tab is active.";
Tab* const new_active_tab = tab_at(new_selection.active().value());
Tab* const old_active_tab = selected_tabs_.active().has_value()
? tab_at(selected_tabs_.active().value())
@ -1355,7 +1383,7 @@ std::optional<int> TabStrip::GetModelIndexOf(const TabSlotView* view) const {
const std::optional<int> viewmodel_index =
tab_container_->GetModelIndexOf(view);
// TODO(1392523): The viewmodel (as accessed by
// TODO(crbug.com/40880410): The viewmodel (as accessed by
// `tab_container_->GetModelIndexOf(Tab*)`) can be out of sync with the actual
// TabStripModel when multiple tabs are closed at once. We can check
// IsValidModelIndex to avoid crashes or out of bounds issues, but we can't
@ -1469,9 +1497,9 @@ bool TabStrip::IsAnimatingInTabStrip() const {
void TabStrip::UpdateAnimationTarget(TabSlotView* tab_slot_view,
gfx::Rect target_bounds) {
// TODO(1116121): This may need to do coordinate space transformations if the
// view hierarchy changes so `tab_container_` and `drag_context_` don't share
// spaces.
// TODO(crbug.com/40711732): This may need to do coordinate space
// transformations if the view hierarchy changes so `tab_container_` and
// `drag_context_` don't share spaces.
drag_context_->UpdateAnimationTarget(tab_slot_view, target_bounds);
}
@ -1638,7 +1666,7 @@ void TabStrip::ToggleTabGroupCollapsedState(
// If tab count changed, all tab groups are collapsed and we have
// created a new tab. We need to exit closing mode to resize the new
// tab immediately.
// TODO(crbug/1384151): This should be captured along with the
// TODO(crbug.com/40878307): This should be captured along with the
// ToggleTabGroup logic, so other callers to
// TabStripController::ToggleTabGroupCollapsedState see the same
// behavior.
@ -1700,9 +1728,11 @@ void TabStrip::MaybeStartDrag(
// Check that the source is either a valid tab or a tab group header, which
// are the only valid drag targets.
DCHECK(GetModelIndexOf(source).has_value() ||
source->GetTabSlotViewType() ==
TabSlotView::ViewType::kTabGroupHeader);
CHECK(GetModelIndexOf(source).has_value() ||
source->GetTabSlotViewType() ==
TabSlotView::ViewType::kTabGroupHeader,
base::NotFatalUntil::M128)
<< "Drag source must be a valid tab or a tab group header.";
drag_context_->MaybeStartDrag(source, event, original_selection);
has_reported_tab_drag_metrics_ = false;
@ -1778,18 +1808,11 @@ void TabStrip::OnMouseEventInTab(views::View* source,
void TabStrip::UpdateHoverCard(Tab* tab, HoverCardUpdateType update_type) {
if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("tab-hover-cards") == "tooltip" ||
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("tab-hover-cards") == "none") return;
tab_container_->UpdateHoverCard(tab, update_type);
}
bool TabStrip::ShowDomainInHoverCards() const {
#if BUILDFLAG(IS_CHROMEOS_ASH)
const auto* app_controller = GetBrowser()->app_controller();
if (app_controller && app_controller->system_app()) {
return false;
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("tab-hover-cards") == "none") {
return;
} else {
tab_container_->UpdateHoverCard(tab, update_type);
}
#endif
return true;
}
bool TabStrip::HoverCardIsShowingForTab(Tab* tab) {
@ -1896,9 +1919,8 @@ const Browser* TabStrip::GetBrowser() const {
// TabStrip, views::View overrides:
views::SizeBounds TabStrip::GetAvailableSize(const views::View* child) const {
// We can only reach here if SetAvailableWidthCallback() was never called,
// e.g. if tab scrolling is disabled. Defer to our parent.
DCHECK(child == base::to_address(tab_container_));
CHECK(child == base::to_address(tab_container_), base::NotFatalUntil::M128)
<< "The child view does not match the expected tab_container_ address.";
return parent()->GetAvailableSize(this);
}
@ -1911,11 +1933,12 @@ gfx::Size TabStrip::GetMinimumSize() const {
return min_size;
}
gfx::Size TabStrip::CalculatePreferredSize() const {
gfx::Size TabStrip::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
// `tab_container_` and `drag_context_` overlap (both share TabStrip's
// origin), so we need to be able to cover the union of their bounds.
gfx::Size preferred_size = tab_container_->GetPreferredSize();
preferred_size.SetToMax(drag_context_->GetPreferredSize());
gfx::Size preferred_size = tab_container_->GetPreferredSize(available_size);
preferred_size.SetToMax(drag_context_->GetPreferredSize(available_size));
return preferred_size;
}
@ -1939,12 +1962,14 @@ void TabStrip::Layout(PassKey) {
}
if (tab_container_->bounds() != GetLocalBounds()) {
UpdateHoverCard(nullptr,
TabSlotController::HoverCardUpdateType::kAnimating);
tab_container_->SetBoundsRect(GetLocalBounds());
} else {
// We still need to layout in this case, as the available width may have
// changed, which can change layout outcomes (e.g. affecting tab
// visibility). See https://crbug.com/1370459.
// TODO(crbug.com/1371301): TabContainer should observe available width
// TODO(crbug.com/40870361): TabContainer should observe available width
// changes and invalidate its layout when needed.
tab_container_->DeprecatedLayoutImmediately();
}
@ -2019,7 +2044,9 @@ void TabStrip::NewTabButtonPressed(const ui::Event& event) {
if (ui::Clipboard::IsSupportedClipboardBuffer(
ui::ClipboardBuffer::kSelection)) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
CHECK(clipboard);
CHECK(clipboard)
<< "Clipboard instance is not available, cannot proceed with "
"middle mouse button action.";
std::u16string clipboard_text;
clipboard->ReadText(ui::ClipboardBuffer::kSelection,
/* data_dst = */ nullptr, &clipboard_text);
@ -2148,7 +2175,8 @@ void TabStrip::UpdateContrastRatioValues() {
}
void TabStrip::ShiftTabRelative(Tab* tab, int offset) {
DCHECK_EQ(1, std::abs(offset));
CHECK_EQ(1, std::abs(offset), base::NotFatalUntil::M128)
<< "Offset must be 1 or -1 to shift tab left or right.";
const std::optional<int> maybe_start_index = GetModelIndexOf(tab);
if (!maybe_start_index.has_value()) {
return;
@ -2218,7 +2246,8 @@ void TabStrip::ShiftTabRelative(Tab* tab, int offset) {
void TabStrip::ShiftGroupRelative(const tab_groups::TabGroupId& group,
int offset) {
DCHECK_EQ(1, std::abs(offset));
CHECK_EQ(1, std::abs(offset), base::NotFatalUntil::M128)
<< "Offset must be 1 or -1 to shift the group left or right.";
gfx::Range tabs_in_group = controller_->ListTabsInGroup(group);
const int start_index = tabs_in_group.start();
@ -2238,7 +2267,8 @@ void TabStrip::ShiftGroupRelative(const tab_groups::TabGroupId& group,
std::optional<tab_groups::TabGroupId> target_group =
tab_at(index_of_skipped_over_tab)->group();
if (target_group.has_value()) {
CHECK_NE(target_group.value(), group);
CHECK_NE(target_group.value(), group)
<< "The target group must be different from the current group to move.";
}
const int num_skipped_tabs =
@ -2275,7 +2305,8 @@ void TabStrip::TabContextMenuController::ShowContextMenuForViewImpl(
ui::MenuSourceType source_type) {
// We are only intended to be installed as a context-menu handler for tabs, so
// this cast should be safe.
DCHECK(views::IsViewClass<Tab>(source));
CHECK(views::IsViewClass<Tab>(source), base::NotFatalUntil::M128)
<< "The source must be a Tab class.";
Tab* const tab = static_cast<Tab*>(source);
if (tab->closing()) {
return;

View file

@ -7,11 +7,11 @@
#include <algorithm>
#include <utility>
#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/strcat.h"
#include "base/command_line.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_shader.h"
#include "chrome/browser/themes/theme_properties.h"
@ -997,7 +997,7 @@ void GM2TabStyleViews::PaintBackgroundHover(gfx::Canvas* canvas,
TabStyle::TabSelectionState::kActive, /*hovered=*/false),
hover_controller_->GetAlpha());
// TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
// TODO(crbug.com/40219248): Remove FromColor and make all SkColor4f.
const SkColor4f colors[2] = {
SkColor4f::FromColor(color),
SkColor4f::FromColor(SkColorSetA(color, SK_AlphaTRANSPARENT))};

View file

@ -21,6 +21,7 @@
#include "chrome/browser/ui/browser_otr_state.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
#include "chrome/browser/ui/toolbar/app_menu_model.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
@ -146,7 +147,7 @@ void BrowserAppMenuButton::UpdateThemeBasedState() {
// Outset focus ring should be present for the chip but not when only
// the icon is visible.
views::FocusRing::Get(this)->SetOutsetFocusRingDisabled(
IsLabelPresentAndVisible() ? false : true);
!IsLabelPresentAndVisible());
}
}
@ -198,6 +199,9 @@ bool BrowserAppMenuButton::IsLabelPresentAndVisible() const {
SkColor BrowserAppMenuButton::GetForegroundColor(ButtonState state) const {
if (features::IsChromeRefresh2023() && IsLabelPresentAndVisible()) {
const auto* const color_provider = GetColorProvider();
if (type_and_severity_.use_primary_colors) {
return color_provider->GetColor(kColorAppMenuExpandedForegroundPrimary);
}
return color_provider->GetColor(kColorAppMenuExpandedForegroundDefault);
}
@ -230,30 +234,22 @@ void BrowserAppMenuButton::UpdateTextAndHighlightColor() {
text = l10n_util::GetStringUTF16(message_id);
#else
text = l10n_util::GetStringUTF16(IDS_APP_MENU_BUTTON_UPDATE);
#endif
} else if (type_and_severity_.type ==
AppMenuIconController::IconType::DEFAULT_BROWSER_PROMPT) {
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
tooltip_message_id = IDS_APP_MENU_TOOLTIP_DEFAULT_PROMPT;
text = l10n_util::GetStringUTF16(IDS_APP_MENU_BUTTON_DEFAULT_PROMPT);
#else
tooltip_message_id = IDS_APPMENU_TOOLTIP;
#endif
} else {
tooltip_message_id = IDS_APPMENU_TOOLTIP_ALERT;
text = l10n_util::GetStringUTF16(IDS_APP_MENU_BUTTON_ERROR);
}
std::optional<SkColor> color;
const auto* const color_provider = GetColorProvider();
switch (type_and_severity_.severity) {
case AppMenuIconController::Severity::NONE:
break;
case AppMenuIconController::Severity::LOW:
color = color_provider->GetColor(kColorAppMenuHighlightSeverityLow);
break;
case AppMenuIconController::Severity::MEDIUM:
color = color_provider->GetColor(kColorAppMenuHighlightSeverityMedium);
break;
case AppMenuIconController::Severity::HIGH:
color = color_provider->GetColor(kColorAppMenuHighlightSeverityHigh);
break;
}
SetTooltipText(l10n_util::GetStringUTF16(tooltip_message_id));
SetHighlight(text, color);
SetHighlight(text, GetHighlightColor());
}
bool BrowserAppMenuButton::ShouldPaintBorder() const {
@ -275,11 +271,32 @@ void BrowserAppMenuButton::UpdateLayoutInsets() {
std::optional<SkColor> BrowserAppMenuButton::GetHighlightTextColor() const {
if (features::IsChromeRefresh2023() && IsLabelPresentAndVisible()) {
const auto* const color_provider = GetColorProvider();
if (type_and_severity_.use_primary_colors) {
return color_provider->GetColor(kColorAppMenuExpandedForegroundPrimary);
}
return color_provider->GetColor(kColorAppMenuExpandedForegroundDefault);
}
return std::nullopt;
}
std::optional<SkColor> BrowserAppMenuButton::GetHighlightColor() const {
const auto* const color_provider = GetColorProvider();
if (features::IsChromeRefresh2023() &&
type_and_severity_.use_primary_colors) {
return color_provider->GetColor(kColorAppMenuHighlightPrimary);
}
switch (type_and_severity_.severity) {
case AppMenuIconController::Severity::NONE:
return std::nullopt;
case AppMenuIconController::Severity::LOW:
return color_provider->GetColor(kColorAppMenuHighlightSeverityLow);
case AppMenuIconController::Severity::MEDIUM:
return color_provider->GetColor(kColorAppMenuHighlightSeverityMedium);
case AppMenuIconController::Severity::HIGH:
return color_provider->GetColor(kColorAppMenuHighlightSeverityHigh);
}
}
void BrowserAppMenuButton::OnTouchUiChanged() {
UpdateColorsAndInsets();
PreferredSizeChanged();

View file

@ -4,6 +4,8 @@
#include "chrome/browser/ui/views/toolbar/home_button.h"
#include <string_view>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
@ -82,7 +84,7 @@ void HomePageUndoBubble::Init() {
l10n_util::GetStringUTF16(IDS_TOOLBAR_INFORM_SET_HOME_PAGE), undo_string};
views::StyledLabel* label =
AddChildView(std::make_unique<views::StyledLabel>());
label->SetText(base::JoinString(message, base::StringPiece16(u" ")));
label->SetText(base::JoinString(message, std::u16string_view(u" ")));
gfx::Range undo_range(label->GetText().length() - undo_string.length(),
label->GetText().length());

View file

@ -19,7 +19,7 @@ const char kEnableSnippets[] = "ntp_snippets.enable";
const char kArticlesListVisible[] = "ntp_snippets.list_visible";
// A boolean pref set to true if swapping out NTP isn't enabled or if DSE is
// Google.
// TODO(https://crbug.com/1483475): Inhibit loading feeds in native feeds code
// TODO(crbug.com/40282032): Inhibit loading feeds in native feeds code
// when this pref is set to false.
const char kEnableSnippetsByDse[] = "ntp_snippets_by_dse.enable";

View file

@ -1213,6 +1213,8 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
last_visit_id);
}
delegate_->NotifyVisitedLinksAdded(request);
ScheduleCommit();
}
@ -1462,7 +1464,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
visit_info.visited_link_id = visited_link_info.id;
}
// TODO(crbug.com/1476511): any visit added via sync should not have a
// TODO(crbug.com/40280017): any visit added via sync should not have a
// corresponding entry in the VisitedLinkDatabase.
if (visit_source == VisitSource::SOURCE_SYNCED) {
CHECK(visit_info.visited_link_id == kInvalidVisitedLinkID);
@ -1487,7 +1489,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
return std::make_pair(url_id, visit_info.visit_id);
}
// TODO(crbug.com/1475714): Determine if we want to record these URLs in the
// TODO(crbug.com/40279741): Determine if we want to record these URLs in the
// VisitedLinkDatabase, and if so, plumb the correct value for top_level_site.
void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
VisitSource visit_source) {
@ -1548,7 +1550,11 @@ void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
}
bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) const {
return time < expirer_.GetCurrentExpirationTime();
if (base::CommandLine::ForCurrentProcess()->HasSwitch("keep-all-history")) {
return false;
} else {
return time < expirer_.GetCurrentExpirationTime();
}
}
// static
@ -1690,6 +1696,17 @@ bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
return false;
}
QueryURLResult HistoryBackend::GetMostRecentVisitsForGurl(GURL url,
int max_visits) {
QueryURLResult result;
if (db_ && GetURL(url, &result.row) &&
db_->GetMostRecentVisitsForURL(result.row.id(), max_visits,
&result.visits)) {
result.success = true;
}
return result;
}
bool HistoryBackend::GetForeignVisit(const std::string& originator_cache_guid,
VisitID originator_visit_id,
VisitRow* visit_row) {
@ -1826,7 +1843,7 @@ VisitID HistoryBackend::UpdateSyncedVisit(
// existing row. It'll be updated below, if necessary.
updated_row.segment_id = original_row.segment_id;
// TODO(crbug.com/1476511): any VisitedLinkID associated with `updated_row`
// TODO(crbug.com/40280017): any VisitedLinkID associated with `updated_row`
// will be voided to avoid storing stale/incorrect VisitedLinkIDs once
// elements of the VisitRow's partition key change (in this case the
// referring_visit).
@ -1877,7 +1894,7 @@ bool HistoryBackend::UpdateVisitReferrerOpenerIDs(VisitID visit_id,
row.referring_visit = referrer_id;
row.opener_visit = opener_id;
// TODO(crbug.com/1476511): any VisitedLinkID associated with `row`
// TODO(crbug.com/40280017): any VisitedLinkID associated with `row`
// will be voided to avoid storing stale/incorrect VisitedLinkIDs once
// elements of the VisitRow's partition key change (in this case the
// referring_visit).
@ -2103,6 +2120,13 @@ DomainsVisitedResult HistoryBackend::GetUniqueDomainsVisited(
return db_->GetUniqueDomainsVisited(begin_time, end_time);
}
GetAllAppIdsResult HistoryBackend::GetAllAppIds() {
if (!db_) {
return {};
}
return db_->GetAllAppIds();
}
HistoryLastVisitResult HistoryBackend::GetLastVisitToHost(
const std::string& host,
base::Time begin_time,
@ -2905,7 +2929,7 @@ void HistoryBackend::GetRedirectsFromSpecificVisit(VisitID cur_visit,
visit_set.insert(cur_visit);
while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
if (visit_set.find(cur_visit) != visit_set.end()) {
NOTREACHED() << "Loop in visit chain, giving up";
DUMP_WILL_BE_NOTREACHED_NORETURN() << "Loop in visit chain, giving up";
return;
}
visit_set.insert(cur_visit);
@ -2926,7 +2950,7 @@ void HistoryBackend::GetRedirectsToSpecificVisit(VisitID cur_visit,
visit_set.insert(cur_visit);
while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
if (visit_set.find(cur_visit) != visit_set.end()) {
NOTREACHED() << "Loop in visit chain, giving up";
DUMP_WILL_BE_NOTREACHED_NORETURN() << "Loop in visit chain, giving up";
return;
}
visit_set.insert(cur_visit);
@ -2934,11 +2958,6 @@ void HistoryBackend::GetRedirectsToSpecificVisit(VisitID cur_visit,
}
}
void HistoryBackend::ScheduleAutocomplete(
base::OnceCallback<void(HistoryBackend*, URLDatabase*)> callback) {
std::move(callback).Run(this, db_.get());
}
void HistoryBackend::DeleteFTSIndexDatabases() {
// Find files on disk matching the text databases file pattern so we can
// quickly test for and delete them.
@ -3530,7 +3549,7 @@ void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
// Don't just do the close/delete here, as we are being called by `db` and
// that seems dangerous.
// TODO(https://crbug.com/854258): It is also dangerous to kill the database
// TODO(crbug.com/41395467): It is also dangerous to kill the database
// by a posted task: tasks that run before KillHistoryDatabase still can try
// to use the broken database. Consider protecting against other tasks using
// the DB or consider changing KillHistoryDatabase() to use RazeAndClose()
@ -3594,6 +3613,11 @@ void HistoryBackend::ProcessDBTask(
ProcessDBTaskImpl();
}
void HistoryBackend::RunDBTask(
base::OnceCallback<void(HistoryBackend*, URLDatabase*)> callback) {
std::move(callback).Run(this, db_.get());
}
void HistoryBackend::NotifyFaviconsChanged(const std::set<GURL>& page_urls,
const GURL& icon_url) {
delegate_->NotifyFaviconsChanged(page_urls, icon_url);
@ -3617,7 +3641,7 @@ void HistoryBackend::NotifyURLsModified(const URLRows& changed_urls,
delegate_->NotifyURLsModified(changed_urls);
}
void HistoryBackend::NotifyURLsDeleted(DeletionInfo deletion_info) {
void HistoryBackend::NotifyDeletions(DeletionInfo deletion_info) {
std::set<GURL> origins;
for (const history::URLRow& row : deletion_info.deleted_rows())
origins.insert(row.url().DeprecatedGetOriginAsURL());
@ -3626,12 +3650,12 @@ void HistoryBackend::NotifyURLsDeleted(DeletionInfo deletion_info) {
GetCountsAndLastVisitForOrigins(origins));
for (HistoryBackendObserver& observer : observers_) {
observer.OnURLsDeleted(
observer.OnHistoryDeletions(
this, deletion_info.IsAllHistory(), deletion_info.is_from_expiration(),
deletion_info.deleted_rows(), deletion_info.favicon_urls());
}
delegate_->NotifyURLsDeleted(std::move(deletion_info));
delegate_->NotifyDeletions(std::move(deletion_info));
}
void HistoryBackend::NotifyVisitUpdated(const VisitRow& visit,
@ -3641,10 +3665,23 @@ void HistoryBackend::NotifyVisitUpdated(const VisitRow& visit,
}
}
void HistoryBackend::NotifyVisitDeleted(const VisitRow& visit) {
tracker_.RemoveVisitById(visit.visit_id);
for (HistoryBackendObserver& observer : observers_) {
observer.OnVisitDeleted(visit);
void HistoryBackend::NotifyVisitsDeleted(
const std::vector<DeletedVisit>& visits) {
std::vector<DeletedVisitedLink> links;
for (const DeletedVisit& visit : visits) {
tracker_.RemoveVisitById(visit.visit_row.visit_id);
for (HistoryBackendObserver& observer : observers_) {
observer.OnVisitDeleted(visit.visit_row);
}
// Determine if a VisitedLink was deleted as a result of the deleted Visit.
if (visit.deleted_visited_link.has_value()) {
links.push_back(visit.deleted_visited_link.value());
}
}
// We want to avoid posting a new task for every VisitedLink deleted, so we
// notify the `delegate_` in a batch.
if (!links.empty()) {
delegate_->NotifyVisitedLinksDeleted(links);
}
}
@ -3703,7 +3740,7 @@ void HistoryBackend::DeleteAllHistory() {
// Send out the notification that history is cleared. The in-memory database
// will pick this up and clear itself.
NotifyURLsDeleted(DeletionInfo::ForAllHistory());
NotifyDeletions(DeletionInfo::ForAllHistory());
}
bool HistoryBackend::ClearAllFaviconHistory(

View file

@ -4,6 +4,7 @@
#include "components/user_education/common/feature_promo_controller.h"
#include <optional>
#include <string>
#include "base/auto_reset.h"
@ -14,12 +15,14 @@
#include "base/functional/callback_forward.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/user_metrics.h"
#include "base/notimplemented.h"
#include "build/build_config.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_education/common/feature_promo_data.h"
#include "components/user_education/common/feature_promo_lifecycle.h"
#include "components/user_education/common/feature_promo_registry.h"
#include "components/user_education/common/feature_promo_result.h"
#include "components/user_education/common/feature_promo_session_policy.h"
#include "components/user_education/common/feature_promo_specification.h"
#include "components/user_education/common/feature_promo_storage_service.h"
@ -95,9 +98,10 @@ FeaturePromoControllerCommon::~FeaturePromoControllerCommon() {
}
FeaturePromoResult FeaturePromoControllerCommon::CanShowPromo(
const base::Feature& iph_feature) const {
auto result = CanShowPromoCommon(iph_feature, false);
if (result && !feature_engagement_tracker_->WouldTriggerHelpUI(iph_feature)) {
const FeaturePromoParams& params) const {
auto result = CanShowPromoCommon(params, ShowSource::kNormal);
if (result &&
!feature_engagement_tracker_->WouldTriggerHelpUI(*params.feature)) {
result = FeaturePromoResult::kBlockedByConfig;
}
return result;
@ -105,19 +109,20 @@ FeaturePromoResult FeaturePromoControllerCommon::CanShowPromo(
FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromo(
FeaturePromoParams params) {
const char* feature_name = params.feature.get().name;
auto result = MaybeShowPromoCommon(std::move(params), /* for_demo =*/false);
auto failure = result.failure();
if (failure.has_value()) {
RecordPromoNotShown(feature_name, failure.value());
}
return result;
return MaybeShowPromoImpl(std::move(params), ShowSource::kNormal);
}
bool FeaturePromoControllerCommon::MaybeShowStartupPromo(
FeaturePromoParams params) {
const base::Feature* const iph_feature = &params.feature.get();
// No point in queueing a disabled feature.
if (!in_iph_demo_mode_ && !base::FeatureList::IsEnabled(*iph_feature)) {
RecordPromoNotShown(iph_feature->name,
FeaturePromoResult::kFeatureDisabled);
return false;
}
// If the promo is currently running, fail.
if (GetCurrentPromoFeature() == iph_feature) {
return false;
@ -134,10 +139,8 @@ bool FeaturePromoControllerCommon::MaybeShowStartupPromo(
return false;
}
queued_promos_.emplace_back(
iph_feature,
QueuedPromoData(std::move(params),
session_policy_->SpecificationToPromoInfo(*spec)));
queued_promos_.emplace_back(std::move(params),
session_policy_->SpecificationToPromoInfo(*spec));
// This will fire immediately if the tracker is initialized.
feature_engagement_tracker_->AddOnInitializedCallback(base::BindOnce(
@ -152,38 +155,54 @@ bool FeaturePromoControllerCommon::MaybeShowStartupPromo(
FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromoForDemoPage(
FeaturePromoParams params) {
return MaybeShowPromoCommon(std::move(params), /* for_demo =*/true);
return MaybeShowPromoCommon(std::move(params), ShowSource::kDemo);
}
FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromoImpl(
FeaturePromoParams params,
ShowSource source) {
const char* feature_name = params.feature.get().name;
auto result = MaybeShowPromoCommon(std::move(params), source);
auto failure = result.failure();
if (failure.has_value()) {
RecordPromoNotShown(feature_name, failure.value());
}
return result;
}
FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromoCommon(
FeaturePromoParams params,
bool for_demo) {
ShowSource source) {
// Perform common checks.
const FeaturePromoSpecification* spec = nullptr;
const FeaturePromoSpecification* primary_spec = nullptr;
const FeaturePromoSpecification* display_spec = nullptr;
std::unique_ptr<FeaturePromoLifecycle> lifecycle = nullptr;
ui::TrackedElement* anchor_element = nullptr;
auto result = CanShowPromoCommon(params.feature.get(), for_demo, &spec,
auto result = CanShowPromoCommon(params, source, &primary_spec, &display_spec,
&lifecycle, &anchor_element);
if (!result) {
return result;
}
CHECK(spec);
CHECK(primary_spec);
CHECK(display_spec);
CHECK(lifecycle);
CHECK(anchor_element);
const bool for_demo = source == ShowSource::kDemo;
// If the session policy allows overriding the current promo, abort it.
if (current_promo_) {
EndPromo(*GetCurrentPromoFeature(),
FeaturePromoClosedReason::kOverrideForDemo);
for_demo ? FeaturePromoClosedReason::kOverrideForDemo
: FeaturePromoClosedReason::kOverrideForPrecedence);
}
// If the session policy allows overriding other help bubbles, close them.
if (auto* const help_bubble =
bubble_factory_registry_->GetHelpBubble(anchor_element->context())) {
help_bubble->Close();
help_bubble->Close(HelpBubble::CloseReason::kProgrammaticallyClosed);
}
// TODO(crbug.com/1258216): Currently this must be called before
// TODO(crbug.com/40200981): Currently this must be called before
// ShouldTriggerHelpUI() below. See bug for details.
const bool screen_reader_available =
CheckScreenReaderPromptAvailable(for_demo || in_iph_demo_mode_);
@ -200,7 +219,7 @@ FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromoCommon(
// Construct the parameters for the promotion.
ShowPromoBubbleParams show_params;
show_params.spec = spec;
show_params.spec = display_spec;
show_params.anchor_element = anchor_element;
show_params.screen_reader_prompt_available = screen_reader_available;
show_params.body_format = std::move(params.body_params);
@ -218,7 +237,7 @@ FeaturePromoResult FeaturePromoControllerCommon::MaybeShowPromoCommon(
}
// Update the most recent promo info.
last_promo_info_ = session_policy_->SpecificationToPromoInfo(*spec);
last_promo_info_ = session_policy_->SpecificationToPromoInfo(*primary_spec);
session_policy_->NotifyPromoShown(last_promo_info_);
bubble_closed_callback_ = std::move(params.close_callback);
@ -248,9 +267,10 @@ std::unique_ptr<HelpBubble> FeaturePromoControllerCommon::ShowCriticalPromo(
EndPromo(*current, FeaturePromoClosedReason::kOverrideForPrecedence);
}
// Snooze and tutorial are not supported for critical promos.
DCHECK_NE(FeaturePromoSpecification::PromoType::kSnooze, spec.promo_type());
DCHECK_NE(FeaturePromoSpecification::PromoType::kTutorial, spec.promo_type());
// Snooze, tutorial, and rotating are not supported for critical promos.
CHECK_NE(FeaturePromoSpecification::PromoType::kSnooze, spec.promo_type());
CHECK_NE(FeaturePromoSpecification::PromoType::kTutorial, spec.promo_type());
CHECK_NE(FeaturePromoSpecification::PromoType::kRotating, spec.promo_type());
ShowPromoBubbleParams show_params;
show_params.spec = &spec;
@ -301,15 +321,15 @@ FeaturePromoControllerCommon::GetCurrentPromoSpecificationForAnchor(
}
bool FeaturePromoControllerCommon::HasPromoBeenDismissed(
const base::Feature& iph_feature,
const FeaturePromoParams& params,
FeaturePromoClosedReason* last_close_reason) const {
const FeaturePromoSpecification* const spec =
registry()->GetParamsForFeature(iph_feature);
registry()->GetParamsForFeature(*params.feature);
if (!spec) {
return false;
}
const auto data = storage_service()->ReadPromoData(iph_feature);
const auto data = storage_service()->ReadPromoData(*params.feature);
if (!data) {
return false;
}
@ -324,8 +344,11 @@ bool FeaturePromoControllerCommon::HasPromoBeenDismissed(
case user_education::FeaturePromoSpecification::PromoSubtype::
kActionableAlert:
return data->is_dismissed;
case user_education::FeaturePromoSpecification::PromoSubtype::kPerApp:
return base::Contains(data->shown_for_apps, GetAppId());
case user_education::FeaturePromoSpecification::PromoSubtype::kKeyedNotice:
if (params.key.empty()) {
return false;
}
return base::Contains(data->shown_for_keys, params.key);
}
}
@ -337,7 +360,7 @@ bool FeaturePromoControllerCommon::EndPromo(
auto close_reason_internal =
end_promo_reason == EndFeaturePromoReason::kFeatureEngaged
? FeaturePromoClosedReason::kFeatureEngaged
: FeaturePromoClosedReason::kAbortPromo;
: FeaturePromoClosedReason::kAbortedByFeature;
return EndPromo(iph_feature, close_reason_internal);
}
@ -346,7 +369,7 @@ bool FeaturePromoControllerCommon::EndPromo(
FeaturePromoClosedReason close_reason) {
const auto it = FindQueuedPromo(iph_feature);
if (it != queued_promos_.end()) {
auto& cb = it->second.params.queued_promo_callback;
auto& cb = it->params.queued_promo_callback;
if (cb) {
std::move(cb).Run(iph_feature, FeaturePromoResult::kCanceled);
}
@ -370,7 +393,13 @@ void FeaturePromoControllerCommon::RecordPromoEnded(
current_promo_->OnPromoEnded(close_reason, continue_after_close);
if (!continue_after_close) {
current_promo_.reset();
MaybeShowQueuedPromo();
// Try to show the next queued promo (if any) but only if the current promo
// was not ended by being overridden; in that case a different promo is
// already trying to show.
if (close_reason != FeaturePromoClosedReason::kOverrideForDemo &&
close_reason != FeaturePromoClosedReason::kOverrideForPrecedence) {
MaybeShowQueuedPromo();
}
}
}
@ -440,7 +469,7 @@ bool FeaturePromoControllerCommon::CheckScreenReaderPromptAvailable(
return false;
}
// TODO(crbug.com/1258216): Once we have our answer, immediately dismiss
// TODO(crbug.com/40200981): Once we have our answer, immediately dismiss
// so that this doesn't interfere with actually showing the bubble. This
// dismiss can be moved elsewhere once we support concurrency.
feature_engagement_tracker_->Dismissed(*prompt_feature);
@ -481,26 +510,61 @@ FeaturePromoControllerCommon::GetNextQueuedPromo() {
QueuedPromos::iterator result = queued_promos_.end();
for (auto it = queued_promos_.begin(); it != queued_promos_.end(); ++it) {
if (result == queued_promos_.end() ||
it->second.info.priority > result->second.info.priority) {
it->info.priority > result->info.priority) {
result = it;
}
}
return result;
}
const FeaturePromoControllerCommon::QueuedPromoData*
FeaturePromoControllerCommon::GetNextQueuedPromo() const {
// Const cast is safe here because it does not modify the queue, and only a
// const pointer to the value found is returned.
const auto it =
const_cast<FeaturePromoControllerCommon*>(this)->GetNextQueuedPromo();
return it != queued_promos_.end() ? &*it : nullptr;
}
void FeaturePromoControllerCommon::MaybeShowQueuedPromo() {
// This should only ever be called after the tracker is initialized.
CHECK(feature_engagement_tracker_->IsInitialized());
// Fetch the next-highest-priority promo from the queue.
// If there is already a promo showing, it may be necessary to hold off trying
// to show another.
const std::optional<FeaturePromoSessionPolicy::PromoInfo> current_promo =
(current_promo_ || critical_promo_bubble_)
? std::make_optional(last_promo_info_)
: std::nullopt;
// Also, if the next promo in queue cannot be shown and the current promo is
// not high-priority, any messaging priority must be released.
const bool must_release_on_failure =
!current_promo || current_promo->priority !=
FeaturePromoSessionPolicy::PromoPriority::kHigh;
// Fetch the next-highest-priority promo from the queue. If there's nothing,
// then there's nothing to do.
const auto next = GetNextQueuedPromo();
if (next == queued_promos_.end()) {
messaging_priority_handle_.Release();
if (must_release_on_failure) {
messaging_priority_handle_.Release();
}
return;
}
const bool is_high_priority = next->second.info.priority ==
FeaturePromoSessionPolicy::PromoPriority::kHigh;
// If there is already a promo showing and this promo would not override it,
// bail out.
if (current_promo &&
!session_policy_->CanShowPromo(next->info, current_promo)) {
if (must_release_on_failure) {
messaging_priority_handle_.Release();
}
return;
}
const bool is_high_priority =
next->info.priority == FeaturePromoSessionPolicy::PromoPriority::kHigh;
// Coordinate with the product messaging system to make sure a promo will not
// attempt to be shown over a non-IPH legal notice.
@ -548,13 +612,14 @@ void FeaturePromoControllerCommon::MaybeShowQueuedPromo() {
// Store the data that is needed to show the promo and then remove it from
// the queue.
const base::Feature* const iph_feature = &next->second.params.feature.get();
FeaturePromoParams params = std::move(next->second.params);
const base::Feature* const iph_feature = &next->params.feature.get();
FeaturePromoParams params = std::move(next->params);
queued_promos_.erase(next);
QueuedPromoCallback callback = std::move(params.queued_promo_callback);
// Try to start the promo, assuming the tracker was successfully initialized.
const FeaturePromoResult result = MaybeShowPromo(std::move(params));
const FeaturePromoResult result =
MaybeShowPromoImpl(std::move(params), ShowSource::kQueue);
if (callback) {
std::move(callback).Run(*iph_feature, result);
}
@ -569,9 +634,10 @@ void FeaturePromoControllerCommon::MaybeShowQueuedPromo() {
// Returns whether `iph_feature` is queued to be shown.
bool FeaturePromoControllerCommon::IsPromoQueued(
const base::Feature& iph_feature) const {
return std::any_of(
queued_promos_.begin(), queued_promos_.end(),
[&iph_feature](const auto& pr) { return pr.first == &iph_feature; });
return std::any_of(queued_promos_.begin(), queued_promos_.end(),
[&iph_feature](const QueuedPromoData& data) {
return &data.params.feature.get() == &iph_feature;
});
}
// Returns an iterator into the queued promo list matching `iph_feature`, or
@ -579,38 +645,42 @@ bool FeaturePromoControllerCommon::IsPromoQueued(
FeaturePromoControllerCommon::QueuedPromos::iterator
FeaturePromoControllerCommon::FindQueuedPromo(
const base::Feature& iph_feature) {
return std::find_if(
queued_promos_.begin(), queued_promos_.end(),
[&iph_feature](const auto& pr) { return pr.first == &iph_feature; });
return std::find_if(queued_promos_.begin(), queued_promos_.end(),
[&iph_feature](const QueuedPromoData& data) {
return &data.params.feature.get() == &iph_feature;
});
}
void FeaturePromoControllerCommon::FailQueuedPromos() {
for (auto& [feature, data] : queued_promos_) {
for (auto& data : queued_promos_) {
auto& cb = data.params.queued_promo_callback;
if (cb) {
std::move(cb).Run(*feature, FeaturePromoResult::kError);
std::move(cb).Run(*data.params.feature, FeaturePromoResult::kError);
}
}
queued_promos_.clear();
}
FeaturePromoResult FeaturePromoControllerCommon::CanShowPromoCommon(
const base::Feature& iph_feature,
bool for_demo,
const FeaturePromoSpecification** spec_out,
const FeaturePromoParams& params,
ShowSource source,
const FeaturePromoSpecification** primary_spec_out,
const FeaturePromoSpecification** display_spec_out,
std::unique_ptr<FeaturePromoLifecycle>* lifecycle_out,
ui::TrackedElement** anchor_element_out) const {
const bool for_demo = source == ShowSource::kDemo;
// Ensure that this promo isn't already queued for startup.
//
// Note that this check is bypassed if this is for an explicit demo, but not
// in demo mode, as the IPH may be queued for startup specifically because it
// is being demoed.
if (!for_demo && IsPromoQueued(iph_feature)) {
if (!for_demo && IsPromoQueued(*params.feature)) {
return FeaturePromoResult::kBlockedByPromo;
}
const FeaturePromoSpecification* const spec =
registry()->GetParamsForFeature(iph_feature);
registry()->GetParamsForFeature(*params.feature);
if (!spec) {
return FeaturePromoResult::kError;
}
@ -620,17 +690,16 @@ FeaturePromoResult FeaturePromoControllerCommon::CanShowPromoCommon(
// Engagement tracker more times than necessary, emitting unnecessary logging
// events when features are disabled.
if (!for_demo && !in_iph_demo_mode_ &&
!base::FeatureList::IsEnabled(iph_feature)) {
!base::FeatureList::IsEnabled(*params.feature)) {
return FeaturePromoResult::kFeatureDisabled;
}
// Check the lifecycle, but only if not in demo mode. This is especially
// important for snoozeable, app, and legal notice promos.
std::unique_ptr<FeaturePromoLifecycle> lifecycle;
auto lifecycle = std::make_unique<FeaturePromoLifecycle>(
storage_service_, params.key, &*params.feature, spec->promo_type(),
spec->promo_subtype(), spec->rotating_promos().size());
if (!for_demo && !in_iph_demo_mode_) {
lifecycle = std::make_unique<FeaturePromoLifecycle>(
storage_service_, GetAppId(), &iph_feature, spec->promo_type(),
spec->promo_subtype());
if (const auto result = lifecycle->CanShow(); !result) {
return result;
}
@ -646,11 +715,23 @@ FeaturePromoResult FeaturePromoControllerCommon::CanShowPromoCommon(
// When not in demo mode, refer to the session policy to determine if the
// promo can show.
if (!for_demo && !in_iph_demo_mode_) {
const auto result = session_policy_->CanShowPromo(
session_policy_->SpecificationToPromoInfo(*spec), current_promo);
const auto promo_info = session_policy_->SpecificationToPromoInfo(*spec);
auto result = session_policy_->CanShowPromo(promo_info, current_promo);
if (!result) {
return result;
}
// If this is not from the queue, compare against queued promos as well.
if (source != ShowSource::kQueue) {
if (const auto* const queued = GetNextQueuedPromo()) {
// This is the opposite situation: only exclude this promo if the queued
// promo (which is not yet running) would cancel *this* promo.
result = session_policy_->CanShowPromo(queued->info, promo_info);
if (result) {
return FeaturePromoResult::kBlockedByPromo;
}
}
}
}
// Promos are blocked if some other critical user messaging is queued.
@ -659,9 +740,35 @@ FeaturePromoResult FeaturePromoControllerCommon::CanShowPromoCommon(
return FeaturePromoResult::kBlockedByPromo;
}
// For rotating promos, cycle forward to the next valid index.
auto* anchor_spec = spec;
if (spec->promo_type() == FeaturePromoSpecification::PromoType::kRotating) {
int current_index = lifecycle->GetPromoIndex();
// In demos, when repeating the same repeating promo to test it, the index
// should cycle. However, the updated index is not written until the
// previous promo is ended, which happens later. In order to simulate this,
// base the starting index off the one being used by the previous promo.
if (current_promo_ && current_promo_->iph_feature() == &*params.feature) {
current_index = (current_promo_->GetPromoIndex() + 1) %
spec->rotating_promos().size();
}
// Find the next index in the rotation that has a valid promo. This is the
// actual index that will be used.
int index = current_index;
while (!spec->rotating_promos().at(index).has_value()) {
index = (index + 1) % spec->rotating_promos().size();
CHECK_NE(index, current_index)
<< "Wrapped around while looking for a valid rotating promo; this "
"should have been caught during promo registration.";
}
lifecycle->SetPromoIndex(index);
anchor_spec = &*spec->rotating_promos().at(index);
}
// Fetch the anchor element. For now, assume all elements are Views.
ui::TrackedElement* const anchor_element =
spec->GetAnchorElement(GetAnchorContext());
anchor_spec->GetAnchorElement(GetAnchorContext());
if (!anchor_element) {
return FeaturePromoResult::kBlockedByUi;
}
@ -673,20 +780,16 @@ FeaturePromoResult FeaturePromoControllerCommon::CanShowPromoCommon(
// Output the lifecycle if it was requested.
if (lifecycle_out) {
if (!lifecycle) {
// If in demo mode but the caller has asked for a lifecycle anyway, then
// provide one.
lifecycle = std::make_unique<FeaturePromoLifecycle>(
storage_service_, GetAppId(), &iph_feature, spec->promo_type(),
spec->promo_subtype());
}
*lifecycle_out = std::move(lifecycle);
}
// If the caller has asked for the specification or anchor element, then
// provide them.
if (spec_out) {
*spec_out = spec;
if (primary_spec_out) {
*primary_spec_out = spec;
}
if (display_spec_out) {
*display_spec_out = anchor_spec;
}
if (anchor_element_out) {
*anchor_element_out = anchor_element;
@ -740,6 +843,20 @@ std::unique_ptr<HelpBubble> FeaturePromoControllerCommon::ShowPromoBubbleImpl(
}
switch (spec.promo_type()) {
case FeaturePromoSpecification::PromoType::kToast: {
// Rotating toast promos require a "got it" button.
if (current_promo_ &&
current_promo_->promo_type() ==
FeaturePromoSpecification::PromoType::kRotating) {
bubble_params.buttons = CreateRotatingToastButtons(*spec.feature());
// If no hint is set, promos with buttons take focus. However, toasts do
// not take focus by default. So if the hint isn't already set, set the
// promo not to take focus.
bubble_params.focus_on_show_hint =
bubble_params.focus_on_show_hint.value_or(false);
}
break;
}
case FeaturePromoSpecification::PromoType::kSnooze:
CHECK(spec.feature());
bubble_params.buttons =
@ -762,9 +879,10 @@ std::unique_ptr<HelpBubble> FeaturePromoControllerCommon::ShowPromoBubbleImpl(
spec.custom_action_dismiss_string_id());
break;
case FeaturePromoSpecification::PromoType::kUnspecified:
case FeaturePromoSpecification::PromoType::kToast:
case FeaturePromoSpecification::PromoType::kLegacy:
break;
case FeaturePromoSpecification::PromoType::kRotating:
NOTREACHED_NORETURN() << "Not implemented; should never reach this code.";
}
bool had_screen_reader_promo = false;
@ -779,9 +897,7 @@ std::unique_ptr<HelpBubble> FeaturePromoControllerCommon::ShowPromoBubbleImpl(
auto help_bubble = bubble_factory_registry_->CreateHelpBubble(
params.anchor_element, std::move(bubble_params));
if (help_bubble) {
// Record that the focus help message was actually read to the user. See the
// note in MaybeShowPromoImpl().
// TODO(crbug.com/1258216): Rewrite this when we have the ability for FE
// TODO(crbug.com/40200981): Rewrite this when we have the ability for FE
// promos to ignore other active promos.
if (had_screen_reader_promo) {
feature_engagement_tracker_->NotifyEvent(
@ -806,7 +922,9 @@ void FeaturePromoControllerCommon::FinishContinuedPromo(
}
}
void FeaturePromoControllerCommon::OnHelpBubbleClosed(HelpBubble* bubble) {
void FeaturePromoControllerCommon::OnHelpBubbleClosed(
HelpBubble* bubble,
HelpBubble::CloseReason reason) {
// Since we're in the middle of processing callbacks we can't reset our
// subscription but since it's a weak pointer (internally) and since we should
// should only get called here once, it's not a big deal if we don't reset
@ -814,7 +932,7 @@ void FeaturePromoControllerCommon::OnHelpBubbleClosed(HelpBubble* bubble) {
if (bubble == critical_promo_bubble_) {
critical_promo_bubble_ = nullptr;
} else if (bubble == promo_bubble()) {
if (current_promo_->OnPromoBubbleClosed()) {
if (current_promo_->OnPromoBubbleClosed(reason)) {
current_promo_.reset();
}
}
@ -919,6 +1037,14 @@ void FeaturePromoControllerCommon::OnTutorialAborted(
}
}
std::vector<HelpBubbleButtonParams>
FeaturePromoControllerCommon::CreateRotatingToastButtons(
const base::Feature& feature) {
// For now, use the same "got it" button as a snooze IPH that has run out of
// snoozes.
return CreateSnoozeButtons(feature, /*can_snooze=*/false);
}
std::vector<HelpBubbleButtonParams>
FeaturePromoControllerCommon::CreateSnoozeButtons(const base::Feature& feature,
bool can_snooze) {
@ -1095,10 +1221,29 @@ FeaturePromoControllerCommon::BlockActiveWindowCheckForTesting() {
true);
}
FeaturePromoParams::FeaturePromoParams(const base::Feature& iph_feature)
: feature(iph_feature) {}
FeaturePromoParams::FeaturePromoParams(const base::Feature& iph_feature,
const std::string& promo_key)
: feature(iph_feature), key(promo_key) {}
FeaturePromoParams::FeaturePromoParams(FeaturePromoParams&& other) noexcept =
default;
FeaturePromoParams::~FeaturePromoParams() = default;
std::ostream& operator<<(std::ostream& os, FeaturePromoStatus status) {
switch (status) {
case FeaturePromoStatus::kBubbleShowing:
os << "kBubbleShowing";
break;
case FeaturePromoStatus::kContinued:
os << "kContinued";
break;
case FeaturePromoStatus::kNotRunning:
os << "kNotRunning";
break;
case FeaturePromoStatus::kQueuedForStartup:
os << "kQueuedForStartup";
break;
}
return os;
}
} // namespace user_education

View file

@ -12,6 +12,7 @@ aggregate_vector_icons("components_vector_icons") {
sources = [
"${branding_path_component}/product.icon",
"${branding_path_component}/product_refresh.icon",
"account_circle.icon",
"account_circle_chrome_refresh.icon",
"account_circle_off_chrome_refresh.icon",
@ -44,6 +45,7 @@ aggregate_vector_icons("components_vector_icons") {
"cardboard.icon",
"caret_down.icon",
"caret_up.icon",
"cast.icon",
"celebration.icon",
"certificate.icon",
"certificate_chrome_refresh.icon",
@ -70,7 +72,6 @@ aggregate_vector_icons("components_vector_icons") {
"database_off.icon",
"description.icon",
"devices.icon",
"devices_chrome_refresh.icon",
"devices_off.icon",
"devices_off_chrome_refresh.icon",
"document_scanner.icon",
@ -102,6 +103,7 @@ aggregate_vector_icons("components_vector_icons") {
"font_download.icon",
"font_download_chrome_refresh.icon",
"font_download_off_chrome_refresh.icon",
"forward_10.icon",
"forward_arrow.icon",
"forward_arrow_chrome_refresh.icon",
"google_color.icon",
@ -121,6 +123,8 @@ aggregate_vector_icons("components_vector_icons") {
"info_refresh.icon",
"insert_drive_file_outline.icon",
"keyboard.icon",
"keyboard_lock.icon",
"keyboard_lock_off.icon",
"launch.icon",
"launch_chrome_refresh.icon",
"launch_off_chrome_refresh.icon",
@ -178,6 +182,8 @@ aggregate_vector_icons("components_vector_icons") {
"picture_in_picture_alt.icon",
"play_arrow.icon",
"play_arrow_chrome_refresh.icon",
"pointer_lock.icon",
"pointer_lock_off.icon",
"printer.icon",
"privacy_sandbox.icon",
"protected_content.icon",
@ -188,6 +194,7 @@ aggregate_vector_icons("components_vector_icons") {
"reload.icon",
"reload_chrome_refresh.icon",
"replay.icon",
"replay_10.icon",
"save_cloud.icon",
"screen_share.icon",
"search.icon",
@ -207,6 +214,8 @@ aggregate_vector_icons("components_vector_icons") {
"settings_outline.icon",
"shopping_bag.icon",
"shopping_bag_refresh.icon",
"skip_next.icon",
"skip_previous.icon",
"sms.icon",
"storage_access.icon",
"storage_access_off.icon",
@ -225,6 +234,7 @@ aggregate_vector_icons("components_vector_icons") {
"usb.icon",
"usb_chrome_refresh.icon",
"usb_off_chrome_refresh.icon",
"video_library.icon",
"videocam.icon",
"videocam_chrome_refresh.icon",
"videocam_off.icon",
@ -267,6 +277,7 @@ aggregate_vector_icons("components_vector_icons") {
"google_chrome/google_lens_full_logo.icon",
"google_chrome/google_lens_full_logo_dark.icon",
"google_chrome/google_lens_logo.icon",
"google_chrome/google_lens_monochrome_logo.icon",
"google_chrome/google_password_manager.icon",
"google_chrome/google_pay_logo.icon",
"google_chrome/google_search_companion_logo.icon",

View file

@ -6,6 +6,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <memory>
@ -84,6 +85,10 @@ inline bool UseV4L2Codec(
#endif
}
#if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
static const char kMaliConfPath[] = "/etc/mali_platform.conf";
#endif
#if BUILDFLAG(IS_CHROMEOS) && defined(__aarch64__)
static const char kLibGlesPath[] = "/usr/lib64/libGLESv2.so.2";
static const char kLibEglPath[] = "/usr/lib64/libEGL.so.1";
@ -195,6 +200,13 @@ void AddArmMaliGpuPermissions(std::vector<BrokerFilePermission>* permissions) {
permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
#if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// Files needed for protected DMA allocations.
static const char kDmaHeapPath[] = "/dev/dma_heap/restricted_mtk_cma";
permissions->push_back(BrokerFilePermission::ReadWrite(kDmaHeapPath));
permissions->push_back(BrokerFilePermission::ReadOnly(kMaliConfPath));
#endif
// Non-privileged render nodes for format enumeration.
// https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes
base::FileEnumerator enumerator(
@ -250,7 +262,7 @@ void AddAmdGpuPermissions(std::vector<BrokerFilePermission>* permissions) {
"/usr/lib64/dri/r300_dri.so",
"/usr/lib64/dri/r600_dri.so",
"/usr/lib64/dri/radeonsi_dri.so",
// GPU Log Warning Workaround
// GPU Log Warnings Workaround
"/usr/share/vulkan/icd.d",
"/usr/share/vulkan/icd.d/radeon_icd.x86_64.json"
"/etc/vulkan/icd.d",
@ -430,7 +442,7 @@ void AddVulkanICDPermissions(std::vector<BrokerFilePermission>* permissions) {
static const char* const kReadOnlyICDList[] = {
"intel_icd.x86_64.json", "nvidia_icd.json", "radeon_icd.x86_64.json",
"mali_icd.json"};
"mali_icd.json", "freedreno_icd.aarch64.json"};
for (std::string prefix : kReadOnlyICDPrefixes) {
permissions->push_back(BrokerFilePermission::ReadOnly(prefix));
@ -531,6 +543,16 @@ std::vector<BrokerFilePermission> FilePermissionsForGpu(
}
void LoadArmGpuLibraries() {
#if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// This environmental variable needs to be set before we load libMali if we
// want to instantiate protected Vulkan device queues.
static const char kMaliConfVar[] = "MALI_PLATFORM_CONFIG";
// Note this function will only fail if we run out of memory entirely, in
// which case we would have much bigger problems, so we don't bother to check
// the return value.
setenv(kMaliConfVar, kMaliConfPath, 1);
#endif
// Preload the Mali library.
if (UseChromecastSandboxAllowlist()) {
for (const char* path : kAllowedChromecastPaths) {
@ -619,6 +641,7 @@ void LoadVulkanLibraries() {
dlopen("libvulkan_radeon.so", dlopen_flag);
dlopen("libvulkan_intel.so", dlopen_flag);
dlopen("libGLX_nvidia.so.0", dlopen_flag);
dlopen("libvulkan_freedreno.so", dlopen_flag);
}
void LoadChromecastV4L2Libraries() {

View file

@ -53,6 +53,12 @@ BASE_FEATURE(kApplyNativeOcclusionToCompositor,
#endif
);
// If enabled, native window occlusion tracking will always be used, even if
// CHROME_HEADLESS is set.
BASE_FEATURE(kAlwaysTrackNativeWindowOcclusionForTest,
"AlwaysTrackNativeWindowOcclusionForTest",
base::FEATURE_DISABLED_BY_DEFAULT);
// Field trial param name for `kApplyNativeOcclusionToCompositor`.
const base::FeatureParam<std::string> kApplyNativeOcclusionToCompositorType{
&kApplyNativeOcclusionToCompositor, "type",
@ -119,9 +125,9 @@ BASE_FEATURE(kSupportF11AndF12KeyShortcuts,
base::FEATURE_ENABLED_BY_DEFAULT);
bool AreF11AndF12ShortcutsEnabled() {
// TODO(crbug/1264581): Remove this once kDeviceI18nShortcutsEnabled policy is
// deprecated. This policy allows managed users to still be able to use
// deprecated legacy shortcuts which some enterprise customers rely on.
// TODO(crbug.com/40203434): Remove this once kDeviceI18nShortcutsEnabled
// policy is deprecated. This policy allows managed users to still be able to
// use deprecated legacy shortcuts which some enterprise customers rely on.
if (::ui::ShortcutMappingPrefDelegate::IsInitialized()) {
::ui::ShortcutMappingPrefDelegate* instance =
::ui::ShortcutMappingPrefDelegate::GetInstance();
@ -135,6 +141,17 @@ bool AreF11AndF12ShortcutsEnabled() {
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_OZONE)
BASE_FEATURE(kOzoneBubblesUsePlatformWidgets,
"OzoneBubblesUsePlatformWidgets",
#if BUILDFLAG(IS_CHROMEOS_LACROS)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
);
#endif // BUILDFLAG(IS_OZONE)
// Update of the virtual keyboard settings UI as described in
// https://crbug.com/876901.
BASE_FEATURE(kInputMethodSettingsUiUpdate,
@ -177,7 +194,7 @@ BASE_FEATURE(kSystemCaptionStyle,
// When enabled, the feature will query the OS for a default cursor size,
// to be used in determining the concrete object size of a custom cursor in
// blink. Currently enabled by default on Windows only.
// TODO(crbug.com/1333523) - Implement for other platforms.
// TODO(crbug.com/40845719) - Implement for other platforms.
BASE_FEATURE(kSystemCursorSizeSupported,
"SystemCursorSizeSupported",
#if BUILDFLAG(IS_WIN)
@ -214,7 +231,7 @@ bool IsUiGpuRasterizationEnabled() {
// Enables scrolling with layers under ui using the ui::Compositor.
BASE_FEATURE(kUiCompositorScrollWithLayers,
"UiCompositorScrollWithLayers",
// TODO(https://crbug.com/615948): Use composited scrolling on all platforms.
// TODO(crbug.com/40471184): Use composited scrolling on all platforms.
#if BUILDFLAG(IS_APPLE)
base::FEATURE_ENABLED_BY_DEFAULT
#else
@ -226,7 +243,7 @@ BASE_FEATURE(kUiCompositorScrollWithLayers,
// native apps on Windows.
BASE_FEATURE(kExperimentalFlingAnimation,
"ExperimentalFlingAnimation",
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// TODO(crbug.com/40118868): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_WIN) || \
(BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
@ -255,11 +272,6 @@ BASE_FEATURE(kFocusFollowsCursor,
base::FEATURE_DISABLED_BY_DEFAULT);
#if BUILDFLAG(IS_WIN)
// Enables InputPane API for controlling on screen keyboard.
BASE_FEATURE(kInputPaneOnScreenKeyboard,
"InputPaneOnScreenKeyboard",
base::FEATURE_ENABLED_BY_DEFAULT);
// Enables using WM_POINTER instead of WM_TOUCH for touch events.
BASE_FEATURE(kPointerEventsForTouch,
"PointerEventsForTouch",
@ -279,8 +291,8 @@ BASE_FEATURE(kImprovedKeyboardShortcuts,
bool IsImprovedKeyboardShortcutsEnabled() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug/1264581): Remove this once kDeviceI18nShortcutsEnabled policy is
// deprecated.
// TODO(crbug.com/40203434): Remove this once kDeviceI18nShortcutsEnabled
// policy is deprecated.
if (::ui::ShortcutMappingPrefDelegate::IsInitialized()) {
::ui::ShortcutMappingPrefDelegate* instance =
::ui::ShortcutMappingPrefDelegate::GetInstance();
@ -367,12 +379,6 @@ bool IsNotificationGesturesUpdateEnabled() {
return base::FeatureList::IsEnabled(kNotificationGesturesUpdate);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
BASE_FEATURE(kHandwritingGesture,
"HandwritingGesture",
base::FEATURE_ENABLED_BY_DEFAULT);
#endif
BASE_FEATURE(kSynchronousPageFlipTesting,
"SynchronousPageFlipTesting",
base::FEATURE_ENABLED_BY_DEFAULT);
@ -461,10 +467,13 @@ bool IsVariableRefreshRateEnabled() {
}
// Special default case for devices with |kVariableRefreshRateDefaultEnabled|
// set. Requires |kVariableRefreshRateAvailable| to also be set.
// set. Requires |kVariableRefreshRateAvailable| to also be set. We also check
// if the FeatureList exists as it can be null during the ASSERT_DEATH
// handling.
// TODO(b/310666603): Remove after VRR is enabled-by-default for all hardware.
if (!base::FeatureList::GetInstance()->IsFeatureOverridden(
kEnableVariableRefreshRate.name) &&
if (!(base::FeatureList::GetInstance() &&
base::FeatureList::GetInstance()->IsFeatureOverridden(
kEnableVariableRefreshRate.name)) &&
base::FeatureList::IsEnabled(kVariableRefreshRateDefaultEnabled) &&
base::FeatureList::IsEnabled(kVariableRefreshRateAvailable)) {
return true;
@ -493,20 +502,6 @@ bool IsLacrosColorManagementEnabled() {
return base::FeatureList::IsEnabled(kLacrosColorManagement);
}
BASE_FEATURE(kCustomizeChromeSidePanel,
"CustomizeChromeSidePanel",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kCustomizeChromeSidePanelNoChromeRefresh2023,
"CustomizeChromeSidePanelNoChromeRefresh2023",
base::FEATURE_ENABLED_BY_DEFAULT);
bool CustomizeChromeSupportsChromeRefresh2023() {
return base::FeatureList::IsEnabled(kCustomizeChromeSidePanel) &&
!base::FeatureList::IsEnabled(
kCustomizeChromeSidePanelNoChromeRefresh2023);
}
BASE_FEATURE(kChromeRefresh2023,
"ChromeRefresh2023",
base::FEATURE_DISABLED_BY_DEFAULT);
@ -515,122 +510,20 @@ BASE_FEATURE(kChromeRefreshSecondary2023,
"ChromeRefreshSecondary2023",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kChromeRefresh2023NTB,
"ChromeRefresh2023NTB",
base::FEATURE_DISABLED_BY_DEFAULT);
const char kChromeRefresh2023NTBVariationKey[] = "Variation";
constexpr base::FeatureParam<ChromeRefresh2023NTBVariation>::Option
ChromeRefresh2023NTBVariationOption[] = {
{ChromeRefresh2023NTBVariation::kGM2Full, "GM2Full"},
{ChromeRefresh2023NTBVariation::kGM3OldIconNoBackground,
"GM3OldIconNoBackground"},
{ChromeRefresh2023NTBVariation::kGM3OldIconWithBackground,
"GM3OldIconWithBackground"},
{ChromeRefresh2023NTBVariation::kGM3NewIconNoBackground,
"GM3NewIconNoBackground"},
{ChromeRefresh2023NTBVariation::kGM3NewIconWithBackground,
"GM3NewIconWithBackground"},
{ChromeRefresh2023NTBVariation::kNoChoice, "No Choice"}};
const base::FeatureParam<ChromeRefresh2023NTBVariation>
kChromeRefresh2023NTBValue(&kChromeRefresh2023NTB,
kChromeRefresh2023NTBVariationKey,
ChromeRefresh2023NTBVariation::kNoChoice,
&ChromeRefresh2023NTBVariationOption);
ChromeRefresh2023NTBVariation GetChromeRefresh2023NTB() {
ChromeRefresh2023NTBVariation option = kChromeRefresh2023NTBValue.Get();
if (option == ChromeRefresh2023NTBVariation::kNoChoice) {
if (!IsChromeRefresh2023()) {
return ChromeRefresh2023NTBVariation::kGM2Full;
} else {
return ChromeRefresh2023NTBVariation::kGM3NewIconNoBackground;
}
}
return option;
}
BASE_FEATURE(kChromeRefresh2023TopChromeFont,
"ChromeRefresh2023TopChromeFont",
base::FEATURE_DISABLED_BY_DEFAULT);
bool IsChromeRefresh2023() {
if (!CustomizeChromeSupportsChromeRefresh2023()) {
// Bail before checking any other feature flags so that associated studies
// don't get activated.
return false;
}
return base::FeatureList::IsEnabled(kChromeRefresh2023) ||
base::FeatureList::IsEnabled(kChromeRefreshSecondary2023);
}
BASE_FEATURE(kChromeWebuiRefresh2023,
"ChromeWebuiRefresh2023",
base::FEATURE_DISABLED_BY_DEFAULT);
bool IsChromeWebuiRefresh2023() {
if (!CustomizeChromeSupportsChromeRefresh2023()) {
// Bail before checking any other feature flags so that associated studies
// don't get activated.
return false;
}
return IsChromeRefresh2023() &&
(base::FeatureList::IsEnabled(kChromeWebuiRefresh2023) ||
base::FeatureList::IsEnabled(kChromeRefreshSecondary2023));
}
constexpr base::FeatureParam<ChromeRefresh2023Level>::Option
kChromeRefresh2023LevelOption[] = {{ChromeRefresh2023Level::kLevel1, "1"},
{ChromeRefresh2023Level::kLevel2, "2"}};
const base::FeatureParam<ChromeRefresh2023Level> kChromeRefresh2023Level(
&kChromeRefresh2023,
"level",
ChromeRefresh2023Level::kLevel2,
&kChromeRefresh2023LevelOption);
ChromeRefresh2023Level GetChromeRefresh2023LevelUncached() {
if (!CustomizeChromeSupportsChromeRefresh2023()) {
// Bail before checking any other feature flags so that associated studies
// don't get activated.
return ChromeRefresh2023Level::kDisabled;
}
// For simplicity, the secondary field trial to enable chrome refresh will
// also enable the omnibox refresh.
if (base::FeatureList::IsEnabled(kChromeRefreshSecondary2023)) {
return ChromeRefresh2023Level::kLevel2;
}
return IsChromeRefresh2023() ? kChromeRefresh2023Level.Get()
: ChromeRefresh2023Level::kDisabled;
}
ChromeRefresh2023Level GetChromeRefresh2023Level() {
// Cached due to frequent calls for performance optimization.
// Please update `GetChromeRefresh2023LevelUncached()` for any changes.
static const ChromeRefresh2023Level level =
GetChromeRefresh2023LevelUncached();
return level;
base::FeatureList::IsEnabled(kChromeRefreshSecondary2023);
}
BASE_FEATURE(kBubbleMetricsApi,
"BubbleMetricsApi",
base::FEATURE_DISABLED_BY_DEFAULT);
#if BUILDFLAG(IS_MAC)
// When enabled, images will be written to the system clipboard as both a TIFF
// and a PNG (as opposed to just a TIFF). This requires encoding the sanitized
// bitmap to a PNG on the UI thread on copy, which may cause jank. This matches
// the behavior of other platforms.
// TODO(https://crbug.com/1443646): Remove this flag eventually.
BASE_FEATURE(kMacClipboardWriteImageWithPng,
"MacClipboardWriteImageWithPng",
base::FEATURE_ENABLED_BY_DEFAULT);
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_APPLE)
// Font Smoothing was enabled by default prior to introducing this feature.
// We want to experiment with disabling it to align with CR2023 designs.
@ -645,4 +538,7 @@ BASE_FEATURE(kUseGammaContrastRegistrySettings,
base::FEATURE_ENABLED_BY_DEFAULT);
#endif // BUILDFLAG(IS_WIN)
BASE_FEATURE(kBubbleFrameViewTitleIsHeading,
"BubbleFrameViewTitleIsHeading",
base::FEATURE_ENABLED_BY_DEFAULT);
} // namespace features