diff --git a/DEPS b/DEPS index 1b24dff..27944f7 100644 --- a/DEPS +++ b/DEPS
@@ -294,7 +294,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'e84f5ed7d152063a4efd1399eb379305ebe5d3d6', + 'skia_revision': 'd37ac42bd8d6ff5a91f6bef83a09260524cae274', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -406,7 +406,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '203951a0d6e8a190839bf7a59e00d4df1b45835f', + 'quiche_revision': '1852058ed84fc551bd4cb9dba8330446d7d02411', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ink # and whatever else without interference from each other. @@ -474,7 +474,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'cros_components_revision': '97dc8c7a1df880206cc54d9913a7e9d73677072a', + 'cros_components_revision': 'e7f1a1f42262790f48a9b69761c6c3e45ef225ca', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1563,7 +1563,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '0942c904bb5a624a6b2a10f0550ff9d35b419504', + '0b19c12de7a158deb75f357e88759d445a9d7721', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1717,7 +1717,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '-vqiQr1TxuVkiMwnwlZW9xZr22EcZKAIQqxEHKRZHjQC', + 'version': 'eC0hJWeKwG4zHsm2yGfpxc-rvzQHBmJYdNrA3KQH2ScC', }, ], 'condition': 'checkout_android and non_git_source', @@ -4673,7 +4673,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '37e9f4b495cdbb05bd7ec76311668998b6053bf9', + 'a8b6dc620e36af6428e9953791c2b66ebd6b3641', 'condition': 'checkout_src_internal', }, @@ -4739,7 +4739,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '97f5aa28bc4471c48f2f4488c5671bee87b9922a', + '91544a50032a3960c09f26b99b4aab8efbaee788', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc index 4b32a64..2b7e4629 100644 --- a/android_webview/browser/aw_contents.cc +++ b/android_webview/browser/aw_contents.cc
@@ -1585,7 +1585,8 @@ /*planned_max_preloading_type=*/content::PreloadingType:: kPrerender), /*preloading_attempt=*/nullptr, /*url_match_predicate=*/{}, - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); int32_t handle_id = -1; if (prerender_handle) {
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index 1427e93..c7590c4 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -832,6 +832,7 @@ Flag.baseFeature("InProcessGpuUseIOThread"), Flag.baseFeature("EnableCustomInputStreamBufferSize"), Flag.baseFeature("NetworkServiceDedicatedThread"), + Flag.baseFeature("NetworkServiceTaskScheduler"), Flag.baseFeature("BrowserThreadPoolAdjustment"), Flag.baseFeature( AwFeatures.WEBVIEW_DISABLE_CHIPS,
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index b412794..fe6630f0 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1806,7 +1806,7 @@ // Enables lobster restriction based on the current active IME. BASE_FEATURE(kLobsterDisabledByInvalidIME, "LobsterDisabledByInvalidIME", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); // Controls lobster availability on managed accounts. BASE_FEATURE(kLobsterForManagedUsers, @@ -1814,7 +1814,7 @@ base::FEATURE_ENABLED_BY_DEFAULT); // Enables lobster i18n response. -BASE_FEATURE(kLobsterI18n, "LobsterI18n", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kLobsterI18n, "LobsterI18n", base::FEATURE_ENABLED_BY_DEFAULT); // Enables lobster entry point in quick insert zero state. BASE_FEATURE(kLobsterQuickInsertZeroState,
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 61c020573..88ee0954 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -663,15 +663,16 @@ ASSERT_EQ(0u, active_layer()->tilings()->num_tilings()); } -TEST_F(LegacySWPictureLayerImplTest, ZoomOutCrash) { +TEST_F(LegacySWPictureLayerImplTest, ZoomOut) { gfx::Size layer_bounds(1300, 1900); - // Set up the high and low res tilings before pinch zoom. + // Set up the high res tilings before pinch zoom. SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); EXPECT_EQ(0u, active_layer()->tilings()->num_tilings()); SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f); - EXPECT_EQ(32.f, active_layer()->HighResTiling()->contents_scale_key()); + EXPECT_BOTH_EQ(num_tilings(), 1u); + EXPECT_BOTH_EQ(tilings()->tiling_at(0)->contents_scale_key(), 32.0f); // Since this test simulates a pinch it needs an input handler. // TODO(bokan): This is a raster unit test, it shouldn't be using a real @@ -681,8 +682,9 @@ host_impl()->GetInputHandler().PinchGestureBegin( gfx::Point(), ui::ScrollInputType::kTouchscreen); SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f); - SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f); EXPECT_EQ(active_layer()->tilings()->NumHighResTilings(), 1); + EXPECT_EQ(1.0f, + pending_layer()->tilings()->tiling_at(0)->contents_scale_key()); } TEST_F(LegacySWPictureLayerImplTest, ScaledBoundsOverflowInt) { @@ -692,7 +694,7 @@ gfx::Size layer_bounds(600000, 60); - // Set up the high and low res tilings before pinch zoom. + // Set up the high res tilings before pinch zoom. SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); EXPECT_EQ(0u, active_layer()->tilings()->num_tilings()); @@ -812,8 +814,7 @@ // Ensure UpdateTiles won't remove any tilings. active_layer()->MarkAllTilingsUsed(); - // Zoom out further, close to our low-res scale factor. We should - // create a new tiling. + // Zoom out further. We should create a new tiling. SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f); ASSERT_EQ(3u, active_layer()->tilings()->num_tilings()); @@ -978,7 +979,7 @@ host_impl()->AdvanceToNextFrame(base::Milliseconds(1)); UpdateDrawProperties(host_impl()->pending_tree()); - // Masks are scaled, and do not have a low res tiling. + // Masks are scaled and have only a high res tiling. EXPECT_EQ(1.3f, pending_mask->HighResTiling()->contents_scale_key()); EXPECT_EQ(1u, pending_mask->num_tilings()); @@ -1025,7 +1026,7 @@ host_impl()->AdvanceToNextFrame(base::Milliseconds(1)); UpdateDrawProperties(host_impl()->pending_tree()); - // Masks are scaled, and do not have a low res tiling. + // Masks are scaled and have only a high res tiling. EXPECT_EQ(1.3f, pending_mask->HighResTiling()->contents_scale_key()); EXPECT_EQ(1u, pending_mask->num_tilings()); @@ -3106,7 +3107,6 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetEvictionQueue) { gfx::Size layer_bounds(1000, 1000); - float low_res_factor = 0.25f; host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(500, 500)); @@ -3161,8 +3161,7 @@ all_tiles); std::set<Tile*> unique_tiles; - auto expected_scales = std::to_array<float>({low_res_factor, 1.f}); - size_t scale_index = 0; + auto expected_scale = 1.f; bool reached_visible = false; PrioritizedTile last_tile; size_t distance_decreasing = 0; @@ -3188,13 +3187,7 @@ EXPECT_FALSE(tile->required_for_activation()); - while (std::abs(tile->contents_scale_key() - expected_scales[scale_index]) > - std::numeric_limits<float>::epsilon()) { - ++scale_index; - ASSERT_LT(scale_index, std::size(expected_scales)); - } - - EXPECT_FLOAT_EQ(tile->contents_scale_key(), expected_scales[scale_index]); + EXPECT_FLOAT_EQ(tile->contents_scale_key(), expected_scale); unique_tiles.insert(tile); if (tile->required_for_activation() == @@ -3219,7 +3212,6 @@ EXPECT_EQ(1u, distance_increasing); EXPECT_EQ(11u, distance_decreasing); - scale_index = 0; bool reached_required = false; while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); @@ -3233,16 +3225,9 @@ EXPECT_TRUE(tile->required_for_activation()); } else if (tile->required_for_activation()) { reached_required = true; - scale_index = 0; } - while (std::abs(tile->contents_scale_key() - expected_scales[scale_index]) > - std::numeric_limits<float>::epsilon()) { - ++scale_index; - ASSERT_LT(scale_index, std::size(expected_scales)); - } - - EXPECT_FLOAT_EQ(tile->contents_scale_key(), expected_scales[scale_index]); + EXPECT_FLOAT_EQ(tile->contents_scale_key(), expected_scale); unique_tiles.insert(tile); queue->Pop(); } @@ -3693,7 +3678,7 @@ SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale); // The high resolution tiling is between target and ideal, so is not - // removed. The low res tiling for the old ideal=1.0 scale is removed. + // removed. used_tilings.clear(); active_layer()->CleanUpTilingsOnActiveLayer(used_tilings); ASSERT_EQ(2u, active_layer()->tilings()->num_tilings()); @@ -5160,35 +5145,6 @@ EXPECT_EQ(result.height(), 256); } -TEST_F(LegacySWPictureLayerImplTest, LowResWasHighResCollision) { - gfx::Size layer_bounds(1300, 1900); - - float low_res_factor = 0.25f; - SetupDefaultTrees(layer_bounds); - ResetTilingsAndRasterScales(); - - float page_scale = 2.f; - SetContentsScaleOnBothLayers(page_scale, 1.0f, page_scale); - EXPECT_BOTH_EQ(num_tilings(), 1u); - EXPECT_BOTH_EQ(tilings()->tiling_at(0)->contents_scale_key(), page_scale); - - // Since this test simulates a pinch it needs an input handler. - // TODO(bokan): This is a raster unit test, it shouldn't be using a real - // input handler. - InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl())); - - host_impl()->GetInputHandler().PinchGestureBegin( - gfx::Point(), ui::ScrollInputType::kTouchscreen); - - // Zoom out to exactly the low res factor so that the previous high res - // would be equal to the current low res (if it were possible to have one). - float zoomed = page_scale / low_res_factor; - SetContentsScaleOnBothLayers(zoomed, 1.0f, zoomed); - EXPECT_EQ(1u, pending_layer()->num_tilings()); - EXPECT_EQ(zoomed, - pending_layer()->tilings()->tiling_at(0)->contents_scale_key()); -} - TEST_F(LegacySWPictureLayerImplTest, CompositedImageCalculateContentsScale) { gfx::Size layer_bounds(400, 400); gfx::Rect layer_rect(layer_bounds);
diff --git a/cc/paint/paint_flags.cc b/cc/paint/paint_flags.cc index f165770..118f7f7 100644 --- a/cc/paint/paint_flags.cc +++ b/cc/paint/paint_flags.cc
@@ -244,21 +244,14 @@ return has_discardable_images; } -float PaintFlags::DynamicRangeLimitMixture::ComputeHdrHeadroom( +float PaintFlags::DynamicRangeLimitMixture::ComputeEffectiveHdrHeadroom( float target_hdr_headroom) const { - if (constrained_high_mix == 0.f && standard_mix == 0.f) { - return target_hdr_headroom; - } + // It would make more sense to store only `high_mix` and `constrained_mix`, + // since `standard_mix` is multiplied by zero. const float high_mix = 1.f - constrained_high_mix - standard_mix; - - // Average the headrooms in log-space. - const float log2_high_headroom = std::log2(target_hdr_headroom); - const float log2_constrained_high_headroom = - std::min(1.f, log2_high_headroom); - const float log2_standard_headroom = 0.f; - return std::exp2(standard_mix * log2_standard_headroom + - constrained_high_mix * log2_constrained_high_headroom + - high_mix * log2_high_headroom); + constexpr float kConstrainedMax = 1.f; // Constrained allows at most 1 stop + return constrained_high_mix * std::min(kConstrainedMax, target_hdr_headroom) + + high_mix * target_hdr_headroom; } } // namespace cc
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h index 32dcf07..5b3b2671 100644 --- a/cc/paint/paint_flags.h +++ b/cc/paint/paint_flags.h
@@ -120,7 +120,10 @@ constrained_high_mix(constrained_high_mix) {} friend bool operator==(const DynamicRangeLimitMixture&, const DynamicRangeLimitMixture&) = default; - float ComputeHdrHeadroom(float target_hdr_headroom) const; + // Compute the effective HDR headroom when this limit is applied to + // `target_hdr_headroom`. + float ComputeEffectiveHdrHeadroom(float target_hdr_headroom) const; + float standard_mix = 0.f; float constrained_high_mix = 0.f; // The weight for "high" is implicit and calculated as "one minus the
diff --git a/cc/paint/paint_flags_unittest.cc b/cc/paint/paint_flags_unittest.cc index c910b5c..e0abdff 100644 --- a/cc/paint/paint_flags_unittest.cc +++ b/cc/paint/paint_flags_unittest.cc
@@ -11,6 +11,11 @@ constexpr float kEpsilon = 1e-5f; +float ComputeHdrHeadroom(const PaintFlags::DynamicRangeLimitMixture& d, + float h) { + return std::exp2(d.ComputeEffectiveHdrHeadroom(std::log2(h))); +} + TEST(PaintFlags, DynamicRangeLimitSimple) { const PaintFlags::DynamicRangeLimitMixture kStandard( PaintFlags::DynamicRangeLimit::kStandard); @@ -20,54 +25,54 @@ PaintFlags::DynamicRangeLimit::kHigh); // Target HDR headroom is 1. - EXPECT_NEAR(kStandard.ComputeHdrHeadroom(1.f), 1.f, kEpsilon); - EXPECT_NEAR(kConstrainedHigh.ComputeHdrHeadroom(1.f), 1.f, kEpsilon); - EXPECT_NEAR(kHigh.ComputeHdrHeadroom(1.f), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kStandard, 1.f), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kConstrainedHigh, 1.f), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kHigh, 1.f), 1.f, kEpsilon); // Target HDR headroom is 2^(1/2). The "high" and "constrained-high" are the // same here. constexpr float kSqrt2 = 1.4142135623730951f; - EXPECT_NEAR(kStandard.ComputeHdrHeadroom(kSqrt2), 1.f, kEpsilon); - EXPECT_NEAR(kConstrainedHigh.ComputeHdrHeadroom(kSqrt2), kSqrt2, kEpsilon); - EXPECT_NEAR(kHigh.ComputeHdrHeadroom(kSqrt2), kSqrt2, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kStandard, kSqrt2), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kConstrainedHigh, kSqrt2), kSqrt2, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kHigh, kSqrt2), kSqrt2, kEpsilon); // Target HDR headroom is 4. - EXPECT_NEAR(kStandard.ComputeHdrHeadroom(4.f), 1.f, kEpsilon); - EXPECT_NEAR(kConstrainedHigh.ComputeHdrHeadroom(4.f), 2.f, kEpsilon); - EXPECT_NEAR(kHigh.ComputeHdrHeadroom(4.f), 4.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kStandard, 4.f), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kConstrainedHigh, 4.f), 2.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom(kHigh, 4.f), 4.f, kEpsilon); } TEST(PaintFlags, DynamicRangeLimitMix) { EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(1.f, 0.0f).ComputeHdrHeadroom(4.f), + ComputeHdrHeadroom(PaintFlags::DynamicRangeLimitMixture(1.f, 0.0f), 4.f), 1.f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom( + PaintFlags::DynamicRangeLimitMixture(0.75f, 0.0f), 4.f), + 1.4142135623730951f, kEpsilon); + EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.75f, 0.0f).ComputeHdrHeadroom(4.f), + ComputeHdrHeadroom(PaintFlags::DynamicRangeLimitMixture(0.5f, 0.5f), 4.f), 1.4142135623730951f, kEpsilon); - EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.5f, 0.5f).ComputeHdrHeadroom(4.f), - 1.4142135623730951f, kEpsilon); + EXPECT_NEAR(ComputeHdrHeadroom( + PaintFlags::DynamicRangeLimitMixture(0.25f, 0.5f), 4.f), + 2.f, kEpsilon); + + EXPECT_NEAR(ComputeHdrHeadroom( + PaintFlags::DynamicRangeLimitMixture(0.25f, 0.0f), 4.f), + 2.8284271247461903f, kEpsilon); EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.25f, 0.5f).ComputeHdrHeadroom(4.f), - 2.f, kEpsilon); - - EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.25f, 0.0f).ComputeHdrHeadroom(4.f), + ComputeHdrHeadroom(PaintFlags::DynamicRangeLimitMixture(0.f, 0.5f), 4.f), 2.8284271247461903f, kEpsilon); EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.f, 0.5f).ComputeHdrHeadroom(4.f), - 2.8284271247461903f, kEpsilon); - - EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.f, 0.25f).ComputeHdrHeadroom(4.f), + ComputeHdrHeadroom(PaintFlags::DynamicRangeLimitMixture(0.f, 0.25f), 4.f), 3.363585661014858f, kEpsilon); EXPECT_NEAR( - PaintFlags::DynamicRangeLimitMixture(0.f, 0.f).ComputeHdrHeadroom(4.f), + ComputeHdrHeadroom(PaintFlags::DynamicRangeLimitMixture(0.f, 0.f), 4.f), 4.f, kEpsilon); }
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc index 3ad507f..68acfdb8 100644 --- a/cc/paint/paint_op.cc +++ b/cc/paint/paint_op.cc
@@ -6,6 +6,7 @@ #include "cc/paint/paint_op.h" #include <algorithm> +#include <cmath> #include <limits> #include <memory> #include <type_traits> @@ -1267,13 +1268,15 @@ }); } -static float ComputeEffectiveHdrHeadroom(const PaintFlags* flags, - const PlaybackParams& params) { - if (!flags || params.destination_hdr_headroom == 1.f) { +static float ComputeLinearEffectiveHdrHeadroom(const PaintFlags* flags, + const PlaybackParams& params) { + if (!flags) { return 1.f; } - return flags->getDynamicRangeLimit().ComputeHdrHeadroom( - params.destination_hdr_headroom); + // TODO(https://crbug.com/428575083): Change the callers of this to use log2 + // based headroom. + return std::exp2(flags->getDynamicRangeLimit().ComputeEffectiveHdrHeadroom( + std::log2(params.destination_hdr_headroom))); } void DrawImageOp::RasterWithFlags(const DrawImageOp* op, @@ -1306,7 +1309,7 @@ skia::DrawGainmapImage(canvas, op->image.cached_sk_image_, op->image.gainmap_sk_image_, op->image.gainmap_info_.value(), - ComputeEffectiveHdrHeadroom(flags, params), + ComputeLinearEffectiveHdrHeadroom(flags, params), op->left, op->top, op->sampling, paint); return; } @@ -1316,7 +1319,7 @@ canvas->imageInfo().colorSpace())) { ToneMapUtil::AddGlobalToneMapFilterToPaint( paint, op->image.cached_sk_image_.get(), op->image.hdr_metadata_, - ComputeEffectiveHdrHeadroom(flags, params)); + ComputeLinearEffectiveHdrHeadroom(flags, params)); } SkTiledImageUtils::DrawImage(canvas, sk_image.get(), op->left, op->top, @@ -1445,11 +1448,11 @@ // If the PaintImage uses a gainmap shader, then replace DrawImage with a // shader. if (ToneMapUtil::UseGainmapShader(op->image)) { - skia::DrawGainmapImageRect(c, op->image.cached_sk_image_, - op->image.gainmap_sk_image_, - op->image.gainmap_info_.value(), - ComputeEffectiveHdrHeadroom(flags, params), - adjusted_src, op->dst, sampling, p); + skia::DrawGainmapImageRect( + c, op->image.cached_sk_image_, op->image.gainmap_sk_image_, + op->image.gainmap_info_.value(), + ComputeLinearEffectiveHdrHeadroom(flags, params), adjusted_src, + op->dst, sampling, p); return; } @@ -1461,7 +1464,7 @@ ToneMapUtil::AddGlobalToneMapFilterToPaint( tonemap_paint, op->image.cached_sk_image_.get(), op->image.hdr_metadata_, - ComputeEffectiveHdrHeadroom(flags, params)); + ComputeLinearEffectiveHdrHeadroom(flags, params)); DrawImageRect(c, sk_image.get(), adjusted_src, op->dst, sampling, &tonemap_paint, op->constraint); return;
diff --git a/chrome/VERSION b/chrome/VERSION index 1a67ca8..d764e76 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=140 MINOR=0 -BUILD=7281 +BUILD=7282 PATCH=0
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 94c6b31..c2a0251 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -5489,9 +5489,6 @@ flag_descriptions::kPermissiveUsbPassthroughName, flag_descriptions::kPermissiveUsbPassthroughDescription, kOsCrOS, PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootPermissiveUsbPassthrough")}, - {"camera-angle-backend", flag_descriptions::kCameraAngleBackendName, - flag_descriptions::kCameraAngleBackendDescription, kOsCrOS, - PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootCameraAngleBackend")}, {"crostini-containerless", flag_descriptions::kCrostiniContainerlessName, flag_descriptions::kCrostiniContainerlessDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kCrostiniContainerless)},
diff --git a/chrome/browser/ash/lobster/lobster_candidate_resizer_unittest.cc b/chrome/browser/ash/lobster/lobster_candidate_resizer_unittest.cc index 11909e1..5a35e674 100644 --- a/chrome/browser/ash/lobster/lobster_candidate_resizer_unittest.cc +++ b/chrome/browser/ash/lobster/lobster_candidate_resizer_unittest.cc
@@ -9,7 +9,6 @@ #include "base/functional/callback.h" #include "base/task/sequenced_task_runner.h" #include "base/test/protobuf_matchers.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "chrome/browser/ash/lobster/lobster_candidate_id_generator.h" @@ -36,14 +35,7 @@ ~LobsterCandidateResizerTest() override = default; - void SetUp() override { - feature_list_.InitWithFeatures( - /*enabled_features=*/{ash::features::kLobsterUseRewrittenQuery}, - /*disabled_features=*/{ash::features::kLobsterI18n}); - } - private: - base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_environment_; data_decoder::test::InProcessDataDecoder in_process_data_decoder_; }; @@ -63,7 +55,7 @@ /*seed=*/kFakeBaseGenerationSeed, /*size=*/ gfx::Size(kFullImageDimensionLength, kFullImageDimensionLength), /*num_outputs=*/1, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request, @@ -111,7 +103,7 @@ /*seed=*/kFakeBaseGenerationSeed, /*size=*/ gfx::Size(kFullImageDimensionLength, kFullImageDimensionLength), /*num_outputs=*/1, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request, @@ -156,7 +148,7 @@ /*seed=*/kFakeBaseGenerationSeed, /*size=*/ gfx::Size(kFullImageDimensionLength, kFullImageDimensionLength), /*num_outputs=*/1, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request,
diff --git a/chrome/browser/ash/lobster/lobster_image_provider_from_snapper_unittest.cc b/chrome/browser/ash/lobster/lobster_image_provider_from_snapper_unittest.cc index 7d6b024..f0eb4c7 100644 --- a/chrome/browser/ash/lobster/lobster_image_provider_from_snapper_unittest.cc +++ b/chrome/browser/ash/lobster/lobster_image_provider_from_snapper_unittest.cc
@@ -9,7 +9,6 @@ #include "base/functional/callback.h" #include "base/task/sequenced_task_runner.h" #include "base/test/protobuf_matchers.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "chrome/browser/ash/lobster/lobster_test_utils.h" @@ -36,14 +35,7 @@ ~LobsterImageProviderFromSnapperTest() override = default; - void SetUp() override { - feature_list_.InitWithFeatures( - /*enabled_features=*/{ash::features::kLobsterUseRewrittenQuery}, - /*disabled_features=*/{ash::features::kLobsterI18n}); - } - private: - base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_environment_; data_decoder::test::InProcessDataDecoder in_process_data_decoder_; }; @@ -62,7 +54,7 @@ /*query=*/"a lovely cake", /*seed=*/std::nullopt, /*size=*/ gfx::Size(kPreviewImageDimensionSize, kPreviewImageDimensionSize), /*num_outputs=*/2, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request, @@ -120,7 +112,7 @@ /*seed=*/kFakeBaseGenerationSeed, /*size=*/ gfx::Size(kFullImageDimensionSize, kFullImageDimensionSize), /*num_outputs=*/1, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request, @@ -168,7 +160,7 @@ /*query=*/"a sweet candy", /*seed=*/std::nullopt, /*size=*/ gfx::Size(kPreviewImageDimensionSize, kPreviewImageDimensionSize), /*num_outputs=*/2, /*use_query_rewriter=*/true, - /*use_i18n=*/false)), + /*use_i18n=*/true)), testing::_, testing::_)) .WillOnce(testing::Invoke( [](const manta::proto::Request& request,
diff --git a/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc b/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc index 17c3b2e0..e9a1c38 100644 --- a/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc +++ b/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc
@@ -202,6 +202,8 @@ TestingPrefServiceSimple* local_state_pref() { return &local_state_pref_; } + base::test::ScopedFeatureList& scoped_feature_list() { return feature_list_; } + protected: content::BrowserTaskEnvironment task_environment_; @@ -375,6 +377,8 @@ std::get<1>(GetParam())); } +// This test only applies when we enforce IME restriction that only allows +// Lobster to show when eligibile IMEs are active. class LobsterSystemStateProviderImplImeTest : public LobsterSystemStateProviderImplBaseTest, public ::testing::WithParamInterface<std::tuple< @@ -382,7 +386,10 @@ /*expected_lobster_status=*/ash::LobsterStatus>> { public: void SetUp() override { - SetUpEligibleHardware(); + scoped_feature_list().InitWithFeatures( + /*enabled_features=*/{ash::features::kFeatureManagementLobster, + ash::features::kLobsterDisabledByInvalidIME}, + /*disabled_features=*/{}); SetConsentStatus(chromeos::editor_menu::EditorConsentStatus::kApproved); SetSettingsToggle(/*enabled=*/true); SetOnlineStatus(/*is_online=*/true);
diff --git a/chrome/browser/chrome_back_forward_cache_browsertest.cc b/chrome/browser/chrome_back_forward_cache_browsertest.cc index f60187f..f92582c 100644 --- a/chrome/browser/chrome_back_forward_cache_browsertest.cc +++ b/chrome/browser/chrome_back_forward_cache_browsertest.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/task_manager/task_manager_tester.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/grit/generated_resources.h" @@ -380,7 +381,7 @@ browser()->tab_strip_model()->GetActiveWebContents()); std::unique_ptr<ContentSettingBubbleModel> model( ContentSettingBubbleModel::CreateContentSettingBubbleModel( - browser()->content_setting_bubble_model_delegate(), + browser()->GetFeatures().content_setting_bubble_model_delegate(), browser()->tab_strip_model()->GetActiveWebContents(), ContentSettingsType::MIXEDSCRIPT)); model->OnCustomLinkClicked();
diff --git a/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.cc b/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.cc index df0793a8..66686e2 100644 --- a/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.cc +++ b/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.cc
@@ -54,7 +54,7 @@ return GetWindowAppIcon(); } -GURL WebKioskBrowserControllerBase::GetAppStartUrl() const { +const GURL& WebKioskBrowserControllerBase::GetAppStartUrl() const { return registrar().GetAppStartUrl(app_id()); }
diff --git a/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h b/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h index 0ccfb85..bb545fb 100644 --- a/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h +++ b/chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h
@@ -44,7 +44,7 @@ ui::ImageModel GetWindowIcon() const override; std::u16string GetAppShortName() const override; std::u16string GetFormattedUrlOrigin() const override; - GURL GetAppStartUrl() const override; + const GURL& GetAppStartUrl() const override; bool IsUrlInAppScope(const GURL& url) const override; bool CanUserUninstall() const override; bool IsInstalled() const override;
diff --git a/chrome/browser/content_settings/BUILD.gn b/chrome/browser/content_settings/BUILD.gn index 5430614..bc8123d22 100644 --- a/chrome/browser/content_settings/BUILD.gn +++ b/chrome/browser/content_settings/BUILD.gn
@@ -203,6 +203,7 @@ "//base/test:test_support", "//chrome/browser/profiles:profile", "//chrome/browser/ui", + "//chrome/browser/ui/browser_window", "//chrome/browser/ui/content_settings", "//chrome/test:test_support_ui", "//components/content_settings/browser",
diff --git a/chrome/browser/content_settings/mixed_content_settings_tab_helper_browsertest.cc b/chrome/browser/content_settings/mixed_content_settings_tab_helper_browsertest.cc index 151cc3b..a515ee6 100644 --- a/chrome/browser/content_settings/mixed_content_settings_tab_helper_browsertest.cc +++ b/chrome/browser/content_settings/mixed_content_settings_tab_helper_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/command_line.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -82,8 +83,8 @@ content::TestNavigationObserver observer(web_contents()); std::unique_ptr<ContentSettingBubbleModel> model( ContentSettingBubbleModel::CreateContentSettingBubbleModel( - browser()->content_setting_bubble_model_delegate(), web_contents(), - ContentSettingsType::MIXEDSCRIPT)); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + web_contents(), ContentSettingsType::MIXEDSCRIPT)); model->OnCustomLinkClicked(); // Waits for reload. @@ -156,7 +157,7 @@ browser()->tab_strip_model()->GetActiveWebContents()); std::unique_ptr<ContentSettingBubbleModel> model( ContentSettingBubbleModel::CreateContentSettingBubbleModel( - browser()->content_setting_bubble_model_delegate(), + browser()->GetFeatures().content_setting_bubble_model_delegate(), browser()->tab_strip_model()->GetActiveWebContents(), ContentSettingsType::MIXEDSCRIPT)); model->OnCustomLinkClicked(); @@ -324,7 +325,7 @@ browser()->tab_strip_model()->GetActiveWebContents()); std::unique_ptr<ContentSettingBubbleModel> model( ContentSettingBubbleModel::CreateContentSettingBubbleModel( - browser()->content_setting_bubble_model_delegate(), + browser()->GetFeatures().content_setting_bubble_model_delegate(), browser()->tab_strip_model()->GetActiveWebContents(), ContentSettingsType::MIXEDSCRIPT)); model->OnCustomLinkClicked();
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router_android.cc b/chrome/browser/extensions/api/tabs/tabs_event_router_android.cc index ccebb2b..d72223f 100644 --- a/chrome/browser/extensions/api/tabs/tabs_event_router_android.cc +++ b/chrome/browser/extensions/api/tabs/tabs_event_router_android.cc
@@ -15,7 +15,7 @@ : profile_(profile) { CHECK(profile_); TabModelList::AddObserver(this); - for (TabModel* model : TabModelList::models()) { + for (TabModel* const model : TabModelList::models()) { OnTabModelAdded(model); } }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 13a6167..4eb1b69a3e 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1335,14 +1335,6 @@ "expiry_milestone": 130 }, { - "name": "camera-angle-backend", - "owners": [ - "rjodin@chromium.org", - "chromeos-gfx-gpu@google.com" - ], - "expiry_milestone": 140 - }, - { "name": "camera-mic-effects", "owners": [ "bryantchandler@chromium.org",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index fe000d1..b9e36b5 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -6806,10 +6806,6 @@ const char kPermissiveUsbPassthroughDescription[] = "When enabled, applies more permissive rules passthrough of USB devices."; -const char kCameraAngleBackendName[] = "Camera service ANGLE backend"; -const char kCameraAngleBackendDescription[] = - "When enabled, uses ANGLE as the GL driver in the camera service."; - const char kChromeboxUsbPassthroughRestrictionsName[] = "Limit primary mice/keyboards from USB passthrough on chromeboxes"; const char kChromeboxUsbPassthroughRestrictionsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index c7c9cda0..0c1d53c 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -3982,9 +3982,6 @@ extern const char kPermissiveUsbPassthroughName[]; extern const char kPermissiveUsbPassthroughDescription[]; -extern const char kCameraAngleBackendName[]; -extern const char kCameraAngleBackendDescription[]; - extern const char kDisableBruschettaInstallChecksName[]; extern const char kDisableBruschettaInstallChecksDescription[];
diff --git a/chrome/browser/password_manager/password_change_delegate.h b/chrome/browser/password_manager/password_change_delegate.h index 7c31b0d..bf0f4e4 100644 --- a/chrome/browser/password_manager/password_change_delegate.h +++ b/chrome/browser/password_manager/password_change_delegate.h
@@ -17,6 +17,7 @@ // Internal state of a password change flow. Corresponds to // `PasswordChangeFlowState` in enums.xml. These values are persisted to logs. // Entries should not be renumbered and numeric values should never be reused. + // LINT.IfChange(State) enum class State { // Password change is being offered to the user, waiting from the to accept // or reject it. @@ -50,6 +51,7 @@ kMaxValue = kCanceled, }; + // LINT.ThenChange(/tools/metrics/histograms/metadata/password/enums.xml:PasswordChangeFlowState) // An interface used to notify clients (observers) of delegate state. Register // the observer via `PasswordChangeDelegate::AddObserver`.
diff --git a/chrome/browser/password_manager/password_change_delegate_impl_unittest.cc b/chrome/browser/password_manager/password_change_delegate_impl_unittest.cc index eeaab09..9f263c8 100644 --- a/chrome/browser/password_manager/password_change_delegate_impl_unittest.cc +++ b/chrome/browser/password_manager/password_change_delegate_impl_unittest.cc
@@ -159,7 +159,8 @@ ResetDelegate(); histogram_tester.ExpectUniqueSample( PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, - PasswordChangeDelegate::State::kChangePasswordFormNotFound, 1); + PasswordChangeDelegate::State::kChangePasswordFormNotFound, + /*expected_bucket_count=*/1); } TEST_F(PasswordChangeDelegateImplTest, MetricsReportedFlowOffered) { @@ -170,7 +171,8 @@ ResetDelegate(); histogram_tester.ExpectUniqueSample( PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, - PasswordChangeDelegate::State::kOfferingPasswordChange, 1); + PasswordChangeDelegate::State::kOfferingPasswordChange, + /*expected_bucket_count=*/1); } TEST_F(PasswordChangeDelegateImplTest, @@ -182,7 +184,8 @@ ResetDelegate(); histogram_tester.ExpectUniqueSample( PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, - PasswordChangeDelegate::State::kWaitingForAgreement, 1); + PasswordChangeDelegate::State::kWaitingForAgreement, + /*expected_bucket_count=*/1); } TEST_F(PasswordChangeDelegateImplTest, @@ -195,7 +198,8 @@ ResetDelegate(); histogram_tester.ExpectUniqueSample( PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, - PasswordChangeDelegate::State::kWaitingForChangePasswordForm, 1); + PasswordChangeDelegate::State::kWaitingForChangePasswordForm, + /*expected_bucket_count=*/1); } TEST_F(PasswordChangeDelegateImplTest, @@ -237,6 +241,8 @@ TEST_F(PasswordChangeDelegateImplTest, OtpDetectionProcessed) { SetOptimizationFeatureEnabled(true); CreateDelegate(); + base::HistogramTester histogram_tester; + delegate()->StartPasswordChangeFlow(); EXPECT_EQ(delegate()->GetCurrentState(), PasswordChangeDelegate::State::kWaitingForChangePasswordForm); @@ -245,4 +251,28 @@ static_cast<PasswordChangeDelegateImpl*>(delegate())->executor()); EXPECT_EQ(delegate()->GetCurrentState(), PasswordChangeDelegate::State::kOtpDetected); + + ResetDelegate(); + histogram_tester.ExpectUniqueSample( + PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, + PasswordChangeDelegate::State::kOtpDetected, /*expected_bucket_count=*/1); +} + +TEST_F(PasswordChangeDelegateImplTest, PasswordChangeFlowCanceled) { + SetOptimizationFeatureEnabled(true); + CreateDelegate(); + base::HistogramTester histogram_tester; + + delegate()->StartPasswordChangeFlow(); + EXPECT_EQ(delegate()->GetCurrentState(), + PasswordChangeDelegate::State::kWaitingForChangePasswordForm); + + delegate()->CancelPasswordChangeFlow(); + EXPECT_EQ(delegate()->GetCurrentState(), + PasswordChangeDelegate::State::kCanceled); + + ResetDelegate(); + histogram_tester.ExpectUniqueSample( + PasswordChangeDelegateImpl::kFinalPasswordChangeStatusHistogram, + PasswordChangeDelegate::State::kCanceled, /*expected_bucket_count=*/1); }
diff --git a/chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline.cc b/chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline.cc index f4acd6c..d6848c1 100644 --- a/chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline.cc +++ b/chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline.cc
@@ -101,6 +101,7 @@ content::PreloadingHoldbackStatus::kUnspecified, pipeline_info_, preloading_attempt, /*url_match_predicate=*/{}, - std::move(prerender_navigation_handle_callback)); + std::move(prerender_navigation_handle_callback), + /*allow_reuse=*/false); return prerender_handle_ != nullptr; }
diff --git a/chrome/browser/preloading/new_tab_page_preload/new_tab_page_preload_pipeline.cc b/chrome/browser/preloading/new_tab_page_preload/new_tab_page_preload_pipeline.cc index 4600ea6a..4817ca1 100644 --- a/chrome/browser/preloading/new_tab_page_preload/new_tab_page_preload_pipeline.cc +++ b/chrome/browser/preloading/new_tab_page_preload/new_tab_page_preload_pipeline.cc
@@ -89,7 +89,8 @@ preloading_attempt, /*url_match_predicate=*/{}, base::BindRepeating(&page_load_metrics::NavigationHandleUserData:: - AttachNewTabPageNavigationHandleUserData)); + AttachNewTabPageNavigationHandleUserData), + /*allow_reuse=*/false); return prerender_handle_ != nullptr; }
diff --git a/chrome/browser/preloading/prerender/prerender_manager.cc b/chrome/browser/preloading/prerender/prerender_manager.cc index b4e091c8..ff2e3170b 100644 --- a/chrome/browser/preloading/prerender/prerender_manager.cc +++ b/chrome/browser/preloading/prerender/prerender_manager.cc
@@ -204,7 +204,8 @@ content::PreloadPipelineInfo::Create( /*planned_max_preloading_type=*/content::PreloadingType::kPrerender), &preloading_attempt, - /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}); + /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); if (direct_url_input_prerender_handle_) { return direct_url_input_prerender_handle_->GetWeakPtr(); @@ -255,7 +256,8 @@ [](const GURL& url, const std::optional<content::UrlMatchType>&) { return false; }), - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/true); return search_prewarm_handle_ != nullptr; } @@ -304,7 +306,8 @@ /*planned_max_preloading_type=*/content::PreloadingType:: kPrerender), preloading_attempt.get(), std::move(url_match_predicate), - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/true); if (prerender_handle) { CHECK(!search_prerender_task_)
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline.cc b/chrome/browser/preloading/search_preload/search_preload_pipeline.cc index 7805057..83a1eab9 100644 --- a/chrome/browser/preloading/search_preload/search_preload_pipeline.cc +++ b/chrome/browser/preloading/search_preload/search_preload_pipeline.cc
@@ -153,7 +153,8 @@ /*should_prepare_paint_tree=*/true, content::PreloadingHoldbackStatus::kUnspecified, pipeline_info_, attempt, std::move(url_match_predicate), - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); return SearchPreloadSignalResult::kPrerenderTriggered; }
diff --git a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc index 85a28d9..44de74e9 100644 --- a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc +++ b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" #include "content/public/test/browser_test.h" @@ -23,6 +24,17 @@ #include "services/network/public/mojom/cookie_manager.mojom.h" #include "services/network/public/mojom/network_context.mojom.h" +#if BUILDFLAG(IS_CHROMEOS) +#include "base/containers/to_vector.h" +#include "chromeos/ash/components/dbus/hermes/hermes_euicc_client.h" +#include "chromeos/ash/components/dbus/hermes/hermes_manager_client.h" +#include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h" +#include "chromeos/ash/components/dbus/shill/shill_clients.h" +#include "chromeos/ash/components/dbus/shill/shill_service_client.h" +#include "chromeos/ash/components/network/managed_network_configuration_handler_impl.h" +#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" +#endif // BUILDFLAG(IS_CHROMEOS) + namespace { const char kCookieName[] = "A"; @@ -165,4 +177,141 @@ EXPECT_FALSE(tester.GetCookie(kCookieHostname, &cookie)); } +// PinnedTabsResetTest -------------------------------------------------------- + +class PinnedTabsResetTest : public InProcessBrowserTest, + public ProfileResetterTestBase { + protected: + // InProcessBrowserTest: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + resetter_ = std::make_unique<ProfileResetter>(browser()->profile()); + } + + content::WebContents* AddTab(const GURL& url) { + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + return browser()->tab_strip_model()->GetActiveWebContents(); + } +}; + +IN_PROC_BROWSER_TEST_F(PinnedTabsResetTest, ResetPinnedTabs) { + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + + // Start with one tab (about:blank). Navigating it. + content::WebContents* initial_contents = tab_strip_model->GetWebContentsAt(0); + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), GURL("http://example.com/0"))); + initial_contents = tab_strip_model->GetWebContentsAt(0); + + // Add 4 tabs + content::WebContents* tab_contents1 = AddTab(GURL("http://example.com/1")); + content::WebContents* tab_contents2 = AddTab(GURL("http://example.com/2")); + content::WebContents* tab_contents3 = AddTab(GURL("http://example.com/3")); + content::WebContents* tab_contents4 = AddTab(GURL("http://example.com/4")); + + // Current order: initial, tab_contents1, tab_contents2, tab_contents3, + // tab_contents4 + + // Pin tab_contents2 and tab_contents1 + tab_strip_model->SetTabPinned( + tab_strip_model->GetIndexOfWebContents(tab_contents2), true); + tab_strip_model->SetTabPinned( + tab_strip_model->GetIndexOfWebContents(tab_contents1), true); + + // Expected order after pinning: tab_contents2, tab_contents1, initial, + // tab_contents3, tab_contents4 + EXPECT_EQ(5, tab_strip_model->count()); + EXPECT_EQ(tab_contents2, tab_strip_model->GetWebContentsAt(0)); + EXPECT_EQ(tab_contents1, tab_strip_model->GetWebContentsAt(1)); + EXPECT_EQ(initial_contents, tab_strip_model->GetWebContentsAt(2)); + EXPECT_EQ(tab_contents3, tab_strip_model->GetWebContentsAt(3)); + EXPECT_EQ(tab_contents4, tab_strip_model->GetWebContentsAt(4)); + EXPECT_EQ(2, tab_strip_model->IndexOfFirstNonPinnedTab()); + + // Note: unpinning in the function below occurs in reverse order, because + // if we unpin the tab, it could be moved to the right, and traversing + // in left-to-right order would skip some pinned tabs. + ResetAndWait(ProfileResetter::PINNED_TABS); + + // The order should be preserved, just all unpinned. + EXPECT_EQ(tab_contents2, tab_strip_model->GetWebContentsAt(0)); + EXPECT_EQ(tab_contents1, tab_strip_model->GetWebContentsAt(1)); + EXPECT_EQ(initial_contents, tab_strip_model->GetWebContentsAt(2)); + EXPECT_EQ(tab_contents3, tab_strip_model->GetWebContentsAt(3)); + EXPECT_EQ(tab_contents4, tab_strip_model->GetWebContentsAt(4)); + EXPECT_EQ(0, tab_strip_model->IndexOfFirstNonPinnedTab()); +} + +#if BUILDFLAG(IS_CHROMEOS) +// Returns the configured static name servers from `shill_properties`, or an +// empty vector if no static name servers are configured. +std::vector<std::string> GetStaticNameServersFromShillProperties( + const base::Value::Dict& shill_properties) { + const base::Value::Dict* static_ip_config = + shill_properties.FindDict(shill::kStaticIPConfigProperty); + if (!static_ip_config) { + return {}; + } + const base::Value::List* nameservers = + static_ip_config->FindList(shill::kNameServersProperty); + if (!nameservers) { + return {}; + } + return base::ToVector(*nameservers, [](const base::Value& nameserver) { + return nameserver.GetString(); + }); +} + +// DnsConfigResetTest -------------------------------------------------------- + +class DnsConfigResetTest : public InProcessBrowserTest, + public ProfileResetterTestBase { + protected: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + resetter_ = std::make_unique<ProfileResetter>(browser()->profile()); + } +}; + +IN_PROC_BROWSER_TEST_F(DnsConfigResetTest, ResetDnsConfigurations) { + ash::ShillServiceClient::TestInterface* shill_service_client = + ash::ShillServiceClient::Get()->GetTestInterface(); + + // DNS settings. + // Set the profile so this shows up as a configured network. + const std::string kWifi1Path = "/service/wifi1"; + ash::NetworkHandler::Get() + ->managed_network_configuration_handler() + ->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(), + base::Value::List(), base::Value::Dict()); + // Set a static NameServers config. + base::Value::Dict static_ip_config; + base::Value::List name_servers; + name_servers.Append("8.8.3.1"); + name_servers.Append("8.8.2.1"); + name_servers.Append("0.0.0.0"); + name_servers.Append("0.0.0.0"); + static_ip_config.Set(shill::kNameServersProperty, std::move(name_servers)); + shill_service_client->SetServiceProperty( + kWifi1Path, shill::kStaticIPConfigProperty, + base::Value(std::move(static_ip_config))); + + // Verify that network exists and the custom name server has been applied. + const base::Value::Dict* shill_properties = + shill_service_client->GetServiceProperties(kWifi1Path); + ASSERT_TRUE(shill_properties); + EXPECT_THAT(GetStaticNameServersFromShillProperties(*shill_properties), + testing::ElementsAre("8.8.3.1", "8.8.2.1", "0.0.0.0", "0.0.0.0")); + + ResetAndWait(ProfileResetter::DNS_CONFIGURATIONS); + + // Check DNS settings have changed to expected defaults. + // Verify that the given network has it's NameServers field cleared. + EXPECT_THAT(GetStaticNameServersFromShillProperties(*shill_properties), + testing::IsEmpty()); +} +#endif // BUILDFLAG(IS_CHROMEOS) + } // namespace
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc index 4d345f17..63e10f6c 100644 --- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc +++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -40,7 +40,6 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/webdata_services/web_data_service_factory.h" #include "chrome/common/pref_names.h" -#include "chrome/test/base/browser_with_test_window_test.h" #include "components/content_settings/core/browser/content_settings_info.h" #include "components/content_settings/core/browser/content_settings_registry.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -74,17 +73,6 @@ #include "base/win/shortcut.h" #endif -#if BUILDFLAG(IS_CHROMEOS) -#include "base/containers/to_vector.h" -#include "chromeos/ash/components/dbus/hermes/hermes_euicc_client.h" -#include "chromeos/ash/components/dbus/hermes/hermes_manager_client.h" -#include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h" -#include "chromeos/ash/components/dbus/shill/shill_clients.h" -#include "chromeos/ash/components/dbus/shill/shill_service_client.h" -#include "chromeos/ash/components/network/managed_network_configuration_handler_impl.h" -#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" -#endif // BUILDFLAG(IS_CHROMEOS) - using extensions::mojom::ManifestLocation; namespace { @@ -198,61 +186,6 @@ resetter_ = std::make_unique<ProfileResetter>(profile()); } -// PinnedTabsResetTest -------------------------------------------------------- - -class PinnedTabsResetTest : public BrowserWithTestWindowTest, - public ProfileResetterTestBase { - protected: - void SetUp() override; - - std::unique_ptr<content::WebContents> CreateWebContents(); -}; - -void PinnedTabsResetTest::SetUp() { - BrowserWithTestWindowTest::SetUp(); - resetter_ = std::make_unique<ProfileResetter>(profile()); -} - -std::unique_ptr<content::WebContents> PinnedTabsResetTest::CreateWebContents() { - return content::WebContents::Create( - content::WebContents::CreateParams(profile())); -} - -#if BUILDFLAG(IS_CHROMEOS) -// DnsConfigResetTest -------------------------------------------------------- - -class DnsConfigResetTest : public BrowserWithTestWindowTest, - public ProfileResetterTestBase { - protected: - void SetUp() override { - BrowserWithTestWindowTest::SetUp(); - - // Required for initializing NetworkHandler. - ash::HermesProfileClient::InitializeFake(); - ash::HermesManagerClient::InitializeFake(); - ash::HermesEuiccClient::InitializeFake(); - - ash::shill_clients::InitializeFakes(); - ash::NetworkHandler::InitializeFake(); - - // Run the message loop to run the signal connection result callback. - base::RunLoop().RunUntilIdle(); - - resetter_ = std::make_unique<ProfileResetter>(profile()); - } - void TearDown() override { - ash::NetworkHandler::Shutdown(); - ash::shill_clients::Shutdown(); - - ash::HermesEuiccClient::Shutdown(); - ash::HermesManagerClient::Shutdown(); - ash::HermesProfileClient::Shutdown(); - - BrowserWithTestWindowTest::TearDown(); - } -}; -#endif // BUILDFLAG(IS_CHROMEOS) - // ConfigParserTest ----------------------------------------------------------- class ConfigParserTest : public testing::Test { @@ -460,27 +393,6 @@ str->replace(placeholder_pos, placeholder.size(), substitution); } -#if BUILDFLAG(IS_CHROMEOS) -// Returns the configured static name servers from `shill_properties`, or an -// empty vector if no static name servers are configured. -std::vector<std::string> GetStaticNameServersFromShillProperties( - const base::Value::Dict& shill_properties) { - const base::Value::Dict* static_ip_config = - shill_properties.FindDict(shill::kStaticIPConfigProperty); - if (!static_ip_config) { - return {}; - } - const base::Value::List* nameservers = - static_ip_config->FindList(shill::kNameServersProperty); - if (!nameservers) { - return {}; - } - return base::ToVector(*nameservers, [](const base::Value& nameserver) { - return nameserver.GetString(); - }); -} -#endif // BUILDFLAG(IS_CHROMEOS) - /********************* Tests *********************/ TEST_F(ProfileResetterTest, ResetNothing) { @@ -776,39 +688,6 @@ startup_pref.urls); } -TEST_F(PinnedTabsResetTest, ResetPinnedTabs) { - std::unique_ptr<content::WebContents> contents1(CreateWebContents()); - std::unique_ptr<content::WebContents> contents2(CreateWebContents()); - std::unique_ptr<content::WebContents> contents3(CreateWebContents()); - std::unique_ptr<content::WebContents> contents4(CreateWebContents()); - content::WebContents* raw_contents1 = contents1.get(); - content::WebContents* raw_contents2 = contents2.get(); - content::WebContents* raw_contents3 = contents3.get(); - content::WebContents* raw_contents4 = contents4.get(); - TabStripModel* tab_strip_model = browser()->tab_strip_model(); - - tab_strip_model->AppendWebContents(std::move(contents4), true); - tab_strip_model->AppendWebContents(std::move(contents3), true); - tab_strip_model->AppendWebContents(std::move(contents2), true); - tab_strip_model->SetTabPinned(2, true); - tab_strip_model->AppendWebContents(std::move(contents1), true); - tab_strip_model->SetTabPinned(3, true); - - EXPECT_EQ(raw_contents2, tab_strip_model->GetWebContentsAt(0)); - EXPECT_EQ(raw_contents1, tab_strip_model->GetWebContentsAt(1)); - EXPECT_EQ(raw_contents4, tab_strip_model->GetWebContentsAt(2)); - EXPECT_EQ(raw_contents3, tab_strip_model->GetWebContentsAt(3)); - EXPECT_EQ(2, tab_strip_model->IndexOfFirstNonPinnedTab()); - - ResetAndWait(ProfileResetter::PINNED_TABS); - - EXPECT_EQ(raw_contents2, tab_strip_model->GetWebContentsAt(0)); - EXPECT_EQ(raw_contents1, tab_strip_model->GetWebContentsAt(1)); - EXPECT_EQ(raw_contents4, tab_strip_model->GetWebContentsAt(2)); - EXPECT_EQ(raw_contents3, tab_strip_model->GetWebContentsAt(3)); - EXPECT_EQ(0, tab_strip_model->IndexOfFirstNonPinnedTab()); -} - TEST_F(ProfileResetterTest, ResetShortcuts) { ShortcutHandler shortcut; ShortcutCommand command_line = shortcut.CreateWithArguments( @@ -1149,44 +1028,4 @@ ntp_custom_background_service->GetCustomBackground().has_value()); } -#if BUILDFLAG(IS_CHROMEOS) -TEST_F(DnsConfigResetTest, ResetDnsConfigurations) { - ash::ShillServiceClient::TestInterface* shill_service_client = - ash::ShillServiceClient::Get()->GetTestInterface(); - - // DNS settings. - // Set the profile so this shows up as a configured network. - const std::string kWifi1Path = "/service/wifi1"; - ash::NetworkHandler::Get() - ->managed_network_configuration_handler() - ->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(), - base::Value::List(), base::Value::Dict()); - // Set a static NameServers config. - base::Value::Dict static_ip_config; - base::Value::List name_servers; - name_servers.Append("8.8.3.1"); - name_servers.Append("8.8.2.1"); - name_servers.Append("0.0.0.0"); - name_servers.Append("0.0.0.0"); - static_ip_config.Set(shill::kNameServersProperty, std::move(name_servers)); - shill_service_client->SetServiceProperty( - kWifi1Path, shill::kStaticIPConfigProperty, - base::Value(std::move(static_ip_config))); - - // Verify that network exists and the custom name server has been applied. - const base::Value::Dict* shill_properties = - shill_service_client->GetServiceProperties(kWifi1Path); - ASSERT_TRUE(shill_properties); - EXPECT_THAT(GetStaticNameServersFromShillProperties(*shill_properties), - testing::ElementsAre("8.8.3.1", "8.8.2.1", "0.0.0.0", "0.0.0.0")); - - ResetAndWait(ProfileResetter::DNS_CONFIGURATIONS); - - // Check DNS settings have changed to expected defaults. - // Verify that the given network has it's NameServers field cleared. - EXPECT_THAT(GetStaticNameServersFromShillProperties(*shill_properties), - testing::IsEmpty()); -} -#endif // BUILDFLAG(IS_CHROMEOS) - } // namespace
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index bc92fb1..f052cae 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -1903,10 +1903,21 @@ IN_PROC_BROWSER_TEST_F(DiceManageAccountBrowserTest, ClearManagedProfileOnStartup) { - // Initial profile should have been deleted as sign-in and sign out were no - // longer allowed. PrefService* local_state = g_browser_process->local_state(); DCHECK(local_state); + + // Initial profile should have been deleted as sign-in and sign out were no + // longer allowed. If the profile has not yet been deleted, wait for the pref + // to be updated. + if (local_state->GetList(prefs::kProfilesDeleted).empty()) { + base::RunLoop run_loop; + PrefChangeRegistrar pref_registrar; + pref_registrar.Init(local_state); + // Quit the run loop when the 'kProfilesDeleted' pref changes. + pref_registrar.Add(prefs::kProfilesDeleted, run_loop.QuitClosure()); + run_loop.Run(); + } + const base::Value::List& deleted_profiles = local_state->GetList(prefs::kProfilesDeleted); EXPECT_EQ(1U, deleted_profiles.size());
diff --git a/chrome/browser/ui/breadcrumb_manager_browser_agent.cc b/chrome/browser/ui/breadcrumb_manager_browser_agent.cc index 6c110326..df9af42 100644 --- a/chrome/browser/ui/breadcrumb_manager_browser_agent.cc +++ b/chrome/browser/ui/breadcrumb_manager_browser_agent.cc
@@ -6,10 +6,10 @@ #include <optional> +#include "base/check_deref.h" #include "chrome/browser/breadcrumbs/breadcrumb_manager_keyed_service_factory.h" #include "chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "components/breadcrumbs/core/breadcrumb_manager_keyed_service.h" namespace { @@ -24,19 +24,19 @@ } // namespace -BreadcrumbManagerBrowserAgent::BreadcrumbManagerBrowserAgent(Browser* browser) - : browser_(browser) { - browser_->tab_strip_model()->AddObserver(this); +BreadcrumbManagerBrowserAgent::BreadcrumbManagerBrowserAgent( + TabStripModel* tab_strip_model, + content::BrowserContext* browser_context) + : breadcrumb_manager_(CHECK_DEREF( + BreadcrumbManagerKeyedServiceFactory::GetForBrowserContext( + browser_context))) { + tab_strip_model->AddObserver(this); } -BreadcrumbManagerBrowserAgent::~BreadcrumbManagerBrowserAgent() { - browser_->tab_strip_model()->RemoveObserver(this); -} +BreadcrumbManagerBrowserAgent::~BreadcrumbManagerBrowserAgent() = default; void BreadcrumbManagerBrowserAgent::PlatformLogEvent(const std::string& event) { - BreadcrumbManagerKeyedServiceFactory::GetForBrowserContext( - browser_->profile()) - ->AddEvent(event); + breadcrumb_manager_->AddEvent(event); } void BreadcrumbManagerBrowserAgent::OnTabStripModelChanged(
diff --git a/chrome/browser/ui/breadcrumb_manager_browser_agent.h b/chrome/browser/ui/breadcrumb_manager_browser_agent.h index aed7288..d2e9d707 100644 --- a/chrome/browser/ui/breadcrumb_manager_browser_agent.h +++ b/chrome/browser/ui/breadcrumb_manager_browser_agent.h
@@ -5,22 +5,28 @@ #ifndef CHROME_BROWSER_UI_BREADCRUMB_MANAGER_BROWSER_AGENT_H_ #define CHROME_BROWSER_UI_BREADCRUMB_MANAGER_BROWSER_AGENT_H_ -#include <string> - -#include "base/memory/raw_ptr.h" +#include "base/memory/raw_ref.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "components/breadcrumbs/core/breadcrumb_manager_browser_agent.h" -class Browser; class TabStripModel; class TabStripModelChange; struct TabStripSelectionChange; +namespace content { +class BrowserContext; +} // namespace content + +namespace breadcrumbs { +class BreadcrumbManagerKeyedService; +} // namespace breadcrumbs + class BreadcrumbManagerBrowserAgent : public breadcrumbs::BreadcrumbManagerBrowserAgent, public TabStripModelObserver { public: - explicit BreadcrumbManagerBrowserAgent(Browser* browser); + BreadcrumbManagerBrowserAgent(TabStripModel* tab_strip_model, + content::BrowserContext* browser_context); BreadcrumbManagerBrowserAgent(const BreadcrumbManagerBrowserAgent&) = delete; BreadcrumbManagerBrowserAgent& operator=( const BreadcrumbManagerBrowserAgent&) = delete; @@ -36,9 +42,7 @@ const TabStripModelChange& change, const TabStripSelectionChange& selection) override; - // The browser whose tab strip this agent observes. Can't be nullptr because - // |browser_| owns this object. - raw_ptr<Browser> browser_; + const raw_ref<breadcrumbs::BreadcrumbManagerKeyedService> breadcrumb_manager_; }; #endif // CHROME_BROWSER_UI_BREADCRUMB_MANAGER_BROWSER_AGENT_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 32516a8..d6125bb9 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -92,11 +92,9 @@ #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" #include "chrome/browser/ui/bookmarks/bookmark_utils.h" -#include "chrome/browser/ui/breadcrumb_manager_browser_agent.h" #include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_commands.h" -#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" @@ -166,7 +164,6 @@ #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_utils.h" #include "components/bookmarks/common/bookmark_pref_names.h" -#include "components/breadcrumbs/core/breadcrumbs_status.h" #include "components/captive_portal/core/buildflags.h" #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -663,19 +660,13 @@ params.initial_visible_on_all_workspaces_state), creation_source_(params.creation_source), unload_controller_(this), - content_setting_bubble_model_delegate_( - new BrowserContentSettingBubbleModelDelegate(this)), live_tab_context_(new BrowserLiveTabContext(this)), app_controller_(web_app::MaybeCreateAppBrowserController(this)), bookmark_bar_state_(BookmarkBar::HIDDEN), browser_actions_(new BrowserActions(*this)), command_controller_(new chrome::BrowserCommandController(this)), window_has_shown_(false), - user_title_(params.user_title), - breadcrumb_manager_browser_agent_( - breadcrumbs::IsEnabled(g_browser_process->local_state()) - ? std::make_unique<BreadcrumbManagerBrowserAgent>(this) - : nullptr) { + user_title_(params.user_title) { browser_actions_->InitializeBrowserActions(); if (!profile_->IsOffTheRecord()) {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index a795d65..fc24449 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -63,9 +63,7 @@ #endif class BackgroundContents; -class BreadcrumbManagerBrowserAgent; class BrowserActions; -class BrowserContentSettingBubbleModelDelegate; class BrowserLiveTabContext; class BrowserView; class BrowserWindow; @@ -483,10 +481,6 @@ bool should_trigger_session_restore() const { return should_trigger_session_restore_; } - BrowserContentSettingBubbleModelDelegate* - content_setting_bubble_model_delegate() { - return content_setting_bubble_model_delegate_.get(); - } BrowserLiveTabContext* live_tab_context() { return live_tab_context_.get(); } const web_app::AppBrowserController* app_controller() const { return app_controller_.get(); @@ -1402,10 +1396,6 @@ // Dialog box used for opening and saving files. scoped_refptr<ui::SelectFileDialog> select_file_dialog_; - // Helper which implements the ContentSettingBubbleModel interface. - std::unique_ptr<BrowserContentSettingBubbleModelDelegate> - content_setting_bubble_model_delegate_; - // Helper which implements the LiveTabContext interface. std::unique_ptr<BrowserLiveTabContext> live_tab_context_; @@ -1425,10 +1415,6 @@ std::string user_title_; - // Listens for browser-related breadcrumb events to be added to crash reports. - std::unique_ptr<BreadcrumbManagerBrowserAgent> - breadcrumb_manager_browser_agent_; - std::unique_ptr<ScopedKeepAlive> keep_alive_; WarnBeforeClosingCallback warn_before_closing_callback_;
diff --git a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc index 112c9a6..8911da80 100644 --- a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc +++ b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc
@@ -4,15 +4,17 @@ #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "base/check_deref.h" #include "chrome/browser/content_settings/chrome_content_settings_utils.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/tab_dialogs.h" -#include "chrome/common/url_constants.h" -#include "components/google/core/common/google_util.h" +#include "chrome/common/webui_url_constants.h" #include "components/subresource_filter/core/browser/subresource_filter_constants.h" +namespace { // The URL for when the user clicks "Learn more" on the mixed scripting page // icon bubble. constexpr char kInsecureScriptHelpUrl[] = @@ -22,10 +24,11 @@ // permission prompt. constexpr char kNotificationsHelpUrl[] = "https://support.google.com/chrome/answer/3220216"; +} // namespace BrowserContentSettingBubbleModelDelegate:: - BrowserContentSettingBubbleModelDelegate(Browser* browser) - : browser_(browser) {} + BrowserContentSettingBubbleModelDelegate(BrowserWindowInterface* browser) + : browser_(CHECK_DEREF(browser)) {} BrowserContentSettingBubbleModelDelegate:: ~BrowserContentSettingBubbleModelDelegate() = default; @@ -38,17 +41,19 @@ void BrowserContentSettingBubbleModelDelegate::ShowMediaSettingsPage() { // Microphone and camera settings appear in the content settings menu right // next to each other, the microphone section is first. - chrome::ShowContentSettings(browser_, ContentSettingsType::MEDIASTREAM_MIC); + chrome::ShowContentSettings(browser_->GetBrowserForMigrationOnly(), + ContentSettingsType::MEDIASTREAM_MIC); } void BrowserContentSettingBubbleModelDelegate::ShowContentSettingsPage( ContentSettingsType type) { + Browser* const browser = browser_->GetBrowserForMigrationOnly(); if (type == ContentSettingsType::PROTOCOL_HANDLERS) { - chrome::ShowSettingsSubPage(browser_, chrome::kHandlerSettingsSubPage); + chrome::ShowSettingsSubPage(browser, chrome::kHandlerSettingsSubPage); } else if (type == ContentSettingsType::COOKIES) { - chrome::ShowSettingsSubPage(browser_, chrome::kCookieSettingsSubPage); + chrome::ShowSettingsSubPage(browser, chrome::kCookieSettingsSubPage); } else { - chrome::ShowContentSettingsExceptions(browser_, type); + chrome::ShowContentSettingsExceptions(browser, type); } } @@ -68,7 +73,6 @@ default: return; } - DCHECK(!learn_more_url.is_empty()); - chrome::AddSelectedTabWithURL(browser_, learn_more_url, - ui::PAGE_TRANSITION_LINK); + chrome::AddSelectedTabWithURL(browser_->GetBrowserForMigrationOnly(), + learn_more_url, ui::PAGE_TRANSITION_LINK); }
diff --git a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h index aba61aa..beca5e1 100644 --- a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h +++ b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h
@@ -5,17 +5,18 @@ #ifndef CHROME_BROWSER_UI_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_DELEGATE_H_ #define CHROME_BROWSER_UI_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_DELEGATE_H_ -#include "base/memory/raw_ptr.h" +#include "base/memory/raw_ref.h" #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h" -class Browser; +class BrowserWindowInterface; // Implementation of ContentSettingBubbleModelDelegate which uses an instance of // Browser in order to fulfil its duties. class BrowserContentSettingBubbleModelDelegate : public ContentSettingBubbleModelDelegate { public: - explicit BrowserContentSettingBubbleModelDelegate(Browser* browser); + explicit BrowserContentSettingBubbleModelDelegate( + BrowserWindowInterface* browser); BrowserContentSettingBubbleModelDelegate( const BrowserContentSettingBubbleModelDelegate&) = delete; @@ -31,7 +32,7 @@ void ShowLearnMorePage(ContentSettingsType type) override; private: - const raw_ptr<Browser> browser_; + const raw_ref<BrowserWindowInterface> browser_; }; #endif // CHROME_BROWSER_UI_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/browser_window/internal/BUILD.gn b/chrome/browser/ui/browser_window/internal/BUILD.gn index 3fd2e1a..7b95402 100644 --- a/chrome/browser/ui/browser_window/internal/BUILD.gn +++ b/chrome/browser/ui/browser_window/internal/BUILD.gn
@@ -41,6 +41,7 @@ "//chrome/browser/ui/views/side_panel", "//chrome/browser/ui/views/toolbar", "//chrome/browser/ui/web_applications", + "//components/breadcrumbs/core:status", "//components/collaboration/public:public", "//components/commerce/core:feature_list", "//components/data_sharing/public:public",
diff --git a/chrome/browser/ui/browser_window/internal/browser_window_features.cc b/chrome/browser/ui/browser_window/internal/browser_window_features.cc index 3132655..465021c 100644 --- a/chrome/browser/ui/browser_window/internal/browser_window_features.cc +++ b/chrome/browser/ui/browser_window/internal/browser_window_features.cc
@@ -10,6 +10,7 @@ #include "base/feature_list.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/collaboration/collaboration_service_factory.h" #include "chrome/browser/commerce/shopping_service_factory.h" #include "chrome/browser/download/bubble/download_bubble_prefs.h" @@ -21,9 +22,11 @@ #include "chrome/browser/lens/region_search/lens_region_search_controller.h" #include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/breadcrumb_manager_browser_agent.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_command_controller.h" +#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" #include "chrome/browser/ui/browser_instant_controller.h" #include "chrome/browser/ui/browser_location_bar_model_delegate.h" #include "chrome/browser/ui/browser_tab_menu_model_delegate.h" @@ -82,6 +85,7 @@ #include "chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/common/chrome_features.h" +#include "components/breadcrumbs/core/breadcrumbs_status.h" #include "components/collaboration/public/collaboration_service.h" #include "components/commerce/core/commerce_feature_list.h" #include "components/commerce/core/feature_utils.h" @@ -89,6 +93,7 @@ #include "components/lens/lens_features.h" #include "components/omnibox/browser/location_bar_model.h" #include "components/omnibox/browser/location_bar_model_impl.h" +#include "components/prefs/pref_service.h" #include "components/profile_metrics/browser_profile_type.h" #include "components/saved_tab_groups/public/features.h" #include "components/search/ntp_features.h" @@ -241,6 +246,9 @@ data_sharing_bubble_controller_ = std::make_unique<DataSharingBubbleController>(browser); + content_setting_bubble_model_delegate_ = + std::make_unique<BrowserContentSettingBubbleModelDelegate>(browser); + tab_list_bridge_ = std::make_unique<TabListBridge>( *tab_strip_model_, browser->GetUnownedUserDataHost()); @@ -251,6 +259,12 @@ browser->GetTabStripModel(), browser->GetProfile()); #endif + if (breadcrumbs::IsEnabled(g_browser_process->local_state())) { + breadcrumb_manager_browser_agent_ = + std::make_unique<BreadcrumbManagerBrowserAgent>( + browser->GetTabStripModel(), browser->GetProfile()); + } + #if defined(USE_AURA) overscroll_pref_manager_ = std::make_unique<OverscrollPrefManager>( tab_strip_model_,
diff --git a/chrome/browser/ui/browser_window/public/browser_window_features.h b/chrome/browser/ui/browser_window/public/browser_window_features.h index e2800c3..1b634ed 100644 --- a/chrome/browser/ui/browser_window/public/browser_window_features.h +++ b/chrome/browser/ui/browser_window/public/browser_window_features.h
@@ -20,7 +20,9 @@ #endif class BookmarksSidePanelCoordinator; +class BreadcrumbManagerBrowserAgent; class Browser; +class BrowserContentSettingBubbleModelDelegate; class BrowserInstantController; class BrowserLocationBarModelDelegate; class BrowserSyncedWindowDelegate; @@ -352,6 +354,11 @@ return upgrade_notification_controller_.get(); } + BrowserContentSettingBubbleModelDelegate* + content_setting_bubble_model_delegate() { + return content_setting_bubble_model_delegate_.get(); + } + static UserDataFactoryWithOwner<BrowserWindowInterface>& GetUserDataFactoryForTesting(); @@ -493,11 +500,19 @@ std::unique_ptr<UpgradeNotificationController> upgrade_notification_controller_; + // Helper which implements the ContentSettingBubbleModel interface. + std::unique_ptr<BrowserContentSettingBubbleModelDelegate> + content_setting_bubble_model_delegate_; + #if BUILDFLAG(ENABLE_EXTENSIONS) std::unique_ptr<extensions::ExtensionBrowserWindowHelper> extension_browser_window_helper_; #endif + // Listens for browser-related breadcrumb events to be added to crash reports. + std::unique_ptr<BreadcrumbManagerBrowserAgent> + breadcrumb_manager_browser_agent_; + // TODO(crbug.com/423956131): Remove this. raw_ptr<BrowserWindowInterface> browser_ = nullptr;
diff --git a/chrome/browser/ui/content_settings/BUILD.gn b/chrome/browser/ui/content_settings/BUILD.gn index 2f6a188b..07a9e24d 100644 --- a/chrome/browser/ui/content_settings/BUILD.gn +++ b/chrome/browser/ui/content_settings/BUILD.gn
@@ -88,6 +88,7 @@ "//chrome/browser/content_settings:content_settings_factory", "//chrome/browser/content_settings:content_settings_util", "//chrome/browser/profiles:profile", + "//chrome/browser/ui/browser_window", "//chrome/test:test_support", "//components/content_settings/core/test:test_support", "//components/subresource_filter/core/browser:browser",
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc index 3808e7a..78d8fbd 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/content_settings/fake_owner.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/webui_url_constants.h" @@ -72,7 +73,8 @@ ->OnMediaStreamPermissionSet(web_contents->GetLastCommittedURL(), state); return std::make_unique<ContentSettingMediaStreamBubbleModel>( - browser()->content_setting_bubble_model_delegate(), web_contents); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + web_contents); } content::WebContents* GetActiveTab() { @@ -181,7 +183,8 @@ {PageSpecificContentSettings::kMicrophoneAccessed}); std::unique_ptr<ContentSettingBubbleModel> mic_bubble = std::make_unique<ContentSettingMediaStreamBubbleModel>( - browser()->content_setting_bubble_model_delegate(), web_contents); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + web_contents); EXPECT_TRUE(mic_bubble->bubble_content().is_user_modifiable); } @@ -339,7 +342,7 @@ // Creates the ContentSettingPopupBubbleModel in order to emulate clicks. std::unique_ptr<ContentSettingBubbleModel> model( ContentSettingBubbleModel::CreateContentSettingBubbleModel( - browser()->content_setting_bubble_model_delegate(), + browser()->GetFeatures().content_setting_bubble_model_delegate(), browser()->tab_strip_model()->GetActiveWebContents(), ContentSettingsType::POPUPS)); std::unique_ptr<FakeOwner> owner =
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc b/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc index bc3be16b..7d5f9730 100644 --- a/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc +++ b/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -119,7 +120,8 @@ auto model = ContentSettingImageModel::CreateForContentType(ImageType::ADS); std::unique_ptr<ContentSettingBubbleModel> bubble(model->CreateBubbleModel( - browser()->content_setting_bubble_model_delegate(), web_contents)); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + web_contents)); content::TestNavigationObserver observer(nullptr); observer.StartWatchingNewWebContents();
diff --git a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc index dd30768..f9bc5ad 100644 --- a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc +++ b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" #include "chrome/browser/ui/content_settings/fake_owner.h" @@ -179,7 +180,8 @@ // Simulate clicking on the second blocked URL. ContentSettingFramebustBlockBubbleModel framebust_block_bubble_model( - browser()->content_setting_bubble_model_delegate(), GetWebContents()); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + GetWebContents()); EXPECT_FALSE(clicked_index_.has_value()); EXPECT_FALSE(clicked_url_.has_value()); @@ -220,7 +222,8 @@ // Create a content bubble and simulate clicking on the first radio button // before closing it. ContentSettingFramebustBlockBubbleModel framebust_block_bubble_model( - browser()->content_setting_bubble_model_delegate(), GetWebContents()); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + GetWebContents()); std::unique_ptr<FakeOwner> owner = FakeOwner::Create( framebust_block_bubble_model, kDisallowRadioButtonIndex); @@ -250,7 +253,8 @@ // Create a content bubble and simulate clicking on the second radio button // before closing it. ContentSettingFramebustBlockBubbleModel framebust_block_bubble_model( - browser()->content_setting_bubble_model_delegate(), GetWebContents()); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + GetWebContents()); std::unique_ptr<FakeOwner> owner = FakeOwner::Create(framebust_block_bubble_model, kAllowRadioButtonIndex); @@ -285,7 +289,8 @@ // Create a content bubble and simulate clicking on the second radio button // before closing it. ContentSettingFramebustBlockBubbleModel framebust_block_bubble_model( - browser()->content_setting_bubble_model_delegate(), GetWebContents()); + browser()->GetFeatures().content_setting_bubble_model_delegate(), + GetWebContents()); content::TestNavigationObserver navigation_observer(nullptr); navigation_observer.StartWatchingNewWebContents();
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc index 3c80819..2074917 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -126,10 +126,10 @@ return AppBrowserController::GetTitle(); } -GURL HostedAppBrowserController::GetAppStartUrl() const { +const GURL& HostedAppBrowserController::GetAppStartUrl() const { const Extension* extension = GetExtension(); if (!extension) { - return GURL(); + return GURL::EmptyGURL(); } return AppLaunchInfo::GetLaunchWebURL(extension);
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h index 76f94bd..481466e6 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -43,7 +43,7 @@ std::u16string GetTitle() const override; std::u16string GetAppShortName() const override; std::u16string GetFormattedUrlOrigin() const override; - GURL GetAppStartUrl() const override; + const GURL& GetAppStartUrl() const override; bool IsUrlInAppScope(const GURL& url) const override; bool CanUserUninstall() const override; void Uninstall(
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc index e18e16e..c944d559 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/content_settings/content_setting_image_model_states.h" #include "chrome/browser/ui/layout_constants.h" @@ -1121,7 +1122,7 @@ PictureInPictureBrowserFrameView::GetContentSettingBubbleModelDelegate() { // Use the opener browser delegate to open any new tab. Browser* browser = chrome::FindBrowserWithTab(GetWebContents()); - return browser->content_setting_bubble_model_delegate(); + return browser->GetFeatures().content_setting_bubble_model_delegate(); } ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 625b68e..dcdc1d5c9 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -715,7 +715,7 @@ ContentSettingBubbleModelDelegate* ToolbarView::GetContentSettingBubbleModelDelegate() { - return browser_->content_setting_bubble_model_delegate(); + return browser_->GetFeatures().content_setting_bubble_model_delegate(); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc index 605476d..f37f288 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/tabs/public/tab_features.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/view_ids.h" @@ -418,7 +419,9 @@ ContentSettingBubbleModelDelegate* WebAppToolbarButtonContainer::GetContentSettingBubbleModelDelegate() { - return browser_view_->browser()->content_setting_bubble_model_delegate(); + return browser_view_->browser() + ->GetFeatures() + .content_setting_bubble_model_delegate(); } // ImmersiveModeController::Observer:
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc index 6f3ded2..7efe2a7b 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -582,7 +582,7 @@ return std::string(); } -GURL AppBrowserController::GetAppNewTabUrl() const { +const GURL& AppBrowserController::GetAppNewTabUrl() const { return GetAppStartUrl(); }
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h index 6cdee5aa..2959c5a 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.h +++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -178,10 +178,10 @@ virtual std::u16string GetFormattedUrlOrigin() const = 0; // Gets the start_url for the app. - virtual GURL GetAppStartUrl() const = 0; + virtual const GURL& GetAppStartUrl() const = 0; // Gets the new tab URL for tabbed apps. - virtual GURL GetAppNewTabUrl() const; + virtual const GURL& GetAppNewTabUrl() const; // Returns the pinned home tab if there is one, otherwise nullptr. virtual content::WebContents* GetPinnedHomeTab() const;
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index da90bc2..c6b63657 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -446,11 +446,11 @@ return result; } -GURL WebAppBrowserController::GetAppStartUrl() const { +const GURL& WebAppBrowserController::GetAppStartUrl() const { return registrar().GetAppStartUrl(app_id()); } -GURL WebAppBrowserController::GetAppNewTabUrl() const { +const GURL& WebAppBrowserController::GetAppNewTabUrl() const { return registrar().GetAppNewTabUrl(app_id()); }
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h index 484ad20..26c3312 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.h +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -82,8 +82,8 @@ std::u16string GetTitle() const override; std::u16string GetAppShortName() const override; std::u16string GetFormattedUrlOrigin() const override; - GURL GetAppStartUrl() const override; - GURL GetAppNewTabUrl() const override; + const GURL& GetAppStartUrl() const override; + const GURL& GetAppNewTabUrl() const override; content::WebContents* GetPinnedHomeTab() const override; bool ShouldHideNewTabButton() const override; bool IsUrlInHomeTabScope(const GURL& url) const override;
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 49ddce72..07cf68a9 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -338,7 +338,7 @@ return management_to_external_config_map_; } - const std::optional<blink::Manifest::TabStrip> tab_strip() const { + const std::optional<blink::Manifest::TabStrip>& tab_strip() const { return tab_strip_; }
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc index ece6be0..83952a8f 100644 --- a/chrome/browser/web_applications/web_app_registrar.cc +++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -669,15 +669,17 @@ return GetAppEffectiveDisplayMode(app_id) == DisplayMode::kTabbed; } -GURL WebAppRegistrar::GetAppNewTabUrl(const webapps::AppId& app_id) const { +const GURL& WebAppRegistrar::GetAppNewTabUrl( + const webapps::AppId& app_id) const { if (IsTabbedWindowModeEnabled(app_id)) { auto* web_app = GetAppById(app_id); if (!web_app) { - return GURL(); + return GURL::EmptyGURL(); } if (web_app->tab_strip()) { - std::optional<GURL> url = web_app->tab_strip().value().new_tab_button.url; + const std::optional<GURL>& url = + web_app->tab_strip().value().new_tab_button.url; if (url.has_value()) { return url.value(); }
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index 428d391..dd2a4aa7 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -431,7 +431,7 @@ // Returns whether the app should be opened in tabbed window mode. bool IsTabbedWindowModeEnabled(const webapps::AppId& app_id) const; - GURL GetAppNewTabUrl(const webapps::AppId& app_id) const; + const GURL& GetAppNewTabUrl(const webapps::AppId& app_id) const; // Returns the URL of the pinned home tab for tabbed apps which have this // enabled, otherwise returns nullopt.
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 81ad39d7..9d443b6 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1751781337-0be4dfa4b257432a9e23105192fa199111d5e88d-f18179f52616f5556495f5aa39908219927061ce.profdata +chrome-android32-main-1751867715-f2d20a7ae26cc3b90d19a19a08ac554d57e0f44e-d363bce624961fb87bb7bfb4cefa2009cc8cdc4d.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 10d057f..e7076f5d 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1751815143-c9aa9a9fd64fa4b66afd731323f8a93cf4bf4680-0c60d4b9bc565a2ea1ff92793d15571fdfc81f2f.profdata +chrome-android64-main-1751863636-cd1421396c136d17f9ef24af2a2e67ef41c2cb34-6eaf85807a9a0749fd99b2351c7d097d447b195d.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index 521fffeb..c59c99d 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1751750903-688e1f54140647f8d121ac0017eb390a42e54e09-78d16a76c61263d49053b89f8f43c36f785cfaa8.profdata +chrome-android-desktop-x64-main-1751855501-b1870e4303e855160a73e5f64ef9b062beb699cd-9ad267ad0f148357206f2eb1f7acd357c4d2a416.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index a58013b..d7282d24 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1751799075-a47cd1b32cbcc1f40006aff66da531b2f8d1aec0-50c2093adcc75bfb8dd9bcdfe7e7422caa86c933.profdata +chrome-linux-main-1751867715-3d91b7eefeee3021e661ea454247ecbaada557d1-d363bce624961fb87bb7bfb4cefa2009cc8cdc4d.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index b2d5c6dc..4a8b0e19 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1751815143-b658a69ade49fa035fdd9fcfc07d5c5dcc2674f2-0c60d4b9bc565a2ea1ff92793d15571fdfc81f2f.profdata +chrome-mac-arm-main-1751867715-63505c034783fed05e670031f6d9e3562d61f8e3-d363bce624961fb87bb7bfb4cefa2009cc8cdc4d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index b7723db4..bfab790 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1751799075-21c4055ab8697f032544fc2126bfc5da68365030-50c2093adcc75bfb8dd9bcdfe7e7422caa86c933.profdata +chrome-mac-main-1751846036-0bd4039fee6b263cfa761fe8b429daa1e50a0af9-5037e5d1e0f66103399f58e8d8d4b42068d2018d.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 5e06edc..e3fd61ae 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1751799075-c1dd1ce97ad1f3cf239025d8180a122d63f1aaef-50c2093adcc75bfb8dd9bcdfe7e7422caa86c933.profdata +chrome-win-arm64-main-1751846036-14521a118307fefcbd7c0de7c10fd7786984f164-5037e5d1e0f66103399f58e8d8d4b42068d2018d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 3471da7..fd2cb122 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1751781337-0d161790993f6dff85e9737cd44440530d33a199-f18179f52616f5556495f5aa39908219927061ce.profdata +chrome-win32-main-1751846036-244bbaeb75b0346b780763671e87e0515a78c0fe-5037e5d1e0f66103399f58e8d8d4b42068d2018d.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 7b7021d..9bf94ea4 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1751799075-178e9356995fc0cc442bca85c2f050a81945912c-50c2093adcc75bfb8dd9bcdfe7e7422caa86c933.profdata +chrome-win64-main-1751846036-63af2534cd868953766271060869920fe92152b9-5037e5d1e0f66103399f58e8d8d4b42068d2018d.profdata
diff --git a/clank b/clank index 0942c90..0b19c12 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 0942c904bb5a624a6b2a10f0550ff9d35b419504 +Subproject commit 0b19c12de7a158deb75f357e88759d445a9d7721
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc index 820c4d41..a57437d 100644 --- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc +++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc
@@ -68,36 +68,34 @@ return dafs; } -// Finds the first field in |form_structure| with |field.value|=|value|. -AutofillField* FindFirstFieldWithValue(const FormStructure& form_structure, - std::u16string_view value) { - for (const auto& field : form_structure) { - std::u16string trimmed_value; - base::TrimWhitespace(field->value_for_import(), base::TRIM_ALL, - &trimmed_value); - if (trimmed_value == value) { - return field.get(); +// Adds `CREDIT_CARD_VERIFICATION_CODE` to the possible types of fields whose +// value is `last_unlocked_credit_card_cvc` or looks like a CVC. +// +// In the former case, `kKnownValue` is added to the property mask. +// TODO(crbug.com/429655113): Do we need this? If not, remove. +void FindAndSetPossibleCvcFieldTypes( + std::u16string_view last_unlocked_credit_card_cvc, + const FormStructure& form_structure, + base::span<PossibleTypes> possible_types) { + if (!last_unlocked_credit_card_cvc.empty()) { + for (auto [field, pt] : + base::zip(form_structure.fields(), possible_types)) { + if (last_unlocked_credit_card_cvc == + base::TrimWhitespace(field->value_for_import(), base::TRIM_ALL)) { + pt.types.insert(CREDIT_CARD_VERIFICATION_CODE); + pt.known_value = true; + return; + } } } - return nullptr; -} - -// Heuristically identifies all possible credit card verification fields. -AutofillField* HeuristicallyFindCVCFieldForUpload( - const FormStructure& form_structure) { - // Stores a pointer to the explicitly found expiration year. - bool found_explicit_expiration_year_field = false; // The first pass checks the existence of an explicitly marked field for the // credit card expiration year. - for (const auto& field : form_structure) { - const FieldTypeSet& type_set = field->possible_types(); - if (type_set.find(CREDIT_CARD_EXP_2_DIGIT_YEAR) != type_set.end() || - type_set.find(CREDIT_CARD_EXP_4_DIGIT_YEAR) != type_set.end()) { - found_explicit_expiration_year_field = true; - break; - } - } + const bool found_explicit_expiration_year_field = + std::ranges::any_of(possible_types, [](const PossibleTypes& pt) { + return pt.types.contains_any( + {CREDIT_CARD_EXP_2_DIGIT_YEAR, CREDIT_CARD_EXP_4_DIGIT_YEAR}); + }); // Keeps track if a credit card number field was found. bool credit_card_number_found = false; @@ -109,59 +107,33 @@ // * it does not look like an expiration year or an expiration year was // already found; // * it is filled with a 3-4 digit number; - for (const auto& field : form_structure) { - const FieldTypeSet& type_set = field->possible_types(); - - // Checks if the field is of |CREDIT_CARD_NUMBER| type. - if (type_set.find(CREDIT_CARD_NUMBER) != type_set.end()) { + for (auto [field, pt] : base::zip(form_structure.fields(), possible_types)) { + if (pt.types.contains(CREDIT_CARD_NUMBER)) { credit_card_number_found = true; continue; } - // Skip the field if no credit card number was found yet. if (!credit_card_number_found) { continue; } - - // Don't consider fields that already have any prediction. - if (!type_set.empty()) { + if (!pt.types.empty()) { continue; } - std::u16string trimmed_value; - base::TrimWhitespace(field->value_for_import(), base::TRIM_ALL, - &trimmed_value); + const std::u16string& value = field->value_for_import(); + const std::u16string_view trimmed_value = + base::TrimWhitespace(value, base::TRIM_ALL); // Skip the field if it can be confused with a expiration year. if (!found_explicit_expiration_year_field && IsPlausible4DigitExpirationYear(trimmed_value)) { continue; } - - // Skip the field if its value does not like a CVC value. if (!IsPlausibleCreditCardCVCNumber(trimmed_value)) { continue; } - return field.get(); + pt.types.insert(CREDIT_CARD_VERIFICATION_CODE); } - return nullptr; -} - -// Iff the CVC of the credit card is known, find the first field with this -// value (also set |properties_mask| to |kKnownValue|). Otherwise, heuristically -// search for the CVC field if any. -AutofillField* GetBestPossibleCVCFieldForUpload( - const FormStructure& form_structure, - std::u16string_view last_unlocked_credit_card_cvc) { - if (!last_unlocked_credit_card_cvc.empty()) { - AutofillField* result = - FindFirstFieldWithValue(form_structure, last_unlocked_credit_card_cvc); - if (result) { - result->set_properties_mask(FieldPropertiesFlags::kKnownValue); - } - return result; - } - return HeuristicallyFindCVCFieldForUpload(form_structure); } // Returns the FieldTypes for some given EntityInstance defines a non-empty @@ -243,12 +215,14 @@ base::span<const EntityInstance> entities, const std::map<FieldGlobalId, DatesAndFormats>& dates_and_formats, const std::string& app_locale, - FormStructure& form) { - std::map<data_util::Date, std::vector<AutofillField*>> date_to_field; - for (const auto& [field_id, dafs] : dates_and_formats) { - for (const data_util::Date& date : dafs.dates) { - if (AutofillField* field = form.GetFieldById(field_id)) { - date_to_field[date].push_back(field); + const FormStructure& form, + base::span<PossibleTypes> possible_types) { + std::map<data_util::Date, std::vector<size_t>> date_to_field_indices; + for (size_t i = 0; i < form.field_count(); ++i) { + if (auto it = dates_and_formats.find(form.field(i)->global_id()); + it != dates_and_formats.end()) { + for (const data_util::Date& date : it->second.dates) { + date_to_field_indices[date].push_back(i); } } } @@ -262,11 +236,10 @@ data_util::Date date; if (data_util::ParseDate(attribute.GetCompleteInfo(app_locale), u"YYYY-MM-DD", date)) { - if (auto it = date_to_field.find(date); it != date_to_field.end()) { - for (AutofillField* field : it->second) { - FieldTypeSet field_types = field->possible_types(); - field_types.insert(field_type); - field->set_possible_types(field_types); + if (auto it = date_to_field_indices.find(date); + it != date_to_field_indices.end()) { + for (size_t field_index : it->second) { + possible_types[field_index].types.insert(field_type); } } } @@ -321,6 +294,11 @@ } // namespace +PossibleTypes::PossibleTypes() = default; +PossibleTypes::PossibleTypes(PossibleTypes&&) = default; +PossibleTypes& PossibleTypes::operator=(PossibleTypes&&) = default; +PossibleTypes::~PossibleTypes() = default; + DatesAndFormats::DatesAndFormats() = default; DatesAndFormats::DatesAndFormats(base::flat_set<data_util::Date> dates, base::flat_set<std::u16string> formats) @@ -366,7 +344,7 @@ return fields_that_match_state; } -void DeterminePossibleFieldTypesForUpload( +std::vector<PossibleTypes> DeterminePossibleFieldTypesForUpload( base::span<const AutofillProfile> profiles, base::span<const CreditCard> credit_cards, base::span<const EntityInstance> entities, @@ -375,34 +353,33 @@ std::u16string_view last_unlocked_credit_card_cvc, const std::map<FieldGlobalId, DatesAndFormats>& dates_and_formats, const std::string& app_locale, - FormStructure& form) { + const FormStructure& form) { + std::vector<PossibleTypes> possible_types; + possible_types.resize(form.fields().size()); + // Most type detection happens in this loop. - for (const std::unique_ptr<AutofillField>& field : form.fields()) { - field->set_possible_types(GetPossibleFieldTypes( - *field, profiles, credit_cards, entities, loyalty_cards, - fields_that_match_state, app_locale)); + for (auto [field, types] : base::zip(form.fields(), possible_types)) { + types.types = GetPossibleFieldTypes(*field, profiles, credit_cards, + entities, loyalty_cards, + fields_that_match_state, app_locale); } // Date detection is not part of the above loop because dates can span // multiple fields. FindAndSetPossibleDateFieldTypes(entities, dates_and_formats, app_locale, - form); + form, possible_types); // As CVCs are not stored, run special heuristics to detect CVC-like values. - if (AutofillField* cvc_field = GetBestPossibleCVCFieldForUpload( - form, last_unlocked_credit_card_cvc)) { - FieldTypeSet possible_types = cvc_field->possible_types(); - possible_types.insert(CREDIT_CARD_VERIFICATION_CODE); - cvc_field->set_possible_types(possible_types); - } + FindAndSetPossibleCvcFieldTypes(last_unlocked_credit_card_cvc, form, + possible_types); - for (const std::unique_ptr<AutofillField>& field : form.fields()) { - if (field->possible_types().empty()) { - field->set_possible_types({UNKNOWN_TYPE}); + for (auto [field, pt] : base::zip(form.fields(), possible_types)) { + if (pt.types.empty()) { + pt.types = {UNKNOWN_TYPE}; } } - DisambiguatePossibleFieldTypes(form); + return DisambiguatePossibleFieldTypes(form, std::move(possible_types)); } FieldTypeSet DetermineAvailableFieldTypes(
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h index fadf005..fd8563d 100644 --- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h +++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h
@@ -25,6 +25,24 @@ class FormStructure; class LoyaltyCard; +// The result of DeterminePossibleFieldTypesForUpload() for a specific +// AutofillField. +struct PossibleTypes { + PossibleTypes(); + PossibleTypes(const PossibleTypes&) = delete; + PossibleTypes& operator=(const PossibleTypes&) = delete; + PossibleTypes(PossibleTypes&&); + PossibleTypes& operator=(PossibleTypes&&); + ~PossibleTypes(); + + // The FieldTypes for which data on file matches the field's value. + FieldTypeSet types; + + // Indicates if the value is a known CVC value. + // TODO(crbug.com/429655113): Do we need this? If not, remove. + bool known_value = false; +}; + // Note that the `dates` and `formats` are not aligned (i.e., do not base::zip() // them!). They may even be of distinct size (see Example 2 of // ExtractDatesInFields()). @@ -76,12 +94,12 @@ const std::string& app_locale); // Determines the `FieldType`s for which profiles etc. define non-empty -// values. The result is stored in FormStructure::possible_types(). +// values. // // This is potentially expensive -- on the order of 50ms even for a small set of // `stored_data`. Hence, it should not run on the UI thread -- to avoid // locking up the UI -- nor on the IO thread -- to avoid blocking IPC calls. -void DeterminePossibleFieldTypesForUpload( +[[nodiscard]] std::vector<PossibleTypes> DeterminePossibleFieldTypesForUpload( base::span<const AutofillProfile> profiles, base::span<const CreditCard> credit_cards, base::span<const EntityInstance> entities, @@ -90,7 +108,7 @@ std::u16string_view last_unlocked_credit_card_cvc, const std::map<FieldGlobalId, DatesAndFormats>& dates_and_formats, const std::string& app_locale, - FormStructure& form); + const FormStructure& form); // Returns the set of `FieldType`s for which the given profiles etc. contain // non-empty values.
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc index 71c2441a..07f5c2d 100644 --- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc +++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc
@@ -31,6 +31,7 @@ using ::autofill::test::CreateTestFormField; using ::autofill::test::CreateTestSelectField; using ::testing::Contains; +using ::testing::Each; using ::testing::ElementsAre; using ::testing::Field; using ::testing::IsEmpty; @@ -56,30 +57,21 @@ } void CheckThatOnlyFieldByIndexHasThisPossibleType( - const FormStructure& form_structure, + base::span<const PossibleTypes> possible_types, size_t field_index, FieldType type, - FieldPropertiesMask mask) { - EXPECT_TRUE(field_index < form_structure.field_count()); - - for (size_t i = 0; i < form_structure.field_count(); i++) { + bool known_value) { + EXPECT_LT(field_index, possible_types.size()); + for (size_t i = 0; i < possible_types.size(); i++) { if (i == field_index) { - EXPECT_THAT(form_structure.field(i)->possible_types(), ElementsAre(type)); - EXPECT_EQ(mask, form_structure.field(i)->properties_mask()); + EXPECT_THAT(possible_types[i].types, ElementsAre(type)) << "i=" << i; + EXPECT_EQ(possible_types[i].known_value, known_value) << "i=" << i; } else { - EXPECT_THAT(form_structure.field(i)->possible_types(), - Not(Contains(type))); + EXPECT_THAT(possible_types[i].types, Not(Contains(type))) << "i=" << i; } } } -void CheckThatNoFieldHasThisPossibleType(const FormStructure& form_structure, - FieldType type) { - for (size_t i = 0; i < form_structure.field_count(); i++) { - EXPECT_THAT(form_structure.field(i)->possible_types(), Not(Contains(type))); - } -} - struct TestAddressFillData { TestAddressFillData(const char* first, const char* middle, @@ -310,13 +302,10 @@ test::SetProfileInfo(&profiles[3], "Vincent", "Wilhelm", "van Gogh", "NL"); profiles[3].set_guid(MakeGuid(4)); - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", "4234-5678-9012-3456", "04", "2999", "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); FormData form; form.set_name(u"MyForm"); @@ -328,17 +317,17 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, "en-us", - *form_structure); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + profiles, {credit_card}, std::vector<EntityInstance>(), + std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, + "en-us", *form_structure); - ASSERT_EQ(1U, form_structure->field_count()); - - FieldTypeSet possible_types = form_structure->field(0)->possible_types(); - EXPECT_EQ(possible_types, expected_possible_types); + ASSERT_EQ(form_structure->field_count(), possible_types.size()); + EXPECT_THAT(possible_types[0].types, + UnorderedElementsAreArray(expected_possible_types)); } INSTANTIATE_TEST_SUITE_P(DeterminePossibleFieldTypesForUploadTest, @@ -365,9 +354,6 @@ // BrowserAutofillManager reuses the CVC value to identify a potentially // existing CVC form field to cast a |CREDIT_CARD_VERIFICATION_CODE|-type vote. TEST_F(DeterminePossibleFieldTypesForUploadTest, CrowdsourceCVCFieldByValue) { - std::vector<AutofillProfile> profiles; - std::vector<CreditCard> credit_cards; - constexpr char kCvc[] = "1234"; constexpr char16_t kCvc16[] = u"1234"; constexpr char kFourDigitButNotCvc[] = "6676"; @@ -388,18 +374,18 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - form_structure->field(0)->set_possible_types({CREDIT_CARD_NUMBER}); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/kCvc16, /*dates_and_formats=*/{}, - "en-us", *form_structure); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), std::vector<CreditCard>(), + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/kCvc16, /*dates_and_formats=*/{}, + "en-us", *form_structure); - CheckThatOnlyFieldByIndexHasThisPossibleType( - *form_structure, 2, CREDIT_CARD_VERIFICATION_CODE, - FieldPropertiesFlags::kKnownValue); + CheckThatOnlyFieldByIndexHasThisPossibleType(possible_types, 2, + CREDIT_CARD_VERIFICATION_CODE, + /*known_value=*/true); } // Expiration year field was detected by the server. The other field with a @@ -426,32 +412,22 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types({CREDIT_CARD_NUMBER}); - form_structure->field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR}); - form_structure->field(2)->set_possible_types({UNKNOWN_TYPE}); - - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04", actual_credit_card_exp_year, "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); - // Set up the test profiles. - std::vector<AutofillProfile> profiles; + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), {credit_card}, + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/std::u16string(), + /*dates_and_formats=*/{}, "en-us", *form_structure); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/std::u16string(), - /*dates_and_formats=*/{}, "en-us", *form_structure); - - CheckThatOnlyFieldByIndexHasThisPossibleType(*form_structure, 2, + CheckThatOnlyFieldByIndexHasThisPossibleType(possible_types, 2, CREDIT_CARD_VERIFICATION_CODE, - FieldPropertiesFlags::kNoFlags); + /*known_value=*/false); } // Tests if the CVC field is heuristically detected if it appears after the @@ -478,32 +454,22 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types({CREDIT_CARD_NUMBER}); - form_structure->field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR}); - form_structure->field(2)->set_possible_types({UNKNOWN_TYPE}); - - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04", actual_credit_card_exp_year, "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); - // Set up the test profiles. - std::vector<AutofillProfile> profiles; + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), {credit_card}, + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/std::u16string(), + /*dates_and_formats=*/{}, "en-us", *form_structure); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/std::u16string(), - /*dates_and_formats=*/{}, "en-us", *form_structure); - - CheckThatOnlyFieldByIndexHasThisPossibleType(*form_structure, 2, + CheckThatOnlyFieldByIndexHasThisPossibleType(possible_types, 2, CREDIT_CARD_VERIFICATION_CODE, - FieldPropertiesFlags::kNoFlags); + /*known_value=*/false); } // Tests if the CVC field is heuristically detected if it contains a value which @@ -529,32 +495,22 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types({CREDIT_CARD_NUMBER}); - form_structure->field(1)->set_possible_types({UNKNOWN_TYPE}); - form_structure->field(2)->set_possible_types({UNKNOWN_TYPE}); - - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04", actual_credit_card_exp_year, "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); - // Set up the test profiles. - std::vector<AutofillProfile> profiles; + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), {credit_card}, + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/std::u16string(), + /*dates_and_formats=*/{}, "en-us", *form_structure); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/std::u16string(), - /*dates_and_formats=*/{}, "en-us", *form_structure); - - CheckThatOnlyFieldByIndexHasThisPossibleType(*form_structure, 1, + CheckThatOnlyFieldByIndexHasThisPossibleType(possible_types, 1, CREDIT_CARD_VERIFICATION_CODE, - FieldPropertiesFlags::kNoFlags); + /*known_value=*/false); } // Tests if no CVC field is heuristically detected due to the missing of a @@ -580,30 +536,21 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types({UNKNOWN_TYPE}); - form_structure->field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR}); - form_structure->field(2)->set_possible_types({UNKNOWN_TYPE}); - - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04", actual_credit_card_exp_year, "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); - // Set up the test profiles. - std::vector<AutofillProfile> profiles; - - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/std::u16string(), - /*dates_and_formats=*/{}, "en-us", *form_structure); - CheckThatNoFieldHasThisPossibleType(*form_structure, - CREDIT_CARD_VERIFICATION_CODE); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), {credit_card}, + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/std::u16string(), + /*dates_and_formats=*/{}, "en-us", *form_structure); + EXPECT_THAT(possible_types, + Each(Field(&PossibleTypes::types, + Not(Contains(CREDIT_CARD_VERIFICATION_CODE))))); } // Test if no CVC is found because the candidate has no valid CVC value. @@ -627,32 +574,21 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types( - {CREDIT_CARD_NUMBER, UNKNOWN_TYPE}); - form_structure->field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR}); - form_structure->field(2)->set_possible_types({UNKNOWN_TYPE}); - - // Set up the test credit cards. - std::vector<CreditCard> credit_cards; CreditCard credit_card; test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04", credit_card_exp_year, "1"); credit_card.set_guid(MakeGuid(3)); - credit_cards.push_back(credit_card); - // Set up the test profiles. - std::vector<AutofillProfile> profiles; - - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, std::vector<EntityInstance>(), - std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, "en-us", - *form_structure); - - CheckThatNoFieldHasThisPossibleType(*form_structure, - CREDIT_CARD_VERIFICATION_CODE); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), {credit_card}, + std::vector<EntityInstance>(), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, + "en-us", *form_structure); + EXPECT_THAT(possible_types, + Each(Field(&PossibleTypes::types, + Not(Contains(CREDIT_CARD_VERIFICATION_CODE))))); } // Tests if the loyalty card field detected. @@ -672,24 +608,19 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - // Set the field types. - form_structure->field(0)->set_possible_types({LOYALTY_MEMBERSHIP_PROGRAM}); - - // Set up the test loyalty cards. - std::vector<LoyaltyCard> loyalty_cards; LoyaltyCard loyalty_card = test::CreateLoyaltyCard(); loyalty_card.set_loyalty_card_number(loyalty_card_number); - loyalty_cards.push_back(loyalty_card); - DeterminePossibleFieldTypesForUpload( - std::vector<AutofillProfile>(), std::vector<CreditCard>(), - std::vector<EntityInstance>(), loyalty_cards, - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, "en-us", - *form_structure); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), std::vector<CreditCard>(), + std::vector<EntityInstance>(), {loyalty_card}, + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/u"", /*dates_and_formats=*/{}, + "en-us", *form_structure); - CheckThatOnlyFieldByIndexHasThisPossibleType(*form_structure, 1, + CheckThatOnlyFieldByIndexHasThisPossibleType(possible_types, 1, LOYALTY_MEMBERSHIP_ID, - FieldPropertiesFlags::kNoFlags); + /*known_value=*/false); } // Tests if the Autofill AI field types are crowdsourced. @@ -724,29 +655,28 @@ .issue_date = u"2010-09-01", }); - DeterminePossibleFieldTypesForUpload( - std::vector<AutofillProfile>(), std::vector<CreditCard>(), - base::span_from_ref(entity), std::vector<LoyaltyCard>(), - /*fields_that_match_state=*/{}, - /*last_unlocked_credit_card_cvc=*/u"", - ExtractDatesInFields(form_structure->fields()), "en-US", *form_structure); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + std::vector<AutofillProfile>(), std::vector<CreditCard>(), + base::span_from_ref(entity), std::vector<LoyaltyCard>(), + /*fields_that_match_state=*/{}, + /*last_unlocked_credit_card_cvc=*/u"", + ExtractDatesInFields(form_structure->fields()), "en-US", + *form_structure); - EXPECT_THAT(form_structure->fields()[0]->possible_types(), - UnorderedElementsAre(NAME_FIRST)); - EXPECT_THAT(form_structure->fields()[1]->possible_types(), + EXPECT_THAT(possible_types[0].types, UnorderedElementsAre(NAME_FIRST)); + EXPECT_THAT(possible_types[1].types, UnorderedElementsAre(NAME_LAST, NAME_LAST_SECOND)); - EXPECT_THAT(form_structure->fields()[2]->possible_types(), - UnorderedElementsAre(PASSPORT_NUMBER)); - EXPECT_THAT(form_structure->fields()[3]->possible_types(), + EXPECT_THAT(possible_types[2].types, UnorderedElementsAre(PASSPORT_NUMBER)); + EXPECT_THAT(possible_types[3].types, UnorderedElementsAre(PASSPORT_EXPIRATION_DATE)); - EXPECT_THAT(form_structure->fields()[4]->possible_types(), + EXPECT_THAT(possible_types[4].types, UnorderedElementsAre(PASSPORT_ISSUE_DATE)); - EXPECT_THAT(form_structure->fields()[5]->possible_types(), + EXPECT_THAT(possible_types[5].types, UnorderedElementsAre(PASSPORT_ISSUE_DATE)); - EXPECT_THAT(form_structure->fields()[6]->possible_types(), + EXPECT_THAT(possible_types[6].types, UnorderedElementsAre(PASSPORT_ISSUE_DATE)); - EXPECT_THAT(form_structure->fields()[7]->possible_types(), - UnorderedElementsAre(UNKNOWN_TYPE)); + EXPECT_THAT(possible_types[7].types, UnorderedElementsAre(UNKNOWN_TYPE)); } // Test fixture for PreProcessStateMatchingTypes().
diff --git a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.cc b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.cc index 492d71c..b114bbe 100644 --- a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.cc +++ b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.cc
@@ -5,7 +5,9 @@ #include "components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.h" #include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h" #include "components/autofill/core/browser/field_type_utils.h" +#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_features.h" @@ -13,11 +15,6 @@ namespace { -// Returns `true` if `field` contains multiple possible types. -bool MayHaveAmbiguousPossibleTypes(const AutofillField& field) { - return field.possible_types().size() > 1; -} - // Returns whether the `field` is predicted as being any kind of name. bool IsNameType(const AutofillField& field) { return field.Type().group() == FieldTypeGroup::kName || @@ -31,28 +28,31 @@ // address name types are discarded. If `is_credit_card` is false, the opposite // happens. This is called when we have multiple possible name types from mixed // field type groups. -void SelectProbableNameTypes(AutofillField& field, - bool select_credit_card_names) { +[[nodiscard]] FieldTypeSet SelectProbableNameTypes( + FieldTypeSet possible_types, + bool select_credit_card_names) { FieldTypeSet types_to_keep; - for (FieldType type : field.possible_types()) { - FieldTypeGroup group = GroupTypeOfFieldType(type); - if ((select_credit_card_names && group == FieldTypeGroup::kCreditCard) || - (!select_credit_card_names && group == FieldTypeGroup::kName)) { + for (FieldType type : possible_types) { + if (GroupTypeOfFieldType(type) == (select_credit_card_names + ? FieldTypeGroup::kCreditCard + : FieldTypeGroup::kName)) { types_to_keep.insert(type); } } - - field.set_possible_types(types_to_keep); + return types_to_keep; } // If a field was autofilled on form submission and the value was accepted, set // possible types to the autofilled type. -void SetPossibleTypesToAutofilledTypeIfAvailable(AutofillField& field) { +[[nodiscard]] FieldTypeSet OverridePossibleTypesToAutofilledTypeIfAvailable( + const AutofillField& field, + FieldTypeSet possible_types) { if (field.is_autofilled() && field.autofilled_type() && base::FeatureList::IsEnabled( features::kAutofillDisambiguateContradictingFieldTypes)) { - field.set_possible_types({*field.autofilled_type()}); + return {*field.autofilled_type()}; } + return possible_types; } // Disambiguates name types from mixed field type groups when the name exists in @@ -61,22 +61,22 @@ // Note that generally a name field can legitimately have multiple types // according to the types tree structure, e.g. `NAME_FULL`, `NAME_LAST` and // `NAME_LAST_{FIRST,SECOND}` at the same time. -void MaybeDisambiguateNameTypes(FormStructure& form, - size_t current_field_index) { +[[nodiscard]] FieldTypeSet MaybeDisambiguateNameTypes( + const FormStructure& form, + size_t current_field_index, + FieldTypeSet possible_types) { // Disambiguation is only applicable if there is a mixture of one or more // address related name types ('one or more' because e.g. NAME_LAST and // NAME_LAST_SECOND can be identical) and exactly one credit card related name // type ('exactly one' because credit cards names only support a single last // name). - AutofillField& field = *form.field(current_field_index); - const size_t credit_card_type_count = - NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kCreditCard); - const size_t name_type_count = - NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kName); - if (field.possible_types().size() != - (credit_card_type_count + name_type_count) || + const size_t credit_card_type_count = std::ranges::count( + possible_types, FieldTypeGroup::kCreditCard, GroupTypeOfFieldType); + const size_t name_type_count = std::ranges::count( + possible_types, FieldTypeGroup::kName, GroupTypeOfFieldType); + if (possible_types.size() != credit_card_type_count + name_type_count || credit_card_type_count != 1 || name_type_count == 0) { - return; + return possible_types; } // This case happens when both a profile and a credit card have the same @@ -96,11 +96,11 @@ size_t index = current_field_index; while (index != 0 && !has_found_previous_type) { --index; - AutofillField* prev_field = form.field(index); - if (!IsNameType(*prev_field)) { + const AutofillField& prev_field = *form.field(index); + if (!IsNameType(prev_field)) { has_found_previous_type = true; is_previous_credit_card = - prev_field->Type().group() == FieldTypeGroup::kCreditCard; + prev_field.Type().group() == FieldTypeGroup::kCreditCard; } } @@ -109,11 +109,11 @@ bool is_next_credit_card = false; index = current_field_index; while (++index < form.field_count() && !has_found_next_type) { - AutofillField* next_field = form.field(index); - if (!IsNameType(*next_field)) { + const AutofillField& next_field = *form.field(index); + if (!IsNameType(next_field)) { has_found_next_type = true; is_next_credit_card = - next_field->Type().group() == FieldTypeGroup::kCreditCard; + next_field.Type().group() == FieldTypeGroup::kCreditCard; } } @@ -124,37 +124,39 @@ // name group there is no sure way to disambiguate. if (has_found_previous_type && has_found_next_type && (is_previous_credit_card != is_next_credit_card)) { - return; + return possible_types; } // Otherwise, use the previous (if it was found) or next field group to // decide whether the field is a name or a credit card name. - if (has_found_previous_type) { - SelectProbableNameTypes(field, is_previous_credit_card); - } else { - SelectProbableNameTypes(field, is_next_credit_card); - } + possible_types = SelectProbableNameTypes( + possible_types, has_found_previous_type ? is_previous_credit_card + : is_next_credit_card); } + return possible_types; } } // namespace -void DisambiguatePossibleFieldTypes(FormStructure& form) { +std::vector<PossibleTypes> DisambiguatePossibleFieldTypes( + const FormStructure& form, + std::vector<PossibleTypes> possible_types) { for (size_t i = 0; i < form.field_count(); ++i) { - AutofillField& field = *form.field(i); - if (!MayHaveAmbiguousPossibleTypes(field)) { + if (possible_types[i].types.size() <= 1) { continue; } // Setting possible types to an autofilled value that was accepted by the // user should have the highest priority among disambiguation methods // because it represents user intent the most. - SetPossibleTypesToAutofilledTypeIfAvailable(field); - - if (!MayHaveAmbiguousPossibleTypes(field)) { + possible_types[i].types = OverridePossibleTypesToAutofilledTypeIfAvailable( + *form.field(i), possible_types[i].types); + if (possible_types[i].types.size() <= 1) { continue; } - MaybeDisambiguateNameTypes(form, i); + possible_types[i].types = + MaybeDisambiguateNameTypes(form, i, possible_types[i].types); } + return possible_types; } } // namespace autofill
diff --git a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.h b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.h index 5395f3c..10b5e667 100644 --- a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.h +++ b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types.h
@@ -5,16 +5,23 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CROWDSOURCING_DISAMBIGUATE_POSSIBLE_FIELD_TYPES_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_CROWDSOURCING_DISAMBIGUATE_POSSIBLE_FIELD_TYPES_H_ +#include <vector> + +#include "base/containers/span.h" + namespace autofill { class FormStructure; +struct PossibleTypes; // Applies several heuristics to select the most probable types for fields with // ambiguous possible types. Heuristics are run in order of priority which is // based on reflecting user intent the most. // Note that the case where a single-line street address is ambiguous to address // line 1 is handled on the server. -void DisambiguatePossibleFieldTypes(FormStructure& form); +std::vector<PossibleTypes> DisambiguatePossibleFieldTypes( + const FormStructure& form, + std::vector<PossibleTypes> possible_types); } // namespace autofill
diff --git a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types_unittest.cc b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types_unittest.cc index 56f5968e..f882a58 100644 --- a/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types_unittest.cc +++ b/components/autofill/core/browser/crowdsourcing/disambiguate_possible_field_types_unittest.cc
@@ -6,8 +6,10 @@ #include <algorithm> +#include "base/containers/to_vector.h" #include "base/types/zip.h" #include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/form_data.h" @@ -16,18 +18,12 @@ namespace autofill { -using test::CreateTestFormField; using ::testing::ElementsAre; using ::testing::UnorderedElementsAre; // Tests that `DisambiguatePossibleFieldTypes` makes the correct choices. class DisambiguatePossibleFieldTypesTest : public ::testing::Test { protected: - DisambiguatePossibleFieldTypesTest() { - feature_list_.InitAndEnableFeature( - features::kAutofillDisambiguateContradictingFieldTypes); - } - struct TestFieldData { FieldType predicted_type; FieldTypeSet ambiguous_possible_field_types; @@ -41,35 +37,31 @@ FormData form; for (size_t i = 0; i < test_fields.size(); ++i) { test_api(form).Append( - CreateTestFormField("", "", "", FormControlType::kInputText)); + test::CreateTestFormField("", "", "", FormControlType::kInputText)); } + FormStructure form_structure(form); - for (auto [field, test_field] : - base::zip(form_structure.fields(), test_fields)) { - field->set_possible_types(test_field.ambiguous_possible_field_types); + std::vector<PossibleTypes> possible_types(form_structure.fields().size()); + for (auto [test_field, field, pt] : + base::zip(test_fields, form_structure.fields(), possible_types)) { field->set_server_predictions( - {::autofill::test::CreateFieldPrediction(test_field.predicted_type)}); + {test::CreateFieldPrediction(test_field.predicted_type)}); if (test_field.is_autofilled) { field->set_autofilled_type(test_field.predicted_type); field->set_is_autofilled(true); } + pt.types = test_field.ambiguous_possible_field_types; } - DisambiguatePossibleFieldTypes(form_structure); - - std::vector<FieldTypeSet> disambiguated_possible_field_types; - std::ranges::transform( - form_structure.fields(), - std::back_inserter(disambiguated_possible_field_types), - [](const std::unique_ptr<AutofillField>& field) { - return field->possible_types(); - }); - return disambiguated_possible_field_types; + return base::ToVector(DisambiguatePossibleFieldTypes( + form_structure, std::move(possible_types)), + &PossibleTypes::types); } - protected: + private: test::AutofillUnitTestEnvironment autofill_test_environment_; - base::test::ScopedFeatureList feature_list_; + base::test::ScopedFeatureList feature_list_{ + features::kAutofillDisambiguateContradictingFieldTypes}; }; // Name disambiguation. @@ -82,11 +74,7 @@ {CREDIT_CARD_NAME_FIRST, {NAME_FIRST, CREDIT_CARD_NAME_FIRST}}, {CREDIT_CARD_NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(ADDRESS_HOME_CITY), UnorderedElementsAre(NAME_FIRST), UnorderedElementsAre(NAME_LAST, NAME_LAST_SECOND))); @@ -101,11 +89,7 @@ {CREDIT_CARD_NAME_FIRST, {NAME_FIRST, CREDIT_CARD_NAME_FIRST}}, {CREDIT_CARD_NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(CREDIT_CARD_NUMBER), UnorderedElementsAre(CREDIT_CARD_NAME_FIRST), UnorderedElementsAre(CREDIT_CARD_NAME_LAST))); @@ -120,11 +104,7 @@ {CREDIT_CARD_NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {ADDRESS_HOME_CITY, {ADDRESS_HOME_CITY}}}; - - const std::vector<FieldTypeSet> disambiguated_possible_field_types = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(disambiguated_possible_field_types, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(NAME_FIRST), UnorderedElementsAre(NAME_LAST, NAME_LAST_SECOND), UnorderedElementsAre(ADDRESS_HOME_CITY))); @@ -138,11 +118,7 @@ {NAME_FIRST, {NAME_FIRST, CREDIT_CARD_NAME_FIRST}}, {NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {CREDIT_CARD_NUMBER, {CREDIT_CARD_NUMBER}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(CREDIT_CARD_NAME_FIRST), UnorderedElementsAre(CREDIT_CARD_NAME_LAST), UnorderedElementsAre(CREDIT_CARD_NUMBER))); @@ -158,11 +134,7 @@ {CREDIT_CARD_NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {ADDRESS_HOME_STATE, {ADDRESS_HOME_STATE}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(ADDRESS_HOME_CITY), UnorderedElementsAre(NAME_FIRST), UnorderedElementsAre(NAME_LAST, NAME_LAST_SECOND), @@ -178,11 +150,7 @@ {NAME_FIRST, {NAME_FIRST, CREDIT_CARD_NAME_FIRST}}, {NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {CREDIT_CARD_EXP_4_DIGIT_YEAR, {CREDIT_CARD_EXP_4_DIGIT_YEAR}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(CREDIT_CARD_NUMBER), UnorderedElementsAre(CREDIT_CARD_NAME_FIRST), UnorderedElementsAre(CREDIT_CARD_NAME_LAST), @@ -199,11 +167,8 @@ {NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {CREDIT_CARD_EXP_4_DIGIT_YEAR, {CREDIT_CARD_EXP_4_DIGIT_YEAR}}}; - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - EXPECT_THAT( - kDisambiguatedPossibleFieldTypes, + GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(ADDRESS_HOME_CITY), UnorderedElementsAre(NAME_FIRST, CREDIT_CARD_NAME_FIRST), UnorderedElementsAre(NAME_LAST, CREDIT_CARD_NAME_LAST, @@ -220,12 +185,8 @@ {NAME_FIRST, {NAME_FIRST, CREDIT_CARD_NAME_FIRST}}, {NAME_LAST, {NAME_LAST, CREDIT_CARD_NAME_LAST, NAME_LAST_SECOND}}, {ADDRESS_HOME_CITY, {ADDRESS_HOME_CITY}}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - EXPECT_THAT( - kDisambiguatedPossibleFieldTypes, + GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(CREDIT_CARD_EXP_4_DIGIT_YEAR), UnorderedElementsAre(NAME_FIRST, CREDIT_CARD_NAME_FIRST), UnorderedElementsAre(NAME_LAST, CREDIT_CARD_NAME_LAST, @@ -239,11 +200,7 @@ {ADDRESS_HOME_LINE1, {CREDIT_CARD_EXP_4_DIGIT_YEAR, NAME_FULL, COMPANY_NAME}, true}}; - - const std::vector<FieldTypeSet> kDisambiguatedPossibleFieldTypes = - GetDisambiguatedPossibleFieldTypes(kTestFields); - - EXPECT_THAT(kDisambiguatedPossibleFieldTypes, + EXPECT_THAT(GetDisambiguatedPossibleFieldTypes(kTestFields), ElementsAre(UnorderedElementsAre(ADDRESS_HOME_LINE1))); }
diff --git a/components/autofill/core/browser/crowdsourcing/votes_uploader.cc b/components/autofill/core/browser/crowdsourcing/votes_uploader.cc index c601578..2331236 100644 --- a/components/autofill/core/browser/crowdsourcing/votes_uploader.cc +++ b/components/autofill/core/browser/crowdsourcing/votes_uploader.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_number_conversions.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" +#include "base/types/zip.h" #include "components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.h" #include "components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_manager.h" #include "components/autofill/core/browser/crowdsourcing/determine_possible_field_types.h" @@ -263,10 +264,19 @@ dates_and_formats_by_field = ExtractDatesInFields(form->fields()); - DeterminePossibleFieldTypesForUpload( - profiles, credit_cards, entities, loyalty_cards, - fields_that_match_state, last_unlocked_credit_card_cvc, - dates_and_formats_by_field, app_locale, *form); + std::vector<PossibleTypes> possible_types = + DeterminePossibleFieldTypesForUpload( + profiles, credit_cards, entities, loyalty_cards, + fields_that_match_state, last_unlocked_credit_card_cvc, + dates_and_formats_by_field, app_locale, *form); + + for (auto [field, pt] : base::zip(form->fields(), possible_types)) { + field->set_possible_types(pt.types); + if (pt.known_value) { + field->set_properties_mask(field->properties_mask() | + FieldPropertiesFlags::kKnownValue); + } + } EncodeUploadRequestOptions options; options.encoder = std::move(randomized_encoder);
diff --git a/components/autofill/core/browser/field_type_utils.cc b/components/autofill/core/browser/field_type_utils.cc index 04f7511d..1934c82 100644 --- a/components/autofill/core/browser/field_type_utils.cc +++ b/components/autofill/core/browser/field_type_utils.cc
@@ -12,12 +12,6 @@ namespace autofill { -size_t NumberOfPossibleFieldTypesInGroup(const AutofillField& field, - FieldTypeGroup group) { - return std::ranges::count(field.possible_types(), group, - GroupTypeOfFieldType); -} - bool FieldHasMeaningfulPossibleFieldTypes(const AutofillField& field) { // This function should only be invoked when the possible types have been // determined.
diff --git a/components/autofill/core/browser/field_type_utils.h b/components/autofill/core/browser/field_type_utils.h index 94dc1f7..0ae36c3f 100644 --- a/components/autofill/core/browser/field_type_utils.h +++ b/components/autofill/core/browser/field_type_utils.h
@@ -17,11 +17,6 @@ // determined. bool FieldHasMeaningfulPossibleFieldTypes(const AutofillField& field); -// Returns the number of possible field types (type votes) of a `field` that are -// in a specific `group`. -size_t NumberOfPossibleFieldTypesInGroup(const AutofillField& field, - FieldTypeGroup group); - // Returns true if the type of `field` is a possible type. bool TypeOfFieldIsPossibleType(const AutofillField& field);
diff --git a/components/autofill/core/browser/field_type_utils_unittest.cc b/components/autofill/core/browser/field_type_utils_unittest.cc index 2c4748a3..4603103 100644 --- a/components/autofill/core/browser/field_type_utils_unittest.cc +++ b/components/autofill/core/browser/field_type_utils_unittest.cc
@@ -12,24 +12,6 @@ namespace { -TEST(AutofillFieldTypeUtils, NumberOfPossibleTypesInGroup) { - AutofillField field; - field.set_possible_types({NAME_FIRST, NAME_LAST, CREDIT_CARD_NAME_FIRST}); - - EXPECT_EQ(NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kName), - 2U); - - EXPECT_EQ( - NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kCreditCard), - 1U); - - EXPECT_EQ(NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kAddress), - 0U); - - EXPECT_EQ(NumberOfPossibleFieldTypesInGroup(field, FieldTypeGroup::kPhone), - 0U); -} - TEST(AutofillFieldTypeUtils, FieldHasMeaningfulFieldTypes) { AutofillField field;
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 37e9f4b..a8b6dc6 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 37e9f4b495cdbb05bd7ec76311668998b6053bf9 +Subproject commit a8b6dc620e36af6428e9953791c2b66ebd6b3641
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 16de85a38..81733f95 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -2773,11 +2773,12 @@ hdr_metadata.ndwl = gfx::HdrMetadataNdwl( current_frame()->display_color_spaces.GetSDRMaxLuminanceNits()); } + // TODO(https://crbug.com/428575083): Change this to use log2 based + // headroom. cc::ToneMapUtil::AddGlobalToneMapFilterToPaint( paint, image, hdr_metadata, - quad->dynamic_range_limit.ComputeHdrHeadroom( - current_frame() - ->display_color_spaces.GetHDRMaxLuminanceRelative())); + std::exp2(quad->dynamic_range_limit.ComputeEffectiveHdrHeadroom( + current_frame()->display_color_spaces.GetHdrHeadroom()))); } // From gl_renderer, the final src color will be
diff --git a/content/browser/preloading/prerender/prerender_attributes.cc b/content/browser/preloading/prerender/prerender_attributes.cc index cb43cf7..59daf4be 100644 --- a/content/browser/preloading/prerender/prerender_attributes.cc +++ b/content/browser/preloading/prerender/prerender_attributes.cc
@@ -36,7 +36,8 @@ url_match_predicate, base::RepeatingCallback<void(NavigationHandle&)> prerender_navigation_handle_callback, - scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info) + scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info, + bool allow_reuse) : prerendering_url(prerendering_url), trigger_type(trigger_type), embedder_histogram_suffix(embedder_histogram_suffix), @@ -50,7 +51,8 @@ url_match_predicate(std::move(url_match_predicate)), prerender_navigation_handle_callback( std::move(prerender_navigation_handle_callback)), - preload_pipeline_info(std::move(preload_pipeline_info)) { + preload_pipeline_info(std::move(preload_pipeline_info)), + allow_reuse(allow_reuse) { if (initiator_render_frame_host) { initiator_origin = initiator_render_frame_host->GetLastCommittedOrigin(); initiator_process_id =
diff --git a/content/browser/preloading/prerender/prerender_attributes.h b/content/browser/preloading/prerender/prerender_attributes.h index 96014f60..88d10db 100644 --- a/content/browser/preloading/prerender/prerender_attributes.h +++ b/content/browser/preloading/prerender/prerender_attributes.h
@@ -55,7 +55,8 @@ url_match_predicate, base::RepeatingCallback<void(NavigationHandle&)> prerender_navigation_handle_callback, - scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info); + scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info, + bool allow_reuse); ~PrerenderAttributes(); @@ -144,6 +145,9 @@ // Information of preload pipeline that this prerender belongs to. scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info; + // Whether the created prerender host can be reused for future navigations. + bool allow_reuse = false; + // This is std::nullopt when prerendering is initiated by the browser. std::optional<base::UnguessableToken> initiator_devtools_navigation_token;
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc index e1fde5e..2328a567 100644 --- a/content/browser/preloading/prerender/prerender_browsertest.cc +++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -512,7 +512,8 @@ /*planned_max_preloading_type=*/PreloadingType::kPrerender), preloading_attempt, /*url_match_predicate=*/{}, - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); } bool AddTestUtilJS(RenderFrameHost* host) { @@ -12388,7 +12389,8 @@ PreloadPipelineInfo::Create( /*planned_max_preloading_type=*/PreloadingType::kPrerender), /*preloading_attempt=*/nullptr, /*url_match_predicate=*/{}, - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); EXPECT_TRUE(prerender_handle); test::PrerenderTestHelper::WaitForPrerenderLoadCompletion(web_contents, prerendering_url);
diff --git a/content/browser/preloading/prerender/prerender_host_registry_unittest.cc b/content/browser/preloading/prerender/prerender_host_registry_unittest.cc index 33edc9c5..5fa79d7 100644 --- a/content/browser/preloading/prerender/prerender_host_registry_unittest.cc +++ b/content/browser/preloading/prerender/prerender_host_registry_unittest.cc
@@ -211,7 +211,8 @@ /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}, PreloadPipelineInfoImpl::Create( - /*planned_max_preloading_type=*/PreloadingType::kPrerender)); + /*planned_max_preloading_type=*/PreloadingType::kPrerender), + /*allow_reuse=*/false); case PreloadingTriggerType::kEmbedder: return PrerenderAttributes( url, trigger_type, embedder_histogram_suffix, @@ -225,7 +226,8 @@ /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}, PreloadPipelineInfoImpl::Create( - /*planned_max_preloading_type=*/PreloadingType::kPrerender)); + /*planned_max_preloading_type=*/PreloadingType::kPrerender), + /*allow_reuse=*/false); } }
diff --git a/content/browser/preloading/prerender/prerender_host_unittest.cc b/content/browser/preloading/prerender/prerender_host_unittest.cc index 40edb29..5112e69 100644 --- a/content/browser/preloading/prerender/prerender_host_unittest.cc +++ b/content/browser/preloading/prerender/prerender_host_unittest.cc
@@ -284,7 +284,8 @@ /*should_prepare_paint_tree=*/false, std::move(url_match_predicate), /*prerender_navigation_handle_callback=*/{}, PreloadPipelineInfoImpl::Create( - /*planned_max_preloading_type=*/PreloadingType::kPrerender)); + /*planned_max_preloading_type=*/PreloadingType::kPrerender), + /*allow_reuse=*/false); } void ExpectFinalStatus(PrerenderFinalStatus status) {
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc index 26c55b5..e63628a 100644 --- a/content/browser/preloading/prerenderer_impl.cc +++ b/content/browser/preloading/prerenderer_impl.cc
@@ -372,7 +372,8 @@ /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}, PreloadPipelineInfoImpl::Create( - /*planned_max_preloading_type=*/PreloadingType::kPrerender)); + /*planned_max_preloading_type=*/PreloadingType::kPrerender), + /*allow_reuse=*/false); PreloadingTriggerType trigger_type = PreloadingTriggerTypeFromSpeculationInjectionType(
diff --git a/content/browser/renderer_host/back_forward_cache_metrics.cc b/content/browser/renderer_host/back_forward_cache_metrics.cc index cd265b01..117bb10 100644 --- a/content/browser/renderer_host/back_forward_cache_metrics.cc +++ b/content/browser/renderer_host/back_forward_cache_metrics.cc
@@ -4,6 +4,7 @@ #include "content/browser/renderer_host/back_forward_cache_metrics.h" +#include "base/debug/alias.h" #include "base/debug/crash_logging.h" #include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_functions.h" @@ -231,6 +232,7 @@ page_store_result_->ToString()); RecordHistoryNavigationUMA(navigation, back_forward_cache_allowed); RecordHistoryNavigationUKM(navigation); + SCOPED_CRASH_KEY_BOOL("crbug/427426299", "pstr", !!page_store_tree_result_); if (!navigation->IsServedFromBackForwardCache()) { devtools_instrumentation::BackForwardCacheNotUsed( navigation, page_store_result_.get(), page_store_tree_result_.get()); @@ -241,10 +243,12 @@ std::move(page_store_tree_result_)); } } + SCOPED_CRASH_KEY_BOOL("crbug/427426299", "before_gni", true); // Save the information about the last cross-document main frame navigation // that uses this metrics object. last_committed_cross_document_main_frame_navigation_id_ = navigation->GetNavigationId(); + SCOPED_CRASH_KEY_BOOL("crbug/427426299", "after_gni", true); // BackForwardCacheMetrics can be reused in some cases. Reset fields for UKM // for the next navigation.
diff --git a/content/browser/renderer_host/back_forward_cache_metrics.h b/content/browser/renderer_host/back_forward_cache_metrics.h index 040ac7d..28ad3a1 100644 --- a/content/browser/renderer_host/back_forward_cache_metrics.h +++ b/content/browser/renderer_host/back_forward_cache_metrics.h
@@ -139,8 +139,10 @@ // Notifies that an associated entry has committed a navigation. // |back_forward_cache_allowed| indicates whether back-forward cache is // allowed for the URL of |navigation_request|. - void DidCommitNavigation(NavigationRequest* navigation_request, - bool back_forward_cache_allowed); + // TODO(https://crbug.com/427426299): Remove these annotations. + NOINLINE NOT_TAIL_CALLED void DidCommitNavigation( + NavigationRequest* navigation_request, + bool back_forward_cache_allowed); // Records when another navigation commits away from the most recent entry // associated with |this|. This is the point in time that the previous
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager.cc b/content/browser/renderer_host/page_lifecycle_state_manager.cc index c5613ed01c..2441c3d 100644 --- a/content/browser/renderer_host/page_lifecycle_state_manager.cc +++ b/content/browser/renderer_host/page_lifecycle_state_manager.cc
@@ -10,6 +10,7 @@ #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_macros.h" #include "base/state_transitions.h" +#include "base/strings/stringprintf.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -98,7 +99,8 @@ } void PageLifecycleStateManager::SetBackForwardCacheEntered( - BackForwardCacheEntered entered) { + BackForwardCacheEntered entered, + char context_for_bug_427316606) { static const base::NoDestructor< base::StateTransitions<BackForwardCacheEntered>> transitions(base::StateTransitions<BackForwardCacheEntered>({ @@ -109,17 +111,9 @@ })); // TODO(https://crbug.com/427316606): Remove this when we understand how this // transition sometimes occurs. - switch (entered) { - case BackForwardCacheEntered::kNo: - back_forward_cache_state_counts_.no++; - break; - case BackForwardCacheEntered::kEntering: - back_forward_cache_state_counts_.entering++; - break; - case BackForwardCacheEntered::kEntered: - back_forward_cache_state_counts_.entered++; - break; - } + back_forward_cache_state_tracker_.append( + base::StringPrintf("%c%d", context_for_bug_427316606, entered)); + if (back_forward_cache_entered_ == BackForwardCacheEntered::kNo && entered == BackForwardCacheEntered::kEntered) { DumpWithoutCrashForBug427316606(); @@ -130,12 +124,8 @@ } void PageLifecycleStateManager::DumpWithoutCrashForBug427316606() { - SCOPED_CRASH_KEY_NUMBER("bfcache", "count_no", - back_forward_cache_state_counts_.no); - SCOPED_CRASH_KEY_NUMBER("bfcache", "count_entering", - back_forward_cache_state_counts_.entering); - SCOPED_CRASH_KEY_NUMBER("bfcache", "count_entered", - back_forward_cache_state_counts_.entered); + SCOPED_CRASH_KEY_STRING64("bfcache", "tracker", + back_forward_cache_state_tracker_); base::debug::DumpWithoutCrashing(); } @@ -151,7 +141,7 @@ !last_acknowledged_state_->eviction_enabled); eviction_enabled_ = is_in_back_forward_cache; if (is_in_back_forward_cache) { - SetBackForwardCacheEntered(BackForwardCacheEntered::kEntering); + SetBackForwardCacheEntered(BackForwardCacheEntered::kEntering, 'S'); // When a page is put into BackForwardCache, the page can run a busy loop. // Set a timeout monitor to check that the transition finishes within the // time limit. @@ -165,7 +155,7 @@ // When a page is restored from the back-forward cache, we should reset this // state so that it behaves correctly next time navigation occurs. pagehide_dispatch_ = blink::mojom::PagehideDispatch::kNotDispatched; - SetBackForwardCacheEntered(BackForwardCacheEntered::kNo); + SetBackForwardCacheEntered(BackForwardCacheEntered::kNo, 'S'); } SendUpdatesToRendererIfNeeded(std::move(page_restore_params), @@ -283,7 +273,10 @@ back_forward_cache_entered_ != BackForwardCacheEntered::kEntered) { SCOPED_CRASH_KEY_NUMBER("bfcache", "current_entered_", static_cast<int>(back_forward_cache_entered_)); - SetBackForwardCacheEntered(BackForwardCacheEntered::kEntered); + SCOPED_CRASH_KEY_NUMBER("bfcache", "splsr", + set_page_lifecycle_state_response); + SetBackForwardCacheEntered(BackForwardCacheEntered::kEntered, + set_page_lifecycle_state_response ? 'R' : 'C'); // TODO(https://crbug.com/427316606): Remove this. // This should only happen during a response to SetPageLifecycleState. if (!set_page_lifecycle_state_response) {
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager.h b/content/browser/renderer_host/page_lifecycle_state_manager.h index ea4b6ff..dcca589 100644 --- a/content/browser/renderer_host/page_lifecycle_state_manager.h +++ b/content/browser/renderer_host/page_lifecycle_state_manager.h
@@ -126,7 +126,10 @@ friend std::ostream& operator<<(std::ostream&, const BackForwardCacheEntered&); - void SetBackForwardCacheEntered(BackForwardCacheEntered entered); + // TODO(https://crbug.com/427316606): Remove `context_for_bug_427316606` after + // debugging. + void SetBackForwardCacheEntered(BackForwardCacheEntered entered, + char context_for_bug_427316606); BackForwardCacheEntered back_forward_cache_entered_ = BackForwardCacheEntered::kNo; @@ -158,11 +161,7 @@ raw_ptr<TestDelegate> test_delegate_{nullptr}; // TODO(https://crbug.com/427316606): Remove this after debugging. - struct { - unsigned int no = 0; - unsigned int entering = 0; - unsigned int entered = 0; - } back_forward_cache_state_counts_; + std::string back_forward_cache_state_tracker_; // NOTE: This must be the last member. base::WeakPtrFactory<PageLifecycleStateManager> weak_ptr_factory_{this};
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 378f8e5..f4cb3ab0 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -11973,7 +11973,8 @@ const std::optional<UrlMatchType>&)> url_match_predicate, base::RepeatingCallback<void(NavigationHandle&)> - prerender_navigation_handle_callback) { + prerender_navigation_handle_callback, + bool allow_reuse) { PrerenderAttributes attributes( prerendering_url, trigger_type, embedder_histogram_suffix, /*speculation_rules_params=*/std::nullopt, content::Referrer(), @@ -11983,7 +11984,8 @@ std::move(url_match_predicate), std::move(prerender_navigation_handle_callback), base::WrapRefCounted( - static_cast<PreloadPipelineInfoImpl*>(preload_pipeline_info.get()))); + static_cast<PreloadPipelineInfoImpl*>(preload_pipeline_info.get())), + allow_reuse); #if BUILDFLAG(IS_ANDROID) attributes.additional_headers = std::move(additional_headers); #else
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 6687021..3ca82fa 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -1010,7 +1010,8 @@ PreloadingAttempt* preloading_attempt, base::RepeatingCallback<bool(const GURL&, const std::optional<UrlMatchType>&)>, - base::RepeatingCallback<void(NavigationHandle&)>) override; + base::RepeatingCallback<void(NavigationHandle&)>, + bool allow_reuse) override; void CancelAllPrerendering() override; bool IsAllowedToStartPrerendering() override; void BackNavigationLikely(PreloadingPredictor predictor,
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index adf555c..d1147d661 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -740,6 +740,7 @@ "junit/src/org/chromium/content/browser/webcontents/WebContentsImplTest.java", "junit/src/org/chromium/content/browser/webcontents/WebContentsObserverProxyTest.java", "junit/src/org/chromium/content_public/browser/MessagePayloadTest.java", + "junit/src/org/chromium/content_public/browser/media/capture/ImageHandlerTest.java", ] deps = [
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ImageHandler.java b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ImageHandler.java index 5cdf3b7..c166fa6 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ImageHandler.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ImageHandler.java
@@ -14,6 +14,7 @@ import android.view.Surface; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import org.chromium.build.annotations.NullMarked; @@ -51,15 +52,27 @@ * @param handler The handler on which to run callbacks. */ ImageHandler(ScreenCapture.CaptureState captureState, Delegate delegate, Handler handler) { - mCaptureState = captureState; - mDelegate = delegate; - mHandler = handler; - mImageReader = + this( + captureState, + delegate, + handler, ImageReader.newInstance( captureState.width, captureState.height, captureState.format, - /* maxImages= */ 2); + /* maxImages= */ 2)); + } + + @VisibleForTesting + ImageHandler( + ScreenCapture.CaptureState captureState, + Delegate delegate, + Handler handler, + ImageReader imageReader) { + mCaptureState = captureState; + mDelegate = delegate; + mHandler = handler; + mImageReader = imageReader; mImageReader.setOnImageAvailableListener(this, mHandler); } @@ -178,4 +191,14 @@ throw new IllegalStateException("Unexpected image format: " + image.getFormat()); } } + + /** Returns the current number of images acquired but not yet released. */ + int getAcquiredImageCountForTesting() { + return mAcquiredImageCount; + } + + /** Returns true if close() has been called but images are still pending release. */ + boolean isClosingForTesting() { + return mClosing; + } }
diff --git a/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ImageHandlerTest.java b/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ImageHandlerTest.java new file mode 100644 index 0000000..80f1b58 --- /dev/null +++ b/content/public/android/junit/src/org/chromium/content_public/browser/media/capture/ImageHandlerTest.java
@@ -0,0 +1,107 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content_public.browser.media.capture; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.media.Image; +import android.media.Image.Plane; +import android.media.ImageReader; +import android.os.Handler; +import android.os.Looper; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.content_public.browser.media.capture.ScreenCapture.CaptureState; + +/** Unit tests for {@link ImageHandler}. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class ImageHandlerTest { + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private static final int TEST_WIDTH = 100; + private static final int TEST_HEIGHT = 200; + private static final int TEST_DPI = 300; + private static final Rect TEST_CROP_RECT = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT); + private static final long TEST_TIMESTAMP = 123456789L; + + @Mock private ImageHandler.Delegate mDelegate; + @Mock private ImageReader mImageReader; + + private ImageHandler mImageHandler; + + @Before + public void setUp() { + mImageHandler = + new ImageHandler( + new CaptureState(TEST_WIDTH, TEST_HEIGHT, TEST_DPI, PixelFormat.RGBA_8888), + mDelegate, + new Handler(Looper.getMainLooper()), + mImageReader); + + when(mImageReader.getMaxImages()).thenReturn(2); + } + + private Image createMockImage() { + final Image image = mock(Image.class); + final Plane plane = mock(Plane.class); + when(image.getPlanes()).thenReturn(new Plane[] {plane}); + when(image.getFormat()).thenReturn(PixelFormat.RGBA_8888); + when(image.getCropRect()).thenReturn(TEST_CROP_RECT); + when(image.getTimestamp()).thenReturn(TEST_TIMESTAMP); + return image; + } + + private void onImageAvailable(Image image) { + // Return `image` once, then nothing. + when(mImageReader.acquireLatestImage()).thenReturn(image, (Image) null); + mImageHandler.onImageAvailable(mImageReader); + } + + @Test + public void testImageAcquireAndRelease() throws Exception { + final Image image = createMockImage(); + final Plane plane = image.getPlanes()[0]; + + // Acquire an `Image`. + onImageAvailable(image); + + final ArgumentCaptor<Runnable> releaseCb = ArgumentCaptor.forClass(Runnable.class); + verify(mDelegate) + .onRgbaFrameAvailable( + eq(mImageHandler), + releaseCb.capture(), + eq(TEST_TIMESTAMP), + eq(plane), + eq(TEST_CROP_RECT)); + assertEquals(1, mImageHandler.getAcquiredImageCountForTesting()); + + // Run the release callback. + releaseCb.getValue().run(); + + // Image should be closed now. + verify(image).close(); + assertEquals(0, mImageHandler.getAcquiredImageCountForTesting()); + + verifyNoMoreInteractions(mDelegate); + } +}
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index c5daa64..4a0bc0e 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -1687,7 +1687,8 @@ const std::optional<UrlMatchType>&)> url_match_predicate, base::RepeatingCallback<void(NavigationHandle&)> - prerender_navigation_handle_callback) = 0; + prerender_navigation_handle_callback, + bool allow_reuse) = 0; // Cancels all prerendering hosted on this WebContents. virtual void CancelAllPrerendering() = 0;
diff --git a/content/public/test/prerender_test_util.cc b/content/public/test/prerender_test_util.cc index 0d1384c..75caba25 100644 --- a/content/public/test/prerender_test_util.cc +++ b/content/public/test/prerender_test_util.cc
@@ -708,7 +708,8 @@ PreloadPipelineInfo::Create( /*planned_max_preloading_type=*/PreloadingType::kPrerender), /*preloading_attempt=*/nullptr, /*url_match_predicate=*/{}, - /*prerender_navigation_handle_callback=*/{}); + /*prerender_navigation_handle_callback=*/{}, + /*allow_reuse=*/false); } std::unique_ptr<PrerenderHandle>
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc index 78fc9981..0ec3b11 100644 --- a/content/test/test_web_contents.cc +++ b/content/test/test_web_contents.cc
@@ -510,7 +510,8 @@ /*url_match_predicate=*/{}, /*prerender_navigation_handle_callback=*/{}, PreloadPipelineInfoImpl::Create( - /*planned_max_preloading_type=*/PreloadingType::kPrerender))); + /*planned_max_preloading_type=*/PreloadingType::kPrerender), + /*allow_reuse=*/false)); } TestRenderFrameHost* TestWebContents::AddPrerenderAndCommitNavigation(
diff --git a/infra/config/generated/builder-owners/chrome-build-team@google.com.txt b/infra/config/generated/builder-owners/chrome-build-team@google.com.txt index 0066db0..044e2cd 100644 --- a/infra/config/generated/builder-owners/chrome-build-team@google.com.txt +++ b/infra/config/generated/builder-owners/chrome-build-team@google.com.txt
@@ -12,6 +12,8 @@ build/linux-build-perf-siso build/linux-chromeos-build-perf-ninja build/linux-chromeos-build-perf-siso +build/linux-rbe-trusted-test +build/linux-rbe-untrusted-test build/mac-build-perf-developer build/mac-build-perf-ninja build/mac-build-perf-siso @@ -19,6 +21,8 @@ build/win-build-perf-developer build/win-build-perf-ninja build/win-build-perf-siso +build/win-rbe-trusted-test +build/win-rbe-untrusted-test ci/Deterministic Linux ci/Deterministic Linux (dbg) ci/linux-modules-compile-fyi-rel
diff --git a/infra/config/generated/builders/build/linux-rbe-trusted-test/gn-args.json b/infra/config/generated/builders/build/linux-rbe-trusted-test/gn-args.json new file mode 100644 index 0000000..95e40ac --- /dev/null +++ b/infra/config/generated/builders/build/linux-rbe-trusted-test/gn-args.json
@@ -0,0 +1,19 @@ +{ + "phases": { + "builtin": { + "gn_args": { + "dcheck_always_on": false, + "devtools_skip_typecheck": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "target_cpu": "x64", + "target_os": "linux", + "use_reclient": false, + "use_remoteexec": true, + "use_siso": true + } + } + } +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/linux-rbe-trusted-test/properties.json b/infra/config/generated/builders/build/linux-rbe-trusted-test/properties.json new file mode 100644 index 0000000..e223897 --- /dev/null +++ b/infra/config/generated/builders/build/linux-rbe-trusted-test/properties.json
@@ -0,0 +1,68 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "additional_exclusions": [ + "infra/config/generated/builders/build/linux-rbe-trusted-test/gn-args.json" + ], + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "build", + "builder": "linux-rbe-trusted-test", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.build.test", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "config": "chromium", + "target_platform": "linux" + }, + "legacy_gclient_config": { + "apply_configs": [ + "siso_latest" + ], + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "build", + "builder": "linux-rbe-trusted-test", + "project": "chromium" + } + ] + } + }, + "$build/siso": { + "configs": [ + "builder", + "remote-link" + ], + "enable_cloud_monitoring": true, + "enable_cloud_profiler": true, + "enable_cloud_trace": true, + "experiments": [ + "no-fallback" + ], + "metrics_project": "chromium-reclient-metrics", + "project": "rbe-chromium-trusted-test", + "remote_jobs": 250 + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.build.test", + "recipe": "chrome_build/build_perf_siso" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/linux-rbe-untrusted-test/gn-args.json b/infra/config/generated/builders/build/linux-rbe-untrusted-test/gn-args.json new file mode 100644 index 0000000..de244b67 --- /dev/null +++ b/infra/config/generated/builders/build/linux-rbe-untrusted-test/gn-args.json
@@ -0,0 +1,22 @@ +{ + "phases": { + "builtin": { + "gn_args": { + "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", + "dcheck_always_on": true, + "devtools_skip_typecheck": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "symbol_level": 0, + "target_cpu": "x64", + "target_os": "linux", + "use_clang_coverage": true, + "use_reclient": false, + "use_remoteexec": true, + "use_siso": true + } + } + } +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/linux-rbe-untrusted-test/properties.json b/infra/config/generated/builders/build/linux-rbe-untrusted-test/properties.json new file mode 100644 index 0000000..668f2ea --- /dev/null +++ b/infra/config/generated/builders/build/linux-rbe-untrusted-test/properties.json
@@ -0,0 +1,71 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "additional_exclusions": [ + "infra/config/generated/builders/build/linux-rbe-untrusted-test/gn-args.json" + ], + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "build", + "builder": "linux-rbe-untrusted-test", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.build.test", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "config": "chromium", + "target_platform": "linux" + }, + "legacy_gclient_config": { + "apply_configs": [ + "siso_latest" + ], + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "build", + "builder": "linux-rbe-untrusted-test", + "project": "chromium" + } + ] + } + }, + "$build/code_coverage": { + "use_clang_coverage": true + }, + "$build/siso": { + "configs": [ + "builder", + "remote-link" + ], + "enable_cloud_monitoring": true, + "enable_cloud_profiler": true, + "enable_cloud_trace": true, + "experiments": [ + "no-fallback" + ], + "metrics_project": "chromium-reclient-metrics", + "project": "rbe-chromium-untrusted-test", + "remote_jobs": -1 + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.build.test", + "recipe": "chrome_build/build_perf_siso" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/win-rbe-trusted-test/gn-args.json b/infra/config/generated/builders/build/win-rbe-trusted-test/gn-args.json new file mode 100644 index 0000000..6a1b1493 --- /dev/null +++ b/infra/config/generated/builders/build/win-rbe-trusted-test/gn-args.json
@@ -0,0 +1,19 @@ +{ + "phases": { + "builtin": { + "gn_args": { + "dcheck_always_on": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "symbol_level": 1, + "target_cpu": "x64", + "target_os": "win", + "use_reclient": false, + "use_remoteexec": true, + "use_siso": true + } + } + } +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/win-rbe-trusted-test/properties.json b/infra/config/generated/builders/build/win-rbe-trusted-test/properties.json new file mode 100644 index 0000000..80026a7 --- /dev/null +++ b/infra/config/generated/builders/build/win-rbe-trusted-test/properties.json
@@ -0,0 +1,68 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "additional_exclusions": [ + "infra/config/generated/builders/build/win-rbe-trusted-test/gn-args.json" + ], + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "build", + "builder": "win-rbe-trusted-test", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.build.test", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "config": "chromium", + "target_platform": "win" + }, + "legacy_gclient_config": { + "apply_configs": [ + "siso_latest" + ], + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "build", + "builder": "win-rbe-trusted-test", + "project": "chromium" + } + ] + } + }, + "$build/siso": { + "configs": [ + "builder", + "remote-link" + ], + "enable_cloud_monitoring": true, + "enable_cloud_profiler": true, + "enable_cloud_trace": true, + "experiments": [ + "no-fallback" + ], + "metrics_project": "chromium-reclient-metrics", + "project": "rbe-chromium-trusted-test", + "remote_jobs": 250 + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.build.test", + "recipe": "chrome_build/build_perf_siso" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/win-rbe-untrusted-test/gn-args.json b/infra/config/generated/builders/build/win-rbe-untrusted-test/gn-args.json new file mode 100644 index 0000000..7d282522 --- /dev/null +++ b/infra/config/generated/builders/build/win-rbe-untrusted-test/gn-args.json
@@ -0,0 +1,24 @@ +{ + "phases": { + "builtin": { + "gn_args": { + "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", + "dcheck_always_on": true, + "enable_dangling_raw_ptr_checks": true, + "enable_dangling_raw_ptr_feature_flag": true, + "enable_resource_allowlist_generation": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "symbol_level": 0, + "target_cpu": "x64", + "target_os": "win", + "use_clang_coverage": true, + "use_reclient": false, + "use_remoteexec": true, + "use_siso": true + } + } + } +} \ No newline at end of file
diff --git a/infra/config/generated/builders/build/win-rbe-untrusted-test/properties.json b/infra/config/generated/builders/build/win-rbe-untrusted-test/properties.json new file mode 100644 index 0000000..e190a76 --- /dev/null +++ b/infra/config/generated/builders/build/win-rbe-untrusted-test/properties.json
@@ -0,0 +1,71 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "additional_exclusions": [ + "infra/config/generated/builders/build/win-rbe-untrusted-test/gn-args.json" + ], + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "build", + "builder": "win-rbe-untrusted-test", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.build.test", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "config": "chromium", + "target_platform": "win" + }, + "legacy_gclient_config": { + "apply_configs": [ + "siso_latest" + ], + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "build", + "builder": "win-rbe-untrusted-test", + "project": "chromium" + } + ] + } + }, + "$build/code_coverage": { + "use_clang_coverage": true + }, + "$build/siso": { + "configs": [ + "builder", + "remote-link" + ], + "enable_cloud_monitoring": true, + "enable_cloud_profiler": true, + "enable_cloud_trace": true, + "experiments": [ + "no-fallback" + ], + "metrics_project": "chromium-reclient-metrics", + "project": "rbe-chromium-untrusted-test", + "remote_jobs": -1 + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.build.test", + "recipe": "chrome_build/build_perf_siso" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/gn_args_locations.json b/infra/config/generated/builders/gn_args_locations.json index afffd66..906571b 100644 --- a/infra/config/generated/builders/gn_args_locations.json +++ b/infra/config/generated/builders/gn_args_locations.json
@@ -127,6 +127,12 @@ "chromium.build.fyi": { "Mac Builder Siso FYI": "build/Mac Builder Siso FYI/gn-args.json" }, + "chromium.build.test": { + "linux-rbe-trusted-test": "build/linux-rbe-trusted-test/gn-args.json", + "linux-rbe-untrusted-test": "build/linux-rbe-untrusted-test/gn-args.json", + "win-rbe-trusted-test": "build/win-rbe-trusted-test/gn-args.json", + "win-rbe-untrusted-test": "build/win-rbe-untrusted-test/gn-args.json" + }, "chromium.cft": { "linux-rel-cft": "ci/linux-rel-cft/gn-args.json", "mac-rel-cft": "ci/mac-rel-cft/gn-args.json",
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 4876977..71f2438 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -1062,6 +1062,152 @@ } } builders { + name: "linux-rbe-trusted-test" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "os:Ubuntu-22.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/build/linux-rbe-trusted-test/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.build.test",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chrome_build/build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.use_per_builder_build_dir_name" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + description_html: "This builder builds Linux CI build with rbe-chroimum-trusted-test.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/ci/Linux Builder\">Linux Builder</a><br/>Builder owner: <a href=mailto:chrome-build-team@google.com>chrome-build-team@google.com</a>" + shadow_builder_adjustments { + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + } + contact_team_email: "chrome-build-team@google.com" + custom_metric_definitions { + name: "/chrome/infra/browser/builds/cached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"true\"" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" + predicates: "has(build.output.properties.ran_tests_retry_shard)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" + predicates: "has(build.output.properties.ran_tests_without_patch)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/uncached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"false\"" + } + } + builders { + name: "linux-rbe-untrusted-test" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "os:Ubuntu-22.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/build/linux-rbe-untrusted-test/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.build.test",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chrome_build/build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.use_per_builder_build_dir_name" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + description_html: "This builder builds Linux CQ build with rbe-chroimum-untrusted-test.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-rel-compilator\">linux-rel-compilator</a><br/>Builder owner: <a href=mailto:chrome-build-team@google.com>chrome-build-team@google.com</a>" + shadow_builder_adjustments { + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + } + contact_team_email: "chrome-build-team@google.com" + custom_metric_definitions { + name: "/chrome/infra/browser/builds/cached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"true\"" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" + predicates: "has(build.output.properties.ran_tests_retry_shard)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" + predicates: "has(build.output.properties.ran_tests_without_patch)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/uncached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"false\"" + } + } + builders { name: "mac-build-perf-developer" swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:mac-build-perf-developer" @@ -1547,6 +1693,152 @@ predicates: "string(build.output.properties.is_cached) == \"false\"" } } + builders { + name: "win-rbe-trusted-test" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "os:Windows-10" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/build/win-rbe-trusted-test/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.build.test",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chrome_build/build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.use_per_builder_build_dir_name" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + description_html: "This builder builds Windows CI build with rbe-chroimum-trusted-test.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/ci/Win x64 Builder\">Win x64 Builder</a><br/>Builder owner: <a href=mailto:chrome-build-team@google.com>chrome-build-team@google.com</a>" + shadow_builder_adjustments { + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + } + contact_team_email: "chrome-build-team@google.com" + custom_metric_definitions { + name: "/chrome/infra/browser/builds/cached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"true\"" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" + predicates: "has(build.output.properties.ran_tests_retry_shard)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" + predicates: "has(build.output.properties.ran_tests_without_patch)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/uncached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"false\"" + } + } + builders { + name: "win-rbe-untrusted-test" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "os:Windows-10" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/build/win-rbe-untrusted-test/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.build.test",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chrome_build/build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.use_per_builder_build_dir_name" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + description_html: "This builder builds Windows CQ build with rbe-chroimum-untrusted-test.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/win-rel-compilator\">win-rel-compilator</a><br/>Builder owner: <a href=mailto:chrome-build-team@google.com>chrome-build-team@google.com</a>" + shadow_builder_adjustments { + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + } + contact_team_email: "chrome-build-team@google.com" + custom_metric_definitions { + name: "/chrome/infra/browser/builds/cached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"true\"" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" + predicates: "has(build.output.properties.ran_tests_retry_shard)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" + predicates: "has(build.output.properties.ran_tests_without_patch)" + } + custom_metric_definitions { + name: "/chrome/infra/browser/builds/uncached_count" + predicates: "has(build.output.properties.is_cached)" + predicates: "string(build.output.properties.is_cached) == \"false\"" + } + } } shadow: "build.shadow" }
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 32ddd85b..ebbe4c0 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -11412,6 +11412,33 @@ } } consoles { + id: "chromium.build.test" + name: "chromium.build.test" + repo_url: "https://chromium.googlesource.com/chromium/src" + refs: "regexp:refs/heads/main" + manifest_name: "REVISION" + builders { + name: "buildbucket/luci.chromium.build/linux-rbe-trusted-test" + category: "trusted" + short_name: "lin" + } + builders { + name: "buildbucket/luci.chromium.build/win-rbe-trusted-test" + category: "trusted" + short_name: "win" + } + builders { + name: "buildbucket/luci.chromium.build/linux-rbe-untrusted-test" + category: "untrusted" + short_name: "lin" + } + builders { + name: "buildbucket/luci.chromium.build/win-rbe-untrusted-test" + category: "untrusted" + short_name: "win" + } +} +consoles { id: "chromium.cft" name: "chromium.cft" repo_url: "https://chromium.googlesource.com/chromium/src"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index 4a3fb168..ea8b52c23 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -4777,6 +4777,24 @@ } } job { + id: "linux-rbe-trusted-test" + realm: "build" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "build" + builder: "linux-rbe-trusted-test" + } +} +job { + id: "linux-rbe-untrusted-test" + realm: "build" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "build" + builder: "linux-rbe-untrusted-test" + } +} +job { id: "linux-rel-cft" realm: "ci" buildbucket { @@ -5733,6 +5751,24 @@ } } job { + id: "win-rbe-trusted-test" + realm: "build" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "build" + builder: "win-rbe-trusted-test" + } +} +job { + id: "win-rbe-untrusted-test" + realm: "build" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "build" + builder: "win-rbe-untrusted-test" + } +} +job { id: "win-rel-cft" realm: "ci" buildbucket { @@ -6114,6 +6150,8 @@ triggers: "linux-build-perf-siso" triggers: "linux-chromeos-build-perf-ninja" triggers: "linux-chromeos-build-perf-siso" + triggers: "linux-rbe-trusted-test" + triggers: "linux-rbe-untrusted-test" triggers: "mac-build-perf-developer" triggers: "mac-build-perf-ninja" triggers: "mac-build-perf-siso" @@ -6121,6 +6159,8 @@ triggers: "win-build-perf-developer" triggers: "win-build-perf-ninja" triggers: "win-build-perf-siso" + triggers: "win-rbe-trusted-test" + triggers: "win-rbe-untrusted-test" gitiles { repo: "https://chromium.googlesource.com/chromium/src" refs: "regexp:refs/heads/main"
diff --git a/infra/config/subprojects/build/build.test.star b/infra/config/subprojects/build/build.test.star new file mode 100644 index 0000000..33598ef --- /dev/null +++ b/infra/config/subprojects/build/build.test.star
@@ -0,0 +1,179 @@ +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Definitions of builders with test RBE instances.""" + +load("//lib/builder_config.star", "builder_config") +load("//lib/builders.star", "os", "siso") +load("//lib/ci.star", "ci") +load("//lib/consoles.star", "consoles") +load("//lib/html.star", "linkify_builder") +load("//project.star", "settings") + +luci.gitiles_poller( + name = "chrome-build-gitiles-trigger", + bucket = "build", + repo = "https://chromium.googlesource.com/chromium/src", + refs = [settings.ref], +) + +ci.defaults.set( + bucket = "build", + triggered_by = ["chrome-build-gitiles-trigger"], + builder_group = "chromium.build.test", + pool = ci.DEFAULT_POOL, + builderless = True, + build_numbers = True, + contact_team_email = "chrome-build-team@google.com", + execution_timeout = 10 * time.hour, + priority = ci.DEFAULT_FYI_PRIORITY, + resultdb_enable = False, + service_account = ci.DEFAULT_SERVICE_ACCOUNT, + shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT, + siso_configs = ["builder", "remote-link"], + siso_experiments = ["no-fallback"], +) + +consoles.console_view( + name = "chromium.build.test", + repo = "https://chromium.googlesource.com/chromium/src", +) + +def cq_build_perf_builder(**kwargs): + # Use CQ RBE instance and high remote_jobs to simulate CQ builds. + return ci.builder( + siso_remote_jobs = siso.remote_jobs.HIGH_JOBS_FOR_CQ, + siso_project = siso.project.TEST_UNTRUSTED, + use_clang_coverage = True, + **kwargs + ) + +def ci_build_perf_builder(**kwargs): + # Use CI RBE instance to simulate CI builds. + return ci.builder( + siso_remote_jobs = siso.remote_jobs.DEFAULT, + siso_project = siso.project.TEST_TRUSTED, + **kwargs + ) + +# Builders with rbe-chromium-untrusted-test. +cq_build_perf_builder( + name = "linux-rbe-untrusted-test", + description_html = "This builder builds Linux CQ build with rbe-chroimum-untrusted-test.<br/>" + + "The build configs and the bot specs should be in sync with " + linkify_builder("try", "linux-rel-compilator", "chromium"), + executable = "recipe:chrome_build/build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "siso_latest", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + target_platform = builder_config.target_platform.LINUX, + ), + ), + gn_args = { + "builtin": "try/linux-rel", + }, + os = os.LINUX_DEFAULT, + console_view_entry = consoles.console_view_entry( + category = "untrusted", + short_name = "lin", + ), +) + +cq_build_perf_builder( + name = "win-rbe-untrusted-test", + description_html = "This builder builds Windows CQ build with rbe-chroimum-untrusted-test.<br/>" + + "The build configs and the bot specs should be in sync with " + linkify_builder("try", "win-rel-compilator", "chromium"), + executable = "recipe:chrome_build/build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "siso_latest", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + target_platform = builder_config.target_platform.WIN, + ), + ), + gn_args = { + "builtin": "try/win-rel", + }, + os = os.WINDOWS_DEFAULT, + console_view_entry = consoles.console_view_entry( + category = "untrusted", + short_name = "win", + ), +) + +# Builders with rbe-chromium-trusted-test. +ci_build_perf_builder( + name = "linux-rbe-trusted-test", + description_html = "This builder builds Linux CI build with rbe-chroimum-trusted-test.<br/>" + + "The build configs and the bot specs should be in sync with " + linkify_builder("ci", "Linux Builder", "chromium"), + executable = "recipe:chrome_build/build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "siso_latest", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + target_platform = builder_config.target_platform.LINUX, + ), + ), + gn_args = { + "builtin": "ci/Linux Builder", + }, + os = os.LINUX_DEFAULT, + console_view_entry = consoles.console_view_entry( + category = "trusted", + short_name = "lin", + ), +) + +ci_build_perf_builder( + name = "win-rbe-trusted-test", + description_html = "This builder builds Windows CI build with rbe-chroimum-trusted-test.<br/>" + + "The build configs and the bot specs should be in sync with " + linkify_builder("ci", "Win x64 Builder", "chromium"), + executable = "recipe:chrome_build/build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "siso_latest", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + target_platform = builder_config.target_platform.WIN, + ), + ), + gn_args = { + "builtin": "ci/Win x64 Builder", + }, + os = os.WINDOWS_DEFAULT, + console_view_entry = consoles.console_view_entry( + category = "trusted", + short_name = "win", + ), +)
diff --git a/infra/config/subprojects/build/subproject.star b/infra/config/subprojects/build/subproject.star index d7a548f..fb3ffa9 100644 --- a/infra/config/subprojects/build/subproject.star +++ b/infra/config/subprojects/build/subproject.star
@@ -14,3 +14,4 @@ exec("./build.fyi.star") exec("./build.star") +exec("./build.test.star")
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index 5d8d0612..f920a08 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -04ae9a93503e1c10bade48c9766b0cfa41e0de72 \ No newline at end of file +855267be987acdfe6f973d9c9ea4ccc7a124fe26 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index 886700e6..12ad1ade 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -a21e68b032e304fa21ba1cdc730473a37cdd45f6 \ No newline at end of file +4440ed82fd7dc0dee553d5023055b97bfedbfa8e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index 4cbcfe59..913507d5 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -caa37b5cfb15a545f7eab1d167f33e26cf1b75d6 \ No newline at end of file +863153f893f07394d90833ad5d7b5f62ee3d6383 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 80a7932..e5b4adb 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -68f1b42af48b31b44b2e4e7dde237a36ba54646a \ No newline at end of file +2a2f53fd8928703d9020fae668aa1c8ed24b3f04 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 8849e647e..c7094d53 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -ced12991698cfadf98df107ec096de797912a1a3 \ No newline at end of file +798417fd25389e432da7ddbf9e9dc5902e2484a0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index 873a096..905e600e 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -76a96e7b0a23c0669f1b943d4fc703cf015cf3ef \ No newline at end of file +7cc64cc7dbbf6b9d623bc83f8270bba3c89b29e2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index 15ccaf4..e0b3922 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -2a5d9089c49951b517841516a639e4ae7875906b \ No newline at end of file +752338ee44a68c79658c391b013a75977a29dbb3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index ead16289..2fc2625 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -93ef5ef40ae93f25eb5bf06df915cb0c6e8e3ae1 \ No newline at end of file +76427e1a5e5c1b467bff96a701b5ead5b65f539a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index 9aa17a9f..8178ab7 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -f0b53cdfe5cf87875241cab331173e1fc9072c97 \ No newline at end of file +febd50b587ca6a86512f9fd0f450240a71f918d6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 60d322ca..063f3417 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -75ac393d943f2138edebdcd86d56b547f31d3a06 \ No newline at end of file +4e49d2a9fcea9e612ebcbf2fce4046ad7cdfc77c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 72895d5..9aefa24 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -894816f0e4c9cb1bce917f47890586be19329072 \ No newline at end of file +4b7ef546f4a710cdd40d344fde7ea01f41a178b5 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index cefe756..282ce97 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -312185c4f7efea9f119ebbcaf561dc89503bfc14 \ No newline at end of file +20a960156299cdb8bb85218488a7af84010b8f78 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 8df4e8d..21f0ce64 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -e5a0b7f52df9f91fcab4fc2b8a85e07451610713 \ No newline at end of file +83a1bfc5940bbaafb3e63aa744def8ca3869ec7c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index f37597b8..367b143 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -2d65accd84e04e06277202641453989feb848088 \ No newline at end of file +d53b0c7a6acd7e58d5a4f3a86a18a48a6a75dbba \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index ba149f5..51cd680 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -a02cf4958849307d47e4f9ee67cb9637b511cf91 \ No newline at end of file +6d032fdd8548ea7b11cca72d0e40997d8be8cf4c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index 4d2c667..d31e4560 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -9bd3e7f0a5daa44486379e300d34132c44a07fcf \ No newline at end of file +b2f0f89808a3aae3432a17d509beea9792491610 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 7e8b708..28b46c5 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -478955e7b7669d685ecc9b4dcc3a9fe1ebf56c94 \ No newline at end of file +3955286bd17f8303b8a71cce4cecc0918560daf9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 5746729..35e5d41 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -694bf6a9fbcdb0183f06007df8cdccd267834ee9 \ No newline at end of file +e2f06aa71ebd935935ee2143178dc69bb17c56f5 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index f642f5fb..9348372 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -17967e4df3156d6588436a349dc4cf4ff8aaf09d \ No newline at end of file +c191ac24056d8241d6932f238528e54363162d86 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 3cab0f7..0f959df 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -cd2c515620e78abcc4b35d44f441ac3d4bc67eba \ No newline at end of file +abe5080ac9a799e899cce42aa9fb8a07428dcccc \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index a057107..9cfed494 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4e63e4b315709c6c830ba9cf6acbc72301965152 \ No newline at end of file +4dbfb708f455f41eea83addf67153941a7b580c9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 index 6d47aa9..7aa54b9d 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -680d9ef360c9c16a750c3e72a1de92007e2d9035 \ No newline at end of file +aa7095001d1457c1ecf2c38f7e6ac60073377ab8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 2585f79a..250e085d 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -87a97e03c91b11144295a6b1d888e19e6b1c2476 \ No newline at end of file +267556bf7429a2257131190a9296a2e13ce5d0ee \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 index ee232d2..cc4bdf94 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -1ce8288c700269bd6dfa58619abde73ed22094b9 \ No newline at end of file +915d2d1b13d1e09d319665c6f19ad7456821fd6d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index e1592e39..114cc0b 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -15c016a3366c4d161f3d337933b4b739e7a08514 \ No newline at end of file +3020bdcfb33ef9c8c8812ac9a1e3c4bcd77ce45c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 68061e91..42c0fbaf 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -7ca35463967f7965de30fc75c15933e29f6006e4 \ No newline at end of file +40e6fbf3b6bc01029225a9ee6e765e5dc15d3746 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index c16f0a6..4c052e1 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -5e230e64bb1e5a461633e21dfafdc17d379e70d9 \ No newline at end of file +81a41d8cbc85a48208adb1d70623af490bb315d2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 527de78..10f55e2e 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -2108901c0d1073f11ba1bab2eca1075de9f5742b \ No newline at end of file +2b32acbf8202f830832d0e36a2321a5d4826e05c \ No newline at end of file
diff --git a/ios_internal b/ios_internal index 97f5aa2..91544a5 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 97f5aa28bc4471c48f2f4488c5671bee87b9922a +Subproject commit 91544a50032a3960c09f26b99b4aab8efbaee788
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc index f96af4d9..b033f9c 100644 --- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc +++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -25,12 +25,12 @@ #include "base/task/bind_post_task.h" #include "base/task/single_thread_task_runner.h" #include "base/task/thread_pool.h" -#include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h" #include "media/gpu/chromeos/fourcc.h" #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/macros.h" #include "media/gpu/v4l2/v4l2_device.h" #include "third_party/libyuv/include/libyuv.h" +#include "ui/gfx/native_pixmap.h" #include "ui/ozone/public/ozone_platform.h" #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name) \ @@ -577,26 +577,26 @@ // In this case, we use the R_8 buffer with height == 1 to represent a data // container. As a result, we use plane.stride as size of the data here since // plane.size might be larger due to height alignment. - const gfx::Size output_gmb_buffer_size( + const gfx::Size native_pixmap_size( base::checked_cast<int32_t>(output_frame->layout().planes()[0].stride), 1); - auto output_gmb_buffer = - gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle( - client_native_pixmap_factory_.get(), std::move(output_gmb_handle), - output_gmb_buffer_size, gfx::BufferFormat::R_8, - gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, base::DoNothing()); - if (!output_gmb_buffer) { - VLOGF(1) << "Failed to import gmb buffer"; + std::unique_ptr<gfx::ClientNativePixmap> native_pixmap = + client_native_pixmap_factory_->ImportFromHandle( + std::move(output_gmb_handle).native_pixmap_handle(), + native_pixmap_size, gfx::BufferFormat::R_8, + gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE); + if (!native_pixmap) { + VLOGF(1) << "Failed to import native pixmap"; return 0; } - bool isMapped = output_gmb_buffer->Map(); + bool isMapped = native_pixmap->Map(); if (!isMapped) { - VLOGF(1) << "Failed to map gmb buffer"; + VLOGF(1) << "Failed to map native pixmap"; return 0; } - uint8_t* dst_ptr = static_cast<uint8_t*>(output_gmb_buffer->memory(0)); + uint8_t* dst_ptr = static_cast<uint8_t*>(native_pixmap->GetMemoryAddress(0)); // Fill SOI and EXIF markers. static const uint8_t kJpegStart[] = {0xFF, JPEG_SOI}; @@ -654,7 +654,7 @@ NOTREACHED() << "Unsupported output pixel format"; } - output_gmb_buffer->Unmap(); + native_pixmap->Unmap(); return idx; }
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc index 50908b2b..cf52037 100644 --- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -23,7 +23,6 @@ #include "base/task/thread_pool.h" #include "base/thread_annotations.h" #include "base/trace_event/trace_event.h" -#include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h" #include "media/base/video_frame.h" #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/macros.h" @@ -31,6 +30,7 @@ #include "media/gpu/vaapi/vaapi_utils.h" #include "media/parsers/jpeg_parser.h" #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" +#include "ui/gfx/native_pixmap.h" #include "ui/ozone/public/client_native_pixmap_factory_ozone.h" #include "ui/ozone/public/ozone_platform.h" @@ -289,7 +289,7 @@ return; } - // Create gmb buffer from output VideoFrame. Since the JPEG VideoFrame's coded + // Create GMB handle from output VideoFrame. Since the JPEG VideoFrame's coded // size is the 2D image size, we should use (buffer_size, 1) as the R8 gmb's // size, where buffer_size can be obtained from the first plane's size. auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get()); @@ -298,35 +298,36 @@ // In this case, we use the R_8 buffer with height == 1 to represent a data // container. As a result, we use plane.stride as size of the data here since // plane.size might be larger due to height alignment. - const gfx::Size output_gmb_buffer_size( + const gfx::Size native_pixmap_size( base::checked_cast<int32_t>(output_frame->layout().planes()[0].stride), 1); - auto output_gmb_buffer = - gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle( - client_native_pixmap_factory_.get(), std::move(output_gmb_handle), - output_gmb_buffer_size, gfx::BufferFormat::R_8, - gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, base::DoNothing()); - if (output_gmb_buffer == nullptr) { - VLOGF(1) << "Failed to create GpuMemoryBufferImpl from handle"; + std::unique_ptr<gfx::ClientNativePixmap> native_pixmap = + client_native_pixmap_factory_->ImportFromHandle( + std::move(output_gmb_handle).native_pixmap_handle(), + native_pixmap_size, gfx::BufferFormat::R_8, + gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE); + if (native_pixmap == nullptr) { + VLOGF(1) << "Failed to create NativePixmap from handle"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE); return; } - const bool is_mapped = output_gmb_buffer->Map(); + const bool is_mapped = native_pixmap->Map(); if (!is_mapped) { - VLOGF(1) << "Map the output gmb buffer failed"; + VLOGF(1) << "Map the native pixmap failed"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE); return; } - absl::Cleanup output_gmb_buffer_unmapper = [&output_gmb_buffer] { - output_gmb_buffer->Unmap(); + absl::Cleanup native_pixmap_unmapper = [&native_pixmap] { + native_pixmap->Unmap(); }; // Get the encoded output. DownloadFromVABuffer() is a blocking call. It // would wait until encoding is finished. - uint8_t* output_memory = static_cast<uint8_t*>(output_gmb_buffer->memory(0)); + uint8_t* output_memory = + static_cast<uint8_t*>(native_pixmap->GetMemoryAddress(0)); size_t encoded_size = 0; - // Since the format of |output_gmb_buffer| is gfx::BufferFormat::R_8, we can + // Since the format of |native_pixmap| is gfx::BufferFormat::R_8, we can // use its area as the maximum bytes we need to download to avoid buffer // overflow. // Since we didn't supply EXIF data to the JPEG encoder, it creates a default @@ -349,7 +350,7 @@ const size_t output_offset = exif_buffer_size > 0 ? exif_buffer_size - kApp0DataSize : 0; const size_t output_size = - base::checked_cast<size_t>(output_gmb_buffer->GetSize().GetArea()); + base::checked_cast<size_t>(native_pixmap_size.GetArea()); if (output_offset >= output_size) { VLOGF(1) << "Output buffer size (" << output_size << ") is too small"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
diff --git a/net/BUILD.gn b/net/BUILD.gn index 3bcb0859..b207e436 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -895,6 +895,10 @@ "quic/quic_session_alias_key.h", "quic/quic_session_attempt.cc", "quic/quic_session_attempt.h", + "quic/quic_session_attempt_manager.cc", + "quic/quic_session_attempt_manager.h", + "quic/quic_session_attempt_request.cc", + "quic/quic_session_attempt_request.h", "quic/quic_session_key.cc", "quic/quic_session_key.h", "quic/quic_session_pool.cc", @@ -2939,6 +2943,7 @@ "quic/quic_proxy_client_socket_test_base.h", "quic/quic_proxy_client_socket_unittest.cc", "quic/quic_proxy_datagram_client_socket_unittest.cc", + "quic/quic_session_attempt_manager_unittest.cc", "quic/quic_session_key_unittest.cc", "quic/quic_session_pool_peer.cc", "quic/quic_session_pool_peer.h",
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc index fcad1f5e..26a1950 100644 --- a/net/http/http_stream_pool_attempt_manager.cc +++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -1691,7 +1691,7 @@ // slow. Currently we just cancel them for simplicity. If we want to keep // these attempts in the draining `this`, Group::ConnectingStreamSocketCount() // should check draining AttemptManagers. - CancelTcpBasedAttempts(StreamSocketCloseReason::kAbort); + CancelTcpBasedAttempts(StreamSocketCloseReason::kAttemptManagerDraining); if (quic_attempt_ && quic_attempt_->is_slow()) { CancelQuicAttempt(ERR_ABORTED);
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc index c73e06ff..3cc89ba 100644 --- a/net/http/http_stream_pool_attempt_manager_unittest.cc +++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -5165,7 +5165,9 @@ ASSERT_EQ(quic_session1, quic_session2); } -// Regression test for crbug.com/421877252. +// Regression test for crbug.com/421877252. Ensure that a late-arriving QUIC +// is used by subsequent requests after the first request completes with a +// TLS session. TEST_F(HttpStreamPoolAttemptManagerTest, QuicExistingSessionAfterAttemptComplete) { base::test::ScopedFeatureList feature_list; @@ -5192,11 +5194,6 @@ EXPECT_THAT(requester1.result(), Optional(IsOk())); EXPECT_NE(requester1.negotiated_protocol(), NextProto::kProtoQUIC); - MockConnectCompleter quic_completer2; - AddQuicData(/*host=*/kDefaultDestination, &quic_completer2, - quic::QUIC_CONNECTION_IP_POOLED, - "An active session exists for the given IP."); - SequencedSocketData tcp_data2; tcp_data2.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&tcp_data2); @@ -5207,7 +5204,6 @@ .RequestStream(pool()); quic_completer1.Complete(OK); - quic_completer2.Complete(OK); requester2.WaitForResult(); EXPECT_THAT(requester2.result(), Optional(IsOk()));
diff --git a/net/http/http_stream_pool_quic_attempt.cc b/net/http/http_stream_pool_quic_attempt.cc index cb6e1063..a464dc8 100644 --- a/net/http/http_stream_pool_quic_attempt.cc +++ b/net/http/http_stream_pool_quic_attempt.cc
@@ -25,6 +25,8 @@ #include "net/log/net_log_source_type.h" #include "net/log/net_log_with_source.h" #include "net/quic/quic_session_alias_key.h" +#include "net/quic/quic_session_attempt_manager.h" +#include "net/quic/quic_session_attempt_request.h" #include "net/quic/quic_session_key.h" #include "net/quic/quic_session_pool.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h" @@ -62,30 +64,8 @@ NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_QUIC_ATTEMPT_BOUND, net_log_.source()); - SSLConfig ssl_config; - ssl_config.disable_cert_verification_network_fetches = - stream_key().disable_cert_network_fetches(); - int cert_verify_flags = ssl_config.GetCertVerifyFlags(); - - base::TimeTicks dns_resolution_start_time = - manager_->dns_resolution_start_time(); - // The DNS resolution end time could be null when the resolution is still - // ongoing. In that case, use the current time to make sure the connect - // start time is already greater than the DNS resolution end time. - base::TimeTicks dns_resolution_end_time = - manager_->dns_resolution_end_time().is_null() - ? base::TimeTicks::Now() - : manager_->dns_resolution_end_time(); - - std::set<std::string> dns_aliases = - manager_->service_endpoint_request()->GetDnsAliasResults(); - - session_attempt_ = GetQuicSessionPool()->CreateSessionAttempt( - this, GetKey().session_key(), quic_endpoint_, cert_verify_flags, - dns_resolution_start_time, dns_resolution_end_time, - /*use_dns_aliases=*/true, std::move(dns_aliases), - manager_->CalculateMultiplexedSessionCreationInitiator(), - /*connection_management_config=*/std::nullopt); + request_ = + GetQuicSessionPool()->session_attempt_manager()->CreateRequest(GetKey()); } HttpStreamPool::QuicAttempt::~QuicAttempt() { @@ -103,8 +83,31 @@ manager_->MaybeRunTcpBasedAttemptDelayTimer(); } - int rv = session_attempt_->Start(base::BindOnce( - &QuicAttempt::OnSessionAttemptComplete, weak_ptr_factory_.GetWeakPtr())); + SSLConfig ssl_config; + ssl_config.disable_cert_verification_network_fetches = + stream_key().disable_cert_network_fetches(); + int cert_verify_flags = ssl_config.GetCertVerifyFlags(); + + base::TimeTicks dns_resolution_start_time = + manager_->dns_resolution_start_time(); + // The DNS resolution end time could be null when the resolution is still + // ongoing. In that case, use the current time to make sure the connect + // start time is already greater than the DNS resolution end time. + base::TimeTicks dns_resolution_end_time = + manager_->dns_resolution_end_time().is_null() + ? base::TimeTicks::Now() + : manager_->dns_resolution_end_time(); + + std::set<std::string> dns_aliases = + manager_->service_endpoint_request()->GetDnsAliasResults(); + int rv = request_->RequestSession( + quic_endpoint_, cert_verify_flags, dns_resolution_start_time, + dns_resolution_end_time, /*use_dns_aliases=*/true, std::move(dns_aliases), + manager_->CalculateMultiplexedSessionCreationInitiator(), + /*connection_management_config=*/std::nullopt, net_log_, + base::BindOnce(&QuicAttempt::OnSessionAttemptComplete, + weak_ptr_factory_.GetWeakPtr())); + if (rv == ERR_IO_PENDING) { slow_timer_.Start(FROM_HERE, HttpStreamPool::GetConnectionAttemptDelay(), base::BindOnce(&QuicAttempt::OnSessionAttemptSlow, @@ -165,11 +168,11 @@ result_ = rv; QuicAttemptOutcome outcome(rv); - if (session_attempt_) { - outcome.session = session_attempt_->session(); - session_attempt_->PopulateNetErrorDetails(&outcome.error_details); + if (request_) { + outcome.session = request_->session(); + outcome.error_details = request_->error_details(); } - session_attempt_.reset(); + request_.reset(); manager_->OnQuicAttemptComplete(std::move(outcome)); // `this` is deleted. }
diff --git a/net/http/http_stream_pool_quic_attempt.h b/net/http/http_stream_pool_quic_attempt.h index 585d50af2..6fd8968 100644 --- a/net/http/http_stream_pool_quic_attempt.h +++ b/net/http/http_stream_pool_quic_attempt.h
@@ -18,6 +18,7 @@ #include "net/http/http_stream_pool.h" #include "net/http/http_stream_pool_attempt_manager.h" #include "net/quic/quic_session_attempt.h" +#include "net/quic/quic_session_attempt_request.h" #include "net/quic/quic_session_pool.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h" @@ -67,7 +68,7 @@ const perfetto::Track track_; const perfetto::Flow flow_; - std::unique_ptr<QuicSessionAttempt> session_attempt_; + std::unique_ptr<QuicSessionAttemptRequest> request_; base::OneShotTimer slow_timer_; bool is_slow_ = false; std::optional<int> result_;
diff --git a/net/http/http_stream_pool_tcp_based_attempt.cc b/net/http/http_stream_pool_tcp_based_attempt.cc index 5b4091b..02f84fd 100644 --- a/net/http/http_stream_pool_tcp_based_attempt.cc +++ b/net/http/http_stream_pool_tcp_based_attempt.cc
@@ -60,6 +60,8 @@ return "ExistingSpdySession"; case StreamSocketCloseReason::kUsingExistingQuicSession: return "ExistingQuicSession"; + case StreamSocketCloseReason::kAttemptManagerDraining: + return "AttemptManagerDraining"; case StreamSocketCloseReason::kUnspecified: case StreamSocketCloseReason::kCloseAllConnections: case StreamSocketCloseReason::kIpAddressChanged:
diff --git a/net/quic/quic_session_attempt.h b/net/quic/quic_session_attempt.h index b702cdd..1781433 100644 --- a/net/quic/quic_session_attempt.h +++ b/net/quic/quic_session_attempt.h
@@ -102,6 +102,12 @@ bool session_creation_finished() const { return session_creation_finished_; } + const quic::ParsedQuicVersion& quic_version() const { return quic_version_; } + + const IPEndPoint& ip_endpoint() const { return ip_endpoint_; } + + const ConnectionEndpointMetadata& metadata() const { return metadata_; } + QuicChromiumClientSession* session() const { return session_.get(); } void PopulateNetErrorDetails(NetErrorDetails* details) const;
diff --git a/net/quic/quic_session_attempt_manager.cc b/net/quic/quic_session_attempt_manager.cc new file mode 100644 index 0000000..13fdf44 --- /dev/null +++ b/net/quic/quic_session_attempt_manager.cc
@@ -0,0 +1,244 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_session_attempt_manager.h" + +#include <memory> +#include <optional> +#include <set> +#include <string> + +#include "base/check.h" +#include "base/containers/flat_map.h" +#include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" +#include "base/time/time.h" +#include "net/base/net_errors.h" +#include "net/base/net_export.h" +#include "net/base/reconnect_notifier.h" +#include "net/log/net_log_with_source.h" +#include "net/quic/quic_endpoint.h" +#include "net/quic/quic_session_alias_key.h" +#include "net/quic/quic_session_attempt.h" +#include "net/quic/quic_session_attempt_request.h" +#include "net/quic/quic_session_pool.h" + +namespace net { + +// A Job is responsible for creating a QUIC session for a specific +// QuicSessionAliasKey. It manages multiple concurrent connection attempts +// (`QuicSessionAttempt`) to different endpoints and notifies multiple clients +// (`QuicSessionAttemptRequest`) upon completion. +// +// If any attempt succeeds, the Job immediately notifies all waiting requests +// and cancels any other ongoing attempts. If an attempt fails, the Job will +// wait for other attempts to complete. Only when the last attempt fails does +// the Job notify all waiting requests of the failure. +// +// The Job is owned by the QuicSessionAttemptManager and is destroyed once the +// session is created or all attempts have failed. +class QuicSessionAttemptManager::Job : public QuicSessionAttempt::Delegate { + public: + Job(QuicSessionAttemptManager* manager, + QuicSessionAliasKey key, + const NetLogWithSource& net_log) + : manager_(manager), key_(std::move(key)), net_log_(net_log) {} + + ~Job() override { + // Notify all pending requests that the job is aborted. + if (!requests_.empty()) { + NotifyRequests(ERR_ABORTED, /*session=*/nullptr, NetErrorDetails()); + } + } + + Job(const Job&) = delete; + Job& operator=(const Job&) = delete; + + // Attempts to create a QUIC session for the given endpoint. If an attempt + // already exists for the endpoint, returns ERR_IO_PENDING and the request + // will be notified when the attempt completes. Otherwise, a new attempt is + // created and started, and the request will be notified when the attempt + // completes. + // + // The request will be added to the job and notified upon completion. + int MaybeAttemptEndpoint( + QuicSessionAttemptRequest* request, + QuicEndpoint endpoint, + int cert_verify_flags, + base::TimeTicks dns_resolution_start_time, + base::TimeTicks dns_resolution_end_time, + bool use_dns_aliases, + std::set<std::string> dns_aliases, + MultiplexedSessionCreationInitiator session_creation_initiator, + std::optional<ConnectionManagementConfig> connection_management_config) { + AddRequest(request); + + if (FindAttempt(endpoint)) { + return ERR_IO_PENDING; + } + + std::unique_ptr<QuicSessionAttempt> attempt = + manager_->pool_->CreateSessionAttempt( + this, key_.session_key(), endpoint, cert_verify_flags, + dns_resolution_start_time, dns_resolution_end_time, use_dns_aliases, + std::move(dns_aliases), session_creation_initiator, + std::move(connection_management_config)); + QuicSessionAttempt* raw_attempt = attempt.get(); + auto [_, inserted] = attempts_.emplace(std::move(attempt)); + CHECK(inserted); + int rv = raw_attempt->Start(base::BindOnce( + &Job::OnAttemptComplete, base::Unretained(this), raw_attempt)); + if (rv != ERR_IO_PENDING) { + OnAttemptComplete(raw_attempt, rv); + } + return rv; + } + + // Called by QuicSessionAttemptRequest to remove itself from the job. + void RemoveRequest(QuicSessionAttemptRequest* request) { + auto it = requests_.find(request); + CHECK(it != requests_.end()); + requests_.erase(it); + + if (requests_.empty()) { + manager_->OnJobComplete(this); + // `this` is deleted. + } + } + + // QuicSessionAttempt::Delegate implementation. + QuicSessionPool* GetQuicSessionPool() override { return manager_->pool_; } + const QuicSessionAliasKey& GetKey() override { return key_; } + const NetLogWithSource& GetNetLog() override { return net_log_; } + + private: + void OnAttemptComplete(QuicSessionAttempt* raw_attempt, int rv) { + auto it = attempts_.find(raw_attempt); + CHECK(it != attempts_.end()); + + NetErrorDetails error_details; + if (rv == OK) { + QuicChromiumClientSession* session = raw_attempt->session(); + attempts_.erase(it); + NotifyRequestsAndComplete(rv, session, std::move(error_details)); + return; + } + + raw_attempt->PopulateNetErrorDetails(&error_details); + attempts_.erase(it); + if (!attempts_.empty()) { + // Wait for other attempts to complete. + return; + } + + NotifyRequestsAndComplete(rv, /*session=*/nullptr, + std::move(error_details)); + } + + void AddRequest(QuicSessionAttemptRequest* request) { + auto [_, inserted] = requests_.insert(request); + CHECK(inserted); + } + + QuicSessionAttempt* FindAttempt(const QuicEndpoint& endpoint) { + auto it = std::ranges::find_if(attempts_, [&](const auto& attempt) { + return attempt->quic_version() == endpoint.quic_version && + attempt->ip_endpoint() == endpoint.ip_endpoint && + attempt->metadata() == endpoint.metadata; + }); + return it == attempts_.end() ? nullptr : it->get(); + } + + // Notifies all requests that the job is complete. + void NotifyRequests(int rv, + QuicChromiumClientSession* session, + NetErrorDetails error_details) { + // Cancel other attempts. + attempts_.clear(); + + while (!requests_.empty()) { + raw_ptr<QuicSessionAttemptRequest> request = + requests_.extract(requests_.begin()).value(); + // Use ExtractAsDangling() because `request` may delete itself. + request.ExtractAsDangling()->Complete(rv, session, error_details); + } + CHECK(requests_.empty()); + } + + void NotifyRequestsAndComplete(int rv, + QuicChromiumClientSession* session, + NetErrorDetails error_details) { + NotifyRequests(rv, session, std::move(error_details)); + manager_->OnJobComplete(this); + // `this` is deleted. + } + + raw_ptr<QuicSessionAttemptManager> manager_; + QuicSessionAliasKey key_; + + NetLogWithSource net_log_; + + std::set<raw_ptr<QuicSessionAttemptRequest>> requests_; + + base::flat_set<std::unique_ptr<QuicSessionAttempt>, base::UniquePtrComparator> + attempts_; +}; + +QuicSessionAttemptManager::QuicSessionAttemptManager(QuicSessionPool* pool) + : pool_(pool) {} + +QuicSessionAttemptManager::~QuicSessionAttemptManager() { + // Clear the active jobs, first moving out of the instance variable so that + // calls to RemoveRequest for any pending requests do not cause recursion. + base::flat_map<QuicSessionAliasKey, std::unique_ptr<Job>> active_jobs = + std::move(active_jobs_); + active_jobs.clear(); +} + +std::unique_ptr<QuicSessionAttemptRequest> +QuicSessionAttemptManager::CreateRequest(QuicSessionAliasKey key) { + return base::WrapUnique(new QuicSessionAttemptRequest(this, std::move(key))); +} + +int QuicSessionAttemptManager::RequestSession( + QuicSessionAttemptRequest* request, + QuicEndpoint endpoint, + int cert_verify_flags, + base::TimeTicks dns_resolution_start_time, + base::TimeTicks dns_resolution_end_time, + bool use_dns_aliases, + std::set<std::string> dns_aliases, + MultiplexedSessionCreationInitiator session_creation_initiator, + std::optional<ConnectionManagementConfig> connection_management_config, + const NetLogWithSource& net_log) { + auto it = active_jobs_.find(request->key_); + if (it == active_jobs_.end()) { + it = active_jobs_ + .try_emplace(request->key_, + std::make_unique<Job>(this, request->key_, net_log)) + .first; + } + + return it->second->MaybeAttemptEndpoint( + request, endpoint, cert_verify_flags, dns_resolution_start_time, + dns_resolution_end_time, use_dns_aliases, std::move(dns_aliases), + session_creation_initiator, std::move(connection_management_config)); +} + +void QuicSessionAttemptManager::RemoveRequest( + QuicSessionAttemptRequest* request) { + auto it = active_jobs_.find(request->key_); + if (it == active_jobs_.end()) { + return; + } + it->second->RemoveRequest(request); +} + +void QuicSessionAttemptManager::OnJobComplete(Job* job) { + auto it = active_jobs_.find(job->GetKey()); + CHECK(it != active_jobs_.end()); + active_jobs_.erase(it); +} + +} // namespace net
diff --git a/net/quic/quic_session_attempt_manager.h b/net/quic/quic_session_attempt_manager.h new file mode 100644 index 0000000..79c6579bb --- /dev/null +++ b/net/quic/quic_session_attempt_manager.h
@@ -0,0 +1,92 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_SESSION_ATTEMPT_MANAGER_H_ +#define NET_QUIC_QUIC_SESSION_ATTEMPT_MANAGER_H_ + +#include <memory> +#include <optional> +#include <set> +#include <string> + +#include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" +#include "base/time/time.h" +#include "net/base/net_export.h" +#include "net/base/reconnect_notifier.h" +#include "net/quic/quic_endpoint.h" +#include "net/quic/quic_session_alias_key.h" +#include "net/quic/quic_session_pool.h" + +namespace net { + +class QuicSessionAttemptRequest; +class NetLogWithSource; + +// Manages all in-flight QUIC session attempts. For each QuicSessionAliasKey +// that a client has requested, there can be at most one active +// QuicSessionAttemptManager::Job. A Job manages all attempts for the +// QuicSessionAliasKey (e.g. to different IP addresses) and all clients waiting +// for the result. +// +// The relationship between the manager, jobs, requests, and attempts is as +// follows: +// +// +-------------- QuicSessionAttemptManager -------------+ +// | | | +// Job Job Job +// (for Key1) (for Key2) (for KeyX) +// / \ / \ / \ +// Requests Attempts Requests Attempts Requests Attempts +// | | | | | | +// Request... Attempt... Request... Attempt... Request... Attempt... +// (client A) (endpoint 1) (client C) (endpoint 3) (client X) (endpoint X) +// (client B) (endpoint 2) (endpoint 4) +// +// Owned by the QuicSessionPool. +class NET_EXPORT_PRIVATE QuicSessionAttemptManager { + public: + explicit QuicSessionAttemptManager(QuicSessionPool* pool); + + ~QuicSessionAttemptManager(); + + // Creates a new QuicSessionAttemptRequest for the given key. + std::unique_ptr<QuicSessionAttemptRequest> CreateRequest( + QuicSessionAliasKey key); + + // Called by QuicSessionAttemptRequest to request a session. See + // QuicSessionAttemptRequest for more details. + int RequestSession( + QuicSessionAttemptRequest* request, + QuicEndpoint endpoint, + int cert_verify_flags, + base::TimeTicks dns_resolution_start_time, + base::TimeTicks dns_resolution_end_time, + bool use_dns_aliases, + std::set<std::string> dns_aliases, + MultiplexedSessionCreationInitiator session_creation_initiator, + std::optional<ConnectionManagementConfig> connection_management_config, + const NetLogWithSource& net_log); + + // Called by QuicSessionAttemptRequest to remove itself from the manager. + void RemoveRequest(QuicSessionAttemptRequest* request); + + bool HasActiveJobForTesting(const QuicSessionAliasKey& key) const { + return active_jobs_.find(key) != active_jobs_.end(); + } + + private: + class Job; + + // Called by Job when the last request is completed. + void OnJobComplete(Job* job); + + const raw_ptr<QuicSessionPool> pool_; + + base::flat_map<QuicSessionAliasKey, std::unique_ptr<Job>> active_jobs_; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_SESSION_ATTEMPT_MANAGER_H_
diff --git a/net/quic/quic_session_attempt_manager_unittest.cc b/net/quic/quic_session_attempt_manager_unittest.cc new file mode 100644 index 0000000..5d105ae --- /dev/null +++ b/net/quic/quic_session_attempt_manager_unittest.cc
@@ -0,0 +1,480 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_session_attempt_manager.h" + +#include <memory> +#include <optional> +#include <set> + +#include "base/functional/callback_forward.h" +#include "base/test/scoped_feature_list.h" +#include "base/time/time.h" +#include "net/base/connection_endpoint_metadata.h" +#include "net/base/features.h" +#include "net/base/ip_address.h" +#include "net/base/ip_endpoint.h" +#include "net/base/net_error_details.h" +#include "net/base/net_errors.h" +#include "net/base/network_anonymization_key.h" +#include "net/base/privacy_mode.h" +#include "net/base/proxy_chain.h" +#include "net/base/reconnect_notifier.h" +#include "net/base/session_usage.h" +#include "net/dns/public/secure_dns_policy.h" +#include "net/log/net_log_source_type.h" +#include "net/quic/crypto/proof_verifier_chromium.h" +#include "net/quic/mock_quic_data.h" +#include "net/quic/quic_chromium_client_session.h" +#include "net/quic/quic_endpoint.h" +#include "net/quic/quic_session_alias_key.h" +#include "net/quic/quic_session_attempt_request.h" +#include "net/quic/quic_session_pool_test_base.h" +#include "net/socket/socket_tag.h" +#include "net/socket/socket_test_util.h" +#include "net/spdy/multiplexed_session_creation_initiator.h" +#include "net/test/gtest_util.h" +#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/scheme_host_port.h" +#include "url/url_constants.h" + +namespace net::test { + +namespace { + +IPEndPoint MakeIPEndPoint(std::string_view addr, uint16_t port = 443) { + return IPEndPoint(*IPAddress::FromIPLiteral(addr), port); +} + +class SessionRequester { + public: + explicit SessionRequester(QuicSessionAttemptManager* manager, + quic::ParsedQuicVersion version) + : manager_(manager), + quic_version_(version), + net_log_(NetLogWithSource::Make(NetLog::Get(), + NetLogSourceType::URL_REQUEST)) {} + + SessionRequester(SessionRequester&&) = default; + SessionRequester& operator=(SessionRequester&&) = default; + SessionRequester(const SessionRequester&) = delete; + SessionRequester& operator=(const SessionRequester&) = delete; + + ~SessionRequester() = default; + + SessionRequester& SetIPEndPoint(IPEndPoint ip_endpoint) { + endpoint_ = QuicEndpoint(quic_version_, std::move(ip_endpoint), + ConnectionEndpointMetadata()); + return *this; + } + + int Request() { + QuicSessionAliasKey key( + destination_, + QuicSessionKey(destination_.host(), destination_.port(), privacy_mode_, + proxy_chain_, session_usage_, socket_tag_, + network_anonymization_key_, secure_dns_policy_, + require_dns_https_alpn_)); + request_ = manager_->CreateRequest(key); + int rv = request_->RequestSession( + endpoint_, cert_verify_flags_, dns_resolution_start_time_, + dns_resolution_end_time_, /*use_dns_aliases=*/true, dns_aliases_, + session_creation_initiator_, connection_management_config_, net_log_, + base::BindOnce(&SessionRequester::OnComplete, base::Unretained(this))); + if (rv != ERR_IO_PENDING) { + OnComplete(rv); + } + return rv; + } + + int WaitForResult() { + if (result_.has_value()) { + return *result_; + } + + CHECK(!wait_for_result_closure_); + base::RunLoop run_loop; + wait_for_result_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + CHECK(result_.has_value()); + return *result_; + } + + void ResetRequest() { request_.reset(); } + + const QuicSessionAliasKey& key() const { + CHECK(request_); + return request_->key(); + } + + std::optional<int> result() const { return result_; } + const QuicChromiumClientSession* session() const { return session_; } + const NetErrorDetails& error_details() const { return error_details_; } + + private: + void OnComplete(int result) { + CHECK(!result_.has_value()); + CHECK(request_); + + result_ = result; + if (result_ == OK) { + session_ = request_->session(); + } else { + error_details_ = request_->error_details(); + } + request_.reset(); + // Clear the request to avoid dangling pointer. + manager_ = nullptr; + + if (wait_for_result_closure_) { + std::move(wait_for_result_closure_).Run(); + } + } + + raw_ptr<QuicSessionAttemptManager> manager_; + quic::ParsedQuicVersion quic_version_; + + // For calculating the session key. + url::SchemeHostPort destination_{ + url::kHttpsScheme, QuicSessionPoolTestBase::kDefaultServerHostName, + QuicSessionPoolTestBase::kDefaultServerPort}; + PrivacyMode privacy_mode_ = PRIVACY_MODE_DISABLED; + ProxyChain proxy_chain_ = ProxyChain::Direct(); + SessionUsage session_usage_ = SessionUsage::kDestination; + SocketTag socket_tag_; + NetworkAnonymizationKey network_anonymization_key_; + SecureDnsPolicy secure_dns_policy_ = SecureDnsPolicy::kAllow; + bool require_dns_https_alpn_ = false; + + // For calling RequestSession(). + QuicEndpoint endpoint_{quic_version_, + IPEndPoint(IPAddress::IPv4Localhost(), 443), + ConnectionEndpointMetadata()}; + int cert_verify_flags_ = 0; + base::TimeTicks dns_resolution_start_time_ = base::TimeTicks::Now(); + base::TimeTicks dns_resolution_end_time_ = base::TimeTicks::Now(); + std::set<std::string> dns_aliases_; + MultiplexedSessionCreationInitiator session_creation_initiator_ = + MultiplexedSessionCreationInitiator::kUnknown; + std::optional<ConnectionManagementConfig> connection_management_config_; + NetLogWithSource net_log_; + + std::unique_ptr<QuicSessionAttemptRequest> request_; + + base::OnceClosure wait_for_result_closure_; + + std::optional<int> result_; + raw_ptr<QuicChromiumClientSession> session_ = nullptr; + NetErrorDetails error_details_; +}; + +} // namespace + +class QuicSessionAttemptManagerTest + : public QuicSessionPoolTestBase, + public ::testing::TestWithParam<quic::ParsedQuicVersion> { + protected: + QuicSessionAttemptManagerTest() : QuicSessionPoolTestBase(GetParam()) {} + + void InitializeWithDefaultProofVerifyDetails() { + Initialize(); + crypto_client_stream_factory_.AddProofVerifyDetails( + &default_verify_details_); + } + + SessionRequester CreateRequester() { + return SessionRequester(pool_->session_attempt_manager(), GetParam()); + } + + QuicSessionAttemptManager* session_attempt_manager() { + return pool_->session_attempt_manager(); + } + + private: + ProofVerifyDetailsChromium default_verify_details_ = + DefaultProofVerifyDetails(); +}; + +INSTANTIATE_TEST_SUITE_P(/**/, + QuicSessionAttemptManagerTest, + ::testing::ValuesIn(AllSupportedQuicVersions())); + +TEST_P(QuicSessionAttemptManagerTest, RequestSessionSync) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(net::features::kAsyncQuicSession); + + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddReadPauseForever(); + socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + SessionRequester requester = CreateRequester(); + int result = requester.Request(); + EXPECT_THAT(result, IsOk()); + EXPECT_TRUE(requester.session()); +} + +TEST_P(QuicSessionAttemptManagerTest, RequestSessionAsync) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddReadPauseForever(); + socket_data.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + SessionRequester requester = CreateRequester(); + int result = requester.Request(); + EXPECT_THAT(result, IsError(ERR_IO_PENDING)); + + result = requester.WaitForResult(); + EXPECT_THAT(result, IsOk()); +} + +TEST_P(QuicSessionAttemptManagerTest, MultipleRequestsSameSessionSuccess) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddReadPauseForever(); + socket_data.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + // Create three requesters for the same session. + SessionRequester requester1 = CreateRequester(); + SessionRequester requester2 = CreateRequester(); + SessionRequester requester3 = CreateRequester(); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + + // All requesters should succeed and get the same session. + EXPECT_THAT(requester1.WaitForResult(), IsOk()); + EXPECT_THAT(requester2.WaitForResult(), IsOk()); + EXPECT_THAT(requester3.WaitForResult(), IsOk()); + + EXPECT_TRUE(requester1.session()); + EXPECT_EQ(requester1.session(), requester2.session()); + EXPECT_EQ(requester1.session(), requester3.session()); +} + +TEST_P(QuicSessionAttemptManagerTest, MultipleRequestsSameSessionFailure) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddConnect(ASYNC, ERR_ADDRESS_IN_USE); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + // Create three requesters for the same session. + SessionRequester requester1 = CreateRequester(); + SessionRequester requester2 = CreateRequester(); + SessionRequester requester3 = CreateRequester(); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + + // All requesters should fail with the same error. + EXPECT_THAT(requester1.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); + EXPECT_THAT(requester2.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); + EXPECT_THAT(requester3.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); + + EXPECT_FALSE(requester1.session()); + EXPECT_FALSE(requester2.session()); + EXPECT_FALSE(requester3.session()); +} + +// Test multiple endpoints for the same session: One succeeds, one fails. +TEST_P(QuicSessionAttemptManagerTest, MultipleEndpointsSuccessAndFailure) { + InitializeWithDefaultProofVerifyDetails(); + + // Create two mock sockets for two different endpoints. + MockQuicData socket_data1(version_); + socket_data1.AddConnect(ASYNC, ERR_CONNECTION_FAILED); + socket_data1.AddSocketDataToFactory(socket_factory_.get()); + + MockQuicData socket_data2(version_); + socket_data2.AddReadPauseForever(); + socket_data2.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data2.AddSocketDataToFactory(socket_factory_.get()); + + SessionRequester requester1 = CreateRequester(); + requester1.SetIPEndPoint(MakeIPEndPoint("192.0.2.1")); + SessionRequester requester2 = CreateRequester(); + requester2.SetIPEndPoint(MakeIPEndPoint("192.0.2.2")); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + + // First endpoint fails but second succeeds, so both requesters should + // receive the successful session. + EXPECT_THAT(requester1.WaitForResult(), IsOk()); + EXPECT_THAT(requester2.WaitForResult(), IsOk()); + + EXPECT_TRUE(requester1.session()); + EXPECT_TRUE(requester2.session()); + EXPECT_EQ(requester1.session(), requester2.session()); +} + +// Test multiple endpoints for the same session: All fail. +TEST_P(QuicSessionAttemptManagerTest, MultipleEndpointsAllFail) { + InitializeWithDefaultProofVerifyDetails(); + + // Create three mock sockets for three different endpoints, all fail + MockQuicData socket_data1(version_); + socket_data1.AddConnect(ASYNC, ERR_CONNECTION_FAILED); + socket_data1.AddSocketDataToFactory(socket_factory_.get()); + + MockQuicData socket_data2(version_); + socket_data2.AddConnect(ASYNC, ERR_ADDRESS_UNREACHABLE); + socket_data2.AddSocketDataToFactory(socket_factory_.get()); + + MockQuicData socket_data3(version_); + socket_data3.AddConnect(ASYNC, ERR_CONNECTION_REFUSED); + socket_data3.AddSocketDataToFactory(socket_factory_.get()); + + SessionRequester requester1 = CreateRequester(); + requester1.SetIPEndPoint(MakeIPEndPoint("2001:db8::1")); + SessionRequester requester2 = CreateRequester(); + requester2.SetIPEndPoint(MakeIPEndPoint("2001:db8::2")); + SessionRequester requester3 = CreateRequester(); + requester3.SetIPEndPoint(MakeIPEndPoint("2001:db8::3")); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + + // All should fail with the last error. + EXPECT_THAT(requester1.WaitForResult(), IsError(ERR_CONNECTION_REFUSED)); + EXPECT_THAT(requester2.WaitForResult(), IsError(ERR_CONNECTION_REFUSED)); + EXPECT_THAT(requester3.WaitForResult(), IsError(ERR_CONNECTION_REFUSED)); + + // No sessions should be created. + EXPECT_FALSE(requester1.session()); + EXPECT_FALSE(requester2.session()); + EXPECT_FALSE(requester3.session()); +} + +// Test multiple endpoints for the same session: All sessions succeed, +// but only the first one is used. +TEST_P(QuicSessionAttemptManagerTest, MultipleEndpointsAllSuccess) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data1(version_); + socket_data1.AddReadPauseForever(); + socket_data1.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data1.AddSocketDataToFactory(socket_factory_.get()); + + // This would succeed but should be cancelled. + MockQuicData socket_data2(version_); + socket_data2.AddReadPauseForever(); + socket_data2.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data2.AddSocketDataToFactory(socket_factory_.get()); + + SessionRequester requester1 = CreateRequester(); + requester1.SetIPEndPoint(MakeIPEndPoint("2001:db8::1")); + SessionRequester requester2 = CreateRequester(); + requester2.SetIPEndPoint(MakeIPEndPoint("192.0.2.1")); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + + // Both should succeed and have the same session. + EXPECT_THAT(requester1.WaitForResult(), IsOk()); + EXPECT_THAT(requester2.WaitForResult(), IsOk()); + + EXPECT_TRUE(requester1.session()); + EXPECT_TRUE(requester2.session()); + EXPECT_EQ(requester1.session(), requester2.session()); +} + +TEST_P(QuicSessionAttemptManagerTest, JobCompletesWhenAllRequestsCancelled) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddConnect(ASYNC, ERR_IO_PENDING); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + // Create multiple pending requests. + SessionRequester requester1 = CreateRequester(); + SessionRequester requester2 = CreateRequester(); + SessionRequester requester3 = CreateRequester(); + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + + const QuicSessionAliasKey key = requester1.key(); + + // Cancel first two requests. + requester1.ResetRequest(); + requester2.ResetRequest(); + + // At this point, the Job should still exist because requester3 is active. + EXPECT_TRUE(session_attempt_manager()->HasActiveJobForTesting(key)); + + // Cancel the last request. This should destroy the Job. + requester3.ResetRequest(); + EXPECT_FALSE(session_attempt_manager()->HasActiveJobForTesting(key)); +} + +TEST_P(QuicSessionAttemptManagerTest, CancelSomeRequestsWhileOthersComplete) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddReadPauseForever(); + socket_data.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + // Create multiple pending requests. + SessionRequester requester1 = CreateRequester(); + SessionRequester requester2 = CreateRequester(); + SessionRequester requester3 = CreateRequester(); + SessionRequester requester4 = CreateRequester(); + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester4.Request(), IsError(ERR_IO_PENDING)); + + // Cancel two requests before connection completes. + requester1.ResetRequest(); + requester2.ResetRequest(); + + // Complete connection attempt. Remaining requests should succeed. + EXPECT_THAT(requester3.WaitForResult(), IsOk()); + EXPECT_THAT(requester4.WaitForResult(), IsOk()); + + EXPECT_TRUE(requester3.session()); + EXPECT_TRUE(requester4.session()); + EXPECT_EQ(requester3.session(), requester4.session()); +} + +TEST_P(QuicSessionAttemptManagerTest, DestroyManagerWithPendingRequests) { + InitializeWithDefaultProofVerifyDetails(); + + MockQuicData socket_data(version_); + socket_data.AddReadPauseForever(); + socket_data.AddWrite(ASYNC, ConstructInitialSettingsPacket()); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + // Create multiple pending requests. + SessionRequester requester1 = CreateRequester(); + SessionRequester requester2 = CreateRequester(); + SessionRequester requester3 = CreateRequester(); + + EXPECT_THAT(requester1.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester2.Request(), IsError(ERR_IO_PENDING)); + EXPECT_THAT(requester3.Request(), IsError(ERR_IO_PENDING)); + + // Destroy the pool (which contains the manager) while requests are + // pending. + pool_.reset(); + + EXPECT_THAT(requester1.WaitForResult(), IsError(ERR_ABORTED)); + EXPECT_THAT(requester2.WaitForResult(), IsError(ERR_ABORTED)); + EXPECT_THAT(requester3.WaitForResult(), IsError(ERR_ABORTED)); +} + +} // namespace net::test
diff --git a/net/quic/quic_session_attempt_request.cc b/net/quic/quic_session_attempt_request.cc new file mode 100644 index 0000000..12c7b0df --- /dev/null +++ b/net/quic/quic_session_attempt_request.cc
@@ -0,0 +1,70 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_session_attempt_request.h" + +#include <optional> +#include <set> +#include <string> +#include <utility> + +#include "base/check.h" +#include "net/base/completion_once_callback.h" +#include "net/base/net_error_details.h" +#include "net/base/net_errors.h" +#include "net/quic/quic_session_attempt_manager.h" + +namespace net { + +QuicSessionAttemptRequest::QuicSessionAttemptRequest( + QuicSessionAttemptManager* manager, + QuicSessionAliasKey key) + : manager_(manager), key_(std::move(key)) {} + +QuicSessionAttemptRequest::~QuicSessionAttemptRequest() { + if (manager_ && callback_) { + manager_->RemoveRequest(this); + } +} + +int QuicSessionAttemptRequest::RequestSession( + QuicEndpoint endpoint, + int cert_verify_flags, + base::TimeTicks dns_resolution_start_time, + base::TimeTicks dns_resolution_end_time, + bool use_dns_aliases, + std::set<std::string> dns_aliases, + MultiplexedSessionCreationInitiator session_creation_initiator, + std::optional<ConnectionManagementConfig> connection_management_config, + const NetLogWithSource& net_log, + CompletionOnceCallback callback) { + int rv = manager_->RequestSession( + this, std::move(endpoint), cert_verify_flags, dns_resolution_start_time, + dns_resolution_end_time, use_dns_aliases, std::move(dns_aliases), + session_creation_initiator, std::move(connection_management_config), + net_log); + if (rv == ERR_IO_PENDING) { + CHECK(!completed_); + callback_ = std::move(callback); + } else { + CHECK(completed_); + } + return rv; +} + +void QuicSessionAttemptRequest::Complete(int rv, + QuicChromiumClientSession* session, + NetErrorDetails error_details) { + CHECK(!completed_); + completed_ = true; + session_ = session; + error_details_ = std::move(error_details); + + manager_ = nullptr; + if (callback_) { + std::move(callback_).Run(rv); + } +} + +} // namespace net
diff --git a/net/quic/quic_session_attempt_request.h b/net/quic/quic_session_attempt_request.h new file mode 100644 index 0000000..77e1cd51 --- /dev/null +++ b/net/quic/quic_session_attempt_request.h
@@ -0,0 +1,89 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_SESSION_ATTEMPT_REQUEST_H_ +#define NET_QUIC_QUIC_SESSION_ATTEMPT_REQUEST_H_ + +#include <optional> +#include <set> +#include <string> + +#include "base/check.h" +#include "base/memory/raw_ptr.h" +#include "net/base/completion_once_callback.h" +#include "net/base/net_error_details.h" +#include "net/base/net_export.h" +#include "net/quic/quic_session_alias_key.h" +#include "net/quic/quic_session_pool.h" + +namespace net { + +class QuicSessionAttemptManager; + +// Represents a request to attempt creation of a new QUIC session. This class +// is owned by the creator of the request. If the request is still pending when +// the request is destroyed, it will be cancelled. +class NET_EXPORT_PRIVATE QuicSessionAttemptRequest { + public: + QuicSessionAttemptRequest(const QuicSessionAttemptRequest&) = delete; + QuicSessionAttemptRequest& operator=(const QuicSessionAttemptRequest&) = + delete; + + ~QuicSessionAttemptRequest(); + + // Requests a QUIC session. If the request is completed synchronously, returns + // the result. If the request is completed asynchronously, returns + // ERR_IO_PENDING and `callback` will be invoked later. See also + // `QuicSessionAttempt`. + int RequestSession( + QuicEndpoint endpoint, + int cert_verify_flags, + base::TimeTicks dns_resolution_start_time, + base::TimeTicks dns_resolution_end_time, + bool use_dns_aliases, + std::set<std::string> dns_aliases, + MultiplexedSessionCreationInitiator session_creation_initiator, + std::optional<ConnectionManagementConfig> connection_management_config, + const NetLogWithSource& net_log, + CompletionOnceCallback callback); + + const QuicSessionAliasKey& key() const { return key_; } + + // Returns the error details of the request. Populated only if the request is + // failed. Only valid to call after the request is completed. + const NetErrorDetails& error_details() const { + CHECK(completed_); + return error_details_; + } + + // Returns the session of the request. Can be nullptr if the request is + // failed. Only valid to call after the request is completed. + raw_ptr<QuicChromiumClientSession> session() const { + CHECK(completed_); + return session_; + } + + private: + friend class QuicSessionAttemptManager; + + explicit QuicSessionAttemptRequest(QuicSessionAttemptManager* manager, + QuicSessionAliasKey key); + + void Complete(int rv, + QuicChromiumClientSession* session, + NetErrorDetails error_details); + + raw_ptr<QuicSessionAttemptManager> manager_; + const QuicSessionAliasKey key_; + + bool completed_ = false; + CompletionOnceCallback callback_; + + NetErrorDetails error_details_; + raw_ptr<QuicChromiumClientSession> session_; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_SESSION_ATTEMPT_REQUEST_H_
diff --git a/net/quic/quic_session_pool.cc b/net/quic/quic_session_pool.cc index aa02cdbf..7b13f539 100644 --- a/net/quic/quic_session_pool.cc +++ b/net/quic/quic_session_pool.cc
@@ -64,6 +64,7 @@ #include "net/quic/quic_context.h" #include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_server_info.h" +#include "net/quic/quic_session_attempt_manager.h" #include "net/quic/quic_session_key.h" #include "net/quic/quic_session_pool_direct_job.h" #include "net/quic/quic_session_pool_job.h" @@ -656,7 +657,9 @@ quic_context->params()->skip_dns_with_origin_frame), ignore_ip_matching_when_finding_existing_sessions_( quic_context->params() - ->ignore_ip_matching_when_finding_existing_sessions) { + ->ignore_ip_matching_when_finding_existing_sessions), + session_attempt_manager_( + std::make_unique<QuicSessionAttemptManager>(this)) { DCHECK(transport_security_state_); DCHECK(http_server_properties_); if (params_.disable_tls_zero_rtt) { @@ -673,6 +676,10 @@ CloseAllSessions(ERR_ABORTED, quic::QUIC_CONNECTION_CANCELLED); all_sessions_.clear(); + // Reset session attempt manager to ensure there is no active crypto config + // map. + session_attempt_manager_.reset(); + // Clear the active jobs, first moving out of the instance variable so that // calls to CancelRequest for any pending requests do not cause recursion. JobMap active_jobs = std::move(active_jobs_);
diff --git a/net/quic/quic_session_pool.h b/net/quic/quic_session_pool.h index 6281b5da..93b34b2 100644 --- a/net/quic/quic_session_pool.h +++ b/net/quic/quic_session_pool.h
@@ -97,6 +97,7 @@ class QuicCryptoClientStreamFactory; class QuicServerInfo; class QuicSessionPool; +class QuicSessionAttemptManager; class QuicContext; class SCTAuditingDelegate; class SocketPerformanceWatcherFactory; @@ -540,6 +541,10 @@ return host_resolver_->IsHappyEyeballsV3Enabled(); } + QuicSessionAttemptManager* session_attempt_manager() { + return session_attempt_manager_.get(); + } + struct QuicCryptoClientConfigKey; private: @@ -919,6 +924,8 @@ quic::DeterministicConnectionIdGenerator connection_id_generator_{ quic::kQuicDefaultConnectionIdLength}; + std::unique_ptr<QuicSessionAttemptManager> session_attempt_manager_; + std::optional<base::TimeDelta> time_delay_for_waiting_job_for_testing_; base::WeakPtrFactory<QuicSessionPool> weak_factory_{this};
diff --git a/net/socket/stream_socket_close_reason.cc b/net/socket/stream_socket_close_reason.cc index 29410ab..fda9451 100644 --- a/net/socket/stream_socket_close_reason.cc +++ b/net/socket/stream_socket_close_reason.cc
@@ -31,6 +31,8 @@ return "UsingExistingQuicSession"; case StreamSocketCloseReason::kAbort: return "Abort"; + case StreamSocketCloseReason::kAttemptManagerDraining: + return "AttemptManagerDraining"; } }
diff --git a/net/socket/stream_socket_close_reason.h b/net/socket/stream_socket_close_reason.h index 39ba86ac..58b90cb 100644 --- a/net/socket/stream_socket_close_reason.h +++ b/net/socket/stream_socket_close_reason.h
@@ -25,7 +25,8 @@ kUsingExistingSpdySession = 7, kUsingExistingQuicSession = 8, kAbort = 9, - kMaxValue = kAbort, + kAttemptManagerDraining = 10, + kMaxValue = kAttemptManagerDraining, }; // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:StreamSocketCloseReason)
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src index 203951a..1852058 160000 --- a/net/third_party/quiche/src +++ b/net/third_party/quiche/src
@@ -1 +1 @@ -Subproject commit 203951a0d6e8a190839bf7a59e00d4df1b45835f +Subproject commit 1852058ed84fc551bd4cb9dba8330446d7d02411
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index e77a21b..c479d1ec 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -306,7 +306,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13738694/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13739506/artifacts/repository' } mavenCentral() }
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index ec6731de..d8d459ea 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -3386,6 +3386,8 @@ optional BackendNodeId backendNodeId # JavaScript object id of the node wrapper. optional Runtime.RemoteObjectId objectId + # Include all shadow roots. Equals to false if not specified. + experimental optional boolean includeShadowDOM returns # Outer HTML markup. string outerHTML
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom index 368f1661..b4a5aea 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -4912,6 +4912,7 @@ kHTMLCanvasElementLowLatency_WebGL = 5602, kHTMLCanvasElementLowLatency_WebGL_Preserve = 5603, kHTMLCanvasElementLowLatency_WebGL_Discard = 5604, + kAnimatedImageUsedMoreThanOnce = 5605, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/renderer/core/dom/qualified_name.cc b/third_party/blink/renderer/core/dom/qualified_name.cc index 9be3d6d..e708c0a 100644 --- a/third_party/blink/renderer/core/dom/qualified_name.cc +++ b/third_party/blink/renderer/core/dom/qualified_name.cc
@@ -117,7 +117,7 @@ DEFINE_GLOBAL(, QualifiedName, g_any_name); DEFINE_GLOBAL(, QualifiedName, g_null_name); -void QualifiedName::InitAndReserveCapacityForSize(unsigned size) { +void QualifiedName::InitAndReserveCapacityForSize(wtf_size_t size) { DCHECK(g_star_atom.Impl()); GetQualifiedNameCache().ReserveCapacityForSize( size + 2 /*g_star_atom and g_null_atom */);
diff --git a/third_party/blink/renderer/core/dom/qualified_name.h b/third_party/blink/renderer/core/dom/qualified_name.h index f63cb9f..0a10d76 100644 --- a/third_party/blink/renderer/core/dom/qualified_name.h +++ b/third_party/blink/renderer/core/dom/qualified_name.h
@@ -205,7 +205,7 @@ QualifiedNameImpl* Impl() const { return impl_.get(); } // Init routine for globals - static void InitAndReserveCapacityForSize(unsigned size); + static void InitAndReserveCapacityForSize(wtf_size_t size); static const QualifiedName& Null() { return g_null_name; }
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc index 91cc584..16f2b75 100644 --- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc +++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
@@ -631,6 +631,8 @@ return no_serialization; } break; + case Behavior::kIncludeAllShadowRootsForInspector: + break; } }
diff --git a/third_party/blink/renderer/core/editing/serializers/serialization.h b/third_party/blink/renderer/core/editing/serializers/serialization.h index a923233..70965aa 100644 --- a/third_party/blink/renderer/core/editing/serializers/serialization.h +++ b/third_party/blink/renderer/core/editing/serializers/serialization.h
@@ -62,6 +62,8 @@ // Include any shadow root (open or closed) marked `serializable`. Also // include any shadow root in the include_shadow_roots list. kIncludeAnySerializableShadowRoots, + // Include all shadow roots for requests by the inspector. + kIncludeAllShadowRootsForInspector, }; ShadowRootInclusion() = default;
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc index 74a164c..b7d1b352 100644 --- a/third_party/blink/renderer/core/editing/visible_units.cc +++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -495,6 +495,10 @@ // [2] editing/inserting/return-with-object-element.html if (const InlineNodeData* inline_data = block_flow->GetInlineNodeData()) { if (inline_data->ItemsData(false).text_content.empty() && + // Out-of-flow objects (floating and out-of-flow positioned) used to + // represent a U+FFFC Object Replacement Character. Keep the + // historical behavior. + !inline_data->HasFloatingOrOutOfFlowPositioned() && block_flow->HasLineIfEmpty()) { return false; }
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/third_party/blink/renderer/core/html/anchor_element_metrics.cc index 8f67a14..dfca3d01 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -118,10 +118,10 @@ int source_number = CharactersToInt(StringView(source, left, source_right - left), - WTF::NumberParsingOptions(), /*ok=*/nullptr); + NumberParsingOptions(), /*ok=*/nullptr); int target_number = CharactersToInt(StringView(target, left, target_right - left), - WTF::NumberParsingOptions(), /*ok=*/nullptr); + NumberParsingOptions(), /*ok=*/nullptr); // The second number should increment by one and the rest of the strings // should be the same.
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc index d0d04bb2..2ff3450 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -268,11 +268,4 @@ return preferred_2d_raster_mode_ == RasterModeHint::kPreferGPU && CanUseGPU(); } -void CanvasRenderingContextHost::FlushRecordingForCanvas2D(FlushReason reason) { - CHECK(IsRenderingContext2D()); - if (auto* provider = GetResourceProviderForCanvas2D()) { - provider->FlushCanvas(reason); - } -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h index 5b01bdf..7ea7d75e 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
@@ -153,14 +153,8 @@ bool ShouldTryToUseGpuRaster() const; void SetPreferred2DRasterMode(RasterModeHint); - virtual std::unique_ptr<CanvasResourceProvider> - ReplaceResourceProviderForCanvas2D( - std::unique_ptr<CanvasResourceProvider>) = 0; - virtual void DiscardResources() = 0; - void FlushRecordingForCanvas2D(FlushReason reason); - protected: ~CanvasRenderingContextHost() override = default;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 9ebe263a..238920f 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -389,7 +389,7 @@ if (printed_in_current_task || IsPrinting()) { reason = FlushReason::kCanvasPushFrameWhilePrinting; } - FlushRecordingForCanvas2D(reason); + GetResourceProviderForCanvas2D()->FlushCanvas(reason); // If the context is lost, we don't know if we should be producing GPU or // software frames, until we get a new context, since the compositor will @@ -1235,7 +1235,7 @@ if (IsPrinting() && IsRenderingContext2D() && GetResourceProviderForCanvas2D()) { auto* provider = GetResourceProviderForCanvas2D(); - FlushRecordingForCanvas2D(FlushReason::kPrinting); + provider->FlushCanvas(FlushReason::kPrinting); // `FlushRecording` might be a no-op if a flush already happened before. // Fortunately, the last flush recording was kept by the provider. const std::optional<cc::PaintRecord>& last_recording =
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 8cd093e7b..3a394c49 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -269,8 +269,9 @@ bool IsHibernating() const override; void SetTransferToGPUTextureWasInvoked() override; UkmParameters GetUkmParameters() override; + std::unique_ptr<CanvasResourceProvider> ReplaceResourceProviderForCanvas2D( - std::unique_ptr<CanvasResourceProvider>) override; + std::unique_ptr<CanvasResourceProvider>); // This method attempts to ensure that the canvas' resource exists on the GPU. // A HTMLCanvasElement can downgrade itself from GPU to CPU when readback
diff --git a/third_party/blink/renderer/core/html/html_dimension.cc b/third_party/blink/renderer/core/html/html_dimension.cc index 8a611cf..418c337b 100644 --- a/third_party/blink/renderer/core/html/html_dimension.cc +++ b/third_party/blink/renderer/core/html/html_dimension.cc
@@ -62,7 +62,7 @@ bool ok = false; unsigned integer_value = CharactersToUInt( characters.subspan(digits_start, position - digits_start), - WTF::NumberParsingOptions(), &ok); + NumberParsingOptions(), &ok); if (!ok) return HTMLDimension(0., HTMLDimension::kRelative); value += integer_value; @@ -78,8 +78,8 @@ } if (fraction_numbers.size()) { - double fraction_value = CharactersToUInt( - base::span(fraction_numbers), WTF::NumberParsingOptions(), &ok); + double fraction_value = CharactersToUInt(base::span(fraction_numbers), + NumberParsingOptions(), &ok); if (!ok) return HTMLDimension(0., HTMLDimension::kRelative);
diff --git a/third_party/blink/renderer/core/html/html_font_element.cc b/third_party/blink/renderer/core/html/html_font_element.cc index 7ebee421..f41c343 100644 --- a/third_party/blink/renderer/core/html/html_font_element.cc +++ b/third_party/blink/renderer/core/html/html_font_element.cc
@@ -85,7 +85,7 @@ int value = CharactersToInt( characters.subspan(digits_start, static_cast<size_t>(position - digits_start)), - WTF::NumberParsingOptions(), nullptr); + NumberParsingOptions(), nullptr); // Step 9 if (mode == kRelativePlus) {
diff --git a/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc b/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc index 9f9495a8..69a3c53 100644 --- a/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc +++ b/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc
@@ -196,7 +196,7 @@ DCHECK_LT(position, chars.size()); bool ok; - constexpr auto kOptions = WTF::NumberParsingOptions() + constexpr auto kOptions = NumberParsingOptions() .SetAcceptTrailingGarbage() .SetAcceptLeadingPlus(); int wtf_value = CharactersToInt(chars.subspan(position), kOptions, &ok); @@ -237,7 +237,7 @@ DCHECK_LT(position, chars.size()); NumberParsingResult result; - constexpr auto kOptions = WTF::NumberParsingOptions() + constexpr auto kOptions = NumberParsingOptions() .SetAcceptTrailingGarbage() .SetAcceptLeadingPlus() .SetAcceptMinusZeroForUnsigned();
diff --git a/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc b/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc index 48f4384..9861a9f 100644 --- a/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc +++ b/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc
@@ -88,7 +88,7 @@ } return CharactersToInt( attribute.subspan(start, length_excluding_descriptor), - WTF::NumberParsingOptions(), &is_valid); + NumberParsingOptions(), &is_valid); } template <typename CharType>
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc index 23432df..d38b105 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc
@@ -86,8 +86,7 @@ auto [number_data, rest] = buf.split_at(num_digits); // Consume the digits. buf = rest; - return CharactersToUInt(number_data, WTF::NumberParsingOptions(), - &valid_number); + return CharactersToUInt(number_data, NumberParsingOptions(), &valid_number); }); // Since we know that scanDigits only scanned valid (ASCII) digits (and
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc index 26afc21..2b636a4 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -1211,6 +1211,7 @@ std::optional<int> node_id, std::optional<int> backend_node_id, std::optional<String> object_id, + std::optional<bool> include_shadow_dom, WTF::String* outer_html) { Node* node = nullptr; protocol::Response response = @@ -1218,7 +1219,12 @@ if (!response.IsSuccess()) return response; - *outer_html = CreateMarkup(node); + ShadowRootInclusion shadow_roots{ + include_shadow_dom.value_or(false) + ? ShadowRootInclusion::Behavior::kIncludeAllShadowRootsForInspector + : ShadowRootInclusion::Behavior::kOnlyProvidedShadowRoots}; + *outer_html = + CreateMarkup(node, kIncludeNode, kDoNotResolveURLs, shadow_roots); return protocol::Response::Success(); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h index 6a5a0c1b..9ad2455 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
@@ -148,6 +148,7 @@ protocol::Response getOuterHTML(std::optional<int> node_id, std::optional<int> backend_node_id, std::optional<String> object_id, + std::optional<bool> include_shadow_dom, String* outer_html) override; protocol::Response setOuterHTML(int node_id, const String& outer_html) override;
diff --git a/third_party/blink/renderer/core/layout/inline/inline_item.cc b/third_party/blink/renderer/core/layout/inline/inline_item.cc index 7ea4f33..2d84084 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_item.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_item.cc
@@ -208,30 +208,52 @@ unsigned InlineItem::SetBidiLevel(InlineItems& items, unsigned index, unsigned end_offset, - UBiDiLevel level) { - for (; items[index]->end_offset_ < end_offset; index++) { - items[index]->SetBidiLevel(level); - } - InlineItem* item = items[index]; - item->SetBidiLevel(level); - - if (item->end_offset_ == end_offset) { - // Let close items have the same bidi-level as the previous item. - while (index + 1 < items.size() && - items[index + 1]->Type() == InlineItem::kCloseTag) { - items[++index]->SetBidiLevel(level); + UBiDiLevel level, + wtf_size_t num_out_of_flow) { + DCHECK(!num_out_of_flow || + RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()); + InlineItem* item; + for (;; ++index) { + item = items[index]; + item->SetBidiLevel(level); + if (num_out_of_flow && item->IsFloatingOrOutOfFlowPositioned()) { + --num_out_of_flow; } - } else { + if (item->end_offset_ >= end_offset) { + break; + } + } + + // If `end_offset` is in the middle of an `InlineItem`, split it. + if (item->end_offset_ > end_offset) { // If a reused item needs to split, |SetNeedsLayout| to ensure the line is // not reused. LayoutObject* layout_object = item->GetLayoutObject(); - if (layout_object->EverHadLayout() && !layout_object->NeedsLayout()) + if (layout_object->EverHadLayout() && !layout_object->NeedsLayout()) { layout_object->SetNeedsLayout(layout_invalidation_reason::kStyleChange); + } Split(items, index, end_offset); + return index + 1; } + DCHECK_EQ(end_offset, item->end_offset_); - return index + 1; + // Let trailing items have the same bidi-level as the previous item. + for (++index; index < items.size(); ++index) { + item = items[index]; + const bool is_trailing = + !item->Length() && + (item->Type() == InlineItem::kCloseTag || num_out_of_flow); + if (!is_trailing) { + break; + } + item->SetBidiLevel(level); + if (num_out_of_flow && item->IsFloatingOrOutOfFlowPositioned()) { + --num_out_of_flow; + } + } + DCHECK_EQ(num_out_of_flow, 0u); // Check if `num_out_of_flow` is consumed. + return index; } const Font& InlineItem::FontWithSvgScaling() const {
diff --git a/third_party/blink/renderer/core/layout/inline/inline_item.h b/third_party/blink/renderer/core/layout/inline/inline_item.h index 804f5e67..46a2bc0 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_item.h +++ b/third_party/blink/renderer/core/layout/inline/inline_item.h
@@ -89,6 +89,9 @@ void SetTextType(TextItemType text_type) { text_type_ = static_cast<unsigned>(text_type); } + bool IsFloatingOrOutOfFlowPositioned() const { + return Type() == kFloating || Type() == kOutOfFlowPositioned; + } bool IsSymbolMarker() const { return TextType() == TextItemType::kSymbolMarker; } @@ -272,7 +275,8 @@ static unsigned SetBidiLevel(InlineItems&, unsigned index, unsigned end_offset, - UBiDiLevel); + UBiDiLevel, + wtf_size_t num_out_of_flow = 0); // Update `InlineItem::Index()` for the given list. static void UpdateIndex(base::span<Member<InlineItem>> items);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc b/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc index 9c9862c..8a57042 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc
@@ -1285,8 +1285,14 @@ template <typename MappingBuilder> void InlineItemsBuilderTemplate<MappingBuilder>::AppendFloating( LayoutObject* layout_object) { - AppendOpaque(InlineItem::kFloating, uchar::kObjectReplacementCharacter, - layout_object); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + // Out-of-flow elements should be ignored for text processing. + // https://drafts.csswg.org/css-text-3/#text-encoding + AppendOpaque(InlineItem::kFloating, layout_object); + } else { + AppendOpaque(InlineItem::kFloating, uchar::kObjectReplacementCharacter, + layout_object); + } has_floats_ = true; // Floats/exclusions require computing line heights, which is currently // skipped during the bisect. See `ParagraphLineBreaker`. @@ -1297,8 +1303,15 @@ template <typename MappingBuilder> void InlineItemsBuilderTemplate<MappingBuilder>::AppendOutOfFlowPositioned( LayoutObject* layout_object) { - AppendOpaque(InlineItem::kOutOfFlowPositioned, - uchar::kObjectReplacementCharacter, layout_object); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + // Out-of-flow elements should be ignored for text processing. + // https://drafts.csswg.org/css-text-3/#text-encoding + AppendOpaque(InlineItem::kOutOfFlowPositioned, layout_object); + } else { + AppendOpaque(InlineItem::kOutOfFlowPositioned, + uchar::kObjectReplacementCharacter, layout_object); + } + has_out_of_flow_positioned_ = true; } template <typename MappingBuilder> @@ -1698,6 +1711,7 @@ HasBidiControls() || (has_non_orc_16bit_ && Character::MaybeBidiRtl(data->text_content)); data->has_floats_ = has_floats_; + data->has_out_of_flow_positioned_ = has_out_of_flow_positioned_; data->has_initial_letter_box_ = has_initial_letter_box_; data->has_ruby_ = has_ruby_; data->is_block_level_ = IsBlockLevel();
diff --git a/third_party/blink/renderer/core/layout/inline/inline_items_builder.h b/third_party/blink/renderer/core/layout/inline/inline_items_builder.h index 3773a7d..08cfe006 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_items_builder.h +++ b/third_party/blink/renderer/core/layout/inline/inline_items_builder.h
@@ -195,6 +195,7 @@ const bool is_text_combine_; bool has_bidi_controls_ = false; bool has_floats_ = false; + bool has_out_of_flow_positioned_ = false; bool has_initial_letter_box_ = false; bool has_ruby_ = false; bool is_block_level_ = true;
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node.cc b/third_party/blink/renderer/core/layout/inline/inline_node.cc index e78c07c..b9246c11 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_node.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_node.cc
@@ -1288,10 +1288,10 @@ } BidiParagraph bidi; data->text_content.Ensure16Bit(); - if (!bidi.SetParagraph(data->text_content, base_direction)) { + const String& text_content = data->text_content; + if (!bidi.SetParagraph(text_content, base_direction)) { // On failure, give up bidi resolving and reordering. - data->is_bidi_enabled_ = false; - data->SetBaseDirection(TextDirection::kLtr); + data->DisableBidi(); return; } @@ -1303,16 +1303,100 @@ return; } + // If this IFC has out-of-flow objects, create a text with them represented by + // the U+FFFC OBJECT REPLACEMENT CHARACTER. The [CSS Text] defines that + // out-of-flow elements must be ignored for text processing, but many existing + // tests require them to act as a [neutral] like U+FFFC OBJECT REPLACEMENT + // CHARACTER, and all browsers match. + // + // [CSS Text]: https://drafts.csswg.org/css-text-3/#text-encoding + // [neutral]: https://unicode.org/reports/tr9/#ON + struct OutOfFlowItem { + wtf_size_t text_offset; +#if EXPENSIVE_DCHECKS_ARE_ON() + UBiDiLevel level = 0; +#endif // EXPENSIVE_DCHECKS_ARE_ON() + }; + Vector<OutOfFlowItem> out_of_flow_items; + String text_content_with_out_of_flow; + wtf_size_t text_len = text_content.length(); InlineItems& items = data->items; + if (data->HasFloatingOrOutOfFlowPositioned() && + RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) [[unlikely]] { + StringBuilder builder; + wtf_size_t last_offset = 0; + for (const auto item_ptr : items) { + const InlineItem& item = *item_ptr; + if (item.IsFloatingOrOutOfFlowPositioned()) [[unlikely]] { + const wtf_size_t offset = item.StartOffset(); + if (builder.empty()) { + builder.Reserve16BitCapacity(text_len + 16); + } + builder.Append(text_content, last_offset, offset - last_offset); + last_offset = offset; + out_of_flow_items.push_back(OutOfFlowItem{builder.length()}); + builder.Append(uchar::kObjectReplacementCharacter); + } + } + DCHECK_EQ(builder.empty(), out_of_flow_items.empty()); + if (!builder.empty()) { + builder.Append(StringView{text_content, last_offset}); + text_content_with_out_of_flow = builder.ReleaseString(); + if (!bidi.SetParagraph(text_content_with_out_of_flow, base_direction)) { + data->DisableBidi(); + return; + } + text_len = text_content_with_out_of_flow.length(); + + // Add a sentinel to help the loop below. + out_of_flow_items.push_back( + OutOfFlowItem{std::numeric_limits<wtf_size_t>::max()}); + } + } + + // Copy resolved `BidiLevel`s in the `bidi` to the `items`. + // If a boundary is within an `InlineItem`, this involves splitting. + wtf_size_t out_of_flow_item_index = 0; unsigned item_index = 0; - for (unsigned start = 0; start < data->text_content.length();) { + for (unsigned start = 0; start < text_len;) { + DCHECK_EQ(items[item_index]->start_offset_, start - out_of_flow_item_index); UBiDiLevel level; - unsigned end = bidi.GetLogicalRun(start, &level); - DCHECK_EQ(items[item_index]->start_offset_, start); - item_index = InlineItem::SetBidiLevel(items, item_index, end, level); + const unsigned end = bidi.GetLogicalRun(start, &level); + if (out_of_flow_items.empty()) { + item_index = InlineItem::SetBidiLevel(items, item_index, end, level); + } else { + DCHECK(RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()); + wtf_size_t num_out_of_flow_in_this_run = 0; + while (end > out_of_flow_items[out_of_flow_item_index].text_offset) { +#if EXPENSIVE_DCHECKS_ARE_ON() + out_of_flow_items[out_of_flow_item_index].level = level; +#endif // EXPENSIVE_DCHECKS_ARE_ON() + ++out_of_flow_item_index; + ++num_out_of_flow_in_this_run; + } + item_index = InlineItem::SetBidiLevel(items, item_index, + end - out_of_flow_item_index, level, + num_out_of_flow_in_this_run); + } start = end; } -#if DCHECK_IS_ON() + +#if EXPENSIVE_DCHECKS_ARE_ON() + if (!out_of_flow_items.empty()) { + // Check the BiDi level for OOF items are set correctly. + DCHECK(RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()); + DCHECK_EQ(out_of_flow_item_index, out_of_flow_items.size() - 1); + out_of_flow_item_index = 0; + for (const auto item_ptr : items) { + const InlineItem& item = *item_ptr; + if (item.IsFloatingOrOutOfFlowPositioned()) { + DCHECK_EQ(item.BidiLevel(), + out_of_flow_items[out_of_flow_item_index].level); + ++out_of_flow_item_index; + } + } + } + // Check all items have bidi levels, except trailing non-length items. // Items that do not create break opportunities such as kOutOfFlowPositioned // do not have corresponding characters, and that they do not have bidi level @@ -1321,7 +1405,7 @@ item_index++; } DCHECK_EQ(item_index, items.size()); -#endif +#endif // EXPENSIVE_DCHECKS_ARE_ON() } bool InlineNode::IsNGShapeCacheAllowed(
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node_data.cc b/third_party/blink/renderer/core/layout/inline/inline_node_data.cc index b22fdec6..50862514 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_node_data.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_node_data.cc
@@ -8,6 +8,11 @@ namespace blink { +void InlineNodeData::DisableBidi() { + is_bidi_enabled_ = false; + SetBaseDirection(TextDirection::kLtr); +} + void InlineNodeData::Trace(Visitor* visitor) const { visitor->Trace(first_line_items_); visitor->Trace(svg_node_data_);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node_data.h b/third_party/blink/renderer/core/layout/inline/inline_node_data.h index 681c6eb..b092cc5f 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_node_data.h +++ b/third_party/blink/renderer/core/layout/inline/inline_node_data.h
@@ -25,8 +25,13 @@ TextDirection BaseDirection() const { return static_cast<TextDirection>(base_direction_); } + void DisableBidi(); bool HasFloats() const { return has_floats_; } + bool HasOutOfFlowPositioned() const { return has_out_of_flow_positioned_; } + bool HasFloatingOrOutOfFlowPositioned() const { + return HasFloats() || HasOutOfFlowPositioned(); + } bool HasInitialLetterBox() const { return has_initial_letter_box_; } bool HasRuby() const { return has_ruby_; } @@ -79,6 +84,7 @@ unsigned base_direction_ : 1; // TextDirection unsigned has_floats_ : 1; + unsigned has_out_of_flow_positioned_ : 1; // True if this node contains initial letter box. This value is used for // clearing. To control whether subsequent blocks overlap with initial
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node_test.cc b/third_party/blink/renderer/core/layout/inline/inline_node_test.cc index f64db41..270699e5 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_node_test.cc
@@ -233,15 +233,25 @@ "</div>"); InlineNodeForTest node = CreateInlineNode(); node.CollectInlines(); - EXPECT_EQ("abc\uFFFCghi\uFFFCmno", node.Text()) + EXPECT_EQ(RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled() + ? "abcghimno" + : "abc\uFFFCghi\uFFFCmno", + node.Text()) << "floats are appeared as an object replacement character"; InlineItems& items = node.Items(); ASSERT_EQ(5u, items.size()); TEST_ITEM_TYPE_OFFSET(items[0], kText, 0u, 3u); - TEST_ITEM_TYPE_OFFSET(items[1], kFloating, 3u, 4u); - TEST_ITEM_TYPE_OFFSET(items[2], kText, 4u, 7u); - TEST_ITEM_TYPE_OFFSET(items[3], kFloating, 7u, 8u); - TEST_ITEM_TYPE_OFFSET(items[4], kText, 8u, 11u); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + TEST_ITEM_TYPE_OFFSET(items[1], kFloating, 3u, 3u); + TEST_ITEM_TYPE_OFFSET(items[2], kText, 3u, 6u); + TEST_ITEM_TYPE_OFFSET(items[3], kFloating, 6u, 6u); + TEST_ITEM_TYPE_OFFSET(items[4], kText, 6u, 9u); + } else { + TEST_ITEM_TYPE_OFFSET(items[1], kFloating, 3u, 4u); + TEST_ITEM_TYPE_OFFSET(items[2], kText, 4u, 7u); + TEST_ITEM_TYPE_OFFSET(items[3], kFloating, 7u, 8u); + TEST_ITEM_TYPE_OFFSET(items[4], kText, 8u, 11u); + } } TEST_F(InlineNodeTest, CollectInlinesInlineBlock) { @@ -1476,7 +1486,11 @@ "</div>"); GetElementById("remove")->remove(); UpdateAllLifecyclePhasesForTest(); - EXPECT_EQ(String(u"abc \uFFFCx"), GetText()); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + EXPECT_EQ(String(u"abc x"), GetText()); + } else { + EXPECT_EQ(String(u"abc \uFFFCx"), GetText()); + } } // https://crbug.com/109654
diff --git a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc index ff7375ca..1ad7b27 100644 --- a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc +++ b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
@@ -624,6 +624,7 @@ } levels.push_back(item.bidi_level); } + DCHECK_EQ(line_box->size(), levels.size()); // For opaque items, copy bidi levels from adjacent items. if (has_opaque_items) {
diff --git a/third_party/blink/renderer/core/layout/inline/offset_mapping_test.cc b/third_party/blink/renderer/core/layout/inline/offset_mapping_test.cc index f87bbc9..f0aafd05 100644 --- a/third_party/blink/renderer/core/layout/inline/offset_mapping_test.cc +++ b/third_party/blink/renderer/core/layout/inline/offset_mapping_test.cc
@@ -936,8 +936,13 @@ const OffsetMapping& remaining_text_result = *mapping1; ASSERT_EQ(1u, remaining_text_result.GetUnits().size()); - TEST_UNIT(remaining_text_result.GetUnits()[0], - OffsetMappingUnitType::kIdentity, text_node, 1u, 3u, 1u, 3u); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + TEST_UNIT(remaining_text_result.GetUnits()[0], + OffsetMappingUnitType::kIdentity, text_node, 1u, 3u, 0u, 2u); + } else { + TEST_UNIT(remaining_text_result.GetUnits()[0], + OffsetMappingUnitType::kIdentity, text_node, 1u, 3u, 1u, 3u); + } ASSERT_EQ(1u, remaining_text_result.GetRanges().size()); TEST_RANGE(remaining_text_result.GetRanges(), text_node, 0u, 1u); @@ -956,17 +961,34 @@ EXPECT_EQ(0u, *first_letter_result.GetTextContentOffset(Position(text_node, 0))); - EXPECT_EQ( - 1u, *remaining_text_result.GetTextContentOffset(Position(text_node, 1))); - EXPECT_EQ( - 2u, *remaining_text_result.GetTextContentOffset(Position(text_node, 2))); - EXPECT_EQ( - 3u, *remaining_text_result.GetTextContentOffset(Position(text_node, 3))); + + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + EXPECT_EQ(0u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 1))); + EXPECT_EQ(1u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 2))); + EXPECT_EQ(2u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 3))); + } else { + EXPECT_EQ(1u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 1))); + EXPECT_EQ(2u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 2))); + EXPECT_EQ(3u, *remaining_text_result.GetTextContentOffset( + Position(text_node, 3))); + } EXPECT_EQ(Position(text_node, 1), first_letter_result.GetFirstPosition(1)); EXPECT_EQ(Position(text_node, 1), first_letter_result.GetLastPosition(1)); - EXPECT_EQ(Position(text_node, 1), remaining_text_result.GetFirstPosition(1)); - EXPECT_EQ(Position(text_node, 1), remaining_text_result.GetLastPosition(1)); + if (RuntimeEnabledFeatures::LineBreakOofNoOrcEnabled()) { + EXPECT_EQ(Position(text_node, 1), + remaining_text_result.GetFirstPosition(0)); + EXPECT_EQ(Position(text_node, 1), remaining_text_result.GetLastPosition(0)); + } else { + EXPECT_EQ(Position(text_node, 1), + remaining_text_result.GetFirstPosition(1)); + EXPECT_EQ(Position(text_node, 1), remaining_text_result.GetLastPosition(1)); + } } TEST_F(OffsetMappingTest, WhiteSpaceTextNodeWithoutLayoutText) {
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc index 417b86cf..b96e6e91 100644 --- a/third_party/blink/renderer/core/layout/layout_image.cc +++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -281,6 +281,16 @@ void LayoutImage::Paint(const PaintInfo& paint_info) const { NOT_DESTROYED(); ImagePainter(*this).Paint(paint_info); + + if (image_resource_ && image_resource_->MaybeAnimated()) { + if (const auto* cached_image = image_resource_->CachedImage(); + cached_image && (cached_image->NumberOfObservers() > 2)) { + // Images have 2 observers HTMLImageLoader and LayoutImage, when they're + // repeated in the same document they'll have more than 2. + UseCounter::Count(GetDocument(), + WebFeature::kAnimatedImageUsedMoreThanOnce); + } + } } void LayoutImage::AreaElementFocusChanged(HTMLAreaElement* area_element) {
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/third_party/blink/renderer/core/loader/resource/image_resource_content.h index ff9ab3b..0cef5da 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_content.h +++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -206,6 +206,9 @@ bool HasObservers() const { return !observers_.empty() || !finished_observers_.empty(); } + wtf_size_t NumberOfObservers() const { + return observers_.size() + finished_observers_.size(); + } bool CanBeSpeculativelyDecoded() const; ImageDecoder::CompressionFormat GetCompressionFormat() const;
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h index e358b59c..5763b64 100644 --- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h +++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -128,7 +128,7 @@ transfer_to_gpu_texture_was_invoked_ = true; } std::unique_ptr<CanvasResourceProvider> ReplaceResourceProviderForCanvas2D( - std::unique_ptr<CanvasResourceProvider>) override; + std::unique_ptr<CanvasResourceProvider>); void DiscardResources() override; CanvasResourceProvider* GetResourceProviderForCanvas2D() const override { CHECK(IsRenderingContext2D());
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc index d43ec16..858ab092 100644 --- a/third_party/blink/renderer/core/page/create_window.cc +++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -161,7 +161,7 @@ value_string == "true") { value = 1; } else { - value = CharactersToInt(value_string, WTF::NumberParsingOptions::Loose(), + value = CharactersToInt(value_string, NumberParsingOptions::Loose(), /*ok=*/nullptr); }
diff --git a/third_party/blink/renderer/core/streams/readable_stream.idl b/third_party/blink/renderer/core/streams/readable_stream.idl index d5f1bc5f..141cce37 100644 --- a/third_party/blink/renderer/core/streams/readable_stream.idl +++ b/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -12,7 +12,7 @@ [ Exposed=* ] interface ReadableStream { - [RuntimeEnabled=ReadableStreamAsyncIterable, HasAsyncIteratorReturnAlgorithm] async iterable<any>(optional ReadableStreamIteratorOptions options = {}); + [HasAsyncIteratorReturnAlgorithm] async iterable<any>(optional ReadableStreamIteratorOptions options = {}); [CallWith=ScriptState, RaisesException] constructor(optional any underlyingSource, optional any strategy); readonly attribute boolean locked;
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern.cc b/third_party/blink/renderer/core/url_pattern/url_pattern.cc index 9cff9c4..67482209 100644 --- a/third_party/blink/renderer/core/url_pattern/url_pattern.cc +++ b/third_party/blink/renderer/core/url_pattern/url_pattern.cc
@@ -80,7 +80,7 @@ return false; bool port_ok = false; - int port_number = port.Impl()->ToInt(WTF::NumberParsingOptions(), &port_ok); + int port_number = port.Impl()->ToInt(NumberParsingOptions(), &port_ok); if (!port_ok) return false;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 22384cb..c2290dc3 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -292,7 +292,7 @@ !host) { return; } - DCHECK(!host->GetResourceProviderForCanvas2D()); + DCHECK(!GetResourceProviderForCanvas2D()); if (host->IsValidImageSize()) { if (dispatch_context_lost_event_timer_.IsActive()) { @@ -784,7 +784,7 @@ } bool BaseRenderingContext2D::IsAccelerated() const { - auto* resource_provider = Host()->GetResourceProviderForCanvas2D(); + auto* resource_provider = GetResourceProviderForCanvas2D(); return resource_provider ? resource_provider->IsAccelerated() : Host()->ShouldTryToUseGpuRaster(); } @@ -802,7 +802,7 @@ BaseRenderingContext2D::PaintRenderingResultsToSnapshot( SourceDrawingBuffer source_buffer, FlushReason reason) { - CanvasResourceProvider* provider = Host()->GetResourceProviderForCanvas2D(); + CanvasResourceProvider* provider = GetResourceProviderForCanvas2D(); return provider ? provider->Snapshot(reason) : nullptr; } @@ -1509,7 +1509,7 @@ gpu::SyncToken canvas_access_sync_token; bool performed_copy = false; scoped_refptr<gpu::ClientSharedImage> client_si = - host->GetResourceProviderForCanvas2D() + GetResourceProviderForCanvas2D() ->GetBackingClientSharedImageForExternalWrite( &canvas_access_sync_token, gpu::SHARED_IMAGE_USAGE_WEBGPU_READ | @@ -1556,7 +1556,7 @@ // It also gives us a mechanism to detect post-transfer-out draws, which is // used in `transferBackFromWebGPU` to raise an exception. resource_provider_from_webgpu_access_ = - host->ReplaceResourceProviderForCanvas2D(nullptr); + ReplaceResourceProviderForCanvas2D(nullptr); // The user isn't obligated to ever transfer back, which means this resource // provider might stick around for while. Jettison any unnecessary resources. @@ -1592,7 +1592,7 @@ // If this canvas already has a resource provider, this means that drawing has // occurred after `transferToWebGPU`. We disallow transferring back in this // case, and raise an exception instead. - if (host->GetResourceProviderForCanvas2D()) { + if (GetResourceProviderForCanvas2D()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, "The canvas was touched after transferToGPUTexture."); @@ -1615,7 +1615,7 @@ // surrendering our temporary ownership of the provider. CanvasResourceProvider* resource_provider = resource_provider_from_webgpu_access_.get(); - host->ReplaceResourceProviderForCanvas2D( + ReplaceResourceProviderForCanvas2D( std::move(resource_provider_from_webgpu_access_)); resource_provider->SetDelegate(host);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index a10a2b1..7179a09 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -273,7 +273,11 @@ void TryRestoreContextEvent(TimerBase*); void RestoreFromInvalidSizeIfNeeded() override; + virtual CanvasResourceProvider* GetResourceProviderForCanvas2D() const = 0; virtual CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() = 0; + virtual std::unique_ptr<CanvasResourceProvider> + ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider>) = 0; static const char kInheritString[];
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc index 26403a9..eefee3a 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc
@@ -169,6 +169,10 @@ return true; } + CanvasResourceProvider* GetResourceProviderForCanvas2D() const override { + return nullptr; + } + CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() override { return nullptr; } @@ -177,6 +181,10 @@ scoped_refptr<StaticBitmapImage> GetImage(FlushReason) override { return nullptr; } + std::unique_ptr<CanvasResourceProvider> ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider>) override { + return nullptr; + } bool IsComposited() const override { return false; } bool IsPaintable() const override { return true; }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index dd19ad4..5dadd6ea 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -285,7 +285,7 @@ recorder.RestartRecording(); } } else { - host->FlushRecordingForCanvas2D(FlushReason::kWritePixels); + provider->FlushCanvas(FlushReason::kWritePixels); // Short-circuit out if an error occurred while flushing the recording. if (!provider->IsValid()) { @@ -685,7 +685,7 @@ if (!provider) { return nullptr; } - Host()->FlushRecordingForCanvas2D(reason); + provider->FlushCanvas(reason); return provider->Snapshot(reason); } @@ -881,7 +881,7 @@ HTMLCanvasElement* host = canvas(); CHECK(host); - host->FlushRecordingForCanvas2D(reason); + GetResourceProviderForCanvas2D()->FlushCanvas(reason); if (reason == FlushReason::kCanvasPushFrame) { if (host->IsDisplayed()) { // Make sure the GPU is never more than two animation frames behind. @@ -1126,6 +1126,11 @@ } CanvasResourceProvider* +CanvasRenderingContext2D::GetResourceProviderForCanvas2D() const { + return Host()->GetResourceProviderForCanvas2D(); +} + +CanvasResourceProvider* CanvasRenderingContext2D::GetOrCreateCanvas2DResourceProvider() { HTMLCanvasElement* const element = canvas(); if (!element) [[unlikely]] { @@ -1134,4 +1139,10 @@ return element->GetOrCreateCanvasResourceProviderForCanvas2D(); } +std::unique_ptr<CanvasResourceProvider> +CanvasRenderingContext2D::ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider> provider) { + return canvas()->ReplaceResourceProviderForCanvas2D(std::move(provider)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h index 52d14bc..57d80b1 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -29,6 +29,7 @@ #include <stddef.h> +#include <memory> #include <optional> #include "base/check.h" @@ -317,7 +318,10 @@ void ColorSchemeMayHaveChanged() override; + CanvasResourceProvider* GetResourceProviderForCanvas2D() const override; CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() override; + std::unique_ptr<CanvasResourceProvider> ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider>) override; FilterOperations filter_operations_; HashMap<String, FontDescription> fonts_resolved_using_current_style_;
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc index 1d8a92a..abbdaa2 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -133,7 +133,7 @@ if (!GetOrCreateCanvas2DResourceProvider()) { return; } - Host()->FlushRecordingForCanvas2D(reason); + GetResourceProviderForCanvas2D()->FlushCanvas(reason); } // BaseRenderingContext2D implementation @@ -172,8 +172,7 @@ return nullptr; } - if (CanvasResourceProvider* provider = - host->GetResourceProviderForCanvas2D()) { + if (CanvasResourceProvider* provider = GetResourceProviderForCanvas2D()) { if (!provider->IsValid()) { // The canvas context is not lost but the provider is invalid. This // happens if the GPU process dies in the middle of a render task. The @@ -251,21 +250,27 @@ host->SetResourceProviderForCanvas2D(std::move(provider)); - if (host->GetResourceProviderForCanvas2D() && - host->GetResourceProviderForCanvas2D()->IsValid()) { + if (GetResourceProviderForCanvas2D() && + GetResourceProviderForCanvas2D()->IsValid()) { base::UmaHistogramBoolean( "Blink.Canvas.ResourceProviderIsAccelerated", - host->GetResourceProviderForCanvas2D()->IsAccelerated()); - base::UmaHistogramEnumeration( - "Blink.Canvas.ResourceProviderType", - host->GetResourceProviderForCanvas2D()->GetType()); + GetResourceProviderForCanvas2D()->IsAccelerated()); + base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType", + GetResourceProviderForCanvas2D()->GetType()); host->DidDraw(); } - return host->GetResourceProviderForCanvas2D(); + return GetResourceProviderForCanvas2D(); +} + +std::unique_ptr<CanvasResourceProvider> +OffscreenCanvasRenderingContext2D::ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider> provider) { + return HostAsOffscreenCanvas()->ReplaceResourceProviderForCanvas2D( + std::move(provider)); } CanvasResourceProvider* -OffscreenCanvasRenderingContext2D::GetCanvasResourceProvider() const { +OffscreenCanvasRenderingContext2D::GetResourceProviderForCanvas2D() const { return Host()->GetResourceProviderForCanvas2D(); } @@ -351,7 +356,7 @@ if (!IsPaintable()) return nullptr; scoped_refptr<StaticBitmapImage> image = - GetCanvasResourceProvider()->Snapshot(reason); + GetResourceProviderForCanvas2D()->Snapshot(reason); return image; } @@ -382,7 +387,7 @@ if (!is_valid_size_ || isContextLost()) [[unlikely]] { return nullptr; } - CanvasResourceProvider* const provider = GetCanvasResourceProvider(); + CanvasResourceProvider* const provider = GetResourceProviderForCanvas2D(); if (provider == nullptr) [[unlikely]] { return nullptr; } @@ -391,7 +396,7 @@ const MemoryManagedPaintRecorder* OffscreenCanvasRenderingContext2D::Recorder() const { - const CanvasResourceProvider* provider = GetCanvasResourceProvider(); + const CanvasResourceProvider* provider = GetResourceProviderForCanvas2D(); if (provider == nullptr) [[unlikely]] { return nullptr; } @@ -409,8 +414,7 @@ } else { Host()->DidDraw(dirty_rect_for_commit_); } - if (CanvasResourceProvider* provider = - Host()->GetResourceProviderForCanvas2D(); + if (CanvasResourceProvider* provider = GetResourceProviderForCanvas2D(); layer_count_ == 0 && provider != nullptr) [[likely]] { // TODO(crbug.com/1246486): Make auto-flushing layer friendly. provider->FlushIfRecordingLimitExceeded(); @@ -436,7 +440,7 @@ } bool OffscreenCanvasRenderingContext2D::IsPaintable() const { - return Host()->GetResourceProviderForCanvas2D(); + return GetResourceProviderForCanvas2D(); } bool OffscreenCanvasRenderingContext2D::WritePixels( @@ -447,15 +451,15 @@ int y) { DCHECK(IsCanvas2DBufferValid()); - Host()->FlushRecordingForCanvas2D(FlushReason::kWritePixels); + GetResourceProviderForCanvas2D()->FlushCanvas(FlushReason::kWritePixels); // Short-circuit out if an error occurred while flushing the recording. - if (!Host()->GetResourceProviderForCanvas2D()->IsValid()) { + if (!GetResourceProviderForCanvas2D()->IsValid()) { return false; } - return Host()->GetResourceProviderForCanvas2D()->WritePixels( - orig_info, pixels, row_bytes, x, y); + return GetResourceProviderForCanvas2D()->WritePixels(orig_info, pixels, + row_bytes, x, y); } bool OffscreenCanvasRenderingContext2D::ResolveFont(const String& new_font) { @@ -486,13 +490,13 @@ bool OffscreenCanvasRenderingContext2D::IsCanvas2DBufferValid() { if (IsPaintable()) - return GetCanvasResourceProvider()->IsValid(); + return GetResourceProviderForCanvas2D()->IsValid(); return false; } std::optional<cc::PaintRecord> OffscreenCanvasRenderingContext2D::FlushCanvas( FlushReason reason) { - if (CanvasResourceProvider* provider = GetCanvasResourceProvider()) + if (CanvasResourceProvider* provider = GetResourceProviderForCanvas2D()) [[likely]] { return provider->FlushCanvas(reason); }
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h index 7ac5a50..9483efb 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -5,6 +5,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_OFFSCREENCANVAS2D_OFFSCREEN_CANVAS_RENDERING_CONTEXT_2D_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_OFFSCREENCANVAS2D_OFFSCREEN_CANVAS_RENDERING_CONTEXT_2D_H_ +#include <memory> + #include "base/notreached.h" #include "third_party/blink/renderer/core/canvas_interventions/canvas_interventions_enums.h" #include "third_party/blink/renderer/core/html/canvas/canvas_2d_color_params.h" @@ -81,7 +83,7 @@ int Height() const final; bool CanCreateCanvas2dResourceProvider() final; - CanvasResourceProvider* GetCanvasResourceProvider() const; + CanvasResourceProvider* GetResourceProviderForCanvas2D() const override; // Offscreen canvas doesn't have any notion of image orientation. RespectImageOrientationEnum RespectImageOrientation() const final { @@ -163,6 +165,8 @@ scoped_refptr<CanvasResource> ProduceCanvasResource(FlushReason); CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() override; + std::unique_ptr<CanvasResourceProvider> ReplaceResourceProviderForCanvas2D( + std::unique_ptr<CanvasResourceProvider>) override; SkIRect dirty_rect_for_commit_;
diff --git a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist index 63af1543..128c75bb 100644 --- a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist +++ b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
@@ -241,6 +241,7 @@ ../../web_tests/images/resources/animated-10color.gif ../../web_tests/images/resources/animated-gif-with-offsets.gif ../../web_tests/images/resources/animated.gif +../../web_tests/images/resources/animated.png ../../web_tests/images/resources/animated2.gif ../../web_tests/images/resources/apng-test-suite-dispose-op-none-basic.png ../../web_tests/images/resources/apng00.png
diff --git a/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc b/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc index ebabb50f..69a94afc 100644 --- a/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc +++ b/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc
@@ -45,7 +45,7 @@ wtf_size_t end) { return WTF::VisitCharacters( StringView(string, start, end - start), [](auto chars) { - return CharactersToInt(chars, WTF::NumberParsingOptions(), nullptr); + return CharactersToInt(chars, NumberParsingOptions(), nullptr); }); }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h index 8bfa7e58..1ddc927 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
@@ -195,7 +195,7 @@ static bool IsEmptyValue(const SmallStringKey& key) { return key.IsHashTableEmptyValue(); } - static const unsigned kMinimumTableSize = 16; + static const wtf_size_t kMinimumTableSize = 16; }; friend bool operator==(const SmallStringKey&, const SmallStringKey&);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 382c9749..219755b8 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2862,6 +2862,11 @@ base_feature: "none", }, { + // Stop emitting U+FFFC Object Replacement Character for out-of-flow + // objects such as floating or out-of-flow positioned. crbgu.com/40658609 + name: "LineBreakOofNoOrc", + }, + { name: "ListItemWithCounterSetNotSetExplicitValue", status: "stable", }, @@ -3783,10 +3788,6 @@ } }, { - name: "ReadableStreamAsyncIterable", - status: "stable", - }, - { // Enables support for a 'min' option in ReadableStream BYOBReader.read(), // allowing callers to specify the minimum number of bytes to be read into // the buffer before resolving the read request. @@ -4424,6 +4425,10 @@ // Android does not yet support SharedWorker. crbug.com/154571 status: {"Android": "", "default": "stable"}, base_feature: "none", + + // Allow Android to run the origin trial. + origin_trial_feature_name: "SharedWorkerOnAndroid", + origin_trial_os: ["android"], }, { // If enabled, SharedWorker supports extendedLifetime
diff --git a/third_party/blink/renderer/platform/text/bidi_paragraph.cc b/third_party/blink/renderer/platform/text/bidi_paragraph.cc index f27f4f40..93b1e0a 100644 --- a/third_party/blink/renderer/platform/text/bidi_paragraph.cc +++ b/third_party/blink/renderer/platform/text/bidi_paragraph.cc
@@ -14,8 +14,9 @@ bool BidiParagraph::SetParagraph(const String& text, std::optional<TextDirection> base_direction) { DCHECK(!text.IsNull()); - DCHECK(!ubidi_); - ubidi_ = UBidiPtr(ubidi_open()); + if (!ubidi_) { + ubidi_ = UBidiPtr(ubidi_open()); + } UBiDiLevel para_level; if (base_direction) {
diff --git a/third_party/blink/renderer/platform/wtf/hash_counted_set.h b/third_party/blink/renderer/platform/wtf/hash_counted_set.h index 1be7295..c4abeada 100644 --- a/third_party/blink/renderer/platform/wtf/hash_counted_set.h +++ b/third_party/blink/renderer/platform/wtf/hash_counted_set.h
@@ -56,8 +56,8 @@ void swap(HashCountedSet& other) { impl_.swap(other.impl_); } - unsigned size() const { return impl_.size(); } - unsigned Capacity() const { return impl_.capacity(); } + wtf_size_t size() const { return impl_.size(); } + wtf_size_t Capacity() const { return impl_.capacity(); } bool empty() const { return impl_.empty(); } // Iterators iterate over pairs of values (called key) and counts (called
diff --git a/third_party/blink/renderer/platform/wtf/hash_map.h b/third_party/blink/renderer/platform/wtf/hash_map.h index b52171d..f616814c 100644 --- a/third_party/blink/renderer/platform/wtf/hash_map.h +++ b/third_party/blink/renderer/platform/wtf/hash_map.h
@@ -144,7 +144,7 @@ wtf_size_t size() const; wtf_size_t Capacity() const; - void ReserveCapacityForSize(unsigned size) { + void ReserveCapacityForSize(wtf_size_t size) { impl_.ReserveCapacityForSize(size); }
diff --git a/third_party/blink/renderer/platform/wtf/hash_set.h b/third_party/blink/renderer/platform/wtf/hash_set.h index 77c222a..47c38fa 100644 --- a/third_party/blink/renderer/platform/wtf/hash_set.h +++ b/third_party/blink/renderer/platform/wtf/hash_set.h
@@ -88,11 +88,11 @@ void swap(HashSet& ref) { impl_.swap(ref.impl_); } - unsigned size() const; - unsigned Capacity() const; + wtf_size_t size() const; + wtf_size_t Capacity() const; bool empty() const; - void ReserveCapacityForSize(unsigned size) { + void ReserveCapacityForSize(wtf_size_t size) { impl_.ReserveCapacityForSize(size); } @@ -267,12 +267,12 @@ } template <typename T, typename U, typename V> -inline unsigned HashSet<T, U, V>::size() const { +inline wtf_size_t HashSet<T, U, V>::size() const { return impl_.size(); } template <typename T, typename U, typename V> -inline unsigned HashSet<T, U, V>::Capacity() const { +inline wtf_size_t HashSet<T, U, V>::Capacity() const { return impl_.Capacity(); }
diff --git a/third_party/blink/renderer/platform/wtf/hash_set_test.cc b/third_party/blink/renderer/platform/wtf/hash_set_test.cc index 6ac25d2..aef07c4 100644 --- a/third_party/blink/renderer/platform/wtf/hash_set_test.cc +++ b/third_party/blink/renderer/platform/wtf/hash_set_test.cc
@@ -113,11 +113,11 @@ EXPECT_EQ(1U, set.size()); } -template <unsigned size> +template <wtf_size_t size> void TestReserveCapacity(); template <> void TestReserveCapacity<0>() {} -template <unsigned size> +template <wtf_size_t size> void TestReserveCapacity() { HashSet<int> test_set; @@ -125,8 +125,8 @@ EXPECT_EQ(0UL, test_set.Capacity()); test_set.ReserveCapacityForSize(size); - const unsigned initial_capacity = test_set.Capacity(); - const unsigned kMinimumTableSize = HashTraits<int>::kMinimumTableSize; + const wtf_size_t initial_capacity = test_set.Capacity(); + constexpr wtf_size_t kMinimumTableSize = HashTraits<int>::kMinimumTableSize; // reserveCapacityForSize should respect minimumTableSize. EXPECT_GE(initial_capacity, kMinimumTableSize); @@ -139,7 +139,7 @@ // Adding items up to less than half the capacity should not change the // capacity. - unsigned capacity_limit = initial_capacity / 2 - 1; + wtf_size_t capacity_limit = initial_capacity / 2 - 1; for (wtf_size_t i = size; i < capacity_limit; ++i) { test_set.insert(i + 1); EXPECT_EQ(initial_capacity, test_set.Capacity());
diff --git a/third_party/blink/renderer/platform/wtf/hash_table.h b/third_party/blink/renderer/platform/wtf/hash_table.h index 6e7e3b6..7e168e5 100644 --- a/third_party/blink/renderer/platform/wtf/hash_table.h +++ b/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -41,6 +41,7 @@ #include "third_party/blink/renderer/platform/wtf/construct_traits.h" #include "third_party/blink/renderer/platform/wtf/hash_traits.h" #include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" #if !defined(DUMP_HASHTABLE_STATS) #define DUMP_HASHTABLE_STATS 0 @@ -690,11 +691,11 @@ return MakeKnownGoodConstIterator(table_ + table_size_); } - unsigned size() const { + wtf_size_t size() const { DCHECK(!AccessForbidden()); return key_count_; } - unsigned Capacity() const { + wtf_size_t Capacity() const { DCHECK(!AccessForbidden()); return table_size_; } @@ -703,7 +704,7 @@ return !key_count_; } - void ReserveCapacityForSize(unsigned size); + void ReserveCapacityForSize(wtf_size_t size); template <typename IncomingValueType> AddResult insert(IncomingValueType&& value) { @@ -812,8 +813,8 @@ requires Allocator::kIsGarbageCollected; private: - static ValueType* AllocateTable(unsigned size); - static void DeleteAllBucketsAndDeallocate(ValueType* table, unsigned size); + static ValueType* AllocateTable(wtf_size_t size); + static void DeleteAllBucketsAndDeallocate(ValueType* table, wtf_size_t size); struct LookupResult { ValueType* entry; @@ -841,11 +842,11 @@ ValueType* Expand(ValueType* entry = nullptr); void Shrink() { Rehash(table_size_ / 2, nullptr); } - ValueType* ExpandBuffer(unsigned new_table_size, ValueType* entry, bool&); + ValueType* ExpandBuffer(wtf_size_t new_table_size, ValueType* entry, bool&); ValueType* RehashTo(ValueType* new_table, - unsigned new_table_size, + wtf_size_t new_table_size, ValueType* entry); - ValueType* Rehash(unsigned new_table_size, ValueType* entry); + ValueType* Rehash(wtf_size_t new_table_size, ValueType* entry); ValueType* Reinsert(ValueType&&); static void ReinitializeBucket(ValueType& bucket); @@ -890,32 +891,18 @@ // Constructor for hash tables with raw storage. struct RawStorageTag {}; - HashTable(RawStorageTag, ValueType* table, unsigned size) - : table_(table), - table_size_(size), - key_count_(0), - deleted_count_(0) -#if DCHECK_IS_ON() - , - access_forbidden_(0), - modifications_(0) -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - , - stats_(nullptr) -#endif - { - } + HashTable(RawStorageTag, ValueType* table, wtf_size_t size) + : table_(table), table_size_(size) {} ValueType* table_; - unsigned table_size_; - unsigned key_count_; + wtf_size_t table_size_; + wtf_size_t key_count_ = 0; #if DCHECK_IS_ON() - unsigned deleted_count_ : 30; - unsigned access_forbidden_ : 1; - unsigned modifications_; + wtf_size_t deleted_count_ : 30 = 0; + wtf_size_t access_forbidden_ : 1 = 0; + wtf_size_t modifications_ = 0; #else - unsigned deleted_count_ : 31; + wtf_size_t deleted_count_ : 31 = 0; #endif #if DUMP_HASHTABLE_STATS_PER_TABLE @@ -923,7 +910,8 @@ mutable typename std::conditional<Allocator::kIsGarbageCollected, HashTableStats*, - std::unique_ptr<HashTableStats>>::type stats_; + std::unique_ptr<HashTableStats>>::type stats_ = + nullptr; void DumpStats() { if (stats_) { stats_->DumpStats(); @@ -984,9 +972,10 @@ { } -inline unsigned CalculateCapacity(unsigned size) { - for (unsigned mask = size; mask; mask >>= 1) +inline wtf_size_t CalculateCapacity(wtf_size_t size) { + for (wtf_size_t mask = size; mask; mask >>= 1) { size |= mask; // 00110101010 -> 00111111111 + } return (size + 1) * 2; // 00111111111 -> 10000000000 } @@ -996,14 +985,9 @@ typename Traits, typename KeyTraits, typename Allocator> -void HashTable<Key, - Value, - Extractor, - - Traits, - KeyTraits, - Allocator>::ReserveCapacityForSize(unsigned new_size) { - unsigned new_capacity = CalculateCapacity(new_size); +void HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>:: + ReserveCapacityForSize(wtf_size_t new_size) { + wtf_size_t new_capacity = CalculateCapacity(new_size); if (new_capacity < KeyTraits::kMinimumTableSize) new_capacity = KeyTraits::kMinimumTableSize; @@ -1152,7 +1136,7 @@ } template <typename HashTable> - static Value* AllocateTable(unsigned size, size_t alloc_size) { + static Value* AllocateTable(wtf_size_t size, size_t alloc_size) { Value* result = Allocator::template AllocateHashTableBacking<Value, HashTable>( alloc_size); @@ -1160,8 +1144,8 @@ return result; } - static void InitializeTable(Value* table, unsigned size) { - for (unsigned i = 0; i < size; i++) { + static void InitializeTable(Value* table, wtf_size_t size) { + for (wtf_size_t i = 0; i < size; i++) { Reinitialize(table[i]); } } @@ -1185,7 +1169,7 @@ } template <typename HashTable> - static Value* AllocateTable(unsigned size, size_t alloc_size) { + static Value* AllocateTable(wtf_size_t size, size_t alloc_size) { Value* result = Allocator::template AllocateZeroedHashTableBacking<Value, HashTable>( alloc_size); @@ -1193,15 +1177,15 @@ return result; } - static void InitializeTable(Value* table, unsigned size) { + static void InitializeTable(Value* table, wtf_size_t size) { AtomicMemzero(table, size * sizeof(Value)); CheckEmptyValues(table, size); } private: - static void CheckEmptyValues(Value* values, unsigned size) { + static void CheckEmptyValues(Value* values, wtf_size_t size) { #if EXPENSIVE_DCHECKS_ARE_ON() - for (unsigned i = 0; i < size; i++) { + for (wtf_size_t i = 0; i < size; i++) { DCHECK(IsHashTraitsEmptyValue<Traits>(values[i])); } #endif @@ -1498,7 +1482,7 @@ RegisterModification(); EnterAccessForbiddenScope(); - for (unsigned i = 0; i < table_size_; ++i) { + for (wtf_size_t i = 0; i < table_size_; ++i) { if (!IsEmptyOrDeletedBucket(table_[i]) && pred(table_[i])) { DeleteBucket(table_[i]); #if DUMP_HASHTABLE_STATS @@ -1568,7 +1552,7 @@ typename Allocator> Value* HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::AllocateTable( - unsigned size) { + wtf_size_t size) { // Assert that we will not use memset on things with a vtable entry. The // compiler will also check this on some platforms. We would like to check // this on the whole value (key-value pair), but std::is_polymorphic will @@ -1597,7 +1581,7 @@ typename KeyTraits, typename Allocator> void HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>:: - DeleteAllBucketsAndDeallocate(ValueType* table, unsigned size) { + DeleteAllBucketsAndDeallocate(ValueType* table, wtf_size_t size) { // We delete a bucket in the following cases: // - It is not trivially destructible. // - The table is weak (thus garbage collected) and we are currently marking. @@ -1609,7 +1593,7 @@ !std::is_trivially_destructible<ValueType>::value || (WTF::IsWeak<ValueType>::value && Allocator::IsIncrementalMarking()); if (needs_bucket_deletion) { - for (unsigned i = 0; i < size; ++i) { + for (wtf_size_t i = 0; i < size; ++i) { // This code is called when the hash table is cleared or resized. We // have allocated a new backing store and we need to run the // destructors on the old backing store, as it is being freed. If we @@ -1638,7 +1622,7 @@ typename Allocator> Value* HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::Expand( Value* entry) { - unsigned new_size; + wtf_size_t new_size; if (!table_size_) { new_size = KeyTraits::kMinimumTableSize; } else if (MustRehashInPlace()) { @@ -1659,7 +1643,7 @@ typename Allocator> Value* HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::ExpandBuffer( - unsigned new_table_size, + wtf_size_t new_table_size, Value* entry, bool& success) { success = false; @@ -1673,11 +1657,11 @@ success = true; Value* new_entry = nullptr; - unsigned old_table_size = table_size_; + wtf_size_t old_table_size = table_size_; ValueType* original_table = table_; ValueType* temporary_table = AllocateTable(old_table_size); - for (unsigned i = 0; i < old_table_size; i++) { + for (wtf_size_t i = 0; i < old_table_size; i++) { if (&table_[i] == entry) new_entry = &temporary_table[i]; if (IsEmptyOrDeletedBucket(table_[i])) { @@ -1709,7 +1693,7 @@ typename Allocator> Value* HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::RehashTo( ValueType* new_table, - unsigned new_table_size, + wtf_size_t new_table_size, Value* entry) { #if DUMP_HASHTABLE_STATS if (table_size_ != 0) { @@ -1730,7 +1714,7 @@ #endif Value* new_entry = nullptr; - for (unsigned i = 0; i != table_size_; ++i) { + for (wtf_size_t i = 0; i != table_size_; ++i) { if (IsEmptyOrDeletedBucket(table_[i])) { DCHECK_NE(&table_[i], entry); continue; @@ -1745,7 +1729,7 @@ Allocator::TraceBackingStoreIfMarked(new_hash_table.table_); ValueType* old_table = table_; - unsigned old_table_size = table_size_; + wtf_size_t old_table_size = table_size_; // This swaps the newly allocated buffer with the current one. The store to // the current table has to be atomic to prevent races with concurrent marker. @@ -1779,9 +1763,9 @@ typename KeyTraits, typename Allocator> Value* HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::Rehash( - unsigned new_table_size, + wtf_size_t new_table_size, Value* entry) { - unsigned old_table_size = table_size_; + wtf_size_t old_table_size = table_size_; #if DUMP_HASHTABLE_STATS if (old_table_size != 0) { @@ -1861,7 +1845,7 @@ key_count_ = other.key_count_; deleted_count_ = other.deleted_count_; - for (unsigned i = 0; i < table_size_; i++) { + for (wtf_size_t i = 0; i < table_size_; i++) { if (other.IsEmptyBucket(other.table_[i])) { // Do nothing. All entries are initially empty by AllocateTable(). } else if (other.IsDeletedBucket(other.table_[i])) { @@ -1929,7 +1913,7 @@ std::swap(table_size_, other.table_size_); std::swap(key_count_, other.key_count_); // std::swap does not work for bit fields. - unsigned deleted = deleted_count_; + wtf_size_t deleted = deleted_count_; deleted_count_ = other.deleted_count_; other.deleted_count_ = deleted;
diff --git a/third_party/blink/renderer/platform/wtf/hash_traits.h b/third_party/blink/renderer/platform/wtf/hash_traits.h index 8a8422e..4604401 100644 --- a/third_party/blink/renderer/platform/wtf/hash_traits.h +++ b/third_party/blink/renderer/platform/wtf/hash_traits.h
@@ -36,6 +36,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" namespace WTF { @@ -173,9 +174,9 @@ // The allocation pool for nodes is one big chunk that ASAN has no insight // into, so it can cloak errors. Make it as small as possible to force nodes // to be allocated individually where ASAN can see them. - static constexpr unsigned kMinimumTableSize = 1; + static constexpr wtf_size_t kMinimumTableSize = 1; #else - static constexpr unsigned kMinimumTableSize = 8; + static constexpr wtf_size_t kMinimumTableSize = 8; #endif // The NeedsToForbidGCOnMove flag is used to make the hash table move @@ -519,7 +520,8 @@ return IsHashTraitsDeletedValue<FieldTraits>(value.*field); } - static constexpr unsigned kMinimumTableSize = FieldTraits::kMinimumTableSize; + static constexpr wtf_size_t kMinimumTableSize = + FieldTraits::kMinimumTableSize; template <typename U = void> struct NeedsToForbidGCOnMove {
diff --git a/third_party/blink/renderer/platform/wtf/size_assertions.cc b/third_party/blink/renderer/platform/wtf/size_assertions.cc index 9d61c72..7c5e2584 100644 --- a/third_party/blink/renderer/platform/wtf/size_assertions.cc +++ b/third_party/blink/renderer/platform/wtf/size_assertions.cc
@@ -48,17 +48,17 @@ // Don't add anything here because this should stay small. }; -template <typename T, unsigned inlineCapacity = 0> +template <typename T, wtf_size_t inlineCapacity = 0> struct SameSizeAsVectorWithInlineCapacity; template <typename T> struct SameSizeAsVectorWithInlineCapacity<T, 0> { void* buffer_pointer; - unsigned capacity; - unsigned size; + wtf_size_t capacity; + wtf_size_t size; }; -template <typename T, unsigned inlineCapacity> +template <typename T, wtf_size_t inlineCapacity> struct SameSizeAsVectorWithInlineCapacity { SameSizeAsVectorWithInlineCapacity<T, 0> base_capacity; #if !defined(ANNOTATE_CONTIGUOUS_CONTAINER)
diff --git a/third_party/blink/renderer/platform/wtf/text/number_parsing_options.h b/third_party/blink/renderer/platform/wtf/text/number_parsing_options.h index 3cf6950..d0e7edd 100644 --- a/third_party/blink/renderer/platform/wtf/text/number_parsing_options.h +++ b/third_party/blink/renderer/platform/wtf/text/number_parsing_options.h
@@ -11,18 +11,18 @@ #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -namespace WTF { +namespace blink { // Copyable and immutable object representing number parsing flags. class NumberParsingOptions final { STACK_ALLOCATED(); public: - // 'Strict' behavior for WTF::String. + // 'Strict' behavior for blink::String. static constexpr NumberParsingOptions Strict() { return NumberParsingOptions().SetAcceptLeadingPlus().SetAcceptWhiteSpace(); } - // Non-'Strict' behavior for WTF::String. + // Non-'Strict' behavior for blink::String. static constexpr NumberParsingOptions Loose() { return Strict().SetAcceptTrailingGarbage(); } @@ -77,10 +77,6 @@ unsigned accept_minus_zero_for_unsigned_ : 1; }; -} // namespace WTF - -namespace blink { -using WTF::NumberParsingOptions; -} +} // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_NUMBER_PARSING_OPTIONS_H_
diff --git a/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png-expected.html b/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png-expected.html index 4fc57ea..f033a7b 100644 --- a/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png-expected.html +++ b/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png-expected.html
@@ -4,7 +4,9 @@ <div>This file tests the image pasting functionality of DataTransferItems. To try the test manually, right-click on the image > Copy Image, click anywhere in the background of the main page and paste.</div> -<iframe id="src" src="resources/mozilla.gif"></iframe><br> +<div style="height:150px;"> + <img src="resources/mozilla.gif" style="display:block;"> +</div> <img src="resources/mozilla.gif"> </body> </html>
diff --git a/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png.html b/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png.html index 43c2034..d0d8d7c 100644 --- a/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png.html +++ b/third_party/blink/web_tests/editing/pasteboard/data-transfer-items-image-png.html
@@ -3,27 +3,30 @@ <head> <script src="../editing.js"></script> <script> -function paste(event) +function pasted(event) { var items = event.clipboardData.items; for (var i = 0; i < items.length; ++i) { if (items[i].kind == 'file' && items[i].type == 'image/png') { + let dest = document.createElement("img"); + dest.onload = function() { + if (window.testRunner) { + testRunner.notifyDone(); + } + } var blob = items[i].getAsFile(); var url = window.URL.createObjectURL(blob); - document.getElementById('dest').src = url; + document.body.appendChild(dest); + dest.src = url; + break; } } - window.setTimeout(function () { - if (window.testRunner) - testRunner.notifyDone(); - }, 0); } function runTest() { if (!window.testRunner) return; - testRunner.waitUntilDone(); var srcElement = document.getElementById('src'); srcElement.contentWindow.document.execCommand('copy'); eventSender.mouseMoveTo(1, 1); @@ -31,13 +34,14 @@ eventSender.mouseUp(); document.execCommand('paste'); } + +testRunner.waitUntilDone(); </script> </head> -<body onload="runTest()" onpaste="paste(event)"> +<body onpaste="pasted(event)"> <div>This file tests the image pasting functionality of DataTransferItems. To try the test manually, right-click on the image > Copy Image, click anywhere in the background of the main page and paste.</div> -<iframe id="src" src="resources/mozilla.gif"></iframe><br> -<img id="dest"> +<iframe id="src" src="resources/mozilla.gif" onload="runTest()" style="display:block; border:none;"></iframe> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/white-space-processing-049-ref.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/text/white-space-processing-049-ref.xht index 0903a615..2c61f82 100644 --- a/third_party/blink/web_tests/external/wpt/css/CSS2/text/white-space-processing-049-ref.xht +++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/white-space-processing-049-ref.xht
@@ -9,7 +9,7 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> - <style type="text/css"><![CDATA[ + <style type="text/css"> div { background-color: orange; @@ -18,7 +18,6 @@ padding: 0em 2em; width: 3em; } - ]]> </style> </head> @@ -30,4 +29,4 @@ <div>123</div> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/blink/web_tests/images/animated-images-use-counter-001.html b/third_party/blink/web_tests/images/animated-images-use-counter-001.html new file mode 100644 index 0000000..039e52a --- /dev/null +++ b/third_party/blink/web_tests/images/animated-images-use-counter-001.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<body> +<script> +const kAnimatedImageUsedMoreThanOnce = 5605; + +async_test(function(t) { + internals.clearUseCounter(document, kAnimatedImageUsedMoreThanOnce); + + let gif1 = document.createElement("img"); + gif1.src = "resources/animated.gif"; + document.body.appendChild(gif1); + let gif2 = document.createElement("img"); + gif2.src = "resources/animated.gif"; + document.body.appendChild(gif2); + + onload = t.step_func(() => { + requestAnimationFrame(t.step_func(() => { + requestAnimationFrame(t.step_func_done(() => { + assert_true(internals.isUseCounted(document, kAnimatedImageUsedMoreThanOnce)); + })); + })); + }); +}, 'Check that kAnimatedImageUsedMoreThanOnce is counted with a duplicated animated image'); +</script> +</body>
diff --git a/third_party/blink/web_tests/images/animated-images-use-counter-002.html b/third_party/blink/web_tests/images/animated-images-use-counter-002.html new file mode 100644 index 0000000..42de3798 --- /dev/null +++ b/third_party/blink/web_tests/images/animated-images-use-counter-002.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<body> +<script> +const kAnimatedImageUsedMoreThanOnce = 5605; + +async_test(function(t) { + internals.clearUseCounter(document, kAnimatedImageUsedMoreThanOnce); + + let gif1 = document.createElement("img"); + gif1.src = "resources/animated.gif"; + document.body.appendChild(gif1); + + onload = t.step_func(() => { + requestAnimationFrame(t.step_func(() => { + requestAnimationFrame(t.step_func_done(() => { + assert_false(internals.isUseCounted(document, kAnimatedImageUsedMoreThanOnce)); + })); + })); + }); +}, 'Check that kAnimatedImageUsedMoreThanOnce is NOT counted with a single animated image'); +</script> +</body>
diff --git a/third_party/blink/web_tests/images/animated-images-use-counter-003.html b/third_party/blink/web_tests/images/animated-images-use-counter-003.html new file mode 100644 index 0000000..75a1e3f --- /dev/null +++ b/third_party/blink/web_tests/images/animated-images-use-counter-003.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<body> +<script> +const kAnimatedImageUsedMoreThanOnce = 5605; + +async_test(function(t) { + internals.clearUseCounter(document, kAnimatedImageUsedMoreThanOnce); + + let gif1 = document.createElement("img"); + gif1.src = "resources/animated.gif"; + document.body.appendChild(gif1); + let gif2 = document.createElement("img"); + gif2.src = "resources/animated2.gif"; + document.body.appendChild(gif2); + + onload = t.step_func(() => { + requestAnimationFrame(t.step_func(() => { + requestAnimationFrame(t.step_func_done(() => { + assert_false(internals.isUseCounted(document, kAnimatedImageUsedMoreThanOnce)); + })); + })); + }); +}, 'Check that kAnimatedImageUsedMoreThanOnce is NOT counted with different animated image'); +</script> +</body>
diff --git a/third_party/blink/web_tests/images/animated-images-use-counter-004.html b/third_party/blink/web_tests/images/animated-images-use-counter-004.html new file mode 100644 index 0000000..933fd95 --- /dev/null +++ b/third_party/blink/web_tests/images/animated-images-use-counter-004.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<body> +<script> +const kAnimatedImageUsedMoreThanOnce = 5605; + +async_test(function(t) { + internals.clearUseCounter(document, kAnimatedImageUsedMoreThanOnce); + + let png1 = document.createElement("img"); + png1.src = "resources/png-simple.png"; + document.body.appendChild(png1); + let png2 = document.createElement("img"); + png2.src = "resources/png-simple.png"; + document.body.appendChild(png2); + + onload = t.step_func(() => { + requestAnimationFrame(t.step_func(() => { + requestAnimationFrame(t.step_func_done(() => { + assert_false(internals.isUseCounted(document, kAnimatedImageUsedMoreThanOnce)); + })); + })); + }); +}, 'Check that kAnimatedImageUsedMoreThanOnce is NOT counted with duplicated images not animated'); +</script> +</body>
diff --git a/third_party/blink/web_tests/images/animated-images-use-counter-005.html b/third_party/blink/web_tests/images/animated-images-use-counter-005.html new file mode 100644 index 0000000..7a9c3a8 --- /dev/null +++ b/third_party/blink/web_tests/images/animated-images-use-counter-005.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<body> +<script> +const kAnimatedImageUsedMoreThanOnce = 5605; + +async_test(function(t) { + internals.clearUseCounter(document, kAnimatedImageUsedMoreThanOnce); + + let apng1 = document.createElement("img"); + apng1.src = "resources/animated.png"; + document.body.appendChild(apng1); + let apng2 = document.createElement("img"); + apng2.src = "resources/animated.png"; + document.body.appendChild(apng2); + + onload = t.step_func(() => { + requestAnimationFrame(t.step_func(() => { + requestAnimationFrame(t.step_func_done(() => { + assert_true(internals.isUseCounted(document, kAnimatedImageUsedMoreThanOnce)); + })); + })); + }); +}, 'Check that kAnimatedImageUsedMoreThanOnce is counted with a duplicated animated image (APNG)'); +</script> +</body>
diff --git a/third_party/blink/web_tests/images/resources/animated.png b/third_party/blink/web_tests/images/resources/animated.png new file mode 100644 index 0000000..69f3c05 --- /dev/null +++ b/third_party/blink/web_tests/images/resources/animated.png Binary files differ
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML-expected.txt new file mode 100644 index 0000000..712d7d1 --- /dev/null +++ b/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML-expected.txt
@@ -0,0 +1,38 @@ +Tests how DOM domain works with getOuterHTML. + +getOuterHTML(declarativeId, includeShadowDOM=false): +{ + id : <number> + result : { + outerHTML : <div id="declarative"> </div> + } + sessionId : <string> +} + +getOuterHTML(declarativeId, includeShadowDOM=true): +{ + id : <number> + result : { + outerHTML : <div id="declarative"><template shadowrootmode="open"> <div>contents</div> </template> </div> + } + sessionId : <string> +} + +getOuterHTML(jsId, includeShadowDOM=false): +{ + id : <number> + result : { + outerHTML : <div id="js"> </div> + } + sessionId : <string> +} + +getOuterHTML(jsId, includeShadowDOM=true): +{ + id : <number> + result : { + outerHTML : <div id="js"><template shadowrootmode="open"><div>more contents</div></template> </div> + } + sessionId : <string> +} +
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML.js b/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML.js new file mode 100644 index 0000000..f4beb95a --- /dev/null +++ b/third_party/blink/web_tests/inspector-protocol/dom/getOuterHTML.js
@@ -0,0 +1,41 @@ +(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { + var {page, session, dp} = await testRunner.startHTML( + ` + <div id="declarative"> + <template shadowrootmode="open"> + <div>contents</div> + </template> + </div> + <div id="js"> + </div> + <script> + const div = document.createElement('div'); + div.textContent = 'more contents'; + document.getElementById('js').attachShadow({mode: "open"}).appendChild(div); + </script> + `, + 'Tests how DOM domain works with getOuterHTML.'); + + const {result: {root: {nodeId: docId}}} = await dp.DOM.getDocument(); + const {result: {nodeId: declarativeId}} = + await dp.DOM.querySelector({nodeId: docId, selector: '#declarative'}); + const {result: {nodeId: jsId}} = + await dp.DOM.querySelector({nodeId: docId, selector: '#js'}); + + testRunner.log('\ngetOuterHTML(declarativeId, includeShadowDOM=false):'); + testRunner.log(await dp.DOM.getOuterHTML( + {nodeId: declarativeId, includeShadowDOM: false})); + + testRunner.log('\ngetOuterHTML(declarativeId, includeShadowDOM=true):'); + testRunner.log(await dp.DOM.getOuterHTML( + {nodeId: declarativeId, includeShadowDOM: true})); + + testRunner.log('\ngetOuterHTML(jsId, includeShadowDOM=false):'); + testRunner.log( + await dp.DOM.getOuterHTML({nodeId: jsId, includeShadowDOM: false})); + + testRunner.log('\ngetOuterHTML(jsId, includeShadowDOM=true):'); + testRunner.log( + await dp.DOM.getOuterHTML({nodeId: jsId, includeShadowDOM: true})); + testRunner.completeTest(); +});
diff --git a/third_party/blink/web_tests/webaudio/AudioParam/audioparam-setValueCurve-end.html b/third_party/blink/web_tests/webaudio/AudioParam/audioparam-setValueCurve-end.html index 5ede1750..c9e43f9 100644 --- a/third_party/blink/web_tests/webaudio/AudioParam/audioparam-setValueCurve-end.html +++ b/third_party/blink/web_tests/webaudio/AudioParam/audioparam-setValueCurve-end.html
@@ -1,162 +1,143 @@ <!DOCTYPE html> <html> - <head> - <title> - Test Automation Following setValueCurveAtTime Automations - </title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../resources/audit-util.js"></script> - <script src="../resources/audit.js"></script> - <script src="../resources/audio-param.js"></script> - </head> - <body> - <script id="layout-test-code"> - let sampleRate = 12800; - // Some short duration because we don't need to run the test for very - // long. - let testDurationFrames = 256; - let testDurationSec = testDurationFrames / sampleRate; - let curveDuration = testDurationSec / 2; +<head> + <title>Test Automation Following setValueCurveAtTime Automations</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audio-param.js"></script> +</head> +<body> +<script> + const sampleRate = 12800; - let audit = Audit.createTaskRunner(); + // Short duration since the test doesn't require long audio + const testDurationFrames = 256; + const testDurationSec = testDurationFrames / sampleRate; + const curveDuration = testDurationSec / 2; - // Configuration for each test. - // - // Required options: - // automation - Name of automation method to test - // time - Time for the automation method. - // Optional options: - // extraDuration - extra time for the duration of the setValueCurve - // duration. Default is 0. This should not be on a - // sample frame boundary. This is for testing that - // curves that don't end on a frame boundary are handled - // correctly. - // threshold - Error threshold for the test; default is 0. - let testConfigs = [ - { - automation: 'linearRampToValueAtTime', - time: testDurationSec, - threshold: 3.9737e-8 - }, - { - automation: 'linearRampToValueAtTime', - time: testDurationSec, - extraDuration: 0.5 / sampleRate, - threshold: 1.8141e-8 - }, - { - automation: 'exponentialRampToValueAtTime', - time: testDurationSec, - threshold: 3.9737e-8 - }, - { - automation: 'exponentialRampToValueAtTime', - time: testDurationSec, - extraDuration: 0.5 / sampleRate, - threshold: 7.8294e-8 - }, - { - automation: 'setTargetAtTime', - time: curveDuration, - threshold: 1.5895e-7 - }, - { - automation: 'setTargetAtTime', - time: curveDuration + 0.5 / sampleRate, - extraDuration: 0.5 / sampleRate, - threshold: 1.3278e-7 - } - ]; + // Configuration for each test. + // + // Required options: + // automation - Name of automation method to test + // time - Time for the automation method. + // Optional options: + // extraDuration - extra time for the duration of the setValueCurve + // duration. Default is 0. This should not be on a + // sample frame boundary. This is for testing that + // curves that don't end on a frame boundary are handled + // correctly. + // threshold - Error threshold for the test; default is 0. + const testConfigs = [ + { + automation: 'linearRampToValueAtTime', + time: testDurationSec, + threshold: 3.9737e-8 + }, + { + automation: 'linearRampToValueAtTime', + time: testDurationSec, + extraDuration: 0.5 / sampleRate, + threshold: 1.8141e-8 + }, + { + automation: 'exponentialRampToValueAtTime', + time: testDurationSec, + threshold: 3.9737e-8 + }, + { + automation: 'exponentialRampToValueAtTime', + time: testDurationSec, + extraDuration: 0.5 / sampleRate, + threshold: 7.8294e-8 + }, + { + automation: 'setTargetAtTime', + time: curveDuration, + threshold: 1.5895e-7 + }, + { + automation: 'setTargetAtTime', + time: curveDuration + 0.5 / sampleRate, + extraDuration: 0.5 / sampleRate, + threshold: 1.3278e-7 + } + ]; - // Define tests from the configs - for (k in testConfigs) { - audit.define(k + ': ' + testConfigs[k].automation, (function(config) { - return (task, should) => { - runTest(should, config).then(() => task.done()); - }; - })(testConfigs[k])); - } + testConfigs.forEach((config, index) => { + const title = + `Automation after setValueCurve: ${config.automation} ` + + ` (config ${index + 1})`; + promise_test(async t => { + await runTest(config); + }, title); + }); - audit.run(); + async function runTest(options) { + // For the test, use a gain node with a constant input to test the + // automations. + const context = new OfflineAudioContext(1, testDurationFrames, sampleRate); - function runTest(should, options) { - // For the test, use a gain node with a constant input to test the - // automations. - let context = - new OfflineAudioContext(1, testDurationFrames, sampleRate); - let source = context.createBufferSource(); - source.buffer = createConstantBuffer(context, 1, 1); - source.loop = true; + const source = context.createBufferSource(); + source.buffer = createConstantBuffer(context, 1, 1); + source.loop = true; - let gain = context.createGain(); + const gain = context.createGain(); - // Any valid curve is ok. We only use the last value for testing. - let curve = [0, 2, 0.3]; - let actualDuration = curveDuration + (options.extraDuration || 0); - gain.gain.setValueCurveAtTime( - Float32Array.from(curve), 0, actualDuration); + // Any valid curve is ok. We only use the last value for testing. + const curve = [0, 2, 0.3]; + const actualDuration = curveDuration + (options.extraDuration || 0); + gain.gain.setValueCurveAtTime(Float32Array.from(curve), 0, actualDuration); - // Run the desired test automation. The extra parameter (0.01) is only - // used for setTargetAtTime tests; it's ignored for other tests. - let automationValue = 2; - gain.gain[options.automation](automationValue, options.time, 0.01); + // Run the desired test automation. The extra parameter (0.01) is only + // used for setTargetAtTime tests; it's ignored for other tests. + const automationValue = 2; + gain.gain[options.automation](automationValue, options.time, 0.01); - source.connect(gain); - gain.connect(context.destination); + source.connect(gain).connect(context.destination); + source.start(); - source.start(); + const resultBuffer = await context.startRendering(); + const result = resultBuffer.getChannelData(0); - return context.startRendering().then(function(resultBuffer) { - let result = resultBuffer.getChannelData(0); + // Only need to verify that the ramp started at the right + // value. Figure the nearest sample frame to the end curve. + const curveEndFrame = Math.ceil(actualDuration * sampleRate); + const curveEndTime = curveEndFrame / sampleRate; + const finalCurveValue = curve[curve.length - 1]; - // Only need to verify that the ramp started at the right - // value. Figure the nearest sample frame to the end curve. - let curveEndFrame = Math.ceil(actualDuration * sampleRate); + let expectedResult; + // Determine the expected value after the end of the setValueCurve + // event. + if (options.automation === 'linearRampToValueAtTime') { + expectedResult = audioParamLinearRamp( + curveEndTime, finalCurveValue, actualDuration, + automationValue, testDurationSec + ); + } else if (options.automation === 'exponentialRampToValueAtTime') { + expectedResult = audioParamExponentialRamp( + curveEndTime, finalCurveValue, actualDuration, + automationValue, testDurationSec + ); + } else if (options.automation === 'setTargetAtTime') { + expectedResult = audioParamSetTarget( + curveEndTime, finalCurveValue, actualDuration, + automationValue, 0.01 + ); + } - let expectedResult = curve[curve.length - 1]; + const message = + `After setValueCurveAtTime(..., 0, ${actualDuration}), ` + + `${options.automation}(2, ${options.time}` + + `${options.automation === 'setTargetAtTime' ? ', 0.01' : ''})`; - // Determine the expected value after the end of the setValueCurve - // event. - if (options.automation == 'linearRampToValueAtTime') { - expectedResult = audioParamLinearRamp( - curveEndFrame / sampleRate, curve[curve.length - 1], - actualDuration, automationValue, testDurationSec); - } else if (options.automation == 'exponentialRampToValueAtTime') { - expectedResult = audioParamExponentialRamp( - curveEndFrame / sampleRate, curve[curve.length - 1], - actualDuration, automationValue, testDurationSec); - } else if (options.automation == 'setTargetAtTime') { - expectedResult = audioParamSetTarget( - curveEndFrame / sampleRate, curve[curve.length - 1], - actualDuration, automationValue, 0.01); - } + assert_approx_equals( + result[curveEndFrame], expectedResult, + options.threshold || 0, + `${message} — expected value ≈ ${expectedResult} at time ${curveEndTime}` + ); + } - let message = 'setValueCurve(..., ' + 0 + ', ' + actualDuration + - ').' + options.automation + '(2, ' + testDurationSec; - - if (options.automation == 'setTargetAtTime') - message += ', 0.01'; - message += ')'; - - should( - result[curveEndFrame], - message + ': value at time ' + curveEndFrame / sampleRate) - .beCloseTo(expectedResult, {threshold: options.threshold || 0}); - }); - } - - function linearRampValue(t, t0, v0, t1, v1) { - return v0 + (v1 - v0) * (t - t0) / (t1 - t0); - } - - function exponentialRampValue(t, t0, v0, t1, v1) { - return v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0)); - } - - function setTargetValue(t, t0, v0, v1, timeConstant) { - return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant) - } - </script> - </body> +</script> +</body> </html>
diff --git a/third_party/cros-components/src b/third_party/cros-components/src index 97dc8c7..e7f1a1f 160000 --- a/third_party/cros-components/src +++ b/third_party/cros-components/src
@@ -1 +1 @@ -Subproject commit 97dc8c7a1df880206cc54d9913a7e9d73677072a +Subproject commit e7f1a1f42262790f48a9b69761c6c3e45ef225ca
diff --git a/third_party/skia b/third_party/skia index e84f5ed..d37ac42 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit e84f5ed7d152063a4efd1399eb379305ebe5d3d6 +Subproject commit d37ac42bd8d6ff5a91f6bef83a09260524cae274
diff --git a/tools/clang/spanify/SpanifyManualPathsToIgnore.h b/tools/clang/spanify/SpanifyManualPathsToIgnore.h index ec3e8995..5808b97 100644 --- a/tools/clang/spanify/SpanifyManualPathsToIgnore.h +++ b/tools/clang/spanify/SpanifyManualPathsToIgnore.h
@@ -166,6 +166,18 @@ // Included inside a class declaration. Adding top-level #includes (e.g., // for span.h, <vector>) here will cause compilation errors. "gpu/command_buffer/client/gles2_interface_autogen.h", + + // This test seems to deliberately go out of bounds into other contiguous + // regions of memory. + "remoting/base/typed_buffer_unittest.cc", + + // This test is explicitly testing unsafe buffers. + "base/unsafe_buffers_unittest.cc", + + // This test does weird things having a heap of size zero, allocating it + // somewhere else and then assuming they can index it without knowing the + // bounds. + "third_party/blink/renderer/platform/heap/test/heap_test.cc", }; #endif // TOOLS_CLANG_SPANIFY_SPANIFYMANUALPATHSTOIGNORE_H_
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 1d4c07c..9f842db 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -10044,7 +10044,6 @@ <int value="-1473878093" label="HideArcMediaNotifications:disabled"/> <int value="-1473668019" label="token-binding:disabled"/> <int value="-1473537658" label="DeprecateLowUsageCodecs:disabled"/> - <int value="-1473179394" label="CrOSLateBootCameraAngleBackend:enabled"/> <int value="-1473136627" label="enable-web-payments"/> <int value="-1472825316" label="ContextualSearchLongpressResolve:enabled"/> <int value="-1472171434" label="HistoryPageHistorySyncPromo:disabled"/> @@ -16400,7 +16399,6 @@ <int value="880510010" label="enable-permissions-bubbles"/> <int value="880552542" label="ImeUsEnglishModelUpdate:enabled"/> <int value="880638328" label="DriveFsShowCSEFiles:enabled"/> - <int value="881202472" label="CrOSLateBootCameraAngleBackend:disabled"/> <int value="881920916" label="CrosWebAppInstallDialog:disabled"/> <int value="882103442" label="FloatWindow:disabled"/> <int value="882893584" label="UseOfHashAffiliationFetcher:disabled"/>
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml index 95468c5a9..580f701 100644 --- a/tools/metrics/histograms/metadata/blink/enums.xml +++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -6235,6 +6235,7 @@ <int value="5602" label="HTMLCanvasElementLowLatency_WebGL"/> <int value="5603" label="HTMLCanvasElementLowLatency_WebGL_Preserve"/> <int value="5604" label="HTMLCanvasElementLowLatency_WebGL_Discard"/> + <int value="5605" label="AnimatedImageUsedMoreThanOnce"/> </enum> <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) -->
diff --git a/tools/metrics/histograms/metadata/cros_ml/histograms.xml b/tools/metrics/histograms/metadata/cros_ml/histograms.xml index a7d75dc..139fcab 100644 --- a/tools/metrics/histograms/metadata/cros_ml/histograms.xml +++ b/tools/metrics/histograms/metadata/cros_ml/histograms.xml
@@ -5,7 +5,7 @@ --> <!-- -This file is used to generate a comprehensive list of Power histograms +This file is used to generate a comprehensive list of ML Service histograms along with a detailed description for each histogram. For best practices on writing histogram descriptions, see @@ -201,7 +201,7 @@ <histogram name="MachineLearningService.MlCore.DlcFinalInstallResult" enum="MachineLearningServiceDlcFinalInstallResult" - expires_after="2025-08-01"> + expires_after="2026-02-01"> <owner>amoylan@chromium.org</owner> <owner>chenjih@google.com</owner> <owner>nbowe@chromium.org</owner> @@ -360,7 +360,7 @@ <histogram name="MachineLearningService.{ModelName}.CreateGraphExecutorResult.Event" enum="MachineLearningServiceCreateGraphExecutorResultEvent" - expires_after="2025-08-01"> + expires_after="2026-02-01"> <owner>amoylan@chromium.org</owner> <owner>alanlxl@chromium.org</owner> <summary> @@ -371,7 +371,7 @@ </histogram> <histogram name="MachineLearningService.{ModelName}.ExecuteResult.Event" - enum="MachineLearningServiceExecuteResultEvent" expires_after="2025-08-24"> + enum="MachineLearningServiceExecuteResultEvent" expires_after="2026-02-01"> <owner>amoylan@chromium.org</owner> <owner>alanlxl@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/net/enums.xml b/tools/metrics/histograms/metadata/net/enums.xml index 5e7988d..19a3868b8c 100644 --- a/tools/metrics/histograms/metadata/net/enums.xml +++ b/tools/metrics/histograms/metadata/net/enums.xml
@@ -2990,6 +2990,7 @@ <int value="7" label="Using existing SPDY session"/> <int value="8" label="Using existing QUIC session"/> <int value="9" label="Abort"/> + <int value="10" label="AttemptManagerDraining"/> </enum> <!-- LINT.ThenChange(//net/socket/stream_socket_close_reason.h:StreamSocketCloseReason) -->
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 65ae014..e6469ea 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -3401,6 +3401,7 @@ Recorded for each stream attempt upon destruction of the canceled attempt. </summary> <token key="Reason"> + <variant name="AttemptManagerDraining"/> <variant name="ExistingQuicSession"/> <variant name="ExistingSpdySession"/> <variant name="NewQuicSession"/>
diff --git a/tools/metrics/histograms/metadata/password/enums.xml b/tools/metrics/histograms/metadata/password/enums.xml index f7f3cda..2718b83 100644 --- a/tools/metrics/histograms/metadata/password/enums.xml +++ b/tools/metrics/histograms/metadata/password/enums.xml
@@ -767,6 +767,8 @@ <!-- LINT.ThenChange(/chrome/browser/ui/passwords/password_change_ui_controller.h:PasswordChangeDialogAction) --> +<!-- LINT.IfChange(PasswordChangeFlowState) --> + <enum name="PasswordChangeFlowState"> <int value="0" label="Offering password change"/> <int value="1" label="Waiting for privacy notice acceptance"/> @@ -775,8 +777,12 @@ <int value="4" label="Changing password"/> <int value="5" label="Password successfully changed"/> <int value="6" label="Password change failed"/> + <int value="7" label="OTP detected"/> + <int value="8" label="Canceled by the user"/> </enum> +<!-- LINT.ThenChange(/chrome/browser/password_manager/password_change_delegate.h) --> + <!-- LINT.IfChange(PasswordChangeToastEvent) --> <enum name="PasswordChangeToastEvent">
diff --git a/ui/gfx/display_color_spaces.cc b/ui/gfx/display_color_spaces.cc index aa7add2..7b310ec 100644 --- a/ui/gfx/display_color_spaces.cc +++ b/ui/gfx/display_color_spaces.cc
@@ -10,6 +10,7 @@ #include "ui/gfx/display_color_spaces.h" #include <array> +#include <cmath> #include "build/build_config.h" #include "skia/ext/skcolorspace_primaries.h" @@ -132,6 +133,10 @@ hdr_max_luminance_relative_ > 1.f; } +float DisplayColorSpaces::GetHdrHeadroom() const { + return std::log2(hdr_max_luminance_relative_); +} + ColorSpace DisplayColorSpaces::GetScreenInfoColorSpace() const { return GetOutputColorSpace(ContentColorUsage::kHDR, false /* needs_alpha */); }
diff --git a/ui/gfx/display_color_spaces.h b/ui/gfx/display_color_spaces.h index 0592fa49..9094eca 100644 --- a/ui/gfx/display_color_spaces.h +++ b/ui/gfx/display_color_spaces.h
@@ -95,6 +95,9 @@ return hdr_max_luminance_relative_; } + // Returns log2 of GetHDRMaxLuminanceRelative. + float GetHdrHeadroom() const; + // TODO(crbug.com/40144904): These helper functions exist temporarily // to handle the transition of display::ScreenInfo off of ColorSpace. All // calls to these functions are to be eliminated.